from parser import AdjacencyListParser, AdjacencyMatrixParser, IncidenceMatrixParser
import plot as gp

import random as rd
import sys

class GraphException(Exception):
    pass

class Graph:
    def _read(self, file_name):
        print("Opening file '{}'...".format(file_name))
        with open(file_name, mode="rt", encoding="utf-8") as file:
            lines = file.read().splitlines()

        lines = self._remove_comments(lines)
        graph_type, args = self._read_type_and_args(lines[0])

        self._parser = self._get_parser(graph_type, args)
        self._graph_data, self._nodes = self._parser.parse_data(lines[1:])

    def convert(self, file_name):
        self._read(file_name)
        self._parser.write_data(file_name, self._graph_data)

    def display(self, file_name):
        pass
        self._read(file_name)
        gp.make_plot(self._graph_data)

    def generate(self, file_name, nodes_num, edges_or_probability):
        suffix = edges_or_probability[-1]
        if suffix == "e":
            self._gen_edges(file_name, nodes_num, int(edges_or_probability[:-1]))
        elif suffix == "p":
            self._gen_probability(file_name, nodes_num, float(edges_or_probability[:-1]))
        else:
            raise ValueError("invalid suffix in '{}'".format(edges_or_probability))

    def _gen_edges(self, file_name, nodes_num, edges_num):
        # create empty incidence matrix
        matrix = [[0 for edge in range(edges_num)] for node in range(nodes_num)]
        for edge in range(edges_num):
            values_changed = 0
            while values_changed != 2: # check if edge has been set
                node = rd.randrange(nodes_num)

                if matrix[node][edge] == 1:
                    continue
                matrix[node][edge] = 1
                values_changed += 1

        # write incidence matrix
        with open(file_name, mode="wt", encoding="utf-8") as file:
            file.write("incidence-matrix: {} {}\n\n".format(nodes_num, edges_num))
            node_no = 1
            for row in matrix:
                file.write("{} : {}\n".format(node_no,
                                              " ".join(str(node) for node in row)))
                node_no += 1

    def _gen_probability(self, file_name, nodes_num, prob):
        if prob < 0.0: prob = 0.0
        elif prob > 1.0: prob = 1.0

        # create empty adjacency matrix
        matrix = [[0 for node in range(nodes_num)] for node in range(nodes_num)]
        for y in range(nodes_num):
            for x in range(y + 1, nodes_num):
                if rd.random() <= prob:
                    matrix[x][y] = matrix[y][x] = 1

        # write adjacency matrix
        with open(file_name, mode="wt", encoding="utf-8") as file:
            file.write("adjacency-matrix: {}\n\n".format(nodes_num))
            node_no = 1
            for row in matrix:
                file.write("{} : {}\n".format(node_no,
                                              " ".join(str(node) for node in row)))
                node_no += 1

    def _remove_comments(self, lines):
        stripped_lines = []
        for line in lines:
            line, _, _ = line.strip().partition("#")
            if len(line) > 0:
                stripped_lines.append(line)

        return stripped_lines

    def _read_type_and_args(self, header_line):
        ret = header_line.split(":")
        return ret[0], ret[1]

    def _get_parser(self, graph_type, args):
        if graph_type == "adjacency-list":
            return AdjacencyListParser(int(args))
        elif graph_type == "adjacency-matrix":
            return AdjacencyMatrixParser(int(args))
        elif graph_type == "incidence-matrix":
            sizes = args.split()
            return IncidenceMatrixParser(int(sizes[0]), int(sizes[1]))
        else:
            raise GraphException("unknown graph representation")

def print_help():
    print("usage: python {} <command> <file_name> [nodes] [extra]".format(sys.argv[0]))
    print("available commands:")
    print("'convert'  -- converts <file_name> to remaining representations")
    print("'display'  -- display graph from <file_name>")
    print("'generate' -- generate graph based upon [extra] with [nodes] nodes")
    print("              [extra] is either number of edges, e.g. '10e'")
    print("              or probability that edge exists between nodes, e.g. '0.5p'")
    sys.exit(1)

if __name__ == "__main__":
    if len(sys.argv) < 3 or sys.argv[1] == "help":
        print_help()

    g = Graph()
    if sys.argv[1] == "convert":
        g.convert(sys.argv[2])
    elif sys.argv[1] == "display":
        g.display(sys.argv[2])
    elif sys.argv[1] == "generate":
        if len(sys.argv) < 5:
            print_help()
        g.generate(sys.argv[2], int(sys.argv[3]), sys.argv[4])


class Characters:
    def Properties(self, name, phrase1, phrase2):
        self.name=name
        self.phrase1=phrase1
        self.phrase2=phrase2
        self.level=0

    def speak(self, PhraseNumber):
        if PhraseNumber==1:
            print(self.phrase1)
        elif PhraseNumber==2:
            print(self.phrase2)

    def setLevel(self, newLevel):
        self.level=newLevel
        print(self.level)

kungfupanda=Characters()
kungfupanda.Properties("Kung Fu Panda", "Skadoosh", "You have been blinded by pure awesomeness!")
spiderman=Characters()
spiderman.Properties("Spiderman", "Your friendly neighbourhood spiderman.", "Kachow!")

kungfupanda.speak(1)
spiderman.setLevel(2)
spiderman.speak(2)

input("Press enter to finish.")


import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from sklearn.metrics import confusion_matrix

mat = confusion_matrix(y_teste,pred)

axes = sns.heatmap(mat,square=True, annot=True,fmt='d',
                   cbar=True, cmap=plt.cm.Blues)

class_labels = ['Benign','Attack' ]  # Exemplo Principal

axes.set_xlabel('Model Actual')
axes.set_ylabel('Model Prediction')

tick_marks = np.arange(len(class_labels)) + 0.5

axes.set_xticks(tick_marks)
axes.set_xticklabels(class_labels, rotation=90)

axes.set_yticks(tick_marks)
axes.set_yticklabels(class_labels,rotation=0)

axes.set_title('Confusion Matrix')


import process_data
import select_feature
import numpy as np
import pandas as pd
import pickle
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.pipeline import Pipeline
from sklearn.naive_bayes import MultinomialNB
from sklearn.linear_model import  LogisticRegression
from sklearn.linear_model import SGDClassifier
from sklearn import svm
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import KFold
from sklearn.metrics import confusion_matrix, f1_score, classification_report
from sklearn.model_selection import GridSearchCV
from sklearn.model_selection import learning_curve
import matplotlib.pyplot as plt
from sklearn.metrics import precision_recall_curve
from sklearn.metrics import average_precision_score

#string to test
doc_new = ['Trump is running for president in 2016']

#building classifier using naive bayes
nb_pipeline = Pipeline([
        ('NBCV',select_feature.countV),
        ('nb_clf',MultinomialNB())])

nb_pipeline.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_nb = nb_pipeline.predict(process_data.test_news['Statement'])
np.mean(predicted_nb == process_data.test_news['Label'])

#building classifier using logistic regression
logR_pipeline = Pipeline([
        ('LogRCV',select_feature.countV),
        ('LogR_clf',LogisticRegression(max_iter=10000))
        ])

logR_pipeline.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_LogR = logR_pipeline.predict(process_data.test_news['Statement'])
np.mean(predicted_LogR == process_data.test_news['Label'])

#building Linear SVM classfier
svm_pipeline = Pipeline([
        ('svmCV',select_feature.countV),
        ('svm_clf',svm.LinearSVC())
        ])

svm_pipeline.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_svm = svm_pipeline.predict(process_data.test_news['Statement'])
np.mean(predicted_svm == process_data.test_news['Label'])

#using SVM Stochastic Gradient Descent on hinge loss
sgd_pipeline = Pipeline([
        ('svm2CV',select_feature.countV),
        # ('svm2_clf',SGDClassifier(loss='hinge', penalty='l2', alpha=1e-3, n_iter=10))
        ('svm2_clf',SGDClassifier(loss='hinge', penalty='l2', alpha=1e-3))
        ])

sgd_pipeline.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_sgd = sgd_pipeline.predict(process_data.test_news['Statement'])
np.mean(predicted_sgd == process_data.test_news['Label'])

#random forest
random_forest = Pipeline([
        ('rfCV',select_feature.countV),
        ('rf_clf',RandomForestClassifier(n_estimators=200, n_jobs=3))
        ])

random_forest.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_rf = random_forest.predict(process_data.test_news['Statement'])
np.mean(predicted_rf == process_data.test_news['Label'])

#User defined functon for K-Fold cross validatoin
def create_confusion_matrix(classifier):

    k_fold = KFold(n_splits=5)
    scores = []
    confusion = np.array([[0,0],[0,0]])
    for train_ind, test_ind in k_fold.split(process_data.train_news):
        train_text = process_data.train_news.iloc[train_ind]['Statement']
        train_y = process_data.train_news.iloc[train_ind]['Label']

        test_text = process_data.train_news.iloc[test_ind]['Statement']
        test_y = process_data.train_news.iloc[test_ind]['Label']

        classifier.fit(train_text,train_y)
        predictions = classifier.predict(test_text)

        confusion += confusion_matrix(test_y,predictions)
        score = f1_score(test_y,predictions)
        scores.append(score)

    return (print('Total statements classified:', len(process_data.train_news)),
    print('Score:', sum(scores)/len(scores)),
    print('score length', len(scores)),
    print('Confusion matrix:'),
    print(confusion))

print('---------------------Bag of Words---------------------')
create_confusion_matrix(nb_pipeline)
create_confusion_matrix(logR_pipeline)
create_confusion_matrix(svm_pipeline)
create_confusion_matrix(sgd_pipeline)
create_confusion_matrix(random_forest)

#using n-grams
#naive-bayes classifier
nb_pipeline_ngram = Pipeline([
        ('nb_tfidf',select_feature.tfidf_ngram),
        ('nb_clf',MultinomialNB())])

nb_pipeline_ngram.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_nb_ngram = nb_pipeline_ngram.predict(process_data.test_news['Statement'])
np.mean(predicted_nb_ngram == process_data.test_news['Label'])

#logistic regression classifier
logR_pipeline_ngram = Pipeline([
        ('LogR_tfidf',select_feature.tfidf_ngram),
        ('LogR_clf',LogisticRegression(penalty="l2",C=1))
        ])

logR_pipeline_ngram.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_LogR_ngram = logR_pipeline_ngram.predict(process_data.test_news['Statement'])
np.mean(predicted_LogR_ngram == process_data.test_news['Label'])

#linear SVM classifier
svm_pipeline_ngram = Pipeline([
        ('svm_tfidf',select_feature.tfidf_ngram),
        ('svm_clf',svm.LinearSVC())
        ])

svm_pipeline_ngram.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_svm_ngram = svm_pipeline_ngram.predict(process_data.test_news['Statement'])
np.mean(predicted_svm_ngram == process_data.test_news['Label'])

#sgd classifier
sgd_pipeline_ngram = Pipeline([
         ('sgd_tfidf',select_feature.tfidf_ngram),
         ('sgd_clf',SGDClassifier(loss='hinge', penalty='l2', alpha=1e-3))
         ])

sgd_pipeline_ngram.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_sgd_ngram = sgd_pipeline_ngram.predict(process_data.test_news['Statement'])
np.mean(predicted_sgd_ngram == process_data.test_news['Label'])

#random forest classifier
random_forest_ngram = Pipeline([
        ('rf_tfidf',select_feature.tfidf_ngram),
        ('rf_clf',RandomForestClassifier(n_estimators=300,n_jobs=3))
        ])

random_forest_ngram.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_rf_ngram = random_forest_ngram.predict(process_data.test_news['Statement'])
np.mean(predicted_rf_ngram == process_data.test_news['Label'])

print('---------------------TFIDF and N-Grams---------------------')

