From 6860ba9e6019a3c23be1ae4e0b60425b0544cac5 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Thu, 4 Jun 2026 10:44:40 +0200 Subject: [PATCH] BL date --- modules/purchase_trade/purchase.py | 53 +++++++++++++++------ modules/purchase_trade/sale.py | 25 ++++++++++ modules/purchase_trade/tests/test_module.py | 38 +++++++++++++++ 3 files changed, 102 insertions(+), 14 deletions(-) diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index e71cca7..d50f369 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -125,12 +125,16 @@ class Component(metaclass=PoolMeta): if pm: return pm.beg_date - def getEstimatedTriggerPurchase(self,t): - if t == 'delmonth': - return self.getDelMonthDatePurchase() - PE = Pool().get('pricing.estimated') - Date = Pool().get('ir.date') - pe = PE.search([('line','=',self.line),('trigger','=',t)]) + def getEstimatedTriggerPurchase(self,t): + if t == 'delmonth': + return self.getDelMonthDatePurchase() + if self.line and hasattr(self.line, 'get_date'): + trigger_date = self.line.get_date(t) + if trigger_date: + return trigger_date + PE = Pool().get('pricing.estimated') + Date = Pool().get('ir.date') + pe = PE.search([('line','=',self.line),('trigger','=',t)]) if pe: return pe[0].estimated_date else: @@ -1853,14 +1857,35 @@ class Line(metaclass=PoolMeta): LotQt = Pool().get('lot.qt') return LotQt.search([('lot_p','=',self.lots[0].id),('lot_s','>',0)]) - def get_date(self,trigger_event): - trigger_date = None - if self.estimated_date: - trigger_date = [d.estimated_date for d in self.estimated_date if d.trigger == trigger_event] - trigger_date = trigger_date[0] if trigger_date else None - return trigger_date - - def get_tol_min(self,name): + def get_date(self,trigger_event): + if trigger_event == 'bldate': + real_bl_date = self._get_real_bl_date() + if real_bl_date: + return real_bl_date + trigger_date = None + if self.estimated_date: + trigger_date = [d.estimated_date for d in self.estimated_date if d.trigger == trigger_event] + trigger_date = trigger_date[0] if trigger_date else None + return trigger_date + + def _get_real_bl_date(self): + bl_dates = [] + for lot in self.lots or []: + shipment = getattr(lot, 'lot_shipment_in', None) + bl_date = getattr(shipment, 'bl_date', None) + if bl_date: + bl_dates.append(bl_date) + if not bl_dates: + for match in self.get_matched_lines() or []: + shipment = getattr(match, 'lot_shipment_in', None) + bl_date = getattr(shipment, 'bl_date', None) + if bl_date: + bl_dates.append(bl_date) + # Multiple BL dates on one line should not happen; use the first one + # for now and revisit when partial shipments need split maturity/pricing. + return bl_dates[0] if bl_dates else None + + def get_tol_min(self,name): if self.inherit_tol: if self.purchase.tol_min and self.quantity_theorical: return round((1-(self.purchase.tol_min/100))*Decimal(self.quantity_theorical),3) diff --git a/modules/purchase_trade/sale.py b/modules/purchase_trade/sale.py index fda5ff7..afb4892 100755 --- a/modules/purchase_trade/sale.py +++ b/modules/purchase_trade/sale.py @@ -91,6 +91,10 @@ class Component(metaclass=PoolMeta): logger.info("GETTRIGGER:%s",t) if t == 'delmonth': return self.getDelMonthDateSale() + if self.sale_line and hasattr(self.sale_line, 'get_date'): + trigger_date = self.sale_line.get_date(t) + if trigger_date: + return trigger_date PE = Pool().get('pricing.estimated') Date = Pool().get('ir.date') pe = PE.search([('sale_line','=',self.sale_line),('trigger','=',t)]) @@ -1669,6 +1673,10 @@ class SaleLine(metaclass=PoolMeta): return LotQt.search([('lot_s','=',self.lots[0].id),('lot_p','>',0)]) def get_date(self,trigger_event): + if trigger_event == 'bldate': + real_bl_date = self._get_real_bl_date() + if real_bl_date: + return real_bl_date trigger_date = None if self.estimated_date: logger.info("ESTIMATED_DATE:%s",self.estimated_date) @@ -1678,6 +1686,23 @@ class SaleLine(metaclass=PoolMeta): trigger_date = trigger_date[0] if trigger_date else None return trigger_date + def _get_real_bl_date(self): + bl_dates = [] + for lot in self.lots or []: + shipment = getattr(lot, 'lot_shipment_in', None) + bl_date = getattr(shipment, 'bl_date', None) + if bl_date: + bl_dates.append(bl_date) + if not bl_dates: + for match in self.get_matched_lines() or []: + shipment = getattr(match, 'lot_shipment_in', None) + bl_date = getattr(shipment, 'bl_date', None) + if bl_date: + bl_dates.append(bl_date) + # Multiple BL dates on one line should not happen; use the first one + # for now and revisit when partial shipments need split maturity/pricing. + return bl_dates[0] if bl_dates else None + def get_tol_min(self,name): if self.inherit_tol: if self.sale.tol_min and self.quantity_theorical: diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 781baf2..64cfa0d 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -845,6 +845,44 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual(fee.get_amount(), Decimal('3.33')) + def test_purchase_line_bldate_uses_shipment_bl_before_estimated_date(self): + 'purchase line BL trigger uses the real shipment BL date first' + Line = Pool().get('purchase.line') + line = Line() + line.lots = [ + Mock( + lot_shipment_in=Mock( + bl_date=datetime.date(2026, 6, 3))), + ] + line.estimated_date = [ + Mock( + trigger='bldate', + estimated_date=datetime.date(2026, 5, 23)), + ] + + self.assertEqual( + line.get_date('bldate'), + datetime.date(2026, 6, 3)) + + def test_sale_line_bldate_uses_shipment_bl_before_estimated_date(self): + 'sale line BL trigger uses the real shipment BL date first' + Line = Pool().get('sale.line') + line = Line() + line.lots = [ + Mock( + lot_shipment_in=Mock( + bl_date=datetime.date(2026, 6, 3))), + ] + line.estimated_date = [ + Mock( + trigger='bldate', + estimated_date=datetime.date(2026, 5, 23)), + ] + + self.assertEqual( + line.get_date('bldate'), + datetime.date(2026, 6, 3)) + def test_sale_rate_fee_amount_stays_positive_with_negative_delta(self): 'sale rate fee display amount is unsigned even when financing delta is negative' Fee = Pool().get('fee.fee')