From 5f4bb24894ed0448f4379d9f6a605a0c889c657a Mon Sep 17 00:00:00 2001 From: Luis Date: Tue, 29 Mar 2022 12:25:28 +0200 Subject: [PATCH] [ADD] product_update_price_last_purchase --- .../__init__.py | 3 + .../__manifest__.py | 31 ++ .../data/report_paperformat.xml | 20 ++ product_update_price_last_purchase/i18n/es.po | 282 ++++++++++++++++++ .../models/__init__.py | 8 + .../models/ir_actions_report.py | 22 ++ .../models/product_pricelist.py | 25 ++ .../models/product_pricelist_item.py | 12 + .../models/product_product.py | 26 ++ .../models/product_template.py | 144 +++++++++ .../models/res_company.py | 17 ++ .../models/res_config.py | 35 +++ .../models/stock_move.py | 33 ++ .../report/product_barcode.xml | 74 +++++ .../report/report_product_barcode.xml | 35 +++ .../report/report_product_shelf_tag.xml | 44 +++ .../views/actions.xml | 39 +++ .../views/product_view.xml | 92 ++++++ 18 files changed, 942 insertions(+) create mode 100644 product_update_price_last_purchase/__init__.py create mode 100644 product_update_price_last_purchase/__manifest__.py create mode 100644 product_update_price_last_purchase/data/report_paperformat.xml create mode 100644 product_update_price_last_purchase/i18n/es.po create mode 100644 product_update_price_last_purchase/models/__init__.py create mode 100644 product_update_price_last_purchase/models/ir_actions_report.py create mode 100644 product_update_price_last_purchase/models/product_pricelist.py create mode 100644 product_update_price_last_purchase/models/product_pricelist_item.py create mode 100644 product_update_price_last_purchase/models/product_product.py create mode 100644 product_update_price_last_purchase/models/product_template.py create mode 100644 product_update_price_last_purchase/models/res_company.py create mode 100644 product_update_price_last_purchase/models/res_config.py create mode 100644 product_update_price_last_purchase/models/stock_move.py create mode 100644 product_update_price_last_purchase/report/product_barcode.xml create mode 100644 product_update_price_last_purchase/report/report_product_barcode.xml create mode 100644 product_update_price_last_purchase/report/report_product_shelf_tag.xml create mode 100644 product_update_price_last_purchase/views/actions.xml create mode 100644 product_update_price_last_purchase/views/product_view.xml diff --git a/product_update_price_last_purchase/__init__.py b/product_update_price_last_purchase/__init__.py new file mode 100644 index 0000000..2ed39cb --- /dev/null +++ b/product_update_price_last_purchase/__init__.py @@ -0,0 +1,3 @@ +from . import models +from . import report + diff --git a/product_update_price_last_purchase/__manifest__.py b/product_update_price_last_purchase/__manifest__.py new file mode 100644 index 0000000..1b46229 --- /dev/null +++ b/product_update_price_last_purchase/__manifest__.py @@ -0,0 +1,31 @@ +{ + 'name': 'Product Update Sale Price', + 'version': '12.0.1.1.0', + 'category': 'product', + 'summary' : 'Allow updating list_price when the cost price changes in last purchase.', + 'description' : """ + * Setea los impuestos del proveedor al mismo tipo que el impuesto de venta. + * Actualiza el precio de venta según el precio de coste aplicado a una tarifa. + * Filtro para productos actualizados el precio de coste. + * Filtro para productos que necesitan etiqueta nueva. + * Campo que guarda el último precio de compra en vez de usar standard_price y no afectar a la valoración de inventario. + """, + 'author': 'Criptomart', + 'website': 'https://criptomart.net', + 'license': 'AGPL-3', + 'depends': [ + 'base', + 'product', + 'account', + 'stock_account', + ], + 'data': [ + 'views/actions.xml', + 'views/product_view.xml', + 'data/report_paperformat.xml', + 'report/report_product_shelf_tag.xml', + 'report/report_product_barcode.xml', + 'report/product_barcode.xml' + ], + 'installable': True, +} diff --git a/product_update_price_last_purchase/data/report_paperformat.xml b/product_update_price_last_purchase/data/report_paperformat.xml new file mode 100644 index 0000000..03e74be --- /dev/null +++ b/product_update_price_last_purchase/data/report_paperformat.xml @@ -0,0 +1,20 @@ + + + + + Barcodes stickers format + + A4 + 0 + 0 + Portrait + 10 + 5 + 8 + 8 + + 0 + 75 + + + diff --git a/product_update_price_last_purchase/i18n/es.po b/product_update_price_last_purchase/i18n/es.po new file mode 100644 index 0000000..722f46d --- /dev/null +++ b/product_update_price_last_purchase/i18n/es.po @@ -0,0 +1,282 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_update_price_last_purchase +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2022-03-28 17:11+0000\n" +"PO-Revision-Date: 2022-03-28 17:11+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__list_price_automatic +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__list_price_automatic +msgid "Automatic Sale Price" +msgstr "Precio de venta automático" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__list_price_automatic +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__list_price_automatic +msgid "Automatic computation of the PVP from the cost price and the rate defined in the configuration." +msgstr "Cálculo automático del PVP a partir del precio de coste y la tarifa definida en la configuración." + +#. module: product_update_price_last_purchase +#: model:ir.actions.report,name:product_update_price_last_purchase.report_productbarcode +msgid "Barcode" +msgstr "Código de barras" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_pricelist_item__base +msgid "Base price for computation.\n" +"Public Price: The base price will be the Sale/public Price.\n" +"Cost Price : The base price will be the cost price.\n" +"Other Pricelist : Computation of the base price based on another Pricelist." +msgstr "Precio base de cálculo.\n" +"Precio Público: El precio base será el Precio Público / Venta.\n" +"Precio de costo: El precio base será el precio de costo.\n" +"Otra lista de precios: cálculo del precio base basado en otra lista de precios." + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basado en" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__last_purchase_price_compute_type +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__last_purchase_price_compute_type +msgid "Choose whether discounts should influence the calculation of the last purchase price. Select Never update for manual configuration of cost and sale prices.\n" +"\n" +"* Without discounts: does not take into account discounts when updating the last purchase price.\n" +"* First discount: take into account only first discount when updating the last purchase price.\n" +"* Triple discount: take into account all discounts when updating the last purchase price. Needs \"Purchase Triple Discount\" OCA module.\n" +"* Manual update: Select this for manual configuration of cost and sale price. The sales price will not be calculated automatically." +msgstr "Elija si los descuentos deben influir en la actualización del último precio de compra. Seleccione No actualizar nunca para la configuración manual de los precios de coste y venta.\n" +"\n" +"* Sin descuentos: no tiene en cuenta ningún descuento al actualizar el último precio de compra.\n" +"* Primer descuento: tiene en cuenta sólo el primer descuento al actualizar el último precio de compra.\n" +"* Triple descuento: tiene en cuenta todos los descuentos al actualizar el último precio de compra. Necesita el módulo OCA \"Purchase Triple Discount\".\n" +"* Actualización manual: configuración manual del precio de coste y de venta. El precio de venta no se calculará automáticamente." + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_res_config_settings +msgid "Config Settings" +msgstr "Opciones de Configuración" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_packaging__qty +msgid "Contained Quantity" +msgstr "Cantidad contenida" + +#. module: product_update_price_last_purchase +#: selection:product.pricelist.item,base:0 +msgid "Cost" +msgstr "Coste" + +#. module: product_update_price_last_purchase +#: selection:product.pricelist.item,base:0 +msgid "Cost Price Tax Included" +msgstr "Precio de coste con impuesto incluido" + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.res_config_settings_view_form_pricelists +msgid "Default pricelists for Coops" +msgstr "Tarifas por defecto para cooperativas" + +#. module: product_update_price_last_purchase +#: selection:product.template,last_purchase_price_compute_type:0 +msgid "First discount" +msgstr "Primer descuento" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__last_purchase_price +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__last_purchase_price +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.product_view_inherit_list_price_auto +#: selection:product.pricelist.item,base:0 +msgid "Last purchase price" +msgstr "Último precio de compra" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__last_purchase_price_compute_type +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__last_purchase_price_compute_type +msgid "Last purchase price calculation type" +msgstr "Cálculo de último precio de compra" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__list_price_updated +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__list_price_updated +msgid "Last purchase price updated" +msgstr "Último precio de compra actualizado" + +#. module: product_update_price_last_purchase +#: selection:product.template,last_purchase_price_compute_type:0 +msgid "Manual update" +msgstr "Actualización manual" + +#. module: product_update_price_last_purchase +#: code:addons/product_update_price_last_purchase/models/product_template.py:38 +#, python-format +msgid "Not found a valid pricelist to compute sale price. Check configuration in General Settings." +msgstr "" + +#. module: product_update_price_last_purchase +#: selection:product.pricelist.item,base:0 +msgid "Other Pricelist" +msgstr "Otra tarifa" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__list_price +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__list_price +msgid "Price calculated according to the configured pricelist, including VAT." +msgstr "Precio calculado según la tarifa configurada, incluyendo el IVA." + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_product_pricelist +msgid "Pricelist" +msgstr "Tarifa" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_product_pricelist_item +msgid "Pricelist Item" +msgstr "Elemento de tarifa" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_res_config_settings__product_pricelist_automatic +msgid "Pricelist applied to automatic calculation of sales price" +msgstr "Tarifa aplicada al cálculo automático del precio de venta" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_res_company__product_pricelist_automatic +msgid "Pricelist applied to the automatic selling price" +msgstr "Tarifa aplicada al PVP automáticamente" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: product_update_price_last_purchase +#: model:ir.actions.report,name:product_update_price_last_purchase.report_product_product_barcode +#: model:ir.actions.report,name:product_update_price_last_purchase.report_product_template_barcode +#: model:ir.actions.report,name:product_update_price_last_purchase.report_productbarcode_laosa +#: model:ir.actions.report,name:product_update_price_last_purchase.report_simple_barcode_laosa +msgid "Product Barcode (PDF)" +msgstr "Código de barras del producto (PDF)" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_product_packaging +msgid "Product Packaging" +msgstr "Empaquetado del producto" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.view_product_search_form_inherit_tags +msgid "Products that have changed their sales price and no label has been printed." +msgstr "Productos que han cambiado su PVP y no se ha impreso su etiqueta." + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.view_product_search_form_inherit_updated +msgid "Products that have recently changed their cost price and have not updated their selling price." +msgstr "Productos que han cambiado recientemente su precio de coste y no han actualizado su PVP." + +#. module: product_update_price_last_purchase +#: selection:product.pricelist.item,base:0 +msgid "Public Price" +msgstr "Precio público" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_res_company__product_pricelist_automatic +#: model:ir.model.fields,help:product_update_price_last_purchase.field_res_config_settings__product_pricelist_automatic +msgid "Rate that applies to all products that update the selling price automatically." +msgstr "Tarifa que se aplica a todos los productos que actualizan el precio de venta automáticamente." + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_ir_actions_report +msgid "Report Action" +msgstr "Reportar la acción" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__list_price +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__list_price +msgid "Sale price with VAT" +msgstr "PVP con impuestos" + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.product_view_inherit_list_price_auto +msgid "Sale price." +msgstr "PVP" + +#. module: product_update_price_last_purchase +#: model:ir.model,name:product_update_price_last_purchase.model_stock_move +msgid "Stock Move" +msgstr "Movimiento de stock" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__list_price_updated +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__list_price_updated +msgid "The last cost price has been updated and you need to update the selling price in the database, shelves and scales." +msgstr "Se ha actualizado el último precio de coste y hay que actualizar el PVP en la base de datos, lineales y las balanzas." + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__last_purchase_price +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__last_purchase_price +msgid "The last price at which the product was purchased. It is used as the base price field for calculating the product sale price." +msgstr "El último precio al que se compró el producto. Se utiliza como campo de precio base para calcular el precio de venta del producto." + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_product__to_print +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_template__to_print +msgid "The sale price has been updated on this product and needs to be updated on the shelf." +msgstr "El PVP ha sido actualizado en este producto y necesita ser actualizado en el lineal." + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,help:product_update_price_last_purchase.field_product_packaging__qty +msgid "The total number of products you can have per pallet or box." +msgstr "El numero total de productos que puede tener por palé o caja." + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.view_product_search_form_inherit_tags +msgid "To print" +msgstr "Para imprimir" + +#. module: product_update_price_last_purchase +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_product__to_print +#: model:ir.model.fields,field_description:product_update_price_last_purchase.field_product_template__to_print +msgid "To print label" +msgstr "Pendiente de imprimir etiqueta" + +#. module: product_update_price_last_purchase +#: model_terms:ir.ui.view,arch_db:product_update_price_last_purchase.view_product_search_form_inherit_updated +msgid "To update sales price" +msgstr "Pendiente de actualizar PVP" + +#. module: product_update_price_last_purchase +#: selection:product.template,last_purchase_price_compute_type:0 +msgid "Triple discount" +msgstr "Triple decuento" + +#. module: product_update_price_last_purchase +#: model:ir.actions.server,name:product_update_price_last_purchase.action_product_calculate_theoritical_price +msgid "Update Sales Price" +msgstr "Actualizar PVP" + +#. module: product_update_price_last_purchase +#: selection:product.template,last_purchase_price_compute_type:0 +msgid "Without discounts" +msgstr "Sin descuentos" + diff --git a/product_update_price_last_purchase/models/__init__.py b/product_update_price_last_purchase/models/__init__.py new file mode 100644 index 0000000..e23f31b --- /dev/null +++ b/product_update_price_last_purchase/models/__init__.py @@ -0,0 +1,8 @@ +from . import product_template +from . import product_product +from . import res_company +from . import res_config +from . import ir_actions_report +from . import stock_move +from . import product_pricelist +from . import product_pricelist_item diff --git a/product_update_price_last_purchase/models/ir_actions_report.py b/product_update_price_last_purchase/models/ir_actions_report.py new file mode 100644 index 0000000..b8bf3eb --- /dev/null +++ b/product_update_price_last_purchase/models/ir_actions_report.py @@ -0,0 +1,22 @@ +import logging + +from odoo import api, fields, models + +_logger = logging.getLogger(__name__) + +class IrActionsReport(models.Model): + _inherit = 'ir.actions.report' + + @api.multi + def render_qweb_pdf(self, res_ids=None, data=None): + _logger.debug("render_qweb_pdf : %s -- %s" %(res_ids, data)) + if res_ids: + Model = self.env[self.model] + record_ids = Model.browse(res_ids) + wk_record_ids = Model + for record_id in record_ids: + if self.report_name == "product.report_producttemplatelabel": + record_id.to_print = False + return super(IrActionsReport, self).render_qweb_pdf(res_ids, data) + + diff --git a/product_update_price_last_purchase/models/product_pricelist.py b/product_update_price_last_purchase/models/product_pricelist.py new file mode 100644 index 0000000..2a9faa3 --- /dev/null +++ b/product_update_price_last_purchase/models/product_pricelist.py @@ -0,0 +1,25 @@ +# Copyright (C) 2020: Criptomart (https://criptomart.net) +# @author Santi Noreña () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class ProductPricelist(models.Model): + _inherit = 'product.pricelist' + + @api.multi + def _compute_price_rule(self, products_qty_partner, date=False, uom_id=False): + ProductPricelistItem = self.env['product.pricelist.item'] + ProductProduct = self.env['product.product'] + res = super()._compute_price_rule(products_qty_partner, date=date, uom_id=uom_id) + new_res = res.copy() + for product_id, values in res.items(): + if values[1]: + item_id = values[1] + if item_id: + item = ProductPricelistItem.browse(item_id) + if item.base == 'last_purchase_price': + product = ProductProduct.browse(product_id) + new_res[product_id] = (product.last_purchase_price, item_id) + return new_res diff --git a/product_update_price_last_purchase/models/product_pricelist_item.py b/product_update_price_last_purchase/models/product_pricelist_item.py new file mode 100644 index 0000000..36f1b80 --- /dev/null +++ b/product_update_price_last_purchase/models/product_pricelist_item.py @@ -0,0 +1,12 @@ +# Copyright (C) 2020: Criptomart (https://criptomart.net) +# @author Santi Noreña () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class ProductPricelistItem(models.Model): + _inherit = 'product.pricelist.item' + + base = fields.Selection(selection_add=[ + ('last_purchase_price', 'Last purchase price')]) diff --git a/product_update_price_last_purchase/models/product_product.py b/product_update_price_last_purchase/models/product_product.py new file mode 100644 index 0000000..51baf7d --- /dev/null +++ b/product_update_price_last_purchase/models/product_product.py @@ -0,0 +1,26 @@ +# Copyright (C) 2020: Criptomart (https://criptomart.net) +# @author Santi Noreña () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging + +from odoo import models, fields, api +from odoo.addons import decimal_precision as dp + +_logger = logging.getLogger(__name__) + +class ProductProduct(models.Model): + _inherit = "product.product" + + @api.multi + def write(self, vals): + if vals.get('last_purchase_price'): + vals['list_price_updated'] = True + return super(ProductProduct, self).write(vals) + + +class ProductPackaging(models.Model): + _inherit = "product.packaging" + + qty = fields.Float('Contained Quantity', help="The total number of products you can have per pallet or box.", digits=dp.get_precision('Product Unit of Measure')) + diff --git a/product_update_price_last_purchase/models/product_template.py b/product_update_price_last_purchase/models/product_template.py new file mode 100644 index 0000000..493dd01 --- /dev/null +++ b/product_update_price_last_purchase/models/product_template.py @@ -0,0 +1,144 @@ +# Copyright (C) 2020: Criptomart (https://criptomart.net) +# @author Santi Noreña () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging +import math + +from odoo import exceptions, models, fields, api, _ +from odoo.exceptions import UserError +from odoo.addons import decimal_precision as dp + +_logger = logging.getLogger(__name__) + +class ProductTemplate(models.Model): + _inherit = "product.template" + + @api.multi + def _compute_theoritical_price(self): + partner = self.env['res.users'].browse(self.env.uid).partner_id + pricelist_obj = self.env['product.pricelist'] + pricelist_id = self.env['ir.config_parameter'].sudo().get_param('product_laosa.product_pricelist_automatic') or False + pricelist = pricelist_obj.browse(int(pricelist_id)) + _logger.debug("Calculating price with PriceList : %s" %pricelist.name) + if pricelist: + for template in self: + if template.name and template.id and template.last_purchase_price_compute_type != 'manual_update': + partial_price = pricelist.get_product_price(template.product_variant_id, "1", partner) + _logger.debug("partial_price : %s" %partial_price) + # Suma el IVA + for tax in template.taxes_id: + partial_price = partial_price * ( 1 + ( tax.amount / 100) ) + _logger.debug("partial_price after taxes : %s" %partial_price) + # Redondea a 0,05 de precisión + template.list_price = round(round(partial_price / 0.05) * 0.05, -int(math.floor(math.log10(0.05)))) + _logger.debug("final price : %s" %template.list_price) + template.list_price_updated = False + else: + raise UserError(_('Not found a valid pricelist to compute sale price. Check configuration in General Settings.')) + return False + + list_price = fields.Float( + string="Sale price with VAT", + help="Price calculated according to the configured pricelist, including VAT.", + compute="_compute_theoritical_price", + store=True, + readonly=False, + digits=dp.get_precision('Product Price') + ) + + list_price_updated = fields.Boolean( + string="Last purchase price updated", + help="The last cost price has been updated and you need to update the selling price in the database, shelves and scales.", + default=False, + readonly=True + ) + + list_price_automatic = fields.Boolean( + string="Automatic Sale Price", + help="Automatic computation of the PVP from the cost price and the rate defined in the configuration.", + default=True + ) + + to_print = fields.Boolean( + string="To print label", + help="The sale price has been updated on this product and needs to be updated on the shelf.", + default=False, + readonly=True + ) + + last_purchase_price = fields.Float( + string="Last purchase price", + help="The last price at which the product was purchased. It is used as the base price field for calculating the product sale price.", + #readonly=True, + digits=dp.get_precision('Product Price') + ) + + last_purchase_price_compute_type = fields.Selection([ + ('without_discounts', 'Without discounts'), + ('with_discount', 'First discount'), + ('with_three_discounts', 'Triple discount'), + ('manual_update', 'Manual update')], + string="Last purchase price calculation type", + help='Choose whether discounts should influence the calculation of the last purchase price. Select Never update for manual configuration of cost and sale prices.\n' + '\n* Without discounts: does not take into account discounts when updating the last purchase price.\n' + '* First discount: take into account only first discount when updating the last purchase price.\n' + '* Triple discount: take into account all discounts when updating the last purchase price. Needs "Purchase Triple Discount" OCA module.\n' + '* Manual update: Select this for manual configuration of cost and sale price. The sales price will not be calculated automatically.', + default='without_discounts', + required=True + ) + + @api.model + def create(self, vals): + # Set supplier tax same than customer tax + if vals.get('taxes_id'): + tax = self.get_supplier_tax(vals.get('taxes_id')) + vals['supplier_taxes_id'] = tax + vals['list_price_updated'] = True + return super(ProductTemplate, self).create(vals) + + @api.multi + def write(self, vals): + # Set supplier tax same than customer tax + if vals.get('taxes_id'): + tax = self.get_supplier_tax(vals.get('taxes_id')) + vals['supplier_taxes_id'] = tax + # Mark if product needs list price update + if vals.get('last_purchase_price'): + vals['list_price_updated'] = True + # Mark if product needs update the shelf tag + if vals.get('list_price'): + vals['to_print'] = True + return super(ProductTemplate, self).write(vals) + + def get_supplier_tax(self, taxes_id): + tax_obj = self.env['account.tax'] + tax_res = [] + if taxes_id: + if "6, False, []" not in taxes_id: + for tupla in taxes_id: + a, b, c = tupla + if c: + for i in c: + tax = tax_obj.browse(i) + val = tax.amount + if val == 21: + record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva21_bc').id + elif val == 10: + record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva10_bc').id + elif val == 4: + record_id = self.env.ref('l10n_es.1_account_tax_template_p_iva4_bc').id + else: + record_id = self.env['account.tax'].search([ + ('amount','=', val), + ('active','=', True), + ('type_tax_use','=','purchase') + ], + limit=1).id + tax_res.append(record_id) + + return [(6, 0, tax_res)] + + + diff --git a/product_update_price_last_purchase/models/res_company.py b/product_update_price_last_purchase/models/res_company.py new file mode 100644 index 0000000..4d7b39b --- /dev/null +++ b/product_update_price_last_purchase/models/res_company.py @@ -0,0 +1,17 @@ +#import logging + +from odoo import models, fields, api + +#_logger = logging.getLogger(__name__) + +class ResCompany(models.Model): + _inherit = "res.company" + + product_pricelist_automatic = fields.Many2one( + comodel_name='product.pricelist', + string='Pricelist applied to the automatic selling price', + help='Rate that applies to all products that update the selling price automatically.', + ) + + + diff --git a/product_update_price_last_purchase/models/res_config.py b/product_update_price_last_purchase/models/res_config.py new file mode 100644 index 0000000..9727164 --- /dev/null +++ b/product_update_price_last_purchase/models/res_config.py @@ -0,0 +1,35 @@ +#import logging + +from odoo import models, fields, api + +#_logger = logging.getLogger(__name__) + +class ResConfigSettings(models.TransientModel): + _inherit = 'res.config.settings' + + product_pricelist_automatic = fields.Many2one( + related='company_id.product_pricelist_automatic', + comodel_name='product.pricelist', + string='Pricelist applied to automatic calculation of sales price', + readonly=False, + ) + + @api.model + def get_values(self): + res = super(ResConfigSettings, self).get_values() + config_obj = self.env["ir.config_parameter"] + product_pricelist_automatic = config_obj.sudo().get_param( + "product_laosa.product_pricelist_automatic", default=0) + return res + + @api.multi + def set_values(self): + super(ResConfigSettings, self).set_values() + config_obj = self.env["ir.config_parameter"] + config_obj.sudo().set_param( + "product_laosa.product_pricelist_automatic", + int(self.product_pricelist_automatic.id) + ) + + + diff --git a/product_update_price_last_purchase/models/stock_move.py b/product_update_price_last_purchase/models/stock_move.py new file mode 100644 index 0000000..b254f54 --- /dev/null +++ b/product_update_price_last_purchase/models/stock_move.py @@ -0,0 +1,33 @@ +# Copyright 2016-2019 Akretion (http://www.akretion.com/) +# Copyright 2020 Criptomart +# @author: Alexis de Lattre +# @author Santi Noreña () +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +import logging +import math + +from odoo import exceptions, models, fields, api, _ +from odoo.tools import float_is_zero, float_round, float_compare + +_logger = logging.getLogger(__name__) + + +class StockMove(models.Model): + _inherit = 'stock.move' + + @api.multi + def product_price_update_before_done(self): + super(StockMove, self).product_price_update_before_done() + for move in self.filtered(lambda move: move.location_id.usage == 'supplier'): + if move.product_id.last_purchase_price_compute_type == 'with_three_discounts': + price_updated = float_round(move.purchase_line_id.price_subtotal / move.purchase_line_id.product_qty, precision_digits=2) + elif move.product_id.last_purchase_price_compute_type == 'with_discount': + price_updated = float_round(move.purchase_line_id.price_unit * (1 - move.purchase_line_id.discount / 100), precision_digits=2) + else: + price_updated = move.purchase_line_id.price_unit + + if float_compare(move.product_id.last_purchase_price, price_updated, precision_digits=2) and not float_is_zero(move.quantity_done, precision_digits=3): + _logger.info("Update last_purchase_price: %s for product %s Previous price: %s" % (price_updated, move.product_id.default_code, move.product_id.last_purchase_price)) + # Write the last purchase price, as SUPERUSER_ID because a warehouse manager may not have the right to write on products + move.product_id.with_context(force_company=move.company_id.id).sudo().write({'last_purchase_price': price_updated}) diff --git a/product_update_price_last_purchase/report/product_barcode.xml b/product_update_price_last_purchase/report/product_barcode.xml new file mode 100644 index 0000000..4f27aa8 --- /dev/null +++ b/product_update_price_last_purchase/report/product_barcode.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/product_update_price_last_purchase/report/report_product_barcode.xml b/product_update_price_last_purchase/report/report_product_barcode.xml new file mode 100644 index 0000000..6f41d88 --- /dev/null +++ b/product_update_price_last_purchase/report/report_product_barcode.xml @@ -0,0 +1,35 @@ + + + + + + + diff --git a/product_update_price_last_purchase/report/report_product_shelf_tag.xml b/product_update_price_last_purchase/report/report_product_shelf_tag.xml new file mode 100644 index 0000000..399d3d4 --- /dev/null +++ b/product_update_price_last_purchase/report/report_product_shelf_tag.xml @@ -0,0 +1,44 @@ + + + + + + + + diff --git a/product_update_price_last_purchase/views/actions.xml b/product_update_price_last_purchase/views/actions.xml new file mode 100644 index 0000000..bf22acc --- /dev/null +++ b/product_update_price_last_purchase/views/actions.xml @@ -0,0 +1,39 @@ + + + + + + + + Update Sales Price + + + code + + records._compute_theoritical_price() + + + + + + diff --git a/product_update_price_last_purchase/views/product_view.xml b/product_update_price_last_purchase/views/product_view.xml new file mode 100644 index 0000000..ef07bc3 --- /dev/null +++ b/product_update_price_last_purchase/views/product_view.xml @@ -0,0 +1,92 @@ + + + + + + + product.list.price.automatic.form + product.template + form + + + + + + + + + + + + + + + + + + product_update_price_last_purchase.res.config.settings.form + + res.config.settings + + + + +

Default pricelists for Coops

+
+
+
+
+
+
+
+ + + + view.product.search.form.inherit.updated + product.template + + + + + + + + + + + + product_update_price_last_purchase.product.search.form.inherit.tags + product.template + + + + + + + + + +
+