create_confusion_matrix(nb_pipeline_ngram)
create_confusion_matrix(logR_pipeline_ngram)
create_confusion_matrix(svm_pipeline_ngram)
create_confusion_matrix(sgd_pipeline_ngram)
create_confusion_matrix(random_forest_ngram)

print(classification_report(process_data.test_news['Label'], predicted_nb_ngram))
print(classification_report(process_data.test_news['Label'], predicted_LogR_ngram))
print(classification_report(process_data.test_news['Label'], predicted_svm_ngram))
print(classification_report(process_data.test_news['Label'], predicted_sgd_ngram))
print(classification_report(process_data.test_news['Label'], predicted_rf_ngram))

process_data.test_news['Label'].shape

#grid-search parameter optimization
#random forest classifier parameters
parameters = {'rf_tfidf__ngram_range': [(1, 1), (1, 2),(1,3),(1,4),(1,5)],
               'rf_tfidf__use_idf': (True, False),
               'rf_clf__max_depth': (1,2,3,4,5,6,7,8,9,10,11,12,13,14,15)
}

gs_clf = GridSearchCV(random_forest_ngram, parameters, n_jobs=-1)
gs_clf = gs_clf.fit(process_data.train_news['Statement'][:10000],process_data.train_news['Label'][:10000])

gs_clf.best_score_
gs_clf.best_params_
gs_clf.cv_results_

#logistic regression parameters
parameters = {'LogR_tfidf__ngram_range': [(1, 1), (1, 2),(1,3),(1,4),(1,5)],
               'LogR_tfidf__use_idf': (True, False),
               'LogR_tfidf__smooth_idf': (True, False)
}

gs_clf = GridSearchCV(logR_pipeline_ngram, parameters, n_jobs=-1)
gs_clf = gs_clf.fit(process_data.train_news['Statement'][:10000],process_data.train_news['Label'][:10000])

gs_clf.best_score_
gs_clf.best_params_
gs_clf.cv_results_

#Linear SVM
parameters = {'svm_tfidf__ngram_range': [(1, 1), (1, 2),(1,3),(1,4),(1,5)],
               'svm_tfidf__use_idf': (True, False),
               'svm_tfidf__smooth_idf': (True, False),
               'svm_clf__penalty': ('l1','l2'),
}

gs_clf = GridSearchCV(svm_pipeline_ngram, parameters, n_jobs=-1)
gs_clf = gs_clf.fit(process_data.train_news['Statement'][:10000],process_data.train_news['Label'][:10000])

#finding the model with best performing parameters
gs_clf.best_score_
gs_clf.best_params_
gs_clf.cv_results_

#running both random forest and logistic regression models again with best parameter found with GridSearch method
random_forest_final = Pipeline([
        ('rf_tfidf',TfidfVectorizer(stop_words='english',ngram_range=(1,3),use_idf=True,smooth_idf=True)),
        ('rf_clf',RandomForestClassifier(n_estimators=300,n_jobs=3,max_depth=10))
        ])

random_forest_final.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_rf_final = random_forest_final.predict(process_data.test_news['Statement'])
np.mean(predicted_rf_final == process_data.test_news['Label'])
print(classification_report(process_data.test_news['Label'], predicted_rf_final))

logR_pipeline_final = Pipeline([
        ('LogR_tfidf',TfidfVectorizer(stop_words='english',ngram_range=(1,5),use_idf=True,smooth_idf=False)),
        ('LogR_clf',LogisticRegression(penalty="l2",C=1))
        ])

logR_pipeline_final.fit(process_data.train_news['Statement'],process_data.train_news['Label'])
predicted_LogR_final = logR_pipeline_final.predict(process_data.test_news['Statement'])
np.mean(predicted_LogR_final == process_data.test_news['Label'])
print(classification_report(process_data.test_news['Label'], predicted_LogR_final))

#saving best model to the disk
model_file = 'final_model.sav'
pickle.dump(logR_pipeline_ngram,open(model_file,'wb'))

def find_most_informative_features(model, vect, clf, text=None, n=50):
    # Extract the vectorizer and the classifier from the pipeline
    vectorizer = model.named_steps[vect]
    classifier = model.named_steps[clf]

     # Check to make sure that we can perform this computation
    if not hasattr(classifier, 'coef_'):
        raise TypeError(
            "Cannot compute most informative features on {}.".format(
                classifier.__class__.__name__
            )
        )

    if text is not None:
        # Compute the coefficients for the text
        tvec = model.transform([text]).toarray()
    else:
        # Otherwise simply use the coefficients
        tvec = classifier.coef_

    # Zip the feature names with the coefs and sort
    coefs = sorted(
        zip(tvec[0], vectorizer.get_feature_names()),
        reverse=True
    )

    # Get the top n and bottom n coef, name pairs
    topn  = zip(coefs[:n], coefs[:-(n+1):-1])

    # Create the output string to return
    output = []

    # If text, add the predicted value to the output.
    if text is not None:
        output.append("\"{}\"".format(text))
        output.append(
            "Classified as: {}".format(model.predict([text]))
        )
        output.append("")

    # Create two columns with most negative and most positive features.
    for (cp, fnp), (cn, fnn) in topn:
        output.append(
            "{:0.4f}{: >15}    {:0.4f}{: >15}".format(
                cp, fnp, cn, fnn
            )
        )
    print(output)

find_most_informative_features(logR_pipeline_ngram,vect='LogR_tfidf',clf='LogR_clf')
find_most_informative_features(nb_pipeline_ngram,vect='nb_tfidf',clf='nb_clf')
find_most_informative_features(svm_pipeline_ngram,vect='svm_tfidf',clf='svm_clf')
find_most_informative_features(sgd_pipeline_ngram,vect='sgd_tfidf',clf='sgd_clf')


import sys

my_results_file = sys.argv[1]
file = open(my_results_file, 'r')
test_y = file.read().split('\n')
file.close()
file = open('test_y_correct_labels', 'r')
test_labels = file.read().split('\n')
file.close()
hits = 0
N = len(test_y)
if N != len(test_labels):
    print("Wrong number of predictions!")
else:
    for y, y_hat in zip(test_y, test_labels):
        if y == y_hat:
            hits += 1
print(f'{my_results_file} accuracy is {str(round(hits * 100. / N, 2))}%')


import connection

# Write the first 10 letters next to each other
# Clicking on letters load shows starting with that letter that has more than 20 episodes
# title, year, episode count, actor count
# Page mustn’t reload (so you have to do it with fetch)

@connection.connection_handler
def get_shows_by_letter(cursor, letter):
    query = f"""
    SELECT s.title, s.year, COUNT(e.id) as episode_count
    FROM shows s
    JOIN seasons se ON s.id = se.show_id
    JOIN episodes e ON se.id = e.season_id
    WHERE s.title LIKE '{letter}%'
    GROUP BY s.id, s.title, year
    having COUNT(e.id) > 20"""
    cursor.execute(query)
    return cursor.fetchall()


import threading
import logging

from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.osv import expression

_logger = logging.getLogger(__name__)

class StockPicking(models.Model):
    _inherit = "stock.picking"

    is_hold = fields.Boolean(string='On Hold', help='The transfer is On Hold can not be selected on Packing process in Barcode app')

    def _action_done(self):
        """
        Override _action_done function on picking for processing single wave
        There are 2 cases need to be concern:
        1. Completing picking for single pickings:
            Odoo will insert new record into single_packing_queue to prevent duplication
            between packers when running packing process
        2. Validating packing for single pickings
            Remove record out of single_packing_queue when user validate pack transfer of single picking manually
        """
        res = super(StockPicking, self)._action_done()
        single_packing_queue_env = self.env['single.packing.queue']
        single_pickings = self.filtered(lambda p: p.state == 'done'
                                        and p.is_single_picking
                                        and p.sequence_code == 'PICK')
        if single_pickings:
            existed_pickings_ids = single_packing_queue_env.search([('picking_id', 'in', single_pickings.ids)]).mapped('picking_id')
            vals = [{'product_id': single_picking.move_lines[0].product_id.id,
                     'picking_id': single_picking.id,
                     'shipping_date': single_picking.scheduled_date,
                     'warehouse_id': single_picking.picking_type_id.warehouse_id.id}
                    for single_picking in single_pickings.filtered(lambda p:p.id not in existed_pickings_ids)]
            single_packing_queue_env.create(vals)

        if not self._context.get('not_delete_picking_in_queue', False):
            single_pack_transfers = self.filtered(lambda p: p.state == 'done'
                                                  and p.is_single_picking
                                                  and p.sequence_code == 'OUT')
            if single_pack_transfers:
                single_pick_transfers = single_pack_transfers.mapped('move_lines.move_orig_ids.picking_id')
                single_packing_queue_env.search([('picking_id', 'in', single_pick_transfers.ids)]).unlink()
        return res

    def unhold_picking(self):
        self.ensure_one()
        pick_transfers = self.mapped('move_lines.move_orig_ids').mapped('picking_id')
        for pick_transfer in pick_transfers:
            if pick_transfer.state == 'done' and pick_transfer.is_single_picking and pick_transfer.sequence_code == 'PICK':
                self.env['single.packing.queue'].insert_record(self)

        pick_ship_transfers = pick_transfers + self
        pick_ship_transfers.write({'is_hold': False})

    def action_hold_shipping(self):
        self.ensure_one()
        pick_ship_transfers = self.mapped('move_lines.move_orig_ids').mapped('picking_id') + self
        pick_ship_transfers.sudo().write({'is_hold': True})
        return True

    def prepare_data_shipping_client_action(self):
        transfers = self.mapped('move_lines.move_orig_ids.picking_id') + self
        picking_bins = ','.join(list(filter(lambda b: b, transfers.mapped('picking_bins'))))

        return {
            'pickingID': self.id,
            'isSinglePicking': self.is_single_picking,
            'shippingID': self.id,
            'shipping_weight': self.weight,
            'ship_date': self.scheduled_date,
            'picking_bins': picking_bins.split(',') if picking_bins else [],
            'order': {
                'id': self.sale_id.id,
                'name': self.sale_id.name,
            },
            'moveLines': [{
                'id': move.id,
                'product': {
                    'id': move.product_id.id,
                    'name': move.product_id.name_get()[0][1]
                },
                'quantity_done': move.quantity_done,
                'demand_qty': move.product_uom_qty,
                'uom': move.product_uom.name
            } for move in self.move_lines]
        }

    @api.model
    def get_transfer_for_shipping(self, barcode, is_single_picking=False, shipping_id=None):
        """
        After scanning the product/pin, get the OUT transfer of this product corresponding the PICK transfers in the batch
        """
        if not self.env.user.warehouse_id:
            raise UserError(_("Please set up warehouse in User Settings"))
        record = self.browse()
        # Search Single Picking on Queue to ensure that don't have duplication between packers
        if shipping_id and is_single_picking:
            self.env['single.packing.queue'].insert_record(shipping_id)
        picking = self.env['single.packing.queue'].get_picking(barcode, self.env.user.warehouse_id.id)
        if picking:
            record = picking.mapped('move_lines.move_dest_ids').mapped('picking_id')[:1]
        if not record:
            domain = [('is_single_picking', '=', False),
                      ('is_hold', '=', False),
                      ('picking_type_id.warehouse_id.id', '=', self.env.user.warehouse_id.id),
                      ('picking_bins', 'ilike', barcode)]
            state_domain = expression.OR([[('state', '=', 'assigned'), ('sequence_code', '=', 'OUT')],
                                          [('state', '=', 'done'), ('sequence_code', '=', 'PICK')]])
            domain = expression.AND([domain, state_domain])

            records = self.sudo().search(domain, order='date_deadline asc')

            for rec in records:
                picking_bins = rec.picking_bins or ''
                if barcode in map(lambda s: s.strip(), picking_bins.split(',')):
                    if rec.sequence_code == 'PICK':
                        rec = rec.mapped('move_lines.move_dest_ids').mapped('picking_id')[:1]
                    if rec.state not in ('cancel', 'done'):
                        record = rec
                        break
        if not record:
            return None

        return record.prepare_data_shipping_client_action()

    def done_and_print_label(self):
        """This method will be called when packer completed packaging for shipment
        Validating shipment will be run in background for performance purpose
        """
        self.ensure_one()
        todo_move_lines = self.move_lines.filtered(lambda m: m.product_uom_qty > m.reserved_availability)
        if todo_move_lines:
            return {
                'success': False,
                'error_message': 'Cannot validate partially picked orders.',
            }

        move_lines = [(1, m.id, {'quantity_done': m.product_uom_qty}) for m in self.move_lines]
        self.sudo().write({'move_lines': move_lines})

        def action_done():
            ctx = {
                'done_ship_transfer': True,
                'not_delete_picking_in_queue': True
            }
            threaded_sending = threading.Thread(target=self.with_context(ctx).async_action_done, kwargs={'ids': self.ids})
            threaded_sending.start()

        self.env.cr.postcommit.add(action_done)

        # Clear picking bins on all picking and packing after printing label
        transfers = self.mapped('move_lines.move_orig_ids').mapped('picking_id') + self
        transfers.sudo().write({'picking_bins': False})

        return {'success': True}

    def get_order_ref(self):
        self.ensure_one()
        return self.origin


