23.03.26
This commit is contained in:
@@ -812,26 +812,41 @@ class PenaltyRuleTier(ModelSQL, ModelView):
|
|||||||
threshold_unit = fields.Many2One('assay.unit', "Unit")
|
threshold_unit = fields.Many2One('assay.unit', "Unit")
|
||||||
deduction_per_unit = fields.Numeric("Deduction / unit")
|
deduction_per_unit = fields.Numeric("Deduction / unit")
|
||||||
penalty_value = fields.Numeric("Penalty Value (USD/DMT)")
|
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):
|
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 = Decimal(str(grade))
|
||||||
|
|
||||||
# Grade en dessous du seuil bas → ce palier ne s'applique pas
|
|
||||||
if grade <= self.threshold_from:
|
if grade <= self.threshold_from:
|
||||||
return Decimal(0)
|
return Decimal(0)
|
||||||
|
|
||||||
# Excès au-dessus du seuil bas, plafonné au seuil haut si existant
|
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)
|
excess_top = grade if self.threshold_to is None else min(grade, self.threshold_to)
|
||||||
excess = excess_top - self.threshold_from
|
taxable = excess_top - self.threshold_from
|
||||||
|
|
||||||
# USD/DMT × DMT
|
elif self.mode == 'full':
|
||||||
return (excess * self.penalty_value).quantize(Decimal('0.01'))
|
# 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):
|
class PenaltyRule(ModelSQL, ModelView):
|
||||||
"Penalty Rule"
|
"Penalty Rule"
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<tree editable="1">
|
<tree editable="1">
|
||||||
|
<field name="mode"/>
|
||||||
<field name="threshold_from"/>
|
<field name="threshold_from"/>
|
||||||
<field name="threshold_to"/>
|
<field name="threshold_to"/>
|
||||||
<field name="threshold_unit"/>
|
<field name="threshold_unit"/>
|
||||||
|
|||||||
Reference in New Issue
Block a user