changeset ea3e6b32ddb0 in modules/stock_shipment_cost:default
details: 
https://hg.tryton.org/modules/stock_shipment_cost?cmd=changeset&node=ea3e6b32ddb0
description:
        Use ShipmentCostMixin for supplier shipment

        issue11617
        review419581003
diffstat:

 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(-)

diffs (266 lines):

diff -r db37d1ffe58b -r ea3e6b32ddb0 CHANGELOG
--- a/CHANGELOG Mon May 02 17:04:08 2022 +0200
+++ b/CHANGELOG Thu Sep 01 22:26:46 2022 +0200
@@ -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 -r db37d1ffe58b -r ea3e6b32ddb0 __init__.py
--- a/__init__.py       Mon May 02 17:04:08 2022 +0200
+++ b/__init__.py       Thu Sep 01 22:26:46 2022 +0200
@@ -5,8 +5,9 @@
 from trytond.pool import Pool
 
 from . import carrier, stock, stock_reporting_margin
+from .stock import ShipmentCostMixin
 
-__all__ = ['register']
+__all__ = ['register', 'ShipmentCostMixin']
 
 
 def register():
diff -r db37d1ffe58b -r ea3e6b32ddb0 stock.py
--- a/stock.py  Mon May 02 17:04:08 2022 +0200
+++ b/stock.py  Thu Sep 01 22:26:46 2022 +0200
@@ -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 @@
     __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 @@
 
     @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 @@
                 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 @@
         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 @@
     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 @@
         return self.outgoing_moves
 
 
-class ShipmentOutReturn(ShipmentCostMixin, metaclass=PoolMeta):
+class ShipmentOutReturn(ShipmentOutCostMixin, metaclass=PoolMeta):
     __name__ = 'stock.shipment.out.return'
 
     @property
diff -r db37d1ffe58b -r ea3e6b32ddb0 tests/scenario_stock_shipment_cost.rst
--- a/tests/scenario_stock_shipment_cost.rst    Mon May 02 17:04:08 2022 +0200
+++ b/tests/scenario_stock_shipment_cost.rst    Thu Sep 01 22:26:46 2022 +0200
@@ -13,14 +13,6 @@
     >>> 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 @@
     >>> 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 -r db37d1ffe58b -r ea3e6b32ddb0 view/shipment_out_form.xml
--- a/view/shipment_out_form.xml        Mon May 02 17:04:08 2022 +0200
+++ b/view/shipment_out_form.xml        Thu Sep 01 22:26:46 2022 +0200
@@ -11,6 +11,7 @@
             <label name="cost_used"/>
             <group id="cost_used" col="-1" colspan="3">
                 <field name="cost_used" xexpand="0"/>
+                <field name="cost_currency_used"/>
                 <field name="cost_edit" xexpand="0" xalign="0"/>
             </group>
         </page>

Reply via email to