# coding: UTF-8
"""
Created on 2016/01/12

@author: Yang Wanjun
"""
import datetime
import uuid
import StringIO

from django.db.models import Q, Max, Prefetch
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.contrib.humanize.templatetags import humanize
from django.utils import timezone
from django.core.urlresolvers import reverse

from utils import common, errors, constants
from eb import models
from . import biz_config
from eboa import models as eboa_models
from contract import models as contract_models

def get_batch_manage(name):
    """バッチ名によてバッチを取得する。

    :param name: バッチ名
    :return:
    """
    try:
        return models.BatchManage.objects.get(name=name)
    except ObjectDoesNotExist:
        return None

def is_salesperson_user(user):
    """該当するユーザーは営業員なのか

    :param user:
    :return:
    """
    if hasattr(user, 'salesperson'):
        return True
    else:
        return False

def get_bp_next_employee_id():
    """自動採番するため、次に使う番号を取得する。

    これは最終的に使う社員番号ではありません。
    実際の番号は追加後の主キーを使って、設定しなおしてから、もう一回保存する 。

    :return: string
    """
    max_id = models.Member.objects.all().aggregate(Max('id'))
    max_id = max_id.get('id__max', None)
    if max_id:
        return 'BP%05d' % (int(max_id) + 1,)
    else:
        return ''

def get_company():
    company_list = models.Company.objects.all()
    if company_list.count() == 0:
        return None
    else:
        return company_list[0]

def get_admin_user():
    try:
        return User.objects.get(username='admin')
    except ObjectDoesNotExist:
        return None

def get_year_list():
    start = biz_config.get_year_start()
    end = biz_config.get_year_end()
    return range(int(start), int(end))

def get_members_by_section(all_members, section_id):
    if not section_id:
        return all_members
    today = datetime.date.today()
    return all_members.filter((Q(membersectionperiod__start_date__lte=today) &
                               Q(membersectionperiod__end_date__isnull=True)) |
                              (Q(membersectionperiod__start_date__lte=today) &
                               Q(membersectionperiod__end_date__gte=today)),
                              Q(membersectionperiod__division__pk=section_id) |
                              Q(membersectionperiod__section__pk=section_id) |
                              Q(membersectionperiod__subsection__pk=section_id),
                              membersectionperiod__is_deleted=False)

def get_members_by_salesperson(all_members, salesperson_id):
    if not salesperson_id:
        return all_members
    today = datetime.date.today()
    return all_members.filter((Q(membersalespersonperiod__start_date__lte=today) &
                               Q(membersalespersonperiod__end_date__isnull=True)) |
                              (Q(membersalespersonperiod__start_date__lte=today) &
                               Q(membersalespersonperiod__end_date__gte=today)),
                              membersalespersonperiod__salesperson__pk=salesperson_id,
                              membersalespersonperiod__is_deleted=False)

def get_project_members_by_section(project_members, section_id, date):
    return project_members.filter((Q(member__membersectionperiod__start_date__lte=date) &
                                   Q(member__membersectionperiod__end_date__isnull=date)) |
                                  (Q(member__membersectionperiod__start_date__lte=date) &
                                   Q(member__membersectionperiod__end_date__gte=date)),
                                  Q(member__membersectionperiod__division__pk=section_id) |
                                  Q(member__membersectionperiod__section__pk=section_id) |
                                  Q(member__membersectionperiod__subsection__pk=section_id),
                                  member__membersectionperiod__is_deleted=False).distinct()

def get_project_members_by_salesperson(project_members, salesperson_id, date):
    return project_members.filter((Q(member__membersalespersonperiod__start_date__lte=date) &
                                   Q(member__membersalespersonperiod__end_date__isnull=date)) |
                                  (Q(member__membersalespersonperiod__start_date__lte=date) &
                                   Q(member__membersalespersonperiod__end_date__gte=date)),
                                  member__membersalespersonperiod__salesperson__pk=salesperson_id,
                                  member__membersalespersonperiod__is_deleted=False).distinct()

def get_on_sales_top_org():
    """営業対象のトップレベルの部署を取得する

    :return:
    """
    return models.Section.objects.public_filter(is_on_sales=True, parent__isnull=True)

def get_on_sales_section():
    """営業対象の部署を取得する。

    :return:
    """
    return models.Section.objects.public_filter(is_on_sales=True)

def get_members_in_coming():
    """新規入場要員リストを取得する。

    :return:
    """
    today = datetime.date.today()
    return models.Member.objects.public_filter(join_date__gt=today)

def get_subcontractor_all_members():
    """すべての協力社員を取得する。

    :return:
    """
    return models.get_sales_members().filter(subcontractor__isnull=False)

def get_subcontractor_sales_members():
    """すべての協力社員を取得する。

    :return:
    """
    return get_subcontractor_all_members().filter(is_on_sales=True)

def get_subcontractor_working_members(date=None):
    """対象月の稼働中の協力社員を取得する。

    :param date: 対象年月
    :return:
    """
    if not date:
        first_day = last_day = datetime.date.today()
    else:
        first_day = common.get_first_day_by_month(date)
        last_day = common.get_last_day_by_month(date)

    return get_subcontractor_sales_members().filter(projectmember__start_date__lte=last_day,
                                                    projectmember__end_date__gte=first_day,
                                                    projectmember__is_deleted=False,
                                                    projectmember__status=2).distinct()

def get_subcontractor_waiting_members(date=None):
    """対象月の待機中の協力社員を取得する

    :param date: 対象年月
    :return:
    """
    working_members = get_subcontractor_working_members(date)
    return get_subcontractor_sales_members().exclude(pk__in=working_members)

def get_subcontractor_off_sales_members():
    """営業対象外の協力社員を取得する。

    :return:
    """
    return get_subcontractor_all_members().filter(is_on_sales=False)

def get_members_section(section):
    all_members = models.get_sales_members()
    return get_members_by_section(all_members, section.id)

def get_business_partner_members():
    """BPメンバーを取得する

    :return:
    """
    today = datetime.date.today()
    # 現在所属の営業員を取得
    sales_set = models.MemberSalespersonPeriod.objects.filter((Q(start_date__lte=today) & Q(end_date__isnull=True)) |
                                                              (Q(start_date__lte=today) & Q(end_date__gte=today)))
    # 現在の案件
    project_member_set = models.ProjectMember.objects.public_filter(
        start_date__lte=today,
        end_date__gte=today,
        status=2
    )

    queryset = models.Member.objects.filter(
        subcontractor__isnull=False
    ).select_related('subcontractor').order_by('subcontractor')
    return queryset.prefetch_related(
        Prefetch('membersalespersonperiod_set', queryset=sales_set, to_attr='current_salesperson_period'),
        Prefetch('projectmember_set', queryset=project_member_set, to_attr='current_project_member'),
    )

def get_business_partner_members_with_contract():
    queryset = get_business_partner_members()
    contract_set = contract_models.BpContract.objects.public_all().order_by('-start_date')

    return queryset.prefetch_related(
        Prefetch('bpcontract_set', queryset=contract_set, to_attr='latest_contract_set'),
    )

def get_project_members_month_section(section, date, user=None):
    """該当する日付に指定された部署に配属される案件メンバーを取得する。

    :param section: 部署
    :param date: 日付
    :param user:
    :return:
    """
    project_members = models.get_project_members_by_month(date)
    # 出勤情報を取得する
    current_attendance_set = models.MemberAttendance.objects.filter(year="%04d" % date.year,
                                                                    month="%02d" % date.month,
                                                                    is_deleted=False)
    prev_month = common.add_months(date, months=-1)
    prev_attendance_set = models.MemberAttendance.objects.filter(year="%04d" % prev_month.year,
                                                                 month="%02d" % prev_month.month,
                                                                 is_deleted=False)
    # 請求明細情報
    project_request_detail_set = models.ProjectRequestDetail.objects.filter(
        project_request__year="%04d" % date.year,
        project_request__month="%02d" % date.month
    )
    all_children = section.get_children()
    org_pk_list = [org.pk for org in all_children]
    org_pk_list.append(section.pk)

    queryset = project_members.filter((Q(member__membersectionperiod__start_date__lte=date) &
                                       Q(member__membersectionperiod__end_date__isnull=date)) |
                                      (Q(member__membersectionperiod__start_date__lte=date) &
                                       Q(member__membersectionperiod__end_date__gte=date)),
                                      Q(member__membersectionperiod__division__in=org_pk_list) |
                                      Q(member__membersectionperiod__section__in=org_pk_list) |
                                      Q(member__membersectionperiod__subsection__in=org_pk_list),
                                      member__membersectionperiod__is_deleted=False).distinct().prefetch_related(
        Prefetch('member'),
        Prefetch('project'),
        Prefetch('memberattendance_set', queryset=current_attendance_set, to_attr='current_attendance_set'),
        Prefetch('memberattendance_set', queryset=prev_attendance_set, to_attr='prev_attendance_set'),
        Prefetch('projectrequestdetail_set', queryset=project_request_detail_set, to_attr='project_request_detail_set'),
    )
    # 待機案件
    first_day = common.get_first_day_by_month(date)
    last_day = common.get_last_day_by_month(date)
    queryset2 = models.ProjectMember.objects.public_filter(end_date__gte=first_day,
                                                           start_date__lte=last_day,
                                                           project__status=4,
                                                           status=2,
                                                           project__is_reserve=True,
                                                           project__department__in=org_pk_list
                                                           ).distinct().prefetch_related(
        Prefetch('member'),
        Prefetch('project'),
    )

    return queryset | queryset2

def get_lump_projects_by_section(section, date):
    all_children = section.get_children()
    all_children = list(all_children)
    all_children.append(section)
    first_day = common.get_first_day_by_month(date)
    last_day = common.get_last_day_by_month(first_day)

    # 請求情報
    project_request_set = models.ProjectRequest.objects.filter(
        year="%04d" % date.year,
        month="%02d" % date.month
    )
    queryset = models.Project.objects.public_filter(
        is_lump=True,
        department__in=list(all_children),
        start_date__lte=last_day,
        end_date__gte=first_day
    ).distinct().prefetch_related(
        Prefetch('projectrequest_set', queryset=project_request_set, to_attr='project_request_set'),
    )
    return queryset

def get_subcontractor_project_members_month(date):
    """指定月の案件メンバー全部取得する。

    :param date 指定月
    :return
    """
    return models.get_project_members_by_month(date).filter(member__member_type=4)

