<commit_before># -*- coding: utf-8 -*-
# © 2020 Comunitea - <NAME> <<EMAIL>>
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import fields, models, api, _
from datetime import datetime

import logging
_logger = logging.getLogger('--EXPORTACIÓN PRECIOS--')


class ExportPrices(models.Model):

    _name = 'export.prices'

    product_id = fields.Many2one('product.product', 'Product')
    pricelist_id = fields.Many2one('product.pricelist', 'Pricelist')
    qty = fields.Float('Min Quantity')
    price = fields.Float('Price')
    create_mode = fields.Boolean('Is created')
    # ID DEL ITEM PARA QUE ELLOS BORREN SIEMPRE?
    item_id = fields.Integer('Id item')
    
    
    @api.model
    def create_export_qtys_prices_records(self, pricelist, product_prices, create_mode=False):
        tot = len(product_prices)
        idx = 0

        # Borrar los items que ya existan
        item_ids = [x[3] for x in product_prices]
        item_ids = tuple(item_ids) if item_ids else '(-1)'
        sql = """
        delete
        from export_prices
        where  item_id in {}
        """.format(str(item_ids)).replace(',)', ')')
        self._cr.execute(sql)
        self._cr.commit()

        for t in product_prices:
            idx += 1
            # if not t[2]:  # Si precio 0 ignorar
            #     continue
            _logger.info('Creando record producto: {} qty: {}, precio: {} ({}/{})'.format(t[0], t[1], t[2], idx, tot))
            vals = {
                'product_id':t[0],
                'pricelist_id': pricelist.id,
                'qty': t[1],
                'price':t[2],
                'create_mode': create_mode,
                'item_id': t[3]
            }
            self.create(vals)
    
    @api.model
    def get_item_related_product_qtys(self, i, total_res):
        """
        Devuelvo [(p_id, qty, item_id)...] que representan los productos implicados
        por la regla de precios.
        Devuelvo solo los activos
        """
        qty = i['min_quantity']
        res = []
        if i['applied_on'] == '0_product_variant':
            if (i['product_id'], qty, i['id']) not in total_res:
                res.append((i['product_id'], qty, i['id']))
        elif i['applied_on'] == '1_product':
            domain = [('product_tmpl_id', '=', i['product_tmpl_id'])]
            products = self.env['product.product'].search(domain)
            for p in products:
                if (p.id, qty, i['id']) not in total_res:
                    res.append((p.id, qty, i['id']))
        elif i['applied_on'] == '2_product_category':
            domain = [('product_tmpl_id.categ_id', '=', i['categ_id'])]
            products = self.env['product.product'].search(domain)
            for p in products:
                if (p.id, qty, i['id']) not in total_res:
                    res.append((p.id, qty, i['id']))
        elif i['applied_on'] == '3_global':
            # Calculo los productos de la tarifa en la que se basa
            if i['base'] == 'pricelist' and i['base_pricelist_id']:
                # RECURSIVO A LA FUNCIÓN QUE LLAMA A ESTA
                # Debido a que ahora también devuelvo el item_id tengo que
                # corregirlo, porque esto me devuelve el id de la otra tarifa
                rec_res =  self.sql_get_related_products_qtys(i['base_pricelist_id'])
                res2 = [(x[0], x[1], i['id']) for x in rec_res]
                res.extend(res2)
        return res
    
    @api.model
    def sql_get_related_products_qtys(self, pricelist_id):
        """
        Devuelvo los productos asociados a esta tarifa
        """
        res = []

        # Busco por sql sino es lento
        sql = """
        select ppi.id, ppi.applied_on, ppi.product_id, ppi.product_tmpl_id, ppi.categ_id, ppi.min_quantity, 
               ppi.compute_price, ppi.base, ppi.base_pricelist_id, ppi.pricelist_id 
        from product_pricelist_item ppi
        left join product_product pp on pp.id=ppi.product_id
        left join product_template pt on pt.id=ppi.product_tmpl_id
        left join product_category pc on pc.id=ppi.categ_id
        where ppi.pricelist_id = {}
        and 
        ( (ppi.applied_on != '3_global') and (pp.active=true or pt.active or pc.active)
         or
        (ppi.applied_on = '3_global'));
        """.format(pricelist_id) 
        self._cr.execute(sql)
        sql_res = self._cr.fetchall()
        for t in sql_res:
            item_info = {
                'id': t[0],
                'applied_on': t[1],
                'product_id': t[2],
                'product_tmpl_id': t[3],
                'categ_id': t[4],
                'min_quantity': t[5],
                'compute_price': t[6],
                'base': t[7],
                'base_pricelist_id': t[8],
                'pricelist_id': t[9],
            }
            res2 = self.get_item_related_product_qtys(item_info, res)
            res.extend(res2)
        return res

    @api.model
    def create_export_prices(self):
        """
        Para todas las tarifas a exportar, calculo sus productos implicados
        obtengo los precios para esos productos, y creo los registros en la
        tabla
        """
        start = datetime.now()
        domain = [
            ('to_export', '=', True),
        ]
        pricelists = self.env['product.pricelist'].search(domain)
        for pl in pricelists:
            a = datetime.now()
            # Obetener productos-qtys relaccionados
            products_qtys = self.sql_get_related_products_qtys(pl.id)
            # Obtener precios por producto-cantidad
            product_prices = pl.get_export_product_qtys_prices(products_qtys)
            # Crear los registros
            self.create_export_qtys_prices_records(pl, product_prices,
                                                   create_mode=True)

            b = datetime.now()
            _logger.info('Finalizamos tarifa {} en {}'.format(pl.name, datetime.now()))
            _logger.info('TOTAL: {}'.format(b - a))
        end = datetime.now()
        _logger.info('TOTAL EXPORTACION: {}'.format(end - start))
        return

    #************************************************************************** 
    #************************CÁLCULO CAMBIOS DE PRECIOS************************
    #**************************************************************************

    # @api.model
    # def get_related_pricelist_ids(self, pricelist_id):
    #     """
    #     Para un elemento calculo las tarifas donde deberá recalcularse el
    #     precio, solo se busca un nivel ya que no tienen mas
    #     """
    #     # TODO MAS TARIFAS EN CADENA ?(no de momento, solo la cmnt nuestra)
    #     domain = [
    #         ('pricelist_id.to_export', '=', True),
    #         ('base_pricelist_id', '=', pricelist_id)
    #     ]
    #     items = self.env['product.pricelist.item'].search(domain)
    #     pricelists = items.mapped('pricelist_id')
    #     return pricelists._ids
    
    @api.model
    def get_related_items(self, pricelist_id):
        # TODO MAS TARIFAS EN CADENA ?(no de momento, solo la cmnt nuestra)
        domain = [
            ('pricelist_id.to_export', '=', True),
            ('base_pricelist_id', '=', pricelist_id)
        ]
        items = self.env['product.pricelist.item'].search(domain)
        return items<commit_msg>[FIX]prices_export: Tener en cuenta mas de 2 tarifas en cadena<commit_after># -*- coding: utf-8 -*-
