diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py
index ec54115..0e9dcd8 100755
--- a/modules/purchase_trade/__init__.py
+++ b/modules/purchase_trade/__init__.py
@@ -64,6 +64,10 @@ def register():
ctrm_reporting.CTRMFinancialPositionContext,
ctrm_reporting.CTRMNetPosition,
ctrm_reporting.CTRMNetPositionContext,
+ ctrm_reporting.CTRMRealizedPnl,
+ ctrm_reporting.CTRMRealizedPnlContext,
+ ctrm_reporting.CTRMMtmPnl,
+ ctrm_reporting.CTRMMtmPnlContext,
configuration.Configuration,
pricing.ImportPricesStart,
pricing.ImportPricesResult,
diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py
index 58a344f..a5a8d26 100644
--- a/modules/purchase_trade/ctrm_reporting.py
+++ b/modules/purchase_trade/ctrm_reporting.py
@@ -1,4 +1,4 @@
-from sql import Literal
+from sql import Literal, Null
from sql.aggregate import Max, Min, Sum
from sql.conditionals import Case, Coalesce
from sql.functions import CurrentTimestamp
@@ -21,6 +21,7 @@ PHYSICAL_VALUATION_TYPES = [
'market',
]
DERIVATIVE_VALUATION_TYPES = ['derivative']
+ALL_VALUATION_TYPES = PHYSICAL_VALUATION_TYPES + DERIVATIVE_VALUATION_TYPES
class CTRMValuationContextMixin:
@@ -308,3 +309,249 @@ class CTRMNetPosition(ModelSQL, ModelView):
Sum(Coalesce(val.mtm, 0)).as_('mtm'),
where=where,
group_by=group_by)
+
+
+class CTRMPnlContextMixin:
+ date = fields.Date("Valuation Date")
+ product = fields.Many2One('product.product', "Product")
+ counterparty = fields.Many2One('party.party', "Counterparty")
+ currency = fields.Many2One('currency.currency', "Currency")
+ purchase = fields.Many2One('purchase.purchase', "Purchase")
+ sale = fields.Many2One('sale.sale', "Sale")
+ strategy = fields.Many2One('mtm.strategy', "Strategy")
+ state = fields.Char("State")
+
+ @classmethod
+ def default_date(cls):
+ Date = Pool().get('ir.date')
+ return Date.today()
+
+
+class CTRMRealizedPnlContext(CTRMPnlContextMixin, ModelView):
+ "CTRM Realized P&L Context"
+ __name__ = 'ctrm.reporting.pnl.realized.context'
+
+ realization = fields.Selection([
+ ('purchase_and_sale_invoiced', 'Purchase and Sale Invoiced'),
+ ('sale_invoiced', 'Sale Invoiced'),
+ ('purchase_invoiced', 'Purchase Invoiced'),
+ ('all_valued', 'All Valued Lines'),
+ ], "Realization")
+
+ @classmethod
+ def default_realization(cls):
+ return 'purchase_and_sale_invoiced'
+
+
+class CTRMRealizedPnl(ModelSQL, ModelView):
+ "CTRM Realized P&L"
+ __name__ = 'ctrm.reporting.pnl.realized'
+
+ valuation_date = fields.Date("Valuation Date")
+ lot = fields.Many2One('lot.lot', "Lot")
+ purchase = fields.Many2One('purchase.purchase', "Purchase")
+ purchase_line = fields.Many2One('purchase.line', "Purchase Line")
+ purchase_invoice = fields.Many2One('account.invoice', "Purchase Invoice")
+ sale = fields.Many2One('sale.sale', "Sale")
+ sale_line = fields.Many2One('sale.line', "Sale Line")
+ sale_invoice = fields.Many2One('account.invoice', "Sale Invoice")
+ type = fields.Selection([
+ ('priced', 'Price'),
+ ('pur. priced', 'Pur. price'),
+ ('pur. efp', 'Pur. efp'),
+ ('sale priced', 'Sale price'),
+ ('sale efp', 'Sale efp'),
+ ('line fee', 'Line fee'),
+ ('pur. fee', 'Pur. fee'),
+ ('sale fee', 'Sale fee'),
+ ('shipment fee', 'Shipment fee'),
+ ('market', 'Market'),
+ ('derivative', 'Derivative'),
+ ], "Type")
+ reference = fields.Char("Reference")
+ counterparty = fields.Many2One('party.party', "Counterparty")
+ product = fields.Many2One('product.product', "Product")
+ state = fields.Char("State")
+ quantity = fields.Numeric("Quantity", digits=(16, 5))
+ unit = fields.Many2One('product.uom', "Unit")
+ currency = fields.Many2One('currency.currency', "Currency")
+ amount = fields.Numeric("Amount", digits=(16, 2))
+ base_amount = fields.Numeric("Base Amount", digits=(16, 2))
+ strategy = fields.Many2One('mtm.strategy', "Strategy")
+
+ @classmethod
+ def table_query(cls):
+ ValuationLine = Pool().get('valuation.valuation.line')
+ Lot = Pool().get('lot.lot')
+ InvoiceLine = Pool().get('account.invoice.line')
+ Invoice = Pool().get('account.invoice')
+
+ val = ValuationLine.__table__()
+ lot = Lot.__table__()
+ purchase_invoice_line = InvoiceLine.__table__()
+ purchase_invoice = Invoice.__table__()
+ sale_invoice_line = InvoiceLine.__table__()
+ sale_invoice = Invoice.__table__()
+
+ context = Transaction().context
+ realization = context.get(
+ 'realization', 'purchase_and_sale_invoiced')
+ where = val.type.in_(ALL_VALUATION_TYPES)
+ if context.get('date'):
+ where &= val.date == context['date']
+ if context.get('product'):
+ where &= val.product == context['product']
+ if context.get('counterparty'):
+ where &= val.counterparty == context['counterparty']
+ if context.get('currency'):
+ where &= val.currency == context['currency']
+ if context.get('purchase'):
+ where &= val.purchase == context['purchase']
+ if context.get('sale'):
+ where &= val.sale == context['sale']
+ if context.get('strategy'):
+ where &= val.strategy == context['strategy']
+ if context.get('state'):
+ where &= val.state == context['state']
+
+ if realization == 'purchase_and_sale_invoiced':
+ where &= lot.invoice_line != Null
+ where &= lot.sale_invoice_line != Null
+ elif realization == 'sale_invoiced':
+ where &= lot.sale_invoice_line != Null
+ elif realization == 'purchase_invoiced':
+ where &= lot.invoice_line != Null
+
+ return (
+ val
+ .join(lot, 'LEFT', condition=lot.id == val.lot)
+ .join(purchase_invoice_line, 'LEFT',
+ condition=purchase_invoice_line.id == lot.invoice_line)
+ .join(purchase_invoice, 'LEFT',
+ condition=purchase_invoice.id == purchase_invoice_line.invoice)
+ .join(sale_invoice_line, 'LEFT',
+ condition=sale_invoice_line.id == lot.sale_invoice_line)
+ .join(sale_invoice, 'LEFT',
+ condition=sale_invoice.id == sale_invoice_line.invoice)
+ .select(
+ Literal(0).as_('create_uid'),
+ CurrentTimestamp().as_('create_date'),
+ Literal(None).as_('write_uid'),
+ Literal(None).as_('write_date'),
+ val.id.as_('id'),
+ val.date.as_('valuation_date'),
+ val.lot.as_('lot'),
+ val.purchase.as_('purchase'),
+ val.line.as_('purchase_line'),
+ purchase_invoice.id.as_('purchase_invoice'),
+ val.sale.as_('sale'),
+ val.sale_line.as_('sale_line'),
+ sale_invoice.id.as_('sale_invoice'),
+ val.type.as_('type'),
+ val.reference.as_('reference'),
+ val.counterparty.as_('counterparty'),
+ val.product.as_('product'),
+ val.state.as_('state'),
+ val.quantity.as_('quantity'),
+ val.unit.as_('unit'),
+ val.currency.as_('currency'),
+ val.amount.as_('amount'),
+ val.base_amount.as_('base_amount'),
+ val.strategy.as_('strategy'),
+ where=where))
+
+
+class CTRMMtmPnlContext(CTRMPnlContextMixin, ModelView):
+ "CTRM Mark-to-Market Context"
+ __name__ = 'ctrm.reporting.pnl.mtm.context'
+
+
+class CTRMMtmPnl(ModelSQL, ModelView):
+ "CTRM Mark-to-Market"
+ __name__ = 'ctrm.reporting.pnl.mtm'
+
+ valuation_date = fields.Date("Valuation Date")
+ lot = fields.Many2One('lot.lot', "Lot")
+ purchase = fields.Many2One('purchase.purchase', "Purchase")
+ purchase_line = fields.Many2One('purchase.line', "Purchase Line")
+ sale = fields.Many2One('sale.sale', "Sale")
+ sale_line = fields.Many2One('sale.line', "Sale Line")
+ type = fields.Selection([
+ ('priced', 'Price'),
+ ('pur. priced', 'Pur. price'),
+ ('pur. efp', 'Pur. efp'),
+ ('sale priced', 'Sale price'),
+ ('sale efp', 'Sale efp'),
+ ('line fee', 'Line fee'),
+ ('pur. fee', 'Pur. fee'),
+ ('sale fee', 'Sale fee'),
+ ('shipment fee', 'Shipment fee'),
+ ('market', 'Market'),
+ ('derivative', 'Derivative'),
+ ], "Type")
+ reference = fields.Char("Reference")
+ counterparty = fields.Many2One('party.party', "Counterparty")
+ product = fields.Many2One('product.product', "Product")
+ state = fields.Char("State")
+ quantity = fields.Numeric("Quantity", digits=(16, 5))
+ unit = fields.Many2One('product.uom', "Unit")
+ price = fields.Numeric("Price", digits=(16, 4))
+ mtm_price = fields.Numeric("MTM Price", digits=(16, 4))
+ currency = fields.Many2One('currency.currency', "Currency")
+ amount = fields.Numeric("Amount", digits=(16, 2))
+ mtm = fields.Numeric("MTM", digits=(16, 2))
+ mtm_delta = fields.Numeric("MTM Delta", digits=(16, 2))
+ strategy = fields.Many2One('mtm.strategy', "Strategy")
+
+ @classmethod
+ def table_query(cls):
+ ValuationLine = Pool().get('valuation.valuation.line')
+ val = ValuationLine.__table__()
+
+ context = Transaction().context
+ where = val.type.in_(ALL_VALUATION_TYPES)
+ if context.get('date'):
+ where &= val.date == context['date']
+ if context.get('product'):
+ where &= val.product == context['product']
+ if context.get('counterparty'):
+ where &= val.counterparty == context['counterparty']
+ if context.get('currency'):
+ where &= val.currency == context['currency']
+ if context.get('purchase'):
+ where &= val.purchase == context['purchase']
+ if context.get('sale'):
+ where &= val.sale == context['sale']
+ if context.get('strategy'):
+ where &= val.strategy == context['strategy']
+ if context.get('state'):
+ where &= val.state == context['state']
+
+ return val.select(
+ Literal(0).as_('create_uid'),
+ CurrentTimestamp().as_('create_date'),
+ Literal(None).as_('write_uid'),
+ Literal(None).as_('write_date'),
+ val.id.as_('id'),
+ val.date.as_('valuation_date'),
+ val.lot.as_('lot'),
+ val.purchase.as_('purchase'),
+ val.line.as_('purchase_line'),
+ val.sale.as_('sale'),
+ val.sale_line.as_('sale_line'),
+ val.type.as_('type'),
+ val.reference.as_('reference'),
+ val.counterparty.as_('counterparty'),
+ val.product.as_('product'),
+ val.state.as_('state'),
+ val.quantity.as_('quantity'),
+ val.unit.as_('unit'),
+ val.price.as_('price'),
+ val.mtm_price.as_('mtm_price'),
+ val.currency.as_('currency'),
+ val.amount.as_('amount'),
+ val.mtm.as_('mtm'),
+ (Coalesce(val.mtm, 0) - Coalesce(val.amount, 0)).as_(
+ 'mtm_delta'),
+ val.strategy.as_('strategy'),
+ where=where)
diff --git a/modules/purchase_trade/ctrm_reporting.xml b/modules/purchase_trade/ctrm_reporting.xml
index 865491b..a6906f3 100644
--- a/modules/purchase_trade/ctrm_reporting.xml
+++ b/modules/purchase_trade/ctrm_reporting.xml
@@ -60,6 +60,46 @@
+
+ ctrm.reporting.pnl.realized.context
+ form
+ ctrm_pnl_realized_context_form
+
+
+ ctrm.reporting.pnl.realized
+ tree
+ ctrm_pnl_realized_list
+
+
+ Realized P&L
+ ctrm.reporting.pnl.realized
+ ctrm.reporting.pnl.realized.context
+
+
+
+
+
+
+
+ ctrm.reporting.pnl.mtm.context
+ form
+ ctrm_pnl_mtm_context_form
+
+
+ ctrm.reporting.pnl.mtm
+ tree
+ ctrm_pnl_mtm_list
+
+
+ Mark-to-Market
+ ctrm.reporting.pnl.mtm
+ ctrm.reporting.pnl.mtm.context
+
+
+
+
+
+