diff --git a/modules/purchase_trade/docs/business-rules.md b/modules/purchase_trade/docs/business-rules.md index b23a8ea..f642591 100644 --- a/modules/purchase_trade/docs/business-rules.md +++ b/modules/purchase_trade/docs/business-rules.md @@ -542,6 +542,25 @@ Owner technique: `a completer` - Priorite: - `importante` +### BR-PT-016 - Les fees `% rate` utilisent la BL Date estimee + +- Intent: aligner le calcul des frais financiers `% rate` entre achat et vente. +- Description: + - Pour un `fee.fee` en mode `rate`, le calcul ne depend pas du + `payment_term`. + - La date de fin est toujours issue de l'onglet `Estimated date` de la ligne + achat ou vente: + - chercher `trigger = bldate` + - prendre `estimated_date` + - ajouter `fin_int_delta` +- Resultat attendu: + - purchase et sale appliquent la meme formule: + `fee_date -> BL Date + financing delta` + - si aucune Estimated Date `bldate` n'est renseignee, aucun montant `% rate` + n'est calcule +- Priorite: + - `importante` + ## 4) Exemples concrets ### Exemple E1 - Augmentation simple diff --git a/modules/purchase_trade/fee.py b/modules/purchase_trade/fee.py index 48bed22..04ade1b 100755 --- a/modules/purchase_trade/fee.py +++ b/modules/purchase_trade/fee.py @@ -371,22 +371,32 @@ class Fee(ModelSQL,ModelView): ) return round(factor * self.line.unit_price * self._get_amount_quantity() * sign,2) - if self.sale_line: - if self.sale_line.sale.payment_term: - beg_date = self.fee_date if self.fee_date else Date.today() - est_date = self.sale_line.sale.payment_term.lines[0].get_date(beg_date,self.sale_line) - logger.info("EST_DATE:%s",est_date) - if est_date and beg_date: - factor = InterestCalculator.calculate( - start_date=beg_date, - end_date=est_date, - rate=self.price/100, - rate_type='annual', - convention='ACT/360', - compounding='simple' - ) - logger.info("FACTOR:%s",factor) - return round(factor * self.sale_line.unit_price * self._get_amount_quantity() * sign,2) + if self.sale_line: + if self.sale_line.estimated_date: + beg_date = self.fee_date if self.fee_date else Date.today() + est_lines = [ + dd for dd in self.sale_line.estimated_date + if dd.trigger == 'bldate' + ] + est_line = est_lines[0] if est_lines else None + if est_line and est_line.estimated_date: + est_date = est_line.estimated_date + datetime.timedelta( + days=est_line.fin_int_delta or 0 + ) + logger.info("EST_DATE:%s", est_date) + if est_date and beg_date: + factor = InterestCalculator.calculate( + start_date=beg_date, + end_date=est_date, + rate=self.price/100, + rate_type='annual', + convention='ACT/360', + compounding='simple' + ) + logger.info("FACTOR:%s", factor) + return round( + factor * self.sale_line.unit_price + * self._get_amount_quantity() * sign, 2) elif self.mode == 'perqt': if self.shipment_in: diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 777eb1d..1c893b2 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -273,6 +273,35 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual(fee.get_amount(), Decimal('13.33')) + def test_sale_rate_fee_amount_uses_bl_date_estimate(self): + 'sale rate fee amount uses BL estimated date plus financing delta' + Fee = Pool().get('fee.fee') + fee = Fee() + fee.mode = 'rate' + fee.price = Decimal('12') + fee.fee_date = datetime.date(2026, 4, 23) + fee.quantity = Decimal('10') + fee.unit = Mock() + fee.shipment_in = None + fee.line = None + fee.sale_line = Mock( + unit_price=Decimal('100'), + lots=[], + estimated_date=[ + Mock( + trigger='bldate', + estimated_date=datetime.date(2026, 5, 23), + fin_int_delta=10, + ), + ], + ) + + with patch('trytond.modules.purchase_trade.fee.Pool') as PoolMock: + PoolMock.return_value.get.return_value = Mock( + today=Mock(return_value=datetime.date(2026, 4, 23))) + + self.assertEqual(fee.get_amount(), Decimal('13.33')) + def test_create_pnl_price_from_line_keeps_finished_physical_sale_line(self): 'purchase valuation keeps finished sale-side pnl on physical lots' Valuation = Pool().get('valuation.valuation')