def get_next_change_list():
    """入退場リスト

    :return:
    """
    first_day = common.get_first_day_current_month()
    last_day = common.get_last_day_by_month(first_day)
    next_first_day = common.get_first_day_by_month(common.add_months(first_day, 1))
    next_last_day = common.get_last_day_by_month(next_first_day)
    members = models.Member.objects.public_filter(Q(projectmember__end_date__gte=first_day,
                                                    projectmember__end_date__lte=last_day,
                                                    projectmember__is_deleted=False,
                                                    projectmember__status=2) |
                                                  Q(projectmember__start_date__gte=next_first_day,
                                                      projectmember__start_date__lte=next_last_day,
                                                      projectmember__is_deleted=False,
                                                      projectmember__status=2)).distinct()
    return members.filter(membersectionperiod__section__is_on_sales=True)

def get_subcontractor_release_members_by_month(date):
    """指定年月にリリースする協力社員を取得する。

    :param date 指定月
    """
    return models.get_release_members_by_month(date).filter(member__member_type=4)

def get_subcontractor_release_current_month():
    """今月にリリースする協力社員を取得する

    """
    return get_subcontractor_release_members_by_month(datetime.date.today())

def get_subcontractor_release_next_month():
    """来月にリリースする協力社員を取得する

    """
    next_month = common.add_months(datetime.date.today(), 1)
    return get_subcontractor_release_members_by_month(next_month)

def get_subcontractor_release_next_2_month():
    """再来月にリリースする協力社員を取得する

    """
    next_month = common.add_months(datetime.date.today(), 2)
    return get_subcontractor_release_members_by_month(next_month)

def get_projects(q=None, o=None):
    """案件を取得する。

    :param q:絞り込み条件
    :param o:並び順
    :return:
    """
    projects = models.Project.objects.public_all()
    today = datetime.date.today()
    working_members = models.ProjectMember.objects.public_filter(start_date__lte=today,
                                                                 end_date__gte=today)
    projects = projects.prefetch_related(
        'projectmember_set',
        Prefetch('projectmember_set', queryset=working_members, to_attr='working_project_members')
    )
    if q:
        projects = projects.filter(**q)
    if o:
        projects = projects.order_by(*o)
    return projects

def get_projects_orders(ym, q=None, o=None):
    """案件の注文情報を取得する。

    :param ym:対象年月
    :param q:絞り込み条件
    :param o:並び順
    :return:
    """
    first_day = common.get_first_day_from_ym(ym)
    last_day = common.get_last_day_by_month(first_day)

    project_orders = models.ClientOrder.projects.through.objects\
        .filter(Q(clientorder__isnull=True) | Q(clientorder__start_date__lte=last_day,
                                                clientorder__end_date__gte=first_day),
                project__start_date__lte=last_day,
                project__end_date__gte=first_day).distinct()

    if q:
        if 'project__projectrequest__request_no__contains' in q:
            q.update({'project__projectrequest__year': ym[:4],
                      'project__projectrequest__month': ym[4:]})
        project_orders = project_orders.filter(**q)

    order_by_request_no = None
    if o:
        if 'project__projectrequest__request_no' in o:
            order_by_request_no = 'ASC'
            o.remove('project__projectrequest__request_no')
        elif '-project__projectrequest__request_no' in o:
            order_by_request_no = 'DESC'
            o.remove('-project__projectrequest__request_no')
        project_orders = project_orders.order_by(*o)

    all_project_orders = []
    for project_order in project_orders:
        project_request = project_order.project.get_project_request(ym[:4], ym[4:], project_order.clientorder)
        all_project_orders.append((project_order.project, project_request, project_order.clientorder))
    if order_by_request_no == 'ASC':
        all_project_orders.sort(key=lambda d: d[1].request_no)
    elif order_by_request_no == 'DESC':
        all_project_orders.sort(key=lambda d: d[1].request_no, reverse=True)
    return all_project_orders

def get_activities_incoming():
    """これから実施する活動一覧

    :return:
    """
    now = timezone.now()
    activities = models.ProjectActivity.objects.public_filter(open_date__gte=now).order_by('open_date')
    return activities[:5]

def get_user_profile(user):
    """ログインしているユーザの詳細情報を取得する。

    :param user ログインしているユーザ
    """
    if hasattr(user, 'salesperson'):
        return user.salesperson
    return None

def generate_bp_order_data(project_member, year, month, contract, user, bp_order, publish_date=None):
    """ＢＰ注文書を作成するためのデータを取得する。

    :param project_member:
    :param year:
    :param month:
    :param contract:
    :param user:
    :param bp_order:
    :param publish_date
    :return:
    """
    if not contract:
        raise errors.CustomException(constants.ERROR_BP_NO_CONTRACT)
    company = get_company()
    first_day = datetime.date(int(year), int(month), 1)
    if project_member.start_date > first_day:
        first_day = project_member.start_date
    last_day = common.get_last_day_by_month(first_day)
    data = {'DETAIL': {}}
    data['DETAIL']['YM'] = '%04d%02d' % (int(year), int(month))
    # 発行年月日
    publish_date = common.get_bp_order_publish_date(year, month, publish_date)
    data['DETAIL']['PUBLISH_DATE'] = common.to_wareki(publish_date)
    # 下請け会社名
    data['DETAIL']['SUBCONTRACTOR_NAME'] = project_member.member.subcontractor.name
    # 下請け会社郵便番号
    if project_member.member.subcontractor.post_code and len(project_member.member.subcontractor.post_code) == 7:
        post_code = project_member.member.subcontractor.post_code[:3] + '-' + \
                    project_member.member.subcontractor.post_code[3:]
    else:
        post_code = ''
    data['DETAIL']['SUBCONTRACTOR_POST_CODE'] = post_code
    # 下請け会社住所
    data['DETAIL']['SUBCONTRACTOR_ADDRESS1'] = project_member.member.subcontractor.address1
    data['DETAIL']['SUBCONTRACTOR_ADDRESS2'] = project_member.member.subcontractor.address2
    # 下請け会社電話番号
    data['DETAIL']['SUBCONTRACTOR_TEL'] = project_member.member.subcontractor.tel
    # 下請け会社ファックス
    data['DETAIL']['SUBCONTRACTOR_FAX'] = project_member.member.subcontractor.fax
    # 委託業務責任者（乙）
    data['DETAIL']['SUBCONTRACTOR_MASTER'] = project_member.member.subcontractor.president
    # 連絡窓口担当者（甲）
    salesperson = project_member.member.get_salesperson(datetime.date(int(year), int(month), 20))
    data['DETAIL']['MIDDLEMAN'] = unicode(salesperson) if salesperson else ''
    # 連絡窓口担当者（乙）
    data['DETAIL']['SUBCONTRACTOR_MIDDLEMAN'] = project_member.member.subcontractor.middleman
    # 作成者
    create_user = get_user_profile(user)
    data['DETAIL']['AUTHOR_FIRST_NAME'] = create_user.first_name if create_user else ''
    # 会社名
    data['DETAIL']['COMPANY_NAME'] = company.name
    # 本社郵便番号
    data['DETAIL']['POST_CODE'] = common.get_full_postcode(company.post_code)
    # 本社電話番号
    data['DETAIL']['TEL'] = company.tel
    # 代表取締役
    data['DETAIL']['MASTER'] = company.president if company.president else ""
    # 本社住所
    data['DETAIL']['ADDRESS1'] = company.address1
    data['DETAIL']['ADDRESS2'] = company.address2
    # 業務名称
    data['DETAIL']['PROJECT_NAME'] = project_member.project.name
    # 作業期間
    data['DETAIL']['START_DATE'] = common.to_wareki(first_day)
    data['DETAIL']['END_DATE'] = common.to_wareki(last_day)
    # 作業責任者
    data['DETAIL']['MEMBER_NAME'] = unicode(project_member.member)
    # 時給
    data['DETAIL']['IS_HOURLY_PAY'] = contract.is_hourly_pay
    # 基本給
    allowance_base = humanize.intcomma(contract.allowance_base + contract.allowance_other) if contract else ''
    if contract.allowance_base_memo:
        allowance_base_memo = contract.allowance_base_memo
    elif contract.is_hourly_pay:
        allowance_base_memo = u"時間単価：￥%s/h  (消費税を含まない)" % allowance_base
    elif contract.is_fixed_cost:
        allowance_base_memo = u"月額基本料金：￥%s円/月  (固定、税金抜き)" % allowance_base
    else:
        allowance_base_memo = u"月額基本料金：￥%s円/月  (税金抜き)" % allowance_base
    data['DETAIL']['ALLOWANCE_BASE'] = allowance_base
    data['DETAIL']['ALLOWANCE_BASE_MEMO'] = allowance_base_memo
    # 固定
    data['DETAIL']['IS_FIXED_COST'] = contract.is_fixed_cost
    # 計算式を表示するか
    data['DETAIL']['IS_SHOW_FORMULA'] = contract.is_show_formula
    if not contract.is_fixed_cost:
        # 超過単価
        allowance_overtime = humanize.intcomma(contract.allowance_overtime) if contract else ''
        if contract.allowance_overtime_memo:
            allowance_overtime_memo = contract.allowance_overtime_memo
        else:
            allowance_overtime_memo = u"超過単価：￥%s/%sh=￥%s/h" % (
                allowance_base, contract.allowance_time_max, allowance_overtime
            )
        data['DETAIL']['ALLOWANCE_OVERTIME'] = allowance_overtime
        data['DETAIL']['ALLOWANCE_OVERTIME_MEMO'] = allowance_overtime_memo
        # 不足単価
        allowance_absenteeism = humanize.intcomma(contract.allowance_absenteeism) if contract else ''
        if contract.allowance_absenteeism_memo:
            allowance_absenteeism_memo = contract.allowance_absenteeism_memo
        else:
            allowance_absenteeism_memo = u"不足単価：￥%s/%sh=￥%s/h" % (
                allowance_base, contract.allowance_time_min, allowance_absenteeism
            )
        data['DETAIL']['ALLOWANCE_ABSENTEEISM'] = allowance_absenteeism
        data['DETAIL']['ALLOWANCE_ABSENTEEISM_MEMO'] = allowance_absenteeism_memo
        # 基準時間
        data['DETAIL']['ALLOWANCE_TIME_MIN'] = unicode(contract.allowance_time_min)
        data['DETAIL']['ALLOWANCE_TIME_MAX'] = unicode(contract.allowance_time_max)
        if contract.allowance_time_memo:
            allowance_time_memo = contract.allowance_time_memo
        else:
            allowance_time_memo = u"※基準時間：%s～%sh/月" % (contract.allowance_time_min, contract.allowance_time_max)
        data['DETAIL']['ALLOWANCE_TIME_MEMO'] = allowance_time_memo
    # 追記コメント
    data['DETAIL']['COMMENT'] = contract.comment
    # 作業場所
    data['DETAIL']['LOCATION'] = project_member.project.address if project_member.project.address else u"弊社指定場所"
    # 納入物件
    data['DETAIL']['DELIVERY_PROPERTIES'] = models.Config.get_bp_order_delivery_properties()
    # 支払条件
    data['DETAIL']['PAYMENT_CONDITION'] = models.Config.get_bp_order_payment_condition()
    # 契約条項
    data['DETAIL']['CONTRACT_ITEMS'] = models.Config.get_bp_order_contract_items()

    data['DETAIL']['ORDER_NO'] = bp_order.order_no
    return data

