22.03.26
This commit is contained in:
@@ -175,6 +175,7 @@ def register():
|
|||||||
purchase.AssayUnit,
|
purchase.AssayUnit,
|
||||||
purchase.PayableRule,
|
purchase.PayableRule,
|
||||||
purchase.PenaltyRule,
|
purchase.PenaltyRule,
|
||||||
|
purchase.PenaltyRuleTier,
|
||||||
purchase.ConcentrateTerm,
|
purchase.ConcentrateTerm,
|
||||||
backtoback.Backtoback,
|
backtoback.Backtoback,
|
||||||
dimension.AnalyticDimension,
|
dimension.AnalyticDimension,
|
||||||
|
|||||||
@@ -778,23 +778,83 @@ class PayableRule(ModelSQL, ModelView):
|
|||||||
('grade_minus', 'Grade minus deduction'),
|
('grade_minus', 'Grade minus deduction'),
|
||||||
('min_of_both', 'Min(% of grade, grade - deduction)'),
|
('min_of_both', 'Min(% of grade, grade - deduction)'),
|
||||||
], "Method")
|
], "Method")
|
||||||
min_payable = fields.Numeric("Floor (min payable)") # ex: le "min -1" du Cu
|
min_payable = fields.Numeric("Floor (min payable)")
|
||||||
|
|
||||||
|
def compute_payable_quantity(self, grade):
|
||||||
|
"""
|
||||||
|
Retourne la quantité payable dans l'unité du grade.
|
||||||
|
grade : Decimal (ex: Decimal('26.862'))
|
||||||
|
"""
|
||||||
|
grade = Decimal(str(grade))
|
||||||
|
|
||||||
|
if self.payable_method == 'percent':
|
||||||
|
result = grade * self.payable_percent / Decimal(100)
|
||||||
|
|
||||||
|
elif self.payable_method == 'grade_minus':
|
||||||
|
result = grade - self.deduction_value
|
||||||
|
|
||||||
|
elif self.payable_method == 'min_of_both':
|
||||||
|
by_percent = grade * self.payable_percent / Decimal(100)
|
||||||
|
by_deduction = grade - self.deduction_value
|
||||||
|
result = min(by_percent, by_deduction)
|
||||||
|
|
||||||
|
if self.min_payable is not None:
|
||||||
|
result = max(result, self.min_payable)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
class PenaltyRuleTier(ModelSQL, ModelView):
|
||||||
|
"Penalty Rule Tier"
|
||||||
|
__name__ = 'penalty.rule.tier'
|
||||||
|
rule = fields.Many2One('penalty.rule', "Rule", ondelete='CASCADE')
|
||||||
|
threshold_from = fields.Numeric("From")
|
||||||
|
threshold_to = fields.Numeric("To") # None = pas de plafond
|
||||||
|
threshold_unit = fields.Many2One('assay.unit', "Unit")
|
||||||
|
deduction_per_unit = fields.Numeric("Deduction / unit")
|
||||||
|
penalty_value = fields.Numeric("Penalty Value (USD/DMT)")
|
||||||
|
|
||||||
|
def compute_tier_penalty(self, grade, dry_weight_dmt):
|
||||||
|
"""
|
||||||
|
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))
|
||||||
|
dry_weight_dmt = Decimal(str(dry_weight_dmt))
|
||||||
|
|
||||||
|
# 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
|
||||||
|
|
||||||
|
# USD/DMT × DMT
|
||||||
|
return (excess * self.penalty_value * dry_weight_dmt).quantize(Decimal('0.01'))
|
||||||
|
|
||||||
|
|
||||||
class PenaltyRule(ModelSQL, ModelView):
|
class PenaltyRule(ModelSQL, ModelView):
|
||||||
"Penalty Rule"
|
"Penalty Rule"
|
||||||
__name__ = 'penalty.rule'
|
__name__ = 'penalty.rule'
|
||||||
_rec_name = 'name'
|
|
||||||
|
|
||||||
name = fields.Char("Name")
|
name = fields.Char("Name")
|
||||||
element = fields.Many2One('assay.element', "Element")
|
element = fields.Many2One('assay.element', "Element")
|
||||||
|
tiers = fields.One2Many('penalty.rule.tier', 'rule', "Tiers")
|
||||||
|
|
||||||
threshold = fields.Numeric("Treshold")
|
def compute_penalty(self, grade, dry_weight_dmt):
|
||||||
threshold_unit = fields.Many2One('assay.unit',"Unit")
|
"""
|
||||||
|
Retourne la pénalité totale USD en cumulant tous les paliers traversés.
|
||||||
|
grade : Decimal – teneur brute de l'élément
|
||||||
|
dry_weight_dmt: Decimal – poids sec en DMT
|
||||||
|
"""
|
||||||
|
grade = Decimal(str(grade))
|
||||||
|
dry_weight_dmt = Decimal(str(dry_weight_dmt))
|
||||||
|
|
||||||
step = fields.Numeric("Step")
|
total = Decimal(0)
|
||||||
penalty_value = fields.Numeric("Penalty Value")
|
for tier in self.tiers:
|
||||||
currency = fields.Many2One('currency.currency',"Curr")
|
total += tier.compute_tier_penalty(grade, dry_weight_dmt)
|
||||||
unit = fields.Many2One('product.uom',"Unit")
|
|
||||||
|
return total.quantize(Decimal('0.01'))
|
||||||
|
|
||||||
class ConcentrateTerm(ModelSQL, ModelView):
|
class ConcentrateTerm(ModelSQL, ModelView):
|
||||||
"Concentrate Term"
|
"Concentrate Term"
|
||||||
|
|||||||
@@ -211,6 +211,22 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
<field name="name">payable_rule_form</field>
|
<field name="name">payable_rule_form</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.ui.view" id="penalty_rule_view_form">
|
||||||
|
<field name="model">penalty.rule</field>
|
||||||
|
<field name="type">form</field>
|
||||||
|
<field name="name">penalty_rule_form</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.ui.view" id="penalty_rule_view_tree">
|
||||||
|
<field name="model">penalty.rule</field>
|
||||||
|
<field name="type">tree</field>
|
||||||
|
<field name="name">penalty_rule_tree</field>
|
||||||
|
</record>
|
||||||
|
<record model="ir.ui.view" id="penalty_rule_tier_view_tree">
|
||||||
|
<field name="model">penalty.rule.tier</field>
|
||||||
|
<field name="type">tree</field>
|
||||||
|
<field name="name">penalty_rule_tier_tree</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
<menuitem
|
<menuitem
|
||||||
name="Pnl Report"
|
name="Pnl Report"
|
||||||
parent="purchase_trade.menu_global_reporting"
|
parent="purchase_trade.menu_global_reporting"
|
||||||
|
|||||||
8
modules/purchase_trade/view/penalty_rule_form.xml
Normal file
8
modules/purchase_trade/view/penalty_rule_form.xml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<form col="4">
|
||||||
|
<label name="name"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<label name="element"/>
|
||||||
|
<field name="element"/>
|
||||||
|
<newline/>
|
||||||
|
<field name="tiers" colspan="4"/>
|
||||||
|
</form>
|
||||||
7
modules/purchase_trade/view/penalty_rule_tier_tree.xml
Normal file
7
modules/purchase_trade/view/penalty_rule_tier_tree.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<tree editable="1">
|
||||||
|
<field name="threshold_from"/>
|
||||||
|
<field name="threshold_to"/>
|
||||||
|
<field name="threshold_unit"/>
|
||||||
|
<field name="deduction_per_unit"/>
|
||||||
|
<field name="penalty_value"/>
|
||||||
|
</tree>
|
||||||
5
modules/purchase_trade/view/penalty_rule_tree.xml
Normal file
5
modules/purchase_trade/view/penalty_rule_tree.xml
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<tree editable="1">
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="element"/>
|
||||||
|
<field name="tiers"/>
|
||||||
|
</tree>
|
||||||
Reference in New Issue
Block a user