diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py
index 5a9b8b2..76207e6 100755
--- a/modules/purchase_trade/__init__.py
+++ b/modules/purchase_trade/__init__.py
@@ -60,6 +60,8 @@ def register():
global_reporting.GRConfiguration,
ctrm_reporting.CTRMPhysicalPosition,
ctrm_reporting.CTRMPhysicalPositionContext,
+ ctrm_reporting.CTRMFinancialPosition,
+ ctrm_reporting.CTRMFinancialPositionContext,
configuration.Configuration,
pricing.ImportPricesStart,
pricing.ImportPricesResult,
diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py
index 7ff4ee3..9c51a75 100644
--- a/modules/purchase_trade/ctrm_reporting.py
+++ b/modules/purchase_trade/ctrm_reporting.py
@@ -1,5 +1,6 @@
from sql import Literal, Null
from sql.aggregate import Max, Min, Sum
+from sql.conditionals import Case, Coalesce
from sql.functions import CurrentTimestamp
from trytond.model import ModelSQL, ModelView, fields
@@ -21,8 +22,6 @@ class CTRMPhysicalPositionContext(ModelView):
('open', 'Open'),
('physic', 'Physic'),
('shipped', 'Shipped'),
- ('hedge', 'Hedge'),
- ('priced', 'Priced'),
], "Position Type")
@classmethod
@@ -44,8 +43,6 @@ class CTRMPhysicalPosition(ModelSQL, ModelView):
('open', 'Open'),
('physic', 'Physic'),
('shipped', 'Shipped'),
- ('hedge', 'Hedge'),
- ('priced', 'Priced'),
], "Position Type")
physical_qty = fields.Numeric("Physical Quantity", digits=(16, 5))
hedged_qty = fields.Numeric("Hedged Quantity", digits=(16, 5))
@@ -58,8 +55,11 @@ class CTRMPhysicalPosition(ModelSQL, ModelView):
@classmethod
def table_query(cls):
- OpenPosition = Pool().get('open.position')
- op = OpenPosition.__table__()
+ LotReport = Pool().get('lot.report')
+ PurchaseLine = Pool().get('purchase.line')
+ Purchase = Pool().get('purchase.purchase')
+ SaleLine = Pool().get('sale.line')
+ Sale = Pool().get('sale.sale')
context = Transaction().context
as_of = context.get('as_of')
@@ -69,51 +69,209 @@ class CTRMPhysicalPosition(ModelSQL, ModelView):
currency = context.get('currency')
position_type = context.get('position_type')
- where = Literal(True)
+ lot_context = {
+ 'purchase': None,
+ 'sale': None,
+ 'shipment': None,
+ 'type': 'all',
+ 'state': 'all',
+ 'wh': 'all',
+ 'group': 'by_physic',
+ 'origin': 'all',
+ 'ps': 'all',
+ 'shipping_status': 'all',
+ }
if as_of:
- where &= ((op.period_start == Null) | (op.period_start <= as_of))
- where &= ((op.period_end == Null) | (op.period_end >= as_of))
+ lot_context['todate'] = as_of
if product:
- where &= op.product == product
+ lot_context['product'] = product
if supplier:
- where &= op.supplier == supplier
+ lot_context['supplier'] = supplier
if client:
- where &= op.client == client
+ lot_context['client'] = client
+
+ lr = LotReport.table_query(lot_context)
+ pl = PurchaseLine.__table__()
+ pu = Purchase.__table__()
+ sl = SaleLine.__table__()
+ sa = Sale.__table__()
+
+ position_type_expr = Case(
+ (lr.r_lot_type == 'virtual', 'open'),
+ (lr.r_shipping_status.in_(['scheduled', 'shipped', 'received']),
+ 'shipped'),
+ else_='physic')
+ currency_expr = Coalesce(sa.currency, pu.currency)
+ price_expr = Coalesce(sl.unit_price, pl.unit_price, 0)
+
+ where = Literal(True)
if currency:
- where &= op.currency == currency
+ where &= currency_expr == currency
if position_type:
- where &= op.type == position_type
+ where &= position_type_expr == position_type
group_by = [
- op.product,
- op.supplier,
- op.client,
- op.currency,
- op.uom,
- op.type,
- op.period_start,
- op.period_end,
+ lr.r_lot_product,
+ lr.r_supplier,
+ lr.r_client,
+ currency_expr,
+ lr.r_lot_unit,
+ position_type_expr,
]
- return op.select(
+ return (
+ lr
+ .join(pl, 'LEFT', condition=pl.id == lr.r_line)
+ .join(pu, 'LEFT', condition=pu.id == lr.r_purchase)
+ .join(sl, 'LEFT', condition=sl.id == lr.r_sale_line)
+ .join(sa, 'LEFT', condition=sa.id == lr.r_sale)
+ .select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
- Min(op.id).as_('id'),
- op.product.as_('product'),
- op.supplier.as_('supplier'),
- op.client.as_('client'),
- op.currency.as_('currency'),
- op.uom.as_('uom'),
- op.type.as_('position_type'),
- Sum(op.physical_qty).as_('physical_qty'),
- Sum(op.hedged_qty).as_('hedged_qty'),
- Sum(op.net_exposure).as_('net_exposure'),
- Sum(op.amount).as_('amount'),
- Sum(op.mtm).as_('mtm'),
- Sum(op.amount - op.mtm).as_('pnl'),
- Max(op.period_start).as_('period_start'),
- Max(op.period_end).as_('period_end'),
+ Min(lr.id).as_('id'),
+ lr.r_lot_product.as_('product'),
+ lr.r_supplier.as_('supplier'),
+ lr.r_client.as_('client'),
+ currency_expr.as_('currency'),
+ lr.r_lot_unit.as_('uom'),
+ position_type_expr.as_('position_type'),
+ Sum(lr.r_lot_quantity).as_('physical_qty'),
+ Literal(0).as_('hedged_qty'),
+ Sum(lr.r_lot_quantity).as_('net_exposure'),
+ Sum(lr.r_lot_quantity * price_expr).as_('amount'),
+ Literal(None).as_('mtm'),
+ Literal(None).as_('pnl'),
+ Literal(None).as_('period_start'),
+ Literal(None).as_('period_end'),
where=where,
- group_by=group_by)
+ group_by=group_by))
+
+
+class CTRMFinancialPositionContext(ModelView):
+ "CTRM Financial Position Context"
+ __name__ = 'ctrm.reporting.position.financial.context'
+
+ trade_from = fields.Date("Trade Date From")
+ trade_to = fields.Date("Trade Date To")
+ maturity_from = fields.Date("Maturity From")
+ maturity_to = fields.Date("Maturity To")
+ product = fields.Many2One('product.product', "Product")
+ party = fields.Many2One('party.party', "Counterparty")
+ purchase = fields.Many2One('purchase.purchase', "Purchase")
+ sale = fields.Many2One('sale.sale', "Sale")
+ direction = fields.Selection([
+ (None, ''),
+ ('long', 'Long'),
+ ('short', 'Short'),
+ ], 'Direction')
+ state = fields.Selection([
+ (None, ''),
+ ('open', 'Open'),
+ ('closed', 'Closed'),
+ ], 'State')
+ open_only = fields.Boolean("Open Positions Only")
+
+ @classmethod
+ def default_trade_to(cls):
+ Date = Pool().get('ir.date')
+ return Date.today()
+
+ @classmethod
+ def default_open_only(cls):
+ return True
+
+
+class CTRMFinancialPosition(ModelSQL, ModelView):
+ "CTRM Financial Position"
+ __name__ = 'ctrm.reporting.position.financial'
+
+ derivative = fields.Many2One('derivative.derivative', "Derivative")
+ trade_date = fields.Date("Trade Date")
+ maturity_date = fields.Date("Maturity")
+ product = fields.Many2One('product.product', "Product")
+ party = fields.Many2One('party.party', "Counterparty")
+ 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")
+ price_index = fields.Many2One('price.price', "Curve")
+ direction = fields.Selection([
+ ('long', 'Long'),
+ ('short', 'Short'),
+ ], 'Direction')
+ state = fields.Selection([
+ ('open', 'Open'),
+ ('closed', 'Closed'),
+ ], 'State')
+ contract_count = fields.Integer("Nb ct")
+ open_qty = fields.Numeric("Open Quantity", digits='unit')
+ entry_price = fields.Numeric("Entry Price", digits='currency')
+ exit_price = fields.Numeric("Exit Price", digits='currency')
+
+ @classmethod
+ def table_query(cls):
+ Derivative = Pool().get('derivative.derivative')
+ d = Derivative.__table__()
+
+ context = Transaction().context
+ trade_from = context.get('trade_from')
+ trade_to = context.get('trade_to')
+ maturity_from = context.get('maturity_from')
+ maturity_to = context.get('maturity_to')
+ product = context.get('product')
+ party = context.get('party')
+ purchase = context.get('purchase')
+ sale = context.get('sale')
+ direction = context.get('direction')
+ state = context.get('state')
+ open_only = context.get('open_only')
+
+ where = Literal(True)
+ if trade_from:
+ where &= d.trade_date >= trade_from
+ if trade_to:
+ where &= d.trade_date <= trade_to
+ if maturity_from:
+ where &= d.maturity_date >= maturity_from
+ if maturity_to:
+ where &= d.maturity_date <= maturity_to
+ if product:
+ where &= d.product == product
+ if party:
+ where &= d.party == party
+ if purchase:
+ where &= d.purchase == purchase
+ if sale:
+ where &= d.sale == sale
+ if direction:
+ where &= d.direction == direction
+ if state:
+ where &= d.state == state
+ if open_only:
+ where &= d.open_qty > 0
+
+ return d.select(
+ Literal(0).as_('create_uid'),
+ CurrentTimestamp().as_('create_date'),
+ Literal(None).as_('write_uid'),
+ Literal(None).as_('write_date'),
+ d.id.as_('id'),
+ d.id.as_('derivative'),
+ d.trade_date.as_('trade_date'),
+ d.maturity_date.as_('maturity_date'),
+ d.product.as_('product'),
+ d.party.as_('party'),
+ d.purchase.as_('purchase'),
+ d.line.as_('purchase_line'),
+ d.sale.as_('sale'),
+ d.sale_line.as_('sale_line'),
+ d.price_index.as_('price_index'),
+ d.direction.as_('direction'),
+ d.state.as_('state'),
+ d.nb_ct.as_('contract_count'),
+ d.open_qty.as_('open_qty'),
+ d.price.as_('entry_price'),
+ d.exit_price.as_('exit_price'),
+ where=where)
diff --git a/modules/purchase_trade/ctrm_reporting.xml b/modules/purchase_trade/ctrm_reporting.xml
index 6f6f3a3..983ea1f 100644
--- a/modules/purchase_trade/ctrm_reporting.xml
+++ b/modules/purchase_trade/ctrm_reporting.xml
@@ -20,6 +20,26 @@
+
+ ctrm.reporting.position.financial.context
+ form
+ ctrm_position_financial_context_form
+
+
+ ctrm.reporting.position.financial
+ tree
+ ctrm_position_financial_list
+
+
+ 1.2 Financial Paper Position
+ ctrm.reporting.position.financial
+ ctrm.reporting.position.financial.context
+
+
+
+
+
+