From b5d771341d3718901c2ce3a6b1488997e11ec40e Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Mon, 23 Mar 2026 10:10:53 +0100 Subject: [PATCH] 23.03.26 --- modules/purchase_trade/purchase.py | 39 +++++++++++++------ .../view/penalty_rule_tier_tree.xml | 1 + 2 files changed, 28 insertions(+), 12 deletions(-) diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index 260392c..faa1495 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -812,26 +812,41 @@ class PenaltyRuleTier(ModelSQL, ModelView): threshold_unit = fields.Many2One('assay.unit', "Unit") deduction_per_unit = fields.Numeric("Deduction / unit") penalty_value = fields.Numeric("Penalty Value (USD/DMT)") + mode = fields.Selection([ + ('excess', 'Excess above threshold'), + ('full', 'Full grade in tier'), + ('min_or_both', 'Min(grade, cap) — full tier amount'), + ], "Mode") + @classmethod + def default_mode(cls): + return 'excess' + def compute_tier_penalty(self, grade): - """ - Retourne la pénalité USD pour ce palier uniquement. - grade : Decimal – teneur brute de l'élément - dry_weight_dmt: Decimal – poids sec en DMT - """ grade = Decimal(str(grade)) - - # Grade en dessous du seuil bas → ce palier ne s'applique pas + if grade <= self.threshold_from: return Decimal(0) - # Excès au-dessus du seuil bas, plafonné au seuil haut si existant - excess_top = grade if self.threshold_to is None else min(grade, self.threshold_to) - excess = excess_top - self.threshold_from + if self.mode == 'excess': + # Ton comportement actuel : on paye seulement l'excès au-dessus du seuil bas + # Ex Codelco : As=0,7% → palier 0,2-0,5% donne 0,3% d'excès + excess_top = grade if self.threshold_to is None else min(grade, self.threshold_to) + taxable = excess_top - self.threshold_from - # USD/DMT × DMT - return (excess * self.penalty_value).quantize(Decimal('0.01')) + elif self.mode == 'full': + # Pénalité sur toute la teneur dans ce palier dès déclenchement + # Ex : As=0,7% → palier 0,5-1,0% donne 0,7% entier (pas 0,2%) + taxable = grade if self.threshold_to is None else min(grade, self.threshold_to) + elif self.mode == 'min_or_both': + # Pénalité sur min(grade, plafond) — utile quand le contrat dit + # "si As dépasse X%, pénalité sur la tranche entière jusqu'à Y%" + # Ex vente fichier : palier 0,3-0,9%, As=0,6% → taxable = min(0,6%, 0,9%) = 0,6% + cap = self.threshold_to if self.threshold_to is not None else grade + taxable = min(grade, cap) + + return (taxable * self.penalty_value).quantize(Decimal('0.01')) class PenaltyRule(ModelSQL, ModelView): "Penalty Rule" diff --git a/modules/purchase_trade/view/penalty_rule_tier_tree.xml b/modules/purchase_trade/view/penalty_rule_tier_tree.xml index a7c4b86..a2079be 100644 --- a/modules/purchase_trade/view/penalty_rule_tier_tree.xml +++ b/modules/purchase_trade/view/penalty_rule_tier_tree.xml @@ -1,4 +1,5 @@ +