Skip to content

Commit

Permalink
[REF] refactor following PR 320
Browse files Browse the repository at this point in the history
  • Loading branch information
victor-champonnois committed Sep 16, 2022
1 parent 268dada commit 44812ed
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 144 deletions.
101 changes: 6 additions & 95 deletions beesdoo_product/models/beesdoo_product.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import uuid

from odoo import api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.exceptions import UserError
from odoo.tools.translate import _

from odoo.addons import decimal_precision as dp
Expand Down Expand Up @@ -103,6 +103,11 @@ class BeesdooProduct(models.Model):
readonly=True,
store=True,
)
purchase_price = fields.Float(
string="Purchase Price",
compute="_compute_purchase_price",
inverse="_inverse_purchase_price",
)

@api.depends("uom_id", "uom_id.category_id", "uom_id.category_id.type")
@api.multi
Expand Down Expand Up @@ -242,100 +247,6 @@ def _unit_same_category(self):
)
)

@api.multi
@api.depends("purchase_price", "seller_ids")
def _compute_purchase_price_write_date(self):
for product in self:
supplierinfo = product._get_main_supplier_info()
product.purchase_price_write_date = supplierinfo.price_write_date

def write(self, vals):
if (
self.env["ir.config_parameter"]
.sudo()
.get_param("beesdoo_product.auto_write_suggested_price")
):
purchase_price = vals.get("purchase_price")
if purchase_price and purchase_price != self.purchase_price:
# force update of purchase_price (which actually modifies the
# suppliers’ price) to ensure that the next computations that
# depend on it are correct. there are 3 things to do:
# 1. set value in cache
with self.env.do_in_draft():
self.purchase_price = purchase_price
# 2. call inverse compute method
self._inverse_purchase_price()
# 3. remove the value from vals, to avoid the process to happen a
# second time
del vals["purchase_price"]

# Important note: The list price is _only_ changed here if the
# `purchase_price` field of the product is changed. If the
# `price` field of the supplierinfo changes normally, the list price
# here is NOT automatically affected.
self.adapt_list_price(vals)

list_price = vals.get("list_price")
if list_price and list_price != self.list_price:
vals["list_price_write_date"] = fields.Datetime.now()

super().write(vals)

@api.multi
def adapt_list_price(self, vals, suggested_price=None):
self.ensure_one()
if suggested_price is None:
suggested_price = self.suggested_price
vals.setdefault("list_price", suggested_price)

@api.multi
def calculate_suggested_price(self, price=None):
self.ensure_one()
suggested_price_reference = (
self.env["ir.config_parameter"]
.sudo()
.get_param("beesdoo_product.suggested_price_reference")
)
supplier = self._get_main_supplier_info()
if not supplier:
raise ValueError(_("No supplier found for product {}").format(self.id))
if price is None:
price = supplier.price
product_category = supplier.product_tmpl_id.categ_id
supplier_taxes = self.supplier_taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
supplier_taxes_factor = 1 / (1 + sum(supplier_taxes.mapped("amount")) / 100)
sale_taxes = self.taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
sale_taxes_factor = 1 + sum(sale_taxes.mapped("amount")) / 100
profit_margin_supplier = supplier.name.profit_margin
profit_margin_product_category = product_category.profit_margin
profit_margin = profit_margin_supplier or profit_margin_product_category
profit_margin_factor = (
1 / (1 - profit_margin / 100)
if suggested_price_reference == "sale_price"
else (1 + profit_margin / 100)
)

# price of purchase is given for uom_po_id
# suggested *sale* price must be adapted to uom_id
uom_factor = self.uom_po_id.factor / self.uom_id.factor

suggested_price = (
price
* uom_factor
* supplier_taxes_factor
* sale_taxes_factor
* profit_margin_factor
)

if product_category.should_round_suggested_price:
suggested_price = product_category._round(suggested_price)

return suggested_price

@api.multi
def create_request_label_printing_wizard(self):
context = {"active_ids": self.ids}
Expand Down
3 changes: 1 addition & 2 deletions beesdoo_product/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,7 @@ Modification of product module for the needs of beescoop
The only editable field is Purchase Price.
Through "Action > Adapt Sales Price", the user can, on the selected products,
adapt the Sales Price according to the Suggested Price.
Alternatively, 'Automatically write suggested price' can be enabled to make
this last step automatic.


