from django.db import models

from outils.common_imports import *
from outils.common import OdooAPI
from shelfs.models import Shelfs


class Order(models.Model):

    def __init__(self, id):
	    """Init with odoo id."""
	    self.id = int(id)
	    self.o_api = OdooAPI()

    def get_coop_main_coeff(self):
        coeff = None
        try:
            res = self.o_api.search_read('product.coefficient', [['id', '=', settings.COEFF_MAG_ID]], ['value'])
            if res:
                coeff = 1 + float(res[0]['value'])
        except:
            pass
        return coeff

    def get_inactive_products(self):
        """ Get the products in order that are inactive """
        result = []

        f = ['product_id']
        c = [['order_id', '=', self.id]]
        res = self.o_api.search_read('purchase.order.line', c, f)

        pids = []
        for ol in res:
            pids.append(ol['product_id'][0])

        if len(pids) > 0:
            # Get products not active: will block stock transfers
            f = ['id']
            c = [['id', 'in', pids], ['active','=',False]]
            res_prod = self.o_api.search_read('product.product', c, f)

            if res_prod:
                for p in res_prod:
                    for ol in res:
                        if ol['product_id'][0] == p['id']:
                            result.append(ol['product_id'])

        return result


    def get_lines(self, forExport=False, withNullQty=False):
        lines_data = {'lines': None, 'used_coeffs': None}
        f = ['id', 'product_id', 'package_qty', 'product_qty_package', 'product_qty', 'product_uom', 'price_unit', 'partner_id']
        if forExport is True:
            f += ['discount', 'price_subtotal', 'price_tax', 'taxes_id']
        c = [['order_id', '=', self.id]]
        if (withNullQty is False):
            c.append(['product_qty', '>', 0])
        res = self.o_api.search_read('purchase.order.line', c, f)

        pids = []
        partner_id = None
        for p in res:
            pids.append(p['product_id'][0])
            partner_id = p['partner_id'][0]
        used_coeffs = None
        if len(pids) > 0:
            # Adding barcode and other data for every purchased product
            f = ['barcode', 'product_tmpl_id', 'shelf_id']
            if forExport is False:  # i.e for reception
                f += ['taxes_id', 'standard_price']
                # add the 9 product coeffs
                for i in range(1,10):
                    f.append('coeff' + str(i) + '_id')

            c = [['id', 'in', pids]]
            res_bc = self.o_api.search_read('product.product', c, f)
            tmpl_ids = []
            if res_bc:
                taxes = {} # Needed to add tax coeff for each product
                res_tax = self.get_taxes_data_for_lines(res_bc)
                if res_tax:
                    for tax in res_tax:
                        taxes[str(tax['id'])] = tax['amount']

                # Iterate a first time through results to get distinct shelf_ids
                shelf_ids = []
                for l in res_bc:
                    if l['shelf_id'] is not False:
                        try:
                            tmp = shelf_ids.index(l['shelf_id'][0])
                        except:
                            # If index error, id not in array, so add it
                            shelf_ids.append(l['shelf_id'][0])

                shelfs_sortorder = []
                if len(shelf_ids) > 0:
                    shelfs_sortorder = Shelfs.get_shelfs_sortorder(shelf_ids)

                found_coeffs_ids = [] #  Extract from all products, to make a unique query after loop
                for l in res_bc:
                    for p in res:
                        if p['product_id'][0] == l['id']:
                            # coop_logger.info(str(l))
                            p['shelf_sortorder'] = 'X'
                            p['barcode'] = l['barcode']
                            p['product_tmpl_id'] = l['product_tmpl_id'][0]
                            if ('standard_price' in l):
                                p['p_price'] = l['standard_price']
                                # Let's add product coeff order and id (needed to compute sale price in further operations : new_shelf_price for ex.)
                                for i in range(1,10):
                                    if l['coeff' + str(i) + '_id'] is not False:
                                        coeff_id = l['coeff' + str(i) + '_id'][0]
                                        p['coeff' + str(i) + '_id'] = coeff_id
                                        
                                        if coeff_id not in found_coeffs_ids:
                                            found_coeffs_ids.append(coeff_id)

                                p['tax_coeff'] = (1 + (float(taxes[str(l['taxes_id'][0])]))/100)

                            if l['shelf_id'] is not False:
                                for s in shelfs_sortorder:
                                    if l['shelf_id'][0] == s['id']:
                                        p['shelf_sortorder'] = s['sort_order']
                            else:
                                p['shelf_sortorder'] = 'X'

                    tmpl_ids.append(l['product_tmpl_id'][0])
                used_coeffs = self.o_api.search_read('product.coefficient', [['id', 'in', found_coeffs_ids]], ['operation_type', 'value'])

                # Adding indicative_package for every product
                f = ['indicative_package','product_tmpl_id','product_code']
                c = [['product_tmpl_id', 'in', tmpl_ids], ['name', '=', partner_id]]
                res_ip = self.o_api.search_read('product.supplierinfo', c, f)
                if res_ip:
                    for l in res_ip:
                        for p in res:
                            try:
                                if p['product_tmpl_id'] == l['product_tmpl_id'][0]:
                                    p['indicative_package'] = l['indicative_package']
                                    p['ps_info_id'] = l['id']
                                    p['supplier_code'] = l['product_code']
                                    p['active'] = True
                            except Exception as e:
                                # if product is not active, it is not included in res_bc result
                                p['active'] = False
        lines_data['lines'] = res
        lines_data['used_coeffs'] = used_coeffs
        return lines_data

    def get_taxes_data_for_lines(self, lines):
        taxes_id = []
        res = []
        for l in lines:
            if ('taxes_id' in l):
                taxes_id += l['taxes_id']
        if len(taxes_id) > 0:
            taxes_id = set(taxes_id) # to keep only unique values
            f = ['name', 'amount']
            c = [['id', 'in', list(taxes_id)]]
            res = self.o_api.search_read('account.tax', c, f)
        return res

    def export(self):
        res = {'success': True}
        try:
            f = ["id", "name", "date_order", "partner_id", "date_planned", "amount_untaxed", "amount_total", "reception_status"]
            c = [['id', '=', self.id]]
            order = self.o_api.search_read('purchase.order', c, f)
            if order:
                lines_data = self.get_lines(forExport=True)
                lines = lines_data['lines']
                res['taxes'] = self.get_taxes_data_for_lines(lines)
                res['order'] = order[0]
                res['lines'] = lines
        except Exception as e:
            res['error'] = str(e)
            res['success'] = False
        return res

    def attach_file(self, fileName, removeFile = True):
        """
        Attach file to purshase orderself.
        By default, remove entry file after operation.
        """
        try:
            import base64, os
            content = open(fileName, "rb").read()
            b64content = base64.b64encode(content).decode('utf-8')
            # content = open(fileName, "rb").read().encode("utf-8")  # utf-8 encode needed for b64encode
            # b64content = base64.b64encode(content).decode("utf-8")  # utf-8 decode needed : if not Odoo bugs
            name = fileName.replace('temp/', '')
            mimetype = 'text/plain'
            if '.xlsx' in name:
                mimetype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
            # Does a file has already been sent ? (consequence of first validation)
            cond = [['name', '=', name], ['res_model', '=', 'purchase.order'], ['res_id', '=', self.id]]
            existing = self.o_api.search_read('ir.attachment', cond, [], 1)
            if (existing):
                fieldsDatas = {"datas": b64content}
                res = self.o_api.update('ir.attachment', [existing[0]['id']], fieldsDatas)
            else:
                fieldsDatas = {
                                "res_model": 'purchase.order',
                                "name": name,
                                "datas_fname": name,
                                "res_id": self.id,
                                "mimetype": mimetype,
                                "datas": b64content
                            }
                res = self.o_api.create('ir.attachment', fieldsDatas)

            # File is in odoo, remove it from temp storage
            if removeFile :
                os.remove(fileName)
        except Exception as e:
            print (e)
            res = None

        return res

    def attach_message(self, body):
        params = {'message_type': 'comment', 'subtype': 'mail.mt_comment', 'body': body}
        return self.o_api.execute('purchase.order','message_post',[self.id], params)

    def get_custom_barcode_labels_to_print(self):
        import re
        forced_quantity = getattr(settings, 'RECEPTION_PDT_LABELS_NB_FORCE_TO_NB', None)
        fixed_prefix = getattr(settings, 'FIXED_BARCODE_PREFIX', '0490')
        labels_data = {'total': 0, 'details': []}
        lines_data = self.get_lines()
        lines = lines_data['lines']
        bc_pattern = re.compile('^' + fixed_prefix)
        for l in lines:
            if ('barcode' in l) and not (bc_pattern.match(str(l['barcode'])) is None):
                if forced_quantity is not None:
                    l['product_qty'] = forced_quantity
                labels_data['details'].append(l)
                labels_data['total'] += l['product_qty']
        return labels_data

    def get_order_attachment_id(self):
        res = {}
        f = ["id"]
        c = [['res_model', '=', 'purchase.order'], ['res_id', '=', self.id], ['type', 'in', ['binary', 'url']]]

        try:
            attachment = self.o_api.search_read('ir.attachment', c, f)
            res = attachment[0]
        except Exception as e:
            res["id_po"] = self.id
            res["error"] = str(e)

        return res

    @staticmethod
    def create(supplier_id, date_planned, order_lines):
        if len(list(order_lines)) > 0:
            order_data = {
                "partner_id": int(supplier_id),
                "partner_ref": False,
                "currency_id": 1,
                "date_order": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
                "origin": "Aide à la commande",
                "company_id": 1,
                "order_line": [],
                "notes": False,
                "date_planned": date_planned,
                "picking_type_id": 1,
                "dest_address_id": False,
                "incoterm_id": False,
                "payment_term_id": False,
                "fiscal_position_id": False,
                "message_follower_ids": False,
                "message_ids": False
            }

            for line in order_lines:
                product_line_name =  line["name"]
                if "product_code" in line and line["product_code"] is not False:
                    product_code = str(line["product_code"])
                    product_line_name = "[" + product_code + "] " + product_line_name

                order_data["order_line"].append(
                    [
                        0,
                        False,
                        {
                            "package_qty": line["package_qty"],
                            "price_policy": "uom",
                            "indicative_package": True,
                            "product_id": line["product_variant_ids"][0],
                            "name": product_line_name,
                            "date_planned": date_planned,
                            "account_analytic_id": False,
                            "product_qty_package":line["product_qty_package"],
                            "product_qty": line["product_qty"],
                            "product_uom": line["product_uom"],
                            "price_unit": line["price_unit"],
                            "discount": 0,
                            "taxes_id": [
                                [
                                    6,
                                    False,
                                    line["supplier_taxes_id"]
                                ]
                            ]
                        }
                    ]
                )

            api = OdooAPI()
            id_po = api.create('purchase.order', order_data)
            res_confirm = api.execute('purchase.order', 'button_confirm', [id_po])

            res = {
                'id_po': id_po,
                'confirm_po': True,
                'supplier_id': supplier_id,
                'date_planned': date_planned
            }
        else:
            res = {
                'id_po': 0,
                'supplier_id': supplier_id
            }

        return res