def generate_order_data(company, subcontractor, user, ym):
    """註文書を生成するために使うデータを生成する。

    :param company 発注元会社
    :param subcontractor 発注先
    :param user ログインしているユーザ
    :param ym 対象年月
    :return エクセルのバイナリー
    """
    data = {'DETAIL': {}}
    # 発行年月日
    date = datetime.date.today()
    data['DETAIL']['PUBLISH_DATE'] = u"%s年%02d月%02d日" % (date.year, date.month, date.day)
    # 下請け会社名
    data['DETAIL']['SUBCONTRACTOR_NAME'] = subcontractor.name
    # 委託業務責任者（乙）
    data['DETAIL']['SUBCONTRACTOR_MASTER'] = subcontractor.president
    # 作成者
    salesperson = get_user_profile(user)
    data['DETAIL']['AUTHOR_FIRST_NAME'] = salesperson.first_name if salesperson else ''
    # 会社名
    data['DETAIL']['COMPANY_NAME'] = company.name
    # 本社郵便番号
    data['DETAIL']['POST_CODE'] = common.get_full_postcode(company.post_code)
    # 本社電話番号
    data['DETAIL']['TEL'] = company.tel
    # 代表取締役
    member = get_master()
    data['DETAIL']['MASTER'] = u"%s %s" % (member.first_name, member.last_name) if member else ""
    # 本社住所
    data['DETAIL']['ADDRESS1'] = company.address1
    data['DETAIL']['ADDRESS2'] = company.address2
    # 作業期間
    if not ym:
        first_day = common.get_first_day_current_month()
    else:
        first_day = common.get_first_day_from_ym(ym)
    last_day = common.get_last_day_by_month(first_day)
    data['DETAIL']['START_DATE'] = u"%s年%02d月%02d日" % (first_day.year, first_day.month, first_day.day)
    data['DETAIL']['END_DATE'] = u"%s年%02d月%02d日" % (last_day.year, last_day.month, last_day.day)

    members = []
    # 全ての協力社員の注文情報を取得する。
    for member in subcontractor.get_members_by_month(first_day):
        bp_member_info = member.get_bp_member_info(first_day)
        members.append({'ITEM_NAME': member.__unicode__(),  # 協力社員名前
                        'ITEM_COST': humanize.intcomma(member.cost),  # 月額基本料金
                        'ITEM_MIN_HOUR': humanize.intcomma(bp_member_info.min_hours),  # 基準時間（最小値）
                        'ITEM_MAX_HOUR': humanize.intcomma(bp_member_info.max_hours),  # 基準時間（最大値）
                        'ITEM_PLUS_PER_HOUR': humanize.intcomma(bp_member_info.plus_per_hour),  # 超過単価
                        'ITEM_MINUS_PER_HOUR': humanize.intcomma(bp_member_info.minus_per_hour),  # 不足単価
                        })
    data['MEMBERS'] = members

    return data

def get_request_members_in_project(project, client_order, ym):
    """指定案件の指定注文書の中に、対象のメンバーを取得する。

    :param project: 指定案件
    :param client_order: 指定注文書
    :param ym: 対象年月
    :return: メンバーのリスト
    """
    if client_order.projects.public_filter(is_deleted=False).count() > 1:
        # 一つの注文書に複数の案件がある場合
        projects = client_order.projects.public_filter(is_deleted=False)
        project_members = models.ProjectMember.objects.public_filter(project__in=projects)
    elif project.get_order_by_month(ym[:4], ym[4:]).count() > 1:
        # １つの案件に複数の注文書ある場合
        project_members = []
        if client_order.member_comma_list:
            # 重複したメンバーを外す。
            member_id_list = sorted(set(client_order.member_comma_list.split(",")))
            first_day = common.get_first_day_from_ym(ym)
            last_day = common.get_last_day_by_month(first_day)
            for pm_id in member_id_list:
                try:
                    project_members.append(
                        models.ProjectMember.objects.get(pk=int(pm_id), is_deleted=False, status=2,
                                                         start_date__lte=last_day,
                                                         end_date__gte=first_day))
                except ObjectDoesNotExist:
                    pass
    else:
        project_members = project.get_project_members_by_month(ym=ym)
    return project_members

