diff --git a/product_variant_price_choice/__init__.py b/product_variant_price_choice/__init__.py new file mode 100644 index 0000000..6b12b4c --- /dev/null +++ b/product_variant_price_choice/__init__.py @@ -0,0 +1,4 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from . import models +from .hooks import set_sale_price_on_variant diff --git a/product_variant_price_choice/__manifest__.py b/product_variant_price_choice/__manifest__.py new file mode 100644 index 0000000..9455d25 --- /dev/null +++ b/product_variant_price_choice/__manifest__.py @@ -0,0 +1,15 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +{ + "name": "Product Variant Price Choice", + "summary": "Allows to choose how to manage product variants price : attributes extra price or manually", + "version": "14.0.1.0.0", + "category": "Product Management", + "website": "https://remifr82.me", + "author": "RemiFr82, Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "installable": True, + "depends": ["product"], + "data": ["views/product_views.xml"], + "post_init_hook": "set_sale_price_on_variant", +} diff --git a/product_variant_price_choice/hooks.py b/product_variant_price_choice/hooks.py new file mode 100644 index 0000000..9b9046b --- /dev/null +++ b/product_variant_price_choice/hooks.py @@ -0,0 +1,22 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + + +def set_sale_price_on_variant(cr, registry, template_id=None): + sql = """ + UPDATE product_product pp + SET fix_price = pt.list_price + ( + SELECT COALESCE(SUM(ptav.price_extra), 0) + FROM product_variant_combination pvc + LEFT JOIN product_template_attribute_value ptav ON + ptav.id = pvc.product_template_attribute_value_id + WHERE pvc.product_product_id = pp.id + AND ptav.product_tmpl_id = pt.id + ) + FROM product_template pt + WHERE pt.id = pp.product_tmpl_id + """ + if template_id: + sql += "AND pt.id = %s" + cr.execute(sql, (template_id,)) + else: + cr.execute(sql) diff --git a/product_variant_price_choice/i18n/fr.po b/product_variant_price_choice/i18n/fr.po new file mode 100644 index 0000000..fef8e48 --- /dev/null +++ b/product_variant_price_choice/i18n/fr.po @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_variant_price_choice +# +# Translators: +# OCA Transbot , 2016 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 8.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-11-11 03:45+0000\n" +"PO-Revision-Date: 2016-11-11 03:45+0000\n" +"Last-Translator: OCA Transbot , 2016\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: product_variant_price_choice +#: model:ir.model.fields,field_description:product_variant_price_choice.field_product_product__fix_price +msgid "Fixed Price" +msgstr "Prix fixé" + +#. module: product_variant_price_choice +#: model:ir.model.fields,field_description:product_variant_price_choice.field_product_product__list_price +msgid "List Price" +msgstr "Prix de vente" + +#. module: product_variant_price_choice +#: model:ir.model,name:product_variant_price_choice.model_product_product +msgid "Product" +msgstr "Article" + +#. module: product_variant_price_choice +#: model:ir.model,name:product_variant_price_choice.model_product_template +msgid "Product Template" +msgstr "Modèle d'article" + +#. module: product_variant_price_choice +#: model:ir.model.fields,field_description:product_variant_price_choice.field_product_product__lst_price +msgid "Sale Price" +msgstr "Prix de vente" + +#. module: product_variant_price_choice +#: model:ir.model.fields,help:product_variant_price_choice.field_product_product__lst_price +msgid "" +"The sale price is managed from the product template. Click on the 'Configure " +"Variants' button to set the extra attribute prices." +msgstr "" +"Le prix de vente de cet articlé est géré sur son modèle. Cliquez sur le bouton " +"'Confirgurer les variantes' pour renseigner les prix des caractéristiques." diff --git a/product_variant_price_choice/models/__init__.py b/product_variant_price_choice/models/__init__.py new file mode 100644 index 0000000..2a73a40 --- /dev/null +++ b/product_variant_price_choice/models/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html +from . import product diff --git a/product_variant_price_choice/models/product.py b/product_variant_price_choice/models/product.py new file mode 100644 index 0000000..9877e9f --- /dev/null +++ b/product_variant_price_choice/models/product.py @@ -0,0 +1,98 @@ +# License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html + +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + fix_variant_prices = fields.Boolean( + "Set variant prices manually", + default=False, + help="If checked, the extra values from attributes will be ignored and you'll have to define each variant price.", + ) + + def _update_fix_price(self, vals): + if "list_price" in vals: + self.mapped("product_variant_ids").write({"fix_price": vals["list_price"]}) + + @api.model + def create(self, vals): + product_tmpl = super(ProductTemplate, self).create(vals) + if product_tmpl.fix_variant_prices: + product_tmpl._update_fix_price(vals) + return product_tmpl + + def write(self, vals): + res = super(ProductTemplate, self).write(vals) + if self.env.context.get("skip_update_fix_price", False): + return res + for template in self: + if template.fix_variant_prices: + template._update_fix_price(vals) + return res + + +class ProductProduct(models.Model): + _inherit = "product.product" + + list_price = fields.Float( + compute="_compute_list_price", + ) + fix_price = fields.Float(string="Fixed price") + + @api.depends("list_price", "price_extra", "fix_variant_prices", "fix_price") + @api.depends_context("uom") + def _compute_product_lst_price(self): + to_uom = None + if "uom" in self._context: + to_uom = self.env["uom.uom"].browse(self._context["uom"]) + + for product in self: + if not product.fix_variant_prices: + super(ProductProduct, product)._compute_product_lst_price() + else: + price = product.fix_price or product.list_price + if to_uom: + price = product.uom_id._compute_price(price, to_uom) + product.lst_price = price + + def _compute_list_price(self): + for product in self: + price = ( + product.fix_variant_prices + and product.fix_price + or product.product_tmpl_id.list_price + ) + if self._context.get("uom"): + price = ( + self.env["uom.uom"] + .browse(self._context["uom"]) + ._compute_price(price, product.uom_id) + ) + product.list_price = price + + def _set_product_lst_price(self): + for product in self: + if not product.fix_variant_prices: + super(ProductProduct, product)._set_product_lst_price() + else: + if self._context.get("uom"): + price = ( + self.env["uom.uom"] + .browse(self._context["uom"]) + ._compute_price(product.lst_price, product.uom_id) + ) + else: + price = product.lst_price + product.write({"fix_price": price}) + if product.product_variant_count == 1: + product.product_tmpl_id.list_price = price + else: + fix_prices = product.product_tmpl_id.mapped( + "product_variant_ids.fix_price" + ) + # for consistency with price shown in the shop + product.product_tmpl_id.with_context( + skip_update_fix_price=True + ).list_price = min(fix_prices) diff --git a/product_variant_price_choice/views/product_views.xml b/product_variant_price_choice/views/product_views.xml new file mode 100644 index 0000000..4ff5e21 --- /dev/null +++ b/product_variant_price_choice/views/product_views.xml @@ -0,0 +1,59 @@ + + + + + product.template.form.inherited + product.template + + + + + + + + + + + + + + product.product + + + + + + + + + + + product.product + + + + + + + + + + \ No newline at end of file