From a0bd6f0e28cc43a30416d842e0aa67939b7dea3b Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Thu, 16 Jul 2026 15:09:54 +0200 Subject: [PATCH] Bug Pnl --- modules/purchase_trade/coffee.py | 23 ++++++++ modules/purchase_trade/purchase.py | 24 ++++++--- modules/purchase_trade/sale.py | 10 +++- modules/purchase_trade/tests/test_module.py | 59 +++++++++++++++++++++ modules/purchase_trade/valuation.py | 2 + 5 files changed, 109 insertions(+), 9 deletions(-) diff --git a/modules/purchase_trade/coffee.py b/modules/purchase_trade/coffee.py index 48cf7fb..1a3da4b 100644 --- a/modules/purchase_trade/coffee.py +++ b/modules/purchase_trade/coffee.py @@ -1074,6 +1074,17 @@ class CoffeeLabAnalysis(Workflow, ModelSQL, ModelView): class CoffeeLineMixin: + _coffee_attribute_name_fields = [ + ('coffee_origin', None), + ('coffee_type', dict(COFFEE_TYPES)), + ('coffee_process', dict(COFFEE_PROCESS_TYPES)), + ('coffee_variety', None), + ('coffee_crop_year', None), + ('coffee_screen_size', None), + ('coffee_moisture_max', None), + ('coffee_defect_max', None), + ('coffee_cup_score_min', None), + ] _coffee_view_fields = { 'coffee_quality_status', 'coffee_origin', @@ -1131,6 +1142,18 @@ class CoffeeLineMixin: def on_change_with_active_coffee_compatibility(self, name=None): return self.get_active_coffee_compatibility(name) + def _coffee_attributes_name(self): + values = [] + for field_name, selection in self._coffee_attribute_name_fields: + value = getattr(self, field_name, None) + if value is None or value == '': + continue + if selection: + value = selection.get(value, value) + values.append(str(value)) + if values: + return ' | '.join(values) + @classmethod def fields_view_get(cls, view_id=None, view_type='form', level=None): result = super().fields_view_get( diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index 986c60a..a2bbec9 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -2448,14 +2448,22 @@ class Line(metaclass=PoolMeta): @fields.depends('product') def on_change_with_attribute_set(self, name=None): - if self.product and self.product.template and self.product.template.attribute_set: - return self.product.template.attribute_set.id - - @fields.depends('product', 'attributes') - def on_change_with_attributes_name(self, name=None): - if not self.product or not self.product.attribute_set or not self.attributes: - return - + if self.product and self.product.template and self.product.template.attribute_set: + return self.product.template.attribute_set.id + + @fields.depends( + 'product', 'attributes', + 'coffee_origin', 'coffee_type', 'coffee_process', 'coffee_variety', + 'coffee_crop_year', 'coffee_screen_size', 'coffee_moisture_max', + 'coffee_defect_max', 'coffee_cup_score_min') + def on_change_with_attributes_name(self, name=None): + coffee_attributes_name = getattr( + self, '_coffee_attributes_name', lambda: None)() + if coffee_attributes_name: + return coffee_attributes_name + if not self.product or not self.product.attribute_set or not self.attributes: + return + def key(attribute): return getattr(attribute, 'sequence', attribute.name) diff --git a/modules/purchase_trade/sale.py b/modules/purchase_trade/sale.py index 21e2e82..42ca017 100755 --- a/modules/purchase_trade/sale.py +++ b/modules/purchase_trade/sale.py @@ -2264,8 +2264,16 @@ class SaleLine(metaclass=PoolMeta): if self.product and self.product.template and self.product.template.attribute_set: return self.product.template.attribute_set.id - @fields.depends('product', 'attributes') + @fields.depends( + 'product', 'attributes', + 'coffee_origin', 'coffee_type', 'coffee_process', 'coffee_variety', + 'coffee_crop_year', 'coffee_screen_size', 'coffee_moisture_max', + 'coffee_defect_max', 'coffee_cup_score_min') def on_change_with_attributes_name(self, name=None): + coffee_attributes_name = getattr( + self, '_coffee_attributes_name', lambda: None)() + if coffee_attributes_name: + return coffee_attributes_name if not self.product or not self.product.attribute_set or not self.attributes: return diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 088a08b..1b1d056 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -82,6 +82,62 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual([line.sample.reference for line in ordered], ['A', 'R']) + def test_coffee_line_attributes_name_uses_quality_fields(self): + 'coffee line attribute name is built from coffee quality fields' + line = SimpleNamespace( + coffee_origin='Brazil', + coffee_type='arabica', + coffee_process='natural', + coffee_variety='Bourbon', + coffee_crop_year='26/27', + coffee_screen_size='17/18', + coffee_moisture_max=Decimal('11.50'), + coffee_defect_max=12, + coffee_cup_score_min=Decimal('82.00')) + + self.assertEqual( + coffee_module.CoffeeLineMixin._coffee_attributes_name(line), + 'Brazil | Arabica | Natural | Bourbon | 26/27 | 17/18 | ' + '11.50 | 12 | 82.00') + + def test_coffee_line_attributes_name_ignores_empty_quality_fields(self): + 'empty coffee quality fields keep the standard product attributes name' + line = SimpleNamespace( + coffee_origin='', + coffee_type=None, + coffee_process=None, + coffee_variety=None, + coffee_crop_year=None, + coffee_screen_size=None, + coffee_moisture_max=None, + coffee_defect_max=None, + coffee_cup_score_min=None) + + self.assertIsNone( + coffee_module.CoffeeLineMixin._coffee_attributes_name(line)) + + def test_purchase_line_attributes_name_prefers_coffee_quality(self): + 'purchase line attributes name uses coffee quality when available' + line = SimpleNamespace( + _coffee_attributes_name=lambda: 'Brazil | Arabica', + product=None, + attributes=None) + + self.assertEqual( + purchase_module.Line.on_change_with_attributes_name(line), + 'Brazil | Arabica') + + def test_sale_line_attributes_name_prefers_coffee_quality(self): + 'sale line attributes name uses coffee quality when available' + line = SimpleNamespace( + _coffee_attributes_name=lambda: 'Brazil | Arabica', + product=None, + attributes=None) + + self.assertEqual( + sale_module.SaleLine.on_change_with_attributes_name(line), + 'Brazil | Arabica') + def test_coffee_lab_analysis_compliance_uses_line_targets(self): 'coffee lab analysis compliance checks sample line targets' line = SimpleNamespace( @@ -2111,10 +2167,12 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual(values[0]['amount'], Decimal('-200.00')) self.assertEqual(values[0]['base_amount'], Decimal('-200')) + self.assertEqual(values[0]['date'], today) self.assertIsNone(values[0]['mtm_price']) self.assertIsNone(values[0]['mtm']) self.assertEqual(values[1]['amount'], Decimal('200.00')) self.assertEqual(values[1]['base_amount'], Decimal('200')) + self.assertEqual(values[1]['date'], today) self.assertIsNone(values[1]['mtm_price']) self.assertIsNone(values[1]['mtm']) @@ -2154,6 +2212,7 @@ class PurchaseTradeTestCase(ModuleTestCase): values = Valuation.create_pnl_der_from_sale_line(sale_line) self.assertEqual(values[0]['price'], Decimal('100.0000')) + self.assertEqual(values[0]['date'], today) self.assertEqual(values[0]['amount'], Decimal('200.00')) self.assertEqual(values[0]['base_amount'], Decimal('200')) self.assertIsNone(values[0]['mtm_price']) diff --git a/modules/purchase_trade/valuation.py b/modules/purchase_trade/valuation.py index 95bad90..adea88b 100644 --- a/modules/purchase_trade/valuation.py +++ b/modules/purchase_trade/valuation.py @@ -1597,6 +1597,7 @@ class ValuationBase(ModelSQL): @classmethod def create_pnl_der_from_line(cls, line): der_lines = [] + Date = Pool().get('ir.date') for d in line.derivatives or []: currency = line.purchase.currency @@ -1631,6 +1632,7 @@ class ValuationBase(ModelSQL): @classmethod def create_pnl_der_from_sale_line(cls, sale_line): der_lines = [] + Date = Pool().get('ir.date') for d in sale_line.derivatives or []: currency = sale_line.sale.currency