def generate_request_data(company, project, client_order, bank_info, ym, project_request):
    first_day = common.get_first_day_from_ym(ym)
    last_day = common.get_last_day_by_month(first_day)
    data = {'DETAIL': {}, 'EXTRA': {}}
    data['EXTRA']['YM'] = ym
    # お客様郵便番号
    data['DETAIL']['CLIENT_POST_CODE'] = common.get_full_postcode(project.client.post_code)
    # お客様住所
    data['DETAIL']['CLIENT_ADDRESS'] = (project.client.address1 or '') + (project.client.address2 or '')
    # お客様電話番号
    data['DETAIL']['CLIENT_TEL'] = project.client.tel or ''
    # お客様名称
    data['DETAIL']['CLIENT_COMPANY_NAME'] = project.client.name
    # 作業期間
    f = u'%Y年%m月%d日'
    period_start = first_day.strftime(f.encode('utf-8')).decode('utf-8')
    period_end = last_day.strftime(f.encode('utf-8')).decode('utf-8')
    data['DETAIL']['WORK_PERIOD'] = period_start + u" ～ " + period_end
    data['EXTRA']['WORK_PERIOD_START'] = first_day
    data['EXTRA']['WORK_PERIOD_END'] = last_day
    # 注文番号
    data['DETAIL']['ORDER_NO'] = client_order.order_no if client_order.order_no else u""
    # 注文日
    data['DETAIL']['REQUEST_DATE'] = client_order.order_date.strftime('%Y/%m/%d') if client_order.order_date else ""
    # 契約件名
    data['DETAIL']['CONTRACT_NAME'] = project_request.request_name
    # お支払い期限
    data['DETAIL']['REMIT_DATE'] = project.client.get_pay_date(date=first_day).strftime('%Y/%m/%d')
    data['EXTRA']['REMIT_DATE'] = project.client.get_pay_date(date=first_day)
    # 請求番号
    data['DETAIL']['REQUEST_NO'] = project_request.request_no
    # 発行日（対象月の最終日）
    data['DETAIL']['PUBLISH_DATE'] = last_day.strftime(u"%Y年%m月%d日".encode('utf-8')).decode('utf-8')
    data['EXTRA']['PUBLISH_DATE'] = last_day
    # 本社郵便番号
    data['DETAIL']['POST_CODE'] = common.get_full_postcode(company.post_code)
    # 本社住所
    data['DETAIL']['ADDRESS'] = (company.address1 or '') + (company.address2 or '')
    # 会社名
    data['DETAIL']['COMPANY_NAME'] = company.name
    # 代表取締役
    member = get_master()
    data['DETAIL']['MASTER'] = u"%s %s" % (member.first_name, member.last_name) if member else ""
    # 本社電話番号
    data['DETAIL']['TEL'] = company.tel
    # 振込先銀行名称
    data['EXTRA']['BANK'] = bank_info
    data['DETAIL']['BANK_NAME'] = bank_info.bank_name if bank_info else u""
    # 支店番号
    data['DETAIL']['BRANCH_NO'] = bank_info.branch_no if bank_info else u""
    # 支店名称
    data['DETAIL']['BRANCH_NAME'] = bank_info.branch_name if bank_info else u""
    # 預金種類
    data['DETAIL']['ACCOUNT_TYPE'] = bank_info.get_account_type_display() if bank_info else u""
    # 口座番号
    data['DETAIL']['ACCOUNT_NUMBER'] = bank_info.account_number if bank_info else u""
    # 口座名義人
    data['DETAIL']['BANK_ACCOUNT_HOLDER'] = bank_info.account_holder if bank_info else u""

    # 全員の合計明細
    detail_all = dict()
    # メンバー毎の明細
    detail_members = []

    project_members = get_request_members_in_project(project, client_order, ym)
    members_amount = 0
    if project.is_lump:
        members_amount = project.lump_amount
        # 番号
        detail_all['NO'] = u"1"
        # 項目：契約件名に設定
        detail_all['ITEM_NAME_ATTENDANCE_TOTAL'] = data['DETAIL']['CONTRACT_NAME']
        # 数量
        detail_all['ITEM_COUNT'] = u"1"
        # 単位
        detail_all['ITEM_UNIT'] = u"一式"
        # 金額
        detail_all['ITEM_AMOUNT_ATTENDANCE_ALL'] = members_amount
        # 備考
        detail_all['ITEM_COMMENT'] = project.lump_comment if project.is_lump and project.lump_comment else u""
    else:
        for i, project_member in enumerate(project_members):
            dict_expenses = dict()
            # この項目は請求書の出力ではなく、履歴データをProjectRequestDetailに保存するために使う。
            dict_expenses["EXTRA_PROJECT_MEMBER"] = project_member
            # 番号
            dict_expenses['NO'] = str(i + 1)
            # 項目
            dict_expenses['ITEM_NAME'] = project_member.member.__unicode__()
            # 時給の場合
            if project.is_hourly_pay:
                # 単価（円）
                dict_expenses['ITEM_PRICE'] = project_member.hourly_pay or 0
                # Min/Max（H）
                dict_expenses['ITEM_MIN_MAX'] = u""
            else:
                # 単価（円）
                dict_expenses['ITEM_PRICE'] = project_member.price or 0
                # Min/Max（H）
                dict_expenses['ITEM_MIN_MAX'] = "%s/%s" % (int(project_member.min_hours), int(project_member.max_hours))
            dict_expenses.update(project_member.get_attendance_dict(first_day.year, first_day.month))
            # 金額合計
            members_amount += dict_expenses['ITEM_AMOUNT_TOTAL']
            detail_members.append(dict_expenses)

    detail_expenses, expenses_amount = get_request_expenses_list(project,
                                                                 first_day.year,
                                                                 '%02d' % (first_day.month,),
                                                                 project_members)

    data['detail_all'] = detail_all
    data['MEMBERS'] = detail_members
    data['EXPENSES'] = detail_expenses  # 清算リスト
    data['DETAIL']['ITEM_AMOUNT_ATTENDANCE'] = members_amount
    if project.client.decimal_type == '0':
        data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'] = int(round(members_amount * project.client.tax_rate))
    else:
        # 出勤のトータル金額の税金
        data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'] = int(members_amount * project.client.tax_rate)
    data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_ALL'] = members_amount + int(data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'])
    data['DETAIL']['ITEM_AMOUNT_ALL'] = int(data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_ALL']) + expenses_amount
    data['DETAIL']['ITEM_AMOUNT_ALL_COMMA'] = humanize.intcomma(data['DETAIL']['ITEM_AMOUNT_ALL'])

    project_request.amount = data['DETAIL']['ITEM_AMOUNT_ALL']
    project_request.turnover_amount = members_amount
    project_request.tax_amount = data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX']
    project_request.expenses_amount = expenses_amount

    return data

def generate_subcontractor_request_data(subcontractor, year, month, subcontractor_request):
    company = get_company()
    first_day = common.get_first_day_by_month(datetime.date(int(year), int(month), 1))
    last_day = common.get_last_day_by_month(first_day)
    data = {'DETAIL': {}, 'EXTRA': {}}
    data['EXTRA']['YM'] = first_day.strftime('%Y%m')
    data['EXTRA']['COMPANY'] = company
    # お客様郵便番号
    data['DETAIL']['CLIENT_POST_CODE'] = common.get_full_postcode(company.post_code)
    # お客様住所
    data['DETAIL']['CLIENT_ADDRESS'] = (company.address1 or '') + (company.address2 or '')
    # お客様電話番号
    data['DETAIL']['CLIENT_TEL'] = company.tel or ''
    # お客様名称
    data['DETAIL']['CLIENT_COMPANY_NAME'] = company.name
    # 作業期間
    f = u'%Y年%m月%d日'
    period_start = first_day.strftime(f.encode('utf-8')).decode('utf-8')
    period_end = last_day.strftime(f.encode('utf-8')).decode('utf-8')
    data['DETAIL']['WORK_PERIOD'] = period_start + u" ～ " + period_end
    data['EXTRA']['WORK_PERIOD_START'] = first_day
    data['EXTRA']['WORK_PERIOD_END'] = last_day
    # 注文番号
    data['DETAIL']['ORDER_NO'] = u""
    # 注文日
    data['DETAIL']['REQUEST_DATE'] = u""
    # 契約件名
    data['DETAIL']['CONTRACT_NAME'] = u""
    # 部署名称
    data['DETAIL']['ORG_NAME'] = unicode(subcontractor_request.section)
    # お支払い期限
    data['DETAIL']['REMIT_DATE'] = company.get_pay_date(date=first_day).strftime('%Y/%m/%d')
    data['EXTRA']['REMIT_DATE'] = company.get_pay_date(date=first_day)
    # 請求番号
    data['DETAIL']['REQUEST_NO'] = subcontractor_request.request_no
    # 発行日（対象月の最終日）
    data['DETAIL']['PUBLISH_DATE'] = last_day.strftime(u"%Y年%m月%d日".encode('utf-8')).decode('utf-8')
    data['EXTRA']['PUBLISH_DATE'] = last_day
    # 本社郵便番号
    data['DETAIL']['POST_CODE'] = common.get_full_postcode(subcontractor.post_code)
    # 本社住所
    data['DETAIL']['ADDRESS'] = (subcontractor.address1 or '') + (subcontractor.address2 or '')
    # 会社名
    data['DETAIL']['COMPANY_NAME'] = subcontractor.name
    # 代表取締役
    data['DETAIL']['MASTER'] = subcontractor.president
    # 本社電話番号
    data['DETAIL']['TEL'] = subcontractor.tel
    # 振込先銀行名称
    if subcontractor.subcontractorbankinfo_set.all().count() == 0:
        bank_info = None
    else:
        bank_info = subcontractor.subcontractorbankinfo_set.all()[0]
    data['EXTRA']['BANK'] = bank_info
    data['DETAIL']['BANK_NAME'] = bank_info.bank_name if bank_info else u""
    # 支店番号
    data['DETAIL']['BRANCH_NO'] = bank_info.branch_no if bank_info else u""
    # 支店名称
    data['DETAIL']['BRANCH_NAME'] = bank_info.branch_name if bank_info else u""
    # 預金種類
    data['DETAIL']['ACCOUNT_TYPE'] = bank_info.get_account_type_display() if bank_info else u""
    # 口座番号
    data['DETAIL']['ACCOUNT_NUMBER'] = bank_info.account_number if bank_info else u""
    # 口座名義人
    data['DETAIL']['BANK_ACCOUNT_HOLDER'] = bank_info.account_holder if bank_info else u""

    # 全員の合計明細
    detail_all = dict()
    # メンバー毎の明細
    detail_members = []

    section_members = subcontractor.get_members_by_month_and_section(year, month, subcontractor_request.section)
    members_amount = 0
    if False:
        members_amount = 0
        # 番号
        detail_all['NO'] = u"1"
        # 項目：契約件名に設定
        detail_all['ITEM_NAME_ATTENDANCE_TOTAL'] = data['DETAIL']['CONTRACT_NAME']
        # 数量
        detail_all['ITEM_COUNT'] = u"1"
        # 単位
        detail_all['ITEM_UNIT'] = u"一式"
        # 金額
        detail_all['ITEM_AMOUNT_ATTENDANCE_ALL'] = members_amount
        # 備考
        detail_all['ITEM_COMMENT'] = u""
    else:
        for i, member in enumerate(section_members):
            member_attendance_set = models.MemberAttendance.objects.public_filter(
                project_member__member=member,
                year=year,
                month=month,
            )
            if member_attendance_set.count() > 0:
                member_attendance = member_attendance_set[0]
                contract_list = member.bpcontract_set.filter(
                    start_date__lte=last_day,
                    is_deleted=False,
                ).order_by('-start_date')
                if contract_list.count() > 0:
                    contract = contract_list[0]
                    dict_expenses = dict()
                    # この項目は請求書の出力ではなく、履歴データをProjectRequestDetailに保存するために使う。
                    dict_expenses["EXTRA_PROJECT_MEMBER"] = member_attendance.project_member
                    # 番号
                    dict_expenses['NO'] = str(i + 1)
                    # 項目
                    dict_expenses['ITEM_NAME'] = unicode(member)
                    # 時給の場合
                    if contract.is_hourly_pay:
                        # 単価（円）
                        dict_expenses['ITEM_PRICE'] = contract.allowance_base or 0
                        # Min/Max（H）
                        dict_expenses['ITEM_MIN_MAX'] = u""
                    else:
                        # 単価（円）
                        dict_expenses['ITEM_PRICE'] = contract.get_cost() or 0
                        # Min/Max（H）
                        dict_expenses['ITEM_MIN_MAX'] = "%s/%s" % (
                            int(contract.allowance_time_min), int(contract.allowance_time_min)
                        )
                    dict_expenses.update(member_attendance.project_member.get_attendance_dict(first_day.year, first_day.month))
                    # 金額合計
                    members_amount += dict_expenses['ITEM_AMOUNT_TOTAL']
                    detail_members.append(dict_expenses)

    # detail_expenses, expenses_amount = get_request_expenses_list(project,
    #                                                              first_day.year,
    #                                                              '%02d' % (first_day.month,),
    #                                                              project_members)
    detail_expenses, expenses_amount = [], 0

    data['detail_all'] = detail_all
    data['MEMBERS'] = detail_members
    data['EXPENSES'] = detail_expenses  # 清算リスト
    data['DETAIL']['ITEM_AMOUNT_ATTENDANCE'] = members_amount
    if company.decimal_type == '0':
        data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'] = int(round(members_amount * company.tax_rate))
    else:
        # 出勤のトータル金額の税金
        data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'] = int(members_amount * company.tax_rate)
    data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_ALL'] = members_amount + int(data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX'])
    data['DETAIL']['ITEM_AMOUNT_ALL'] = int(data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_ALL']) + expenses_amount
    data['DETAIL']['ITEM_AMOUNT_ALL_COMMA'] = humanize.intcomma(data['DETAIL']['ITEM_AMOUNT_ALL'])

    subcontractor_request.amount = data['DETAIL']['ITEM_AMOUNT_ALL']
    subcontractor_request.turnover_amount = members_amount
    subcontractor_request.tax_amount = data['DETAIL']['ITEM_AMOUNT_ATTENDANCE_TAX']
    subcontractor_request.expenses_amount = expenses_amount

    return data

def get_request_expenses_list(project, year, month, project_members):
    # 清算リスト
    dict_expenses = {}
    for expenses in project.get_expenses(year, month, project_members):
        if expenses.category.name not in dict_expenses:
            dict_expenses[expenses.category.name] = [expenses]
        else:
            dict_expenses[expenses.category.name].append(expenses)
    detail_expenses = []
    expenses_amount = 0
    for key, value in dict_expenses.iteritems():
        d = dict()
        member_list = []
        amount = 0
        for expenses in value:
            member_list.append(expenses.project_member.member.first_name +
                               expenses.project_member.member.last_name +
                               u"￥%s" % (expenses.price,))
            amount += expenses.price
            expenses_amount += expenses.price
        d['ITEM_EXPENSES_CATEGORY_SUMMARY'] = u"%s(%s)" % (key, u"、".join(member_list))
        d['ITEM_EXPENSES_CATEGORY_AMOUNT'] = amount
        detail_expenses.append(d)
    return detail_expenses, expenses_amount

def get_attendance_time_from_eboa(project_member, year, month):
    """EBOAから出勤時間を取得する。

    :param project_member:
    :param year:
    :param month:
    :return:
    """
    if not project_member.member.eboa_user_id:
        return 0

    period = '%04d/%02d' % (int(year), int(month))
    eboa_attendances = eboa_models.EbAttendance.objects.filter(applicant__userid=project_member.member.eboa_user_id,
                                                               period=period)
    if eboa_attendances.count() > 0:
        return float(eboa_attendances[0].totaltime)
    else:
        return 0

def get_master():
    # 代表取締役を取得する。
    members = models.Salesperson.objects.public_filter(member_type=7)
    if members.count() == 1:
        return members[0]
    else:
        return None

def is_first_login(user):
    """初めてのログインなのかどうか

    :param user:
    :return:
    """
    try:
        User.objects.get(username=user.username, last_login__isnull=True)
        return True
    except ObjectDoesNotExist:
        return False
    except MultipleObjectsReturned:
        return False

def gen_qr_code(url_schema, domain):
    import qrcode
    uid = uuid.uuid4()
    # url = domain + reverse('login_qr') + "?uid=" + str(uid)
    url = "%s://%s%s?uid=%s" % (url_schema, domain, reverse('login_qr'), str(uid))
    img = qrcode.make(url)
    output = StringIO.StringIO()
    img.save(output, "PNG")
    contents = output.getvalue().encode("base64")
    output.close()
    return contents


class Boletos:
    def __init__(self, titulo, sala, voleto, precio, nombre, nit, direccion, datos, asientos, No_voleto):
        self.titulo = titulo
        self.sala = sala
        self.voleto = voleto
        self.precio = precio
        self.nombre = nombre
        self.nit = nit
        self.direccion = direccion
        self.datos = datos
        self.asientos = asientos
        self.No_voleto=No_voleto


"""Blender add-on that allows the user to open a Skybrush script (.sky) file
directly in Blender and let the scene render itself automatically.

Requires the `skybrush-studio` Python module. Contact us if you are interested.
"""

bl_info = {
    "name": "Import Skybrush Script Format (.sky)",
    "author": "Tamas Nepusz (CollMot Robotics Ltd.)",
    "description": "Import a Skybrush file directly into Blender",
    "version": (0, 1, 0),
    "blender": (2, 83, 0),
    "location": "File > Import > Skybrush",
    "category": "Import-Export",
}

__license__ = "GPLv3"

#############################################################################
# imports needed to set up the Python path properly

import bpy
import sys

from bpy.path import abspath
from pathlib import Path

#############################################################################
# Note: This code needs to be harmonized with the plugin installer to have
# the same target directory for all add-on specific dependencies.

if bpy.app.version >= (3, 6, 0):
    candidates = [
        abspath(script_directory.directory)
        for script_directory in bpy.context.preferences.filepaths.script_directories
    ]
else:
    candidates = [abspath(bpy.context.preferences.filepaths.script_directory)]
candidates.append(Path(sys.modules[__name__].__file__).parent.parent)

for candidate in candidates:
    path = (Path(candidate) / "vendor" / "skybrush").resolve()
    if path.exists():
        sys.path.insert(0, str(path))
        break

#############################################################################
# imports needed by the addon

import logging

from bpy_extras.io_utils import ImportHelper
from bpy.path import ensure_ext
from bpy.props import (
    BoolProperty,
    EnumProperty,
    FloatProperty,
    IntProperty,
    StringProperty,
)
from bpy.types import Operator
from copy import deepcopy

from skybrush.io.sky.runner import SkybrushScriptRunner
from skybrush.io.blender.renderer import render
from skybrush.io.base.renderer import RenderContext, RenderMode
from skybrush.utils.filesystem import working_directory

from sbstudio.plugin.plugin_helpers import (
    register_in_menu,
    register_operator,
    unregister_from_menu,
    unregister_operator,
)

#############################################################################
# configure logger

log = logging.getLogger(__name__)
logging.basicConfig(
    format="%(asctime)s.%(msecs)03d %(message)s",
    level=logging.INFO,
    datefmt="%H:%M:%S",
)

#############################################################################
# Helper functions for the importer
#############################################################################

def _run_script(filename, context, parameters):
    """Executes a Skybrush script with the given rendering context and
    parameters.

    This is a helper function for the common parts of SkybrushImportOperator_
    and SkybrushReimportOperator_
    """

    log.info(f"import started from '{filename}'")

    runner = SkybrushScriptRunner()
    if "seed" in parameters:
        runner.seed = parameters.pop("seed")

    vars = runner.run(filename)

    log.info("script parsed")

    with working_directory(Path(filename).parent):
        render(vars.get_world(), context, parameters)

    log.info("script rendered, import finished")

#############################################################################
# Operator that allows the user to invoke the import operation
#############################################################################

class SkybrushImportOperator(Operator, ImportHelper):
    """Imports a Skybrush script file directly into Blender."""

    bl_idname = "import.skybrush_sky"
    bl_label = "Import Skybrush SKY"
    bl_options = {"REGISTER"}

    # List of file extensions that correspond to Skybrush files
    filter_glob = StringProperty(default="*.sky", options={"HIDDEN"})
    filename_ext = ".sky"

    # Rendering mode to use when importing the file
    mode = EnumProperty(
        items=[
            (RenderMode.DRAFT.value, "Draft", "Draft rendering (faster)"),
            (
                RenderMode.PRODUCTION.value,
                "Production",
                "Production rendering (slower)",
            ),
        ],
        name="Mode",
        default=RenderMode.DRAFT.value,
        description="Rendering mode to use when executing the Skybrush script",
    )

    # Random seed to use when importing the file
    seed = IntProperty(
        name="Random seed",
        default=0,
        min=0,
        description="Seed value to use when generating random numbers during the execution of the script",
    )

    # amount of glow added to drone objects on render
    glow_strength = FloatProperty(
        name="Glow Strength",
        default=1,
        min=0,
        max=1,
        description="Amount of glow to add to the rendered drone objects",
    )

    # Stores whether the names of the drones and environment items should be
    # shown by default
    show_names = BoolProperty(
        name="Show names",
        default=False,
        description="Show the names of the drones and the environment items in the scene after import",
    )

    # Stores whether the drone trajectories should be shown by default
    show_trajectories = BoolProperty(
        name="Show trajectories",
        default=False,
        description="Show drone trajectories in the scene after import",
    )

    def execute(self, context):
        """Executes the Skybrush import procedure."""
        filepath = ensure_ext(self.filepath, self.filename_ext)
        parameters = {
            "glow_strength": self.glow_strength,
            "seed": self.seed,
            "show_trajectories": self.show_trajectories,
            "show_names": self.show_names,
            "verbose": False,
        }

        context = RenderContext()
        context.mode = self.mode
        context.filename = filepath

        # Make a copy of the context and the parameters before executing the
        # import procedure in case some parameters are mutable and the script
        # modifies them
        parameters_copy = deepcopy(parameters)
        context_copy = deepcopy(context)

        # Notify the reimport operator
        SkybrushReimportOperator.notify_import(filepath, context_copy, parameters_copy)

        # Run the script
        _run_script(filepath, context, parameters)

        return {"FINISHED"}

#############################################################################
# Operator that allows the user to re-run the last import operation
#############################################################################

class SkybrushReimportOperator(Operator):
    """Re-imports the last imported Skybrush script file into Blender."""

    bl_idname = "script.skybrush_reimport"
    bl_label = "Reload Skybrush SKY"
    bl_options = {"REGISTER"}

    _last_operation = None

    @classmethod
    def notify_import(cls, filename, context, parameters):
        """Notifies the plugin that a Skybrush script with the given filename,
        context and parameters were imported.
        """
        cls._last_operation = {
            "context": context,
            "filename": filename,
            "parameters": parameters,
        }

    def execute(self, context):
        """Executes the last imported Skybrush script again."""
        cls = self.__class__
        if cls._last_operation:
            _run_script(**cls._last_operation)
        else:
            self.report({"ERROR"}, "No Skybrush script file has been imported yet")
        return {"FINISHED"}

#############################################################################
# Boilerplate to register this as an item in the File / Import menu
#############################################################################

def menu_func_import(self, context):
    self.layout.operator(
        SkybrushImportOperator.bl_idname, text="Skybrush Script (.sky)"
    )

def menu_func_reimport(self, context):
    self.layout.operator(
        SkybrushReimportOperator.bl_idname, text="Reload Current Skybrush Script"
    )

def register():
    register_operator(SkybrushImportOperator)
    register_operator(SkybrushReimportOperator)
    register_in_menu("File / Import", menu_func_import)
    if bpy.app.version >= (3, 0, 0):
        register_in_menu("Blender / System", menu_func_reimport)

def unregister():
    unregister_operator(SkybrushReimportOperator)
    unregister_operator(SkybrushImportOperator)
    unregister_from_menu("File / Import", menu_func_import)
    if bpy.app.version >= (3, 0, 0):
        unregister_from_menu("Blender / System", menu_func_reimport)

if __name__ == "__main__":
    register()

    # test calls
    # bpy.ops.object.SkybrushImportOperator("INVOKE_DEFAULT")
    # bpy.ops.object.SkybrushReImportOperator("INVOKE_DEFAULT")


import asyncio
import base64
import gzip
import logging
import os
import queue
import threading
from typing import Any, Callable, Coroutine, Optional

import aiohttp

from . import datamodels

logger = logging.getLogger()

# callback type that is awaitable
CALLBACK_T = Callable[[], Coroutine[Any, Any, None]]

class BackgroundWorker:
    def __init__(self, server_url: str, api_key: str, max_tasks=2):
        self.server_url = server_url
        self.api_key = api_key
        self._tcp_conn = None
        self._loop = None
        self._queue: queue.Queue[
            Optional[datamodels.FunctionInformation]
        ] = queue.Queue()
        self._thread: Optional[threading.Thread] = None
        self._thread_for_pid: Optional[int] = None
        self.max_tasks = max_tasks

    @property
    def is_alive(self) -> bool:
        if self._thread_for_pid != os.getpid():
            return False
        if not self._thread:
            return False
        return self._thread.is_alive()

    def _ensure_thread(self):
        if not self.is_alive:
            self.start()

    def start(self):
        if not self.is_alive:
            self._thread = threading.Thread(
                target=self._target, name="dataset_dog.BackgroundWorker"
            )
            self._thread.daemon = True
            self._thread.start()
            self._thread_for_pid = os.getpid()

    def kill(self, *args, **kwargs):
        """
        Kill worker thread. Returns immediately. Not useful for
        waiting on shutdown for events, use `flush` for that.
        """
        logger.debug("background worker got kill request")
        if self._thread:
            self._queue.put(None)

            self._thread.join()

            self._thread = None
            self._thread_for_pid = None

        logger.debug("background worker killed")

    def submit(self, function_info: datamodels.FunctionInformation) -> bool:
        self._ensure_thread()
        try:
            self._queue.put(function_info)
            return True
        except Exception:
            logger.error("Failed submitting job", exc_info=True)
            return False

    def _get_callback_function(
        self,
        function_info: datamodels.FunctionInformation,
    ) -> Callable[[], Coroutine[Any, Any, None]]:
        async def callback_fn():
            async with aiohttp.ClientSession(
                connector=self._tcp_conn,
                connector_owner=False,
                raise_for_status=True,
                loop=self._loop,
            ) as session:
                args = base64.b64encode(gzip.compress(function_info.args))
                kwargs = base64.b64encode(gzip.compress(function_info.kwargs))
                res = base64.b64encode(gzip.compress(function_info.res))
                async with session.post(
                    f"{self.server_url}/api/v1/function_records/",
                    json={
                        "functionName": function_info.function_name,
                        "dataType": "pickle",
                        "dataDump": {
                            "args": args,
                            "kwargs": kwargs,
                            "res": res,
                        },
                        "tags": {},  # TODO: add device info
                    },
                    headers={
                        "Content-Type": "application/json",
                        "Accept": "application/json",
                        "Authorization": f"Bearer {self.api_key}",
                    },
                ) as resp:
                    await resp.read()

        return callback_fn

    async def async_target(self):
        active_tasks = []
        while True:
            if len(active_tasks) >= self.max_tasks:
                try:
                    await asyncio.gather(*active_tasks)
                except Exception:
                    logger.error("Failed submitting job", exc_info=True)
                active_tasks = []
            function_info = self._queue.get()
            if function_info is None:
                logger.debug("background worker got None")
                break
            callback = self._get_callback_function(function_info)
            active_tasks.append(asyncio.create_task(callback()))
            self._queue.task_done()
            await asyncio.sleep(0)

        await asyncio.gather(*active_tasks)

    def _target(self):
        # create new loop because this is a new thread
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        self._loop = loop

        # tcp conn needs to be in the same thread as the loop
        self._tcp_conn = aiohttp.TCPConnector(limit=self.max_tasks)
        logger.debug("Starting background worker")
        loop.run_until_complete(self.async_target())


import serial
import time
import Encrypt
import cv2
from time import sleep
import json
list=['COM1','COM2','COM3','COM4','COM5','COM6','COM7','COM8','COM9','COM10','COM11','COM12','COM13','COM14','COM15','COM16','COM17','COM18',]

COM1='COM1'
COM2='COM2'
COM3='COM3'
COM4='COM4'
COM5='COM5'
COM6='COM6'
COM7='COM7'
COM8='COM8'
COM9='COM9'
COM10='COM10'
COM11='COM11'
COM12='COM12'
COM13='COM13'
COM14='COM14'
COM15='COM15'
COM16='COM16'
COM17='COM17'
COM18='COM18'
COM19='COM19'
time.sleep(1)
ser = serial.Serial()

ser.baudrate = 9600
ser.port = COM5
ser.open()
enc = Encrypt.Encrypt()
name = input("Name:")
surname = input("Surname:")
tcNo = input("Tc no:")
tcNoEnc = (enc.encrypt(tcNo).decode() + "#").encode()
import requests

isPost = False

while True:
    try:
        cc=str(ser.readline())
        key = cc[2:][:-5]
        print(key)
        # arr = key.split("#")
        # # print(arr[1])
        # print(arr[0])
        # print(enc.decrypt((arr[1].encode())))
        if(key[0]=="#"):

            url = 'http://localhost:51922/api/Attendence/PostStudent'
            myobj = {'Name': name,'Surname':surname,"TCNo":tcNo,"CardUID":key[1:len(key)]}
            x = requests.post(url, data = json.dumps(myobj),headers={'Content-type':'application/json', 'Accept':'application/json'})
            print(x)
        if(key == "Type tcno hash, ending with #"):
            sleep(1)
            ser.write(tcNoEnc)

    except Exception as e:
        print(e)
        break
#     39565299#A2ykqnlY+ykvTp4GKQozTSVE7lxbPUPnJqMUWy74elhCsqg/5qEKPA==
# b9a84ca3#sqKImQcF3wX8x2UHlCwOWngkmthjrHUEXKZv1PaBDzO8EQM97zK9ig==


import requests
import pprint
import time

jokes = []  # list shell created to dump jokes from requests in while loop
x =0
while len(jokes) < 1000 or x < 1000: # set this to get as many dad jokes as possible, but not sure why I only get 15-45 or so jokes each time
    req_head = {'accept':'application/json'} # made headers text a variable
    # req_parm = {'format':'json'}
    req_url = 'https://icanhazdadjoke.com/' # made url a variable
    resp = requests.get(req_url, headers=req_head) # request with url and headers parameter
    joke = (resp.json()) # read as json data
    if joke in jokes:
        x +=1
        break
    else:
        jokes.append(joke)# this adds the joke dict to a list for later
        joke = [jokes[jokes.index(joke)]] #this gets the joke # accesses the joke dictionary from the list it's sitting in
        j = joke[0] # this accesses the value of the joke
        print('\n',j['joke']) # prints the joke value separated by line and
        time.sleep(5)
        print("\tstill not laughing yet???")
        time.sleep(2.5)
        print("\t\twell...how about about another!!!")
        time.sleep(2.5)
    # for jo in joke:
    #     print(joke[jo])
    # print(len(jokes))
# pprint.pprint(jokes)
joke_list = [joke['joke'] for joke in jokes] # saves the joke value entry for key value pair in each joke's dictionary
    # print(jokes[1])2
jokes_str = '\n'.join(joke_list) # strings the jokes together into a neat, readable text...
# print(jokes_str, len(joke_list))


import sys
sys.stdin=open('sample_input.txt')

def solution(text):
    result = 1
    stack = []
    opener = ['(', '{', '[']
    closer = [')', '}', ']']

    for char in text:
        if char in opener:
            stack.append(char)

        if char in closer:
            if len(stack) == 0:
                result = 0
                break
            elif char == ')' and stack.pop() != '(':
                result = 0
                break
            elif char == '}' and stack.pop() != '{':
                result = 0
                break
            elif char == ']' and stack.pop() != '[':
                result = 0
                break
    # 스트링이 끝났는데, stack이 남아있다면. (opener > closer)
    else:
        if len(stack) :
            result = 0
    return result

T = int(input())
for tc in range(1, T+1):
    text = input()

    print('#{} {}'.format(tc, solution(text)))


import pymysql  as sql
import common as c

def sql_conn():
	db = sql.connect("localhost","root","","stocki")
	return db

def sql_array(qry,key):
    ret_arr = []
    db_obj  = sql_conn()
    cursor  = db_obj.cursor(sql.cursors.DictCursor)
    try:
        cursor.execute(qry)
        results = cursor.fetchall()
        for row in results:
            if key in row:
                ret_arr.append(row[key])
    except (sql.Error, sql.Warning) as e:
        print("-E- Query Failed")
        print(e)
        db_obj.rollback()
    cursor.close()
    return ret_arr

def sql_insert(table,keys,data,limit):
    c.pr("I","Initiating Insert Operation On Table -> "+table+" Query Limit -> "+str(limit)+" Columns -> "+str(len(data)),0)
    ctr = 0
    dap = ""
    for clm in data:
        if ctr == limit:
            dap = dap[1:]
            qry = "INSERT INTO `"+table+"` ("+keys+") VALUES "+dap
            execQuery(qry)
            dap = ""
            ctr = 0
        ctr = ctr + 1
        dap = dap+","+clm
    if ctr > 1:
        dap = dap[1:]
        qry = "INSERT INTO `"+table+"` ("+keys+") VALUES "+dap
        execQuery(qry)
    return

def sql_hash(table,key,cols,whr):
    query = ""
    ret   = {}
    vals  = cols.split(":")
    col   = key+","+",".join(vals)
    query = "SELECT "+col+" FROM `"+table+"` "+whr
    #c.pr("S",query,1)
    db_obj  = sql_conn()
    cursor  = db_obj.cursor()
    try:
        cursor.execute(query)
        results = cursor.fetchall()
        for row in results:
            k       = row[0]
            ct      = 1
            ret[k]  = {}
            for cl in vals:
                ret[k][cl] = row[ct]
                ct = ct + 1
    except (sql.Error, sql.Warning) as e:
        print("-E- Query Failed -> "+query)
        print(e)
        db_obj.rollback()
    cursor.close()
    del cursor
    db_obj.close()
    return ret

def rcnt(qry):
    db_obj  = sql_conn()
    cursor  = db_obj.cursor()
    rows    = 0
    try:
        cursor.execute(qry)
        rows = cursor.rowcount
    except (sql.Error, sql.Warning) as e:
        print("-E- Query Failed")
        print(e)
        db_obj.rollback()
    cursor.close()
    del cursor
    db_obj.close()
    return rows

def execQuery(qry):
    #c.pr("S","Executing Query "+qry,1)
    db_obj  = sql_conn()
    cursor  = db_obj.cursor()
    try:
        cursor.execute(qry)
        db_obj.commit()
    except (sql.Error, sql.Warning) as e:
        print("-E- Query Failed")
        print(e)
        db_obj.rollback()
    cursor.close()
    del cursor
    db_obj.close()
    return

def sql_single(qry):
    ret_str = ""
    db_obj  = sql_conn()
    cursor  = db_obj.cursor()
    try:
        cursor.execute(qry)
        results = cursor.fetchall()
        for row in results:
            ret_str = row[0]
    except (sql.Error, sql.Warning) as e:
        print("-E- Query Failed")
        print(e)
        db_obj.rollback()
    cursor.close()
    del cursor
    db_obj.close()
    return ret_str

def create_table(name,schema):
    c.pr("I","Creating Table "+name,1)
    var_map = {"FL" : "FLOAT" , "IN" : "INT(11)" , "DT": "DATETIME" ,"TS" : "TIMESTAMP" ,"VC" : "VARCHAR","TX":"TEXT"}
    query   = "CREATE TABLE `"+name+"` ("
    scharr  = schema.split(",")
    for sch in scharr:
        tmp = sch.split(":")
        col = tmp[0]
        dt  = tmp[1]
        if dt == "VC":
            size  = tmp[2]
            query = query+"`"+col+"` "+var_map[dt] + "("+size+") NOT NULL,"
        else:
            query = query+"`"+col+"` "+var_map[dt] + " NOT NULL,\n"
    query = query[0:-2]+")"

    qry = "SELECT * FROM information_schema.tables WHERE table_schema = 'stocki'  AND table_name = '"+name+"' LIMIT 1;"
    execQuery(query)
    if rcnt(qry):
        c.pr("I",str(name+" Table Created"),1)
        execQuery("UPDATE scrips SET status='YES' WHERE scrip='"+name+"'")
    else:
        c.pr("W",str(name+" Table Not Created"),1)
    cursor.close()
    del cursor
    db_obj.close()
    return


# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def removeNthFromEnd(self, head, n):
        dummy = head
        for i in range(n):
            dummy = dummy.next
        if not dummy:
            return head.next
        curr = head
        while dummy.next is not None:
            curr = curr.next
            dummy = dummy.next
        curr.next = curr.next.next
        return head


"""Classes to represent assembly strategies in DnaWeaver."""

from collections import defaultdict
from .ExportsMixin import ExportsMixin
from .PostProcessingMixin import PostProcessingMixin

class DnaQuote(ExportsMixin, PostProcessingMixin):
    """Class to represent the Quote returned by a DNA source in response to
    a quote request for a given DNA sequence.

    Parameters
    ----------

    source
      The DnaSupplier which issued the quote.

    sequence
      The sequence being quoted.

    accepted
      False if the sequence was rejected by the supplier, else True.

    price
      Amount asked by the DnaSupplier to build the requested sequence.

    lead_time
      Number of days required by the DnaSupplier to deliver the sequence.

    assembly_plan
      A dict of the form { (start1, end1): op1, (start2, end2): op2, ...}
      where the `(start, end)` represent sub-segments of the final sequence and
      `op1, op2` represent the AssemblyOperations that create the corresponding
      fragments.

    message
      A message added to the quote for more information, for instance the
      reason of the rejection.

    id
      A string identifying this assembly operation.

    deadline
      If the assembly plan was computed with a dealine in mind, this is the
      number of days at which the sequence should be delivered to ensure that
      the project will be finished on time (so the global deadline minus the
      duration of downstream operations). This is for drawing assembly
      timelines. (see the `propagate_deadline` method for this class).

    metadata
      Any other data on the quote.
    """

    def __init__(
        self,
        source,
        sequence,
        price=None,
        accepted=True,
        lead_time=None,
        assembly_plan=None,
        metadata=None,
        message="",
        id=None,
        deadline=None,
    ):
        self.source = source
        self.accepted = accepted
        self.price = price
        self.lead_time = lead_time
        self.sequence = sequence
        self.message = message
        self.assembly_plan = assembly_plan
        self.full_assembly_plan_computed = False
        self.metadata = metadata or {}
        self.id = id
        self.deadline = None

    def __repr__(self):
        if self.accepted:
            infos = "price %.02f" % self.price
            if self.lead_time is not None:
                infos = infos + " - lead_time %0.1f" % self.lead_time
        else:
            infos = "refused: %s" % self.message
        result = "From %s - %s" % (self.source, infos)
        if len(self.message):
            result += " - " + self.message
        return result

    @property
    def step_duration(self):
        """Duration of the final step of the assembly in the quote.

        Inferred by substracting the lead time of children operations to the
        lead time of this operation.
        """
        children_lead_time = self.children_overall_lead_time()
        if children_lead_time is None:
            return self.lead_time
        else:
            return self.lead_time - self.children_overall_lead_time()

    def compute_assembly_levels(self):
        """Return edges and levels for drawing the assembly graph nicely."""

        levels = defaultdict(lambda: [])
        edges = []

        def rec(subtree, depth=0):

            levels[depth].append(subtree)

            if subtree.assembly_plan is not None:
                for other in subtree.assembly_plan.values():
                    edges.append((other, subtree))
                    rec(other, depth + 1)

        rec(self)
        levels = [levels[i] for i in sorted(levels.keys())][::-1]
        levels = [sorted(level, key=lambda e: e.id)[::-1] for level in levels]
        return edges, levels

    def assembly_step_summary(self):
        """Return a print-friendly, simple string of the ordering plan."""
        plan = "\n  ".join(
            "%s-%s: %s" % (start, end, str(quote))
            for (start, end), quote in sorted(self.assembly_plan.items())
        )
        title = "Ordering plan (%s):" % self.source.name
        final_txt = "%s:\n  %s\nPrice:%.02f" % (title, plan, self.price)
        if self.lead_time is not None:
            final_txt = final_txt + ", total lead_time:%.1f" % self.lead_time
        return final_txt

    def children_total_price(self):
        """Return the total price of all sub-operations (apart from current)."""
        # print ([quote.accepted for quote in self.assembly_plan.values()])
        return sum(quote.price for quote in self.assembly_plan.values())

    def children_overall_lead_time(self):
        """Return the max lead time of all sub-operation (current one not
        included)."""
        if self.assembly_plan is None:
            return None
        lead_times = [quote.lead_time for quote in self.assembly_plan.values()]
        if len(lead_times) == 0:
            return None
        elif any(lead_time is None for lead_time in lead_times):
            return None
        else:
            return max(lead_times)

    def cuts_indices(self):
        """Return the locations of the `cuts` where the sequence is assembled.
        """
        return sorted([segment[1] for segment in self.assembly_plan])[:-1]


from django.contrib.auth.models import User
from posts.models import Comment, Follow, Group, Post
from rest_framework import serializers
from rest_framework.relations import SlugRelatedField
from rest_framework.validators import UniqueTogetherValidator

class PostSerializer(serializers.ModelSerializer):
    author = SlugRelatedField(slug_field='username', read_only=True)

    class Meta:
        fields = '__all__'
        model = Post

class CommentSerializer(serializers.ModelSerializer):
    author = serializers.SlugRelatedField(
        read_only=True, slug_field='username'
    )

    class Meta:
        fields = '__all__'
        model = Comment
        read_only_fields = ('author', 'post')

class GroupSerializer(serializers.ModelSerializer):
    class Meta:
        fields = '__all__'
        model = Group

class FollowSerializer(serializers.ModelSerializer):
    user = serializers.StringRelatedField(
        read_only=True,
        default=serializers.CurrentUserDefault())
    following = serializers.SlugRelatedField(
        slug_field='username', queryset=User.objects.all())

    class Meta:
        fields = '__all__'
        model = Follow
        validators = [
            UniqueTogetherValidator(
                queryset=Follow.objects.all(),
                fields=['user', 'following'],
                message='You already signed up')]

    def create(self, validated_data):
        following = validated_data.pop('following')
        user = self.context['request'].user
        if user == following:
            raise serializers.ValidationError("You can't sign up to yourself")

        return Follow.objects.create(following=following, user=user)

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# @File   : 0122-best-time-to-buy-and-sell-stock-ii.py
# @Date   : 2019/06/30
# @Author : Yuvv <yuvv_th@outlook.com>

from typing import List

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        cur_max = 0
        last_val = None
        # 贪心，只要右边比左边大即可
        for p in prices:
            if last_val is not None:
                if p > last_val:
                    cur_max += p - last_val
            last_val = p

        return cur_max

if __name__ == "__main__":
    s = Solution()
    print(s.maxProfit([7, 1, 5, 3, 6, 4]))  # 7 expected
    print(s.maxProfit([1, 2, 3, 4, 5]))  # 4 expected
    print(s.maxProfit([7, 6, 4, 3, 1]))  # 0 expected