diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py
index bd8fbc9..85b32de 100755
--- a/modules/purchase_trade/__init__.py
+++ b/modules/purchase_trade/__init__.py
@@ -172,6 +172,11 @@ def register():
forex.ForexCategory,
pricing.Component,
pricing.Mtm,
+ pricing.MtmStrategy,
+ pricing.MtmScenario,
+ pricing.MtmSnapshot,
+ pricing.PriceMatrix,
+ pricing.PriceMatrixLine,
pricing.Estimated,
pricing.Pricing,
pricing.Period,
diff --git a/modules/purchase_trade/icons/tradon-mtm.svg b/modules/purchase_trade/icons/tradon-mtm.svg
new file mode 100644
index 0000000..c5c7214
--- /dev/null
+++ b/modules/purchase_trade/icons/tradon-mtm.svg
@@ -0,0 +1,13 @@
+
\ No newline at end of file
diff --git a/modules/purchase_trade/pricing.py b/modules/purchase_trade/pricing.py
index a346d2d..a5d911e 100755
--- a/modules/purchase_trade/pricing.py
+++ b/modules/purchase_trade/pricing.py
@@ -50,8 +50,6 @@ DAYS = [
('sunday', 'Sunday'),
]
-
-
class Estimated(ModelSQL, ModelView):
"Estimated date"
__name__ = 'pricing.estimated'
@@ -59,21 +57,212 @@ class Estimated(ModelSQL, ModelView):
trigger = fields.Selection(TRIGGERS,"Trigger")
estimated_date = fields.Date("Estimated date")
+class MtmScenario(ModelSQL, ModelView):
+ "MtM Scenario"
+ __name__ = 'mtm.scenario'
+
+ name = fields.Char("Scenario", required=True)
+ valuation_date = fields.Date("Valuation Date", required=True)
+ use_last_price = fields.Boolean("Use Last Available Price")
+ calendar = fields.Many2One(
+ 'price.calendar', "Calendar"
+ )
+
+class MtmStrategy(ModelSQL, ModelView):
+ "Mark to Market Strategy"
+ __name__ = 'mtm.strategy'
+
+ name = fields.Char("Name", required=True)
+ active = fields.Boolean("Active", select=True)
+
+ scenario = fields.Many2One(
+ 'mtm.scenario', "Scenario", required=True
+ )
+
+ currency = fields.Many2One(
+ 'currency.currency', "Valuation Currency"
+ )
+
+ components = fields.One2Many(
+ 'mtm.component', 'strategy', "Components"
+ )
+
+ def compute_mtm(self):
+ pool = Pool()
+ Currency = pool.get('currency.currency')
+ total = Decimal(0)
+
+ scenario = self.scenario
+ dt = scenario.valuation_date
+
+ for comp in self.components:
+ value = Decimal(0)
+
+ if comp.price_source_type == 'curve' and comp.price_curve:
+ value = Decimal(
+ comp.price_curve.get_price(
+ dt,
+ self.purchase_line.unit,
+ self.currency,
+ last=scenario.use_last_price
+ )
+ )
+
+ elif comp.price_source_type == 'matrix' and comp.price_matrix:
+ value = self._get_matrix_price(comp, dt)
+
+ if comp.ratio:
+ value *= Decimal(comp.ratio)
+
+ total += value
+
+ return total
+
+ def _get_matrix_price(self, comp, dt):
+ MatrixLine = Pool().get('price.matrix.line')
+
+ domain = [
+ ('matrix', '=', comp.price_matrix.id),
+ ]
+
+ if self.purchase_line:
+ domain += [
+ ('origin', '=', self.purchase_line.from_location),
+ ('destination', '=', self.purchase_line.to_location),
+ ]
+
+ lines = MatrixLine.search(domain)
+ if lines:
+ return Decimal(lines[0].price_value)
+
+ return Decimal(0)
+
+ def run_daily_mtm():
+ Strategy = Pool().get('mtm.strategy')
+ Snapshot = Pool().get('mtm.snapshot')
+
+ for strat in Strategy.search([('active', '=', True)]):
+ amount = strat.compute_mtm()
+ Snapshot.create([{
+ 'strategy': strat.id,
+ 'valuation_date': strat.scenario.valuation_date,
+ 'amount': amount,
+ 'currency': strat.currency.id,
+ }])
+
class Mtm(ModelSQL, ModelView):
- "Mtm"
+ "MtM Component"
__name__ = 'mtm.component'
- fix_type = fields.Many2One('price.fixtype',"Fixation type")
- ratio = fields.Numeric("%")
- price_index = fields.Many2One('price.price',"Curve")
- currency = fields.Function(fields.Many2One('currency.currency',"Curr."),'get_cur')
+ strategy = fields.Many2One(
+ 'mtm.strategy', "Strategy",
+ required=True, ondelete='CASCADE'
+ )
- def get_cur(self,name):
+ name = fields.Char("Component", required=True)
+
+ component_type = fields.Selection([
+ ('commodity', 'Commodity'),
+ ('freight', 'Freight'),
+ ('quality', 'Quality'),
+ ('fx', 'FX'),
+ ('storage', 'Storage'),
+ ('other', 'Other'),
+ ], "Type", required=True)
+
+ fix_type = fields.Many2One('price.fixtype', "Fixation Type")
+
+ price_source_type = fields.Selection([
+ ('curve', 'Curve'),
+ ('matrix', 'Matrix'),
+ ('manual', 'Manual'),
+ ], "Price Source", required=True)
+
+ price_index = fields.Many2One('price.price', "Price Curve")
+ price_matrix = fields.Many2One('price.matrix', "Price Matrix")
+
+ ratio = fields.Numeric("Ratio / %", digits=(16, 6))
+
+ manual_price = fields.Numeric(
+ "Manual Price",
+ digits=(16, 6),
+ help="Price set manually if price_source_type is 'manual'"
+ )
+
+ currency = fields.Many2One('currency.currency', "Currency")
+
+ def get_cur(self, name=None):
if self.price_index:
- PI = Pool().get('price.price')
- pi = PI(self.price_index)
- return pi.price_currency
-
+ return self.price_index.price_currency
+ if self.price_matrix:
+ return self.price_matrix.currency
+ return None
+
+ @fields.depends('price_index','price_matrix')
+ def on_change_with_currency(self):
+ return self.get_cur()
+
+class PriceMatrix(ModelSQL, ModelView):
+ "Price Matrix"
+ __name__ = 'price.matrix'
+
+ name = fields.Char("Name", required=True)
+
+ matrix_type = fields.Selection([
+ ('freight', 'Freight'),
+ ('location', 'Location Spread'),
+ ('quality', 'Quality'),
+ ('storage', 'Storage'),
+ ('other', 'Other'),
+ ], "Matrix Type", required=True)
+
+ unit = fields.Many2One('product.uom', "Unit")
+ currency = fields.Many2One('currency.currency', "Currency")
+
+ calendar = fields.Many2One(
+ 'price.calendar', "Calendar"
+ )
+
+ valid_from = fields.Date("Valid From")
+ valid_to = fields.Date("Valid To")
+
+ lines = fields.One2Many(
+ 'price.matrix.line', 'matrix', "Lines"
+ )
+
+class PriceMatrixLine(ModelSQL, ModelView):
+ "Price Matrix Line"
+ __name__ = 'price.matrix.line'
+
+ matrix = fields.Many2One(
+ 'price.matrix', "Matrix",
+ required=True, ondelete='CASCADE'
+ )
+
+ origin = fields.Many2One('stock.location', "Origin")
+ destination = fields.Many2One('stock.location', "Destination")
+
+ product = fields.Many2One('product.product', "Product")
+ quality = fields.Many2One('product.quality', "Quality")
+
+ price_value = fields.Numeric("Price", digits=(16, 6))
+
+class MtmSnapshot(ModelSQL, ModelView):
+ "MtM Snapshot"
+ __name__ = 'mtm.snapshot'
+
+ strategy = fields.Many2One(
+ 'mtm.strategy', "Strategy",
+ required=True, ondelete='CASCADE'
+ )
+
+ valuation_date = fields.Date("Valuation Date", required=True)
+
+ amount = fields.Numeric("MtM Amount", digits=(16, 6))
+ currency = fields.Many2One('currency.currency', "Currency")
+
+ created_at = fields.DateTime("Created At")
+
class Component(ModelSQL, ModelView):
"Component"
__name__ = 'pricing.component'
diff --git a/modules/purchase_trade/pricing.xml b/modules/purchase_trade/pricing.xml
index 6fbb83d..890c7b2 100755
--- a/modules/purchase_trade/pricing.xml
+++ b/modules/purchase_trade/pricing.xml
@@ -3,6 +3,11 @@
this repository contains the full copyright notices and license terms. -->