Please note that this model makes assumptions when computing the suggested price:

Expand Down
38 changes: 38 additions & 0 deletions sale_adapt_price_wizard/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Copyright 2020 Coop IT Easy SCRL fs
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ProductTemplate(models.Model):
_inherit = "product.template"

def write(self, vals):
if self.env["ir.config_parameter"].get_param(
"beesdoo_product.auto_write_suggested_price"
):
purchase_price = vals.get("purchase_price")
if purchase_price and purchase_price != self.purchase_price:
# force update of purchase_price (which actually modifies the
# suppliers’ price) to ensure that the next computations that
# depend on it are correct. there are 3 things to do:
# 1. set value in cache
with self.env.do_in_draft():
self.purchase_price = purchase_price
# 2. call inverse compute method
self._inverse_purchase_price()
# 3. remove the value from vals, to avoid the process to happen a
# second time
del vals["purchase_price"]

# Important note: The list price is _only_ changed here if the
# `purchase_price` field of the product is changed. If the
# `price` field of the supplierinfo changes normally, the list price
# here is NOT automatically affected.
self.adapt_list_price(vals)

list_price = vals.get("list_price")
if list_price and list_price != self.list_price:
vals["list_price_write_date"] = fields.Datetime.now()

super().write(vals)
2 changes: 2 additions & 0 deletions sale_adapt_price_wizard/readme/DESCRIPTION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@
The only editable field is Purchase Price.
Through "Action > Adapt Sales Price", the user can, on the selected products,
adapt the Sales Price according to the Suggested Price.
Alternatively, 'Automatically write suggested price' can be enabled to make
this last step automatic.
5 changes: 5 additions & 0 deletions sale_adapt_price_wizard/views/product_template_views.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,18 @@
options="{'no_open': True, 'no_create': True, 'no_create_edit': True }"
/>
<field name="purchase_price" />
<field
name="purchase_price_write_date"
string="Purchase Price Last Updated"
/>
<field
name="uom_po_id"
readonly="1"
options="{'no_open': True, 'no_create': True, 'no_create_edit':True }"
/>
<field name="suggested_price" readonly="1" />
<field name="list_price" readonly="1" />
<field name="list_price_write_date" string="Sales Price Last Updated" />
<field
name="uom_id"
readonly="1"
Expand Down
7 changes: 7 additions & 0 deletions sale_adapt_price_wizard/wizard/adapt_sales_price_wizard.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ def _get_selected_products(self):

product_ids = fields.Many2many("product.template", default=_get_selected_products)

@api.multi
def adapt_list_price(self, vals, suggested_price=None):
self.ensure_one()
if suggested_price is None:
suggested_price = self.suggested_price
vals.setdefault("list_price", suggested_price)

@api.multi
def adapt_sales_price(self):
self.ensure_one()
Expand Down
134 changes: 91 additions & 43 deletions sale_suggested_price/models/product_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,86 @@ class ProductTemplate(models.Model):
inverse="_inverse_purchase_price",
)

purchase_price_write_date = fields.Datetime(
string="Purchase Price Last Updated On",
compute="_compute_purchase_price_write_date",
readonly=True,
)
list_price_write_date = fields.Datetime(
string="Sales Price Last Updated On",
default=fields.Datetime.now,
readonly=True,
)

@api.multi
def calculate_suggested_price(self, price=None):
self.ensure_one()
suggested_price_reference = (
self.env["ir.config_parameter"]
.sudo()
.get_param("beesdoo_product.suggested_price_reference")
)
supplier = self._get_main_supplier_info()
if not supplier:
raise ValueError(_("No supplier found for product {}").format(self.id))
if price is None:
price = supplier.price
product_category = supplier.product_tmpl_id.categ_id
supplier_taxes = self.supplier_taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
supplier_taxes_factor = 1 / (1 + sum(supplier_taxes.mapped("amount")) / 100)
sale_taxes = self.taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
sale_taxes_factor = 1 + sum(sale_taxes.mapped("amount")) / 100
profit_margin_supplier = supplier.name.profit_margin
profit_margin_product_category = product_category.profit_margin
profit_margin = profit_margin_supplier or profit_margin_product_category
profit_margin_factor = (
1 / (1 - profit_margin / 100)
if suggested_price_reference == "sale_price"
else (1 + profit_margin / 100)
)