class Orders(models.Model):

    @staticmethod
    def get_lines(oids):
        lines = []
        try:
            api = OdooAPI()
            f = ['id', 'product_id', 'package_qty', 'product_qty_package', 'product_qty', 'product_uom', 'price_unit', 'partner_id']
            c = [['order_id', 'in', oids]]
            res = api.search_read('purchase.order.line', c, f)
            pids = []
            for p in res:
                pids.append(p['product_id'][0])

            if len(pids) > 0:
                # Adding barcode and other data for every purchased product
                f = ['barcode', 'product_tmpl_id', 'shelf_id']
                c = [['id', 'in', pids]]
                res_bc = api.search_read('product.product', c, f)
                for l in res_bc:
                    for p in res:
                        if p['product_id'][0] == l['id']:
                            p['barcode'] = l['barcode']
                            p['product_tmpl_id'] = l['product_tmpl_id'][0]
                lines = res
        except Exception as e:
            coop_logger.error('Orders get_lines(oids) : %s', str(e))

        return lines

    @staticmethod
    def get_custom_barcode_labels_to_print(oids):
        import re
        labels_data = {}
        try:
            forced_quantity = getattr(settings, 'RECEPTION_PDT_LABELS_NB_FORCE_TO_NB', None)
            fixed_prefix = getattr(settings, 'FIXED_BARCODE_PREFIX', '0490')
            bc_pattern = re.compile('^' + fixed_prefix)
            lines_data = Orders.get_lines(oids)
            for l in lines_data:
                if not (bc_pattern.match(str(l['barcode'])) is None):
                    if not (l['product_tmpl_id'] in labels_data):
                        labels_data[l['product_tmpl_id']] = 0
                    if forced_quantity is not None:
                        labels_data[l['product_tmpl_id']] = int(forced_quantity)
                    else:
                        labels_data[l['product_tmpl_id']] += int(l['product_qty'])
        except Exception as e:
            coop_logger.error('Orders get_custom_barcode_labels_to_print(oids) : %s', str(e))

        return labels_data

    @staticmethod
    def get_orders_between_dates(date_from, date_to):
        """@depends on Odoo module lacagette_purchase"""
        o_api = OdooAPI()
        params = {'date_from': date_from, 'date_to': date_to}
        res = {}
        
        try:
            res = o_api.execute('purchase.order', 'get_received_orders_between_dates', [], params)
        except Exception as e:
            res["error"] = str(e)
            coop_logger.error('get_orders_between_dates : %s', str(e))

        return res


class CagetteSuppliers(models.Model):

    @staticmethod
    def get_suppliers():
        api = OdooAPI()

        f = ['id', 'name', 'display_name']
        c = [['supplier', '=', 1], ['parent_id', '=', False]]
        res = api.search_read('res.partner', c, f)

        return res
