From 6869fdfddf48cb57b4c650bc47787769039d00cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Krier?= Date: Thu, 1 Sep 2022 22:26:46 +0200 Subject: [PATCH] Use ShipmentCostMixin for supplier shipment issue11617 review419581003 --- CHANGELOG | 2 + __init__.py | 3 +- stock.py | 112 +++++++++++++++++++++---- tests/scenario_stock_shipment_cost.rst | 11 +-- view/shipment_out_form.xml | 1 + 5 files changed, 103 insertions(+), 26 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index bc5816b472..b54ed5ef7e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Store cost in carrier currency + Version 6.4.0 - 2022-05-02 * Bug fixes (see mercurial logs for details) * Add cost allocation method diff --git a/__init__.py b/__init__.py index 316de733c6..5b777855f7 100644 --- a/__init__.py +++ b/__init__.py @@ -5,8 +5,9 @@ from trytond.modules.stock.stock_reporting_margin import Abstract from trytond.pool import Pool from . import carrier, stock, stock_reporting_margin +from .stock import ShipmentCostMixin -__all__ = ['register'] +__all__ = ['register', 'ShipmentCostMixin'] def register(): diff --git a/stock.py b/stock.py index 16ca585f55..aad0b2ad2f 100644 --- a/stock.py +++ b/stock.py @@ -2,10 +2,12 @@ # this repository contains the full copyright notices and license terms. from decimal import Decimal +from sql import Null + from trytond.model import ModelView, Workflow, fields from trytond.modules.product import price_digits, round_price from trytond.pool import Pool, PoolMeta -from trytond.pyson import Eval +from trytond.pyson import Eval, Bool from trytond.transaction import Transaction @@ -29,26 +31,45 @@ class ShipmentCostMixin: __slots__ = () carrier = fields.Many2One('carrier', 'Carrier', states={ - 'readonly': Eval('state').in_(['done', 'cancelled']), + 'readonly': Eval('shipment_cost_readonly', True), + }) + + cost_currency_used = fields.Function(fields.Many2One( + 'currency.currency', "Cost Currency", + states={ + 'readonly': ( + Eval('shipment_cost_readonly', True) + | ~Eval('cost_edit', False)), + }), + 'on_change_with_cost_currency_used', setter='set_cost') + cost_currency = fields.Many2One( + 'currency.currency', "Cost Currency", + states={ + 'required': Bool(Eval('cost')), + 'readonly': Eval('shipment_cost_readonly', True), }) cost_used = fields.Function(fields.Numeric( "Cost", digits=price_digits, states={ - 'readonly': (Eval('state').in_(['done', 'cancelled']) + 'readonly': ( + Eval('shipment_cost_readonly', True) | ~Eval('cost_edit', False)), }), 'on_change_with_cost_used', setter='set_cost') - cost = fields.Numeric( - "Cost", digits=price_digits, readonly=True,) + cost = fields.Numeric("Cost", digits=price_digits, readonly=True) cost_edit = fields.Boolean( "Edit Cost", states={ - 'readonly': Eval('state').in_(['done', 'cancelled']), - 'invisible': Eval('state').in_(['done', 'cancelled']), + 'readonly': Eval('shipment_cost_readonly', True), + 'invisible': Eval('shipment_cost_readonly', True), }, help="Check to edit the cost.") + shipment_cost_readonly = fields.Function( + fields.Boolean("Shipment Cost Read Only"), + 'on_change_with_shipment_cost_readonly') + def _get_carrier_context(self): return {} @@ -57,25 +78,35 @@ class ShipmentCostMixin: @fields.depends('carrier', 'company', methods=['_get_carrier_context']) def _compute_costs(self): - pool = Pool() - Currency = pool.get('currency.currency') costs = { 'cost': None, + 'cost_currency': None, } if self.carrier: with Transaction().set_context(self._get_carrier_context()): cost, currency_id = self.carrier.get_purchase_price() if cost is not None: - cost = Currency.compute( - Currency(currency_id), cost, self.company.currency, - round=False) costs['cost'] = round_price(cost) + costs['cost_currency'] = currency_id return costs - @fields.depends('cost', 'state', 'cost_edit', methods=['_compute_costs']) + @fields.depends( + 'cost_currency', 'cost_edit', + methods=['_compute_costs', 'on_change_with_shipment_cost_readonly']) + def on_change_with_cost_currency_used(self, name=None): + readonly = self.on_change_with_shipment_cost_readonly() + if not self.cost_edit and not readonly: + return self._compute_costs()['cost_currency'] + elif self.cost_currency: + return self.cost_currency.id + + @fields.depends( + 'cost', 'cost_edit', + methods=['_compute_costs', 'on_change_with_shipment_cost_readonly']) def on_change_with_cost_used(self, name=None): cost = self.cost - if not self.cost_edit and self.state not in {'cancelled', 'done'}: + readonly = self.on_change_with_shipment_cost_readonly() + if not self.cost_edit and not readonly: cost = self._compute_costs()['cost'] return cost @@ -87,13 +118,57 @@ class ShipmentCostMixin: name: value, }) + def on_change_with_shipment_cost_readonly(self, name=None): + raise NotImplementedError + + @classmethod + def index_set_field(cls, name): + index = super().index_set_field(name) + if name == 'cost_used': + index = cls.index_set_field('cost_currency_used') + 1 + return index + @property def shipment_cost_moves(self): raise NotImplementedError def _get_shipment_cost(self): "Return the cost for the shipment in the company currency" - return self.cost_used or Decimal(0) + pool = Pool() + Currency = pool.get('currency.currency') + if self.cost_used: + return Currency.compute( + self.cost_currency_used, self.cost_used, + self.company.currency, round=False) + + +class ShipmentOutCostMixin(ShipmentCostMixin): + + @classmethod + def __register__(cls, module): + pool = Pool() + Company = pool.get('company.company') + table = cls.__table__() + table_h = cls.__table_handler__(module) + company = Company.__table__() + cursor = Transaction().connection.cursor() + + cost_currency_exists = table_h.column_exist('cost_currency') + + super().__register__(module) + + # Migration from 6.4: fill cost_currency + if not cost_currency_exists: + cursor.execute(*table.update( + columns=[table.cost_currency], + values=[company.select( + company.currency, + where=company.id == table.company)], + where=table.cost != Null)) + + @fields.depends('state') + def on_change_with_shipment_cost_readonly(self, name=None): + return self.state in {'done', 'cancelled'} @classmethod def set_shipment_cost(cls, shipments): @@ -102,6 +177,8 @@ class ShipmentCostMixin: moves = [] for shipment in shipments: cost = shipment._get_shipment_cost() + if not cost: + continue factors = getattr(shipment, '_get_allocation_shipment_cost_factors_by_%s' % shipment.allocation_shipment_cost_method)() @@ -152,12 +229,13 @@ class ShipmentCostMixin: def done(cls, shipments): for shipment in shipments: shipment.cost = shipment.cost_used + shipment.cost_currency = shipment.cost_currency_used cls.save(shipments) super().done(shipments) cls.set_shipment_cost(shipments) -class ShipmentOut(ShipmentCostMixin, metaclass=PoolMeta): +class ShipmentOut(ShipmentOutCostMixin, metaclass=PoolMeta): __name__ = 'stock.shipment.out' @property @@ -165,7 +243,7 @@ class ShipmentOut(ShipmentCostMixin, metaclass=PoolMeta): return self.outgoing_moves -class ShipmentOutReturn(ShipmentCostMixin, metaclass=PoolMeta): +class ShipmentOutReturn(ShipmentOutCostMixin, metaclass=PoolMeta): __name__ = 'stock.shipment.out.return' @property diff --git a/tests/scenario_stock_shipment_cost.rst b/tests/scenario_stock_shipment_cost.rst index 3b8130f0a6..8b6c93e63f 100644 --- a/tests/scenario_stock_shipment_cost.rst +++ b/tests/scenario_stock_shipment_cost.rst @@ -13,14 +13,6 @@ Imports:: >>> today = dt.date.today() >>> yesterday = today - dt.timedelta(days=1) -Patch _get_shipment_cost:: - - >>> from unittest.mock import patch - >>> from trytond.modules.stock_shipment_cost.stock import ShipmentCostMixin - >>> mock = patch.object( - ... ShipmentCostMixin, '_get_shipment_cost', - ... return_value=Decimal('5')).start() - Activate modules:: >>> config = activate_modules('stock_shipment_cost') @@ -92,6 +84,9 @@ Create a customer shipment:: >>> shipment.click('assign_force') >>> shipment.click('pick') >>> shipment.click('pack') + >>> shipment.cost_edit = True + >>> shipment.cost_used = Decimal('5') + >>> shipment.cost_currency_used = company.currency >>> shipment.click('done') >>> shipment.state 'done' diff --git a/view/shipment_out_form.xml b/view/shipment_out_form.xml index ec15fb1643..f5f5a5ac2f 100644 --- a/view/shipment_out_form.xml +++ b/view/shipment_out_form.xml @@ -11,6 +11,7 @@ this repository contains the full copyright notices and license terms. -->