# price of purchase is given for uom_po_id
# suggested *sale* price must be adapted to uom_id
uom_factor = self.uom_po_id.factor / self.uom_id.factor

suggested_price = (
price
* uom_factor
* supplier_taxes_factor
* sale_taxes_factor
* profit_margin_factor
)

if product_category.should_round_suggested_price:
suggested_price = product_category._round(suggested_price)

return suggested_price

@api.multi
@api.depends("seller_ids")
def _compute_purchase_price(self):
for product in self:
supplierinfo = product._get_main_supplier_info()
if supplierinfo:
product.purchase_price = supplierinfo.price
else:
product.purchase_price = 0

@api.multi
def _inverse_purchase_price(self):
for product in self:
supplierinfo = product._get_main_supplier_info()
if supplierinfo:
supplierinfo.price = product.purchase_price
else:
raise ValidationError(
_("No Vendor defined for product '%s'") % product.name
)

@api.multi
@api.depends(
"seller_ids",
Expand All @@ -36,50 +116,11 @@ class ProductTemplate(models.Model):
"categ_id.should_round_suggested_price",
)
def _compute_suggested_price(self):
suggested_price_reference = (
self.env["ir.config_parameter"]
.sudo()
.get_param("sale_suggested_price.suggested_price_reference")
)
for product in self:
supplier = product._get_main_supplier_info()
if supplier:
price = supplier.price
supplier_taxes = product.supplier_taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
supplier_taxes_factor = 1 / (
1 + sum(supplier_taxes.mapped("amount")) / 100
)
sale_taxes = product.taxes_id.filtered(
lambda t: t.amount_type == "percent" and t.price_include
)
sale_taxes_factor = 1 + sum(sale_taxes.mapped("amount")) / 100
profit_margin_supplier = supplier.name.profit_margin
profit_margin_product_category = (
supplier.product_tmpl_id.categ_id.profit_margin
)
profit_margin = profit_margin_supplier or profit_margin_product_category
profit_margin_factor = (
1 / (1 - profit_margin / 100)
if suggested_price_reference == "sale_price"
else (1 + profit_margin / 100)
)

# price of purchase is given for uom_po_id
# suggested *sale* price must be adapted to uom_id
uom_factor = product.uom_po_id.factor / product.uom_id.factor

product.suggested_price = (
price
* uom_factor
* supplier_taxes_factor
* sale_taxes_factor
* profit_margin_factor
)
product_category = supplier.product_tmpl_id.categ_id
if product_category.should_round_suggested_price:
product.suggested_price = round_5c(product.suggested_price)
try:
product.suggested_price = product.calculate_suggested_price()
except ValueError:
pass

@api.multi
@api.depends("seller_ids")
Expand All @@ -102,6 +143,13 @@ def _inverse_purchase_price(self):
_("No Vendor defined for product '%s'") % product.name
)

@api.multi
@api.depends("purchase_price", "seller_ids")
def _compute_purchase_price_write_date(self):
for product in self:
supplierinfo = product._get_main_supplier_info()
product.purchase_price_write_date = supplierinfo.price_write_date


def round_5c(price):
return float_round(price, precision_rounding=0.05, rounding_method="HALF")
8 changes: 4 additions & 4 deletions sale_suggested_price/models/res_config_settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def get_values(self):
suggested_price_reference = (
self.env["ir.config_parameter"]
.sudo()
.get_param("beesdoo_product.suggested_price_reference")
.get_param("sale_suggested_price.suggested_price_reference")
)
res.update({"suggested_price_reference": suggested_price_reference})
auto_write_suggested_price = (
self.env["ir.config_parameter"]
.sudo()
.get_param("beesdoo_product.auto_write_suggested_price")
.get_param("sale_suggested_price.auto_write_suggested_price")
)
res.update({"auto_write_suggested_price": auto_write_suggested_price})
return res
Expand All @@ -54,10 +54,10 @@ def get_values(self):
def set_values(self):
super(ResConfigSettings, self).set_values()
self.env["ir.config_parameter"].sudo().set_param(
"beesdoo_product.suggested_price_reference",
"sale_suggested_price.suggested_price_reference",
self.suggested_price_reference,
)
self.env["ir.config_parameter"].sudo().set_param(
"beesdoo_product.auto_write_suggested_price",
"sale_suggested_price.auto_write_suggested_price",
self.auto_write_suggested_price,
)

0 comments on commit 44812ed

Please sign in to comment.