# © 2020 Comunitea - <NAME> <<EMAIL>>
# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
from odoo import fields, models, api, _
from datetime import datetime

import logging
_logger = logging.getLogger('--EXPORTACIÓN PRECIOS--')


class ExportPrices(models.Model):

    _name = 'export.prices'

    product_id = fields.Many2one('product.product', 'Product')
    pricelist_id = fields.Many2one('product.pricelist', 'Pricelist')
    qty = fields.Float('Min Quantity')
    price = fields.Float('Price')
    create_mode = fields.Boolean('Is created')
    # ID DEL ITEM PARA QUE ELLOS BORREN SIEMPRE?
    item_id = fields.Integer('Id item')
    
    
    @api.model
    def create_export_qtys_prices_records(self, pricelist, product_prices, create_mode=False):
        tot = len(product_prices)
        idx = 0

        # Borrar los items que ya existan
        item_ids = [x[3] for x in product_prices]
        item_ids = tuple(item_ids) if item_ids else '(-1)'
        sql = """
        delete
        from export_prices
        where  item_id in {}
        """.format(str(item_ids)).replace(',)', ')')
        self._cr.execute(sql)
        self._cr.commit()

        for t in product_prices:
            idx += 1
            # if not t[2]:  # Si precio 0 ignorar
            #     continue
            _logger.info('Creando record producto: {} qty: {}, precio: {} ({}/{})'.format(t[0], t[1], t[2], idx, tot))
            vals = {
                'product_id':t[0],
                'pricelist_id': pricelist.id,
                'qty': t[1],
                'price':t[2],
                'create_mode': create_mode,
                'item_id': t[3]
            }
            self.create(vals)
    
    @api.model
    def get_item_related_product_qtys(self, i, total_res):
        """
        Devuelvo [(p_id, qty, item_id)...] que representan los productos implicados
        por la regla de precios.
        Devuelvo solo los activos
        """
        qty = i['min_quantity']
        res = []
        if i['applied_on'] == '0_product_variant':
            if (i['product_id'], qty, i['id']) not in total_res:
                res.append((i['product_id'], qty, i['id']))
        elif i['applied_on'] == '1_product':
            domain = [('product_tmpl_id', '=', i['product_tmpl_id'])]
            products = self.env['product.product'].search(domain)
            for p in products:
                if (p.id, qty, i['id']) not in total_res:
                    res.append((p.id, qty, i['id']))
        elif i['applied_on'] == '2_product_category':
            domain = [('product_tmpl_id.categ_id', '=', i['categ_id'])]
            products = self.env['product.product'].search(domain)
            for p in products:
                if (p.id, qty, i['id']) not in total_res:
                    res.append((p.id, qty, i['id']))
        elif i['applied_on'] == '3_global':
            # Calculo los productos de la tarifa en la que se basa
            if i['base'] == 'pricelist' and i['base_pricelist_id']:
                # RECURSIVO A LA FUNCIÓN QUE LLAMA A ESTA
                # Debido a que ahora también devuelvo el item_id tengo que
                # corregirlo, porque esto me devuelve el id de la otra tarifa
                rec_res =  self.sql_get_related_products_qtys(i['base_pricelist_id'])
                res2 = [(x[0], x[1], i['id']) for x in rec_res]
                res.extend(res2)
        return res
    
    @api.model
    def sql_get_related_products_qtys(self, pricelist_id):
        """
        Devuelvo los productos asociados a esta tarifa
        """
        res = []

        # Busco por sql sino es lento
        sql = """
        select ppi.id, ppi.applied_on, ppi.product_id, ppi.product_tmpl_id, ppi.categ_id, ppi.min_quantity, 
               ppi.compute_price, ppi.base, ppi.base_pricelist_id, ppi.pricelist_id 
        from product_pricelist_item ppi
        left join product_product pp on pp.id=ppi.product_id
        left join product_template pt on pt.id=ppi.product_tmpl_id
        left join product_category pc on pc.id=ppi.categ_id
        where ppi.pricelist_id = {}
        and 
        ( (ppi.applied_on != '3_global') and (pp.active=true or pt.active or pc.active)
         or
        (ppi.applied_on = '3_global'));
        """.format(pricelist_id) 
        self._cr.execute(sql)
        sql_res = self._cr.fetchall()
        for t in sql_res:
            item_info = {
                'id': t[0],
                'applied_on': t[1],
                'product_id': t[2],
                'product_tmpl_id': t[3],
                'categ_id': t[4],
                'min_quantity': t[5],
                'compute_price': t[6],
                'base': t[7],
                'base_pricelist_id': t[8],
                'pricelist_id': t[9],
            }
            res2 = self.get_item_related_product_qtys(item_info, res)
            res.extend(res2)
        return res

    @api.model
    def create_export_prices(self):
        """
        Para todas las tarifas a exportar, calculo sus productos implicados
        obtengo los precios para esos productos, y creo los registros en la
        tabla
        """
        start = datetime.now()
        domain = [
            ('to_export', '=', True),
        ]
        pricelists = self.env['product.pricelist'].search(domain)
        for pl in pricelists:
            a = datetime.now()
            # Obetener productos-qtys relaccionados
            products_qtys = self.sql_get_related_products_qtys(pl.id)
            # Obtener precios por producto-cantidad
            product_prices = pl.get_export_product_qtys_prices(products_qtys)
            # Crear los registros
            self.create_export_qtys_prices_records(pl, product_prices,
                                                   create_mode=True)

            b = datetime.now()
            _logger.info('Finalizamos tarifa {} en {}'.format(pl.name, datetime.now()))
            _logger.info('TOTAL: {}'.format(b - a))
        end = datetime.now()
        _logger.info('TOTAL EXPORTACION: {}'.format(end - start))
        return

    #************************************************************************** 
    #************************CÁLCULO CAMBIOS DE PRECIOS************************
    #**************************************************************************

    # @api.model
    # def get_related_pricelist_ids(self, pricelist_id):
    #     """
    #     Para un elemento calculo las tarifas donde deberá recalcularse el
    #     precio, solo se busca un nivel ya que no tienen mas
    #     """
    #     # TODO MAS TARIFAS EN CADENA ?(no de momento, solo la cmnt nuestra)
    #     domain = [
    #         ('pricelist_id.to_export', '=', True),
    #         ('base_pricelist_id', '=', pricelist_id)
    #     ]
    #     items = self.env['product.pricelist.item'].search(domain)
    #     pricelists = items.mapped('pricelist_id')
    #     return pricelists._ids
    
    @api.model
    def get_related_items(self, pricelist_id):
        domain = [
            ('pricelist_id.to_export', '=', True),
            ('base_pricelist_id', '=', pricelist_id)
        ]
        items = self.env['product.pricelist.item'].search(domain)
        for it in items:
            items |= self.get_related_items(it.pricelist_id.id)
        return items
{'fraction_non_alphanumeric': 0.1454643774503177, 'fraction_numerical': 0.006151142355008787, 'mean_word_length': 2.0163098878695207, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '915061', 'n_tokens_mistral': 4936, 'n_tokens_neox': 4623, 'n_words': 1050}