diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py index 76207e6..ec54115 100755 --- a/modules/purchase_trade/__init__.py +++ b/modules/purchase_trade/__init__.py @@ -62,6 +62,8 @@ def register(): ctrm_reporting.CTRMPhysicalPositionContext, ctrm_reporting.CTRMFinancialPosition, ctrm_reporting.CTRMFinancialPositionContext, + ctrm_reporting.CTRMNetPosition, + ctrm_reporting.CTRMNetPositionContext, configuration.Configuration, pricing.ImportPricesStart, pricing.ImportPricesResult, diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py index 9c51a75..58a344f 100644 --- a/modules/purchase_trade/ctrm_reporting.py +++ b/modules/purchase_trade/ctrm_reporting.py @@ -1,4 +1,4 @@ -from sql import Literal, Null +from sql import Literal from sql.aggregate import Max, Min, Sum from sql.conditionals import Case, Coalesce from sql.functions import CurrentTimestamp @@ -8,270 +8,303 @@ from trytond.pool import Pool from trytond.transaction import Transaction -class CTRMPhysicalPositionContext(ModelView): - "CTRM Physical Position Context" - __name__ = 'ctrm.reporting.position.physical.context' +PHYSICAL_VALUATION_TYPES = [ + 'priced', + 'pur. priced', + 'pur. efp', + 'sale priced', + 'sale efp', + 'line fee', + 'pur. fee', + 'sale fee', + 'shipment fee', + 'market', +] +DERIVATIVE_VALUATION_TYPES = ['derivative'] - as_of = fields.Date("As of") + +class CTRMValuationContextMixin: + date = fields.Date("Valuation Date") product = fields.Many2One('product.product', "Product") - supplier = fields.Many2One('party.party', "Supplier") - client = fields.Many2One('party.party', "Client") + counterparty = fields.Many2One('party.party', "Counterparty") currency = fields.Many2One('currency.currency', "Currency") - position_type = fields.Selection([ - (None, ""), - ('open', 'Open'), - ('physic', 'Physic'), - ('shipped', 'Shipped'), - ], "Position Type") + 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_as_of(cls): + def default_date(cls): Date = Pool().get('ir.date') return Date.today() +class CTRMPhysicalPositionContext( + CTRMValuationContextMixin, ModelView): + "CTRM Physical Position Context" + __name__ = 'ctrm.reporting.position.physical.context' + + class CTRMPhysicalPosition(ModelSQL, ModelView): "CTRM Physical Position" __name__ = 'ctrm.reporting.position.physical' + 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'), + ], "Type") + reference = fields.Char("Reference") + counterparty = fields.Many2One('party.party', "Counterparty") product = fields.Many2One('product.product', "Product") - supplier = fields.Many2One('party.party', "Supplier") - client = fields.Many2One('party.party', "Client") + state = fields.Char("State") + price = fields.Numeric("Price", digits=(16, 4)) currency = fields.Many2One('currency.currency', "Currency") - uom = fields.Many2One('product.uom', "Unit") - position_type = fields.Selection([ - ('open', 'Open'), - ('physic', 'Physic'), - ('shipped', 'Shipped'), - ], "Position Type") - physical_qty = fields.Numeric("Physical Quantity", digits=(16, 5)) - hedged_qty = fields.Numeric("Hedged Quantity", digits=(16, 5)) - net_exposure = fields.Numeric("Net Exposure", digits=(16, 5)) + quantity = fields.Numeric("Quantity", digits=(16, 5)) + unit = fields.Many2One('product.uom', "Unit") amount = fields.Numeric("Amount", digits=(16, 2)) + base_amount = fields.Numeric("Base Amount", digits=(16, 2)) + mtm_price = fields.Numeric("MTM Price", digits=(16, 4)) mtm = fields.Numeric("MTM", digits=(16, 2)) - pnl = fields.Numeric("P&L", digits=(16, 2)) - period_start = fields.Date("Period Start") - period_end = fields.Date("Period End") + strategy = fields.Many2One('mtm.strategy', "Strategy") @classmethod def table_query(cls): - 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') + ValuationLine = Pool().get('valuation.valuation.line') + val = ValuationLine.__table__() context = Transaction().context - as_of = context.get('as_of') - product = context.get('product') - supplier = context.get('supplier') - client = context.get('client') - currency = context.get('currency') - position_type = context.get('position_type') + where = val.type.in_(PHYSICAL_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'] - 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: - lot_context['todate'] = as_of - if product: - lot_context['product'] = product - if supplier: - lot_context['supplier'] = supplier - if 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 &= currency_expr == currency - if position_type: - where &= position_type_expr == position_type - - group_by = [ - lr.r_lot_product, - lr.r_supplier, - lr.r_client, - currency_expr, - lr.r_lot_unit, - position_type_expr, - ] - - 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( + return val.select( Literal(0).as_('create_uid'), CurrentTimestamp().as_('create_date'), Literal(None).as_('write_uid'), Literal(None).as_('write_date'), - 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)) + 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.price.as_('price'), + val.currency.as_('currency'), + val.quantity.as_('quantity'), + val.unit.as_('unit'), + val.amount.as_('amount'), + val.base_amount.as_('base_amount'), + val.mtm_price.as_('mtm_price'), + val.mtm.as_('mtm'), + val.strategy.as_('strategy'), + where=where) -class CTRMFinancialPositionContext(ModelView): +class CTRMFinancialPositionContext( + CTRMValuationContextMixin, 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") + valuation_date = fields.Date("Valuation Date") 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') + reference = fields.Char("Reference") + counterparty = fields.Many2One('party.party', "Counterparty") + product = fields.Many2One('product.product', "Product") + state = fields.Char("State") + price = fields.Numeric("Price", digits=(16, 4)) + currency = fields.Many2One('currency.currency', "Currency") + quantity = fields.Numeric("Quantity", digits=(16, 5)) + unit = fields.Many2One('product.uom', "Unit") + amount = fields.Numeric("Amount", digits=(16, 2)) + base_amount = fields.Numeric("Base Amount", digits=(16, 2)) + mtm_price = fields.Numeric("MTM Price", digits=(16, 4)) + mtm = fields.Numeric("MTM", digits=(16, 2)) + strategy = fields.Many2One('mtm.strategy', "Strategy") @classmethod def table_query(cls): - Derivative = Pool().get('derivative.derivative') - d = Derivative.__table__() + ValuationLine = Pool().get('valuation.valuation.line') + val = ValuationLine.__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 = val.type.in_(DERIVATIVE_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'] - 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( + return val.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'), + val.id.as_('id'), + val.date.as_('valuation_date'), + val.purchase.as_('purchase'), + val.line.as_('purchase_line'), + val.sale.as_('sale'), + val.sale_line.as_('sale_line'), + val.reference.as_('reference'), + val.counterparty.as_('counterparty'), + val.product.as_('product'), + val.state.as_('state'), + val.price.as_('price'), + val.currency.as_('currency'), + val.quantity.as_('quantity'), + val.unit.as_('unit'), + val.amount.as_('amount'), + val.base_amount.as_('base_amount'), + val.mtm_price.as_('mtm_price'), + val.mtm.as_('mtm'), + val.strategy.as_('strategy'), where=where) + + +class CTRMNetPositionContext( + CTRMValuationContextMixin, ModelView): + "CTRM Net Position Context" + __name__ = 'ctrm.reporting.position.net.context' + + +class CTRMNetPosition(ModelSQL, ModelView): + "CTRM Net Position" + __name__ = 'ctrm.reporting.position.net' + + valuation_date = fields.Date("Valuation Date") + product = fields.Many2One('product.product', "Product") + counterparty = fields.Many2One('party.party', "Counterparty") + currency = fields.Many2One('currency.currency', "Currency") + unit = fields.Many2One('product.uom', "Unit") + state = fields.Char("State") + strategy = fields.Many2One('mtm.strategy', "Strategy") + physical_quantity = fields.Numeric( + "Physical Quantity", digits=(16, 5)) + derivative_quantity = fields.Numeric( + "Derivative Quantity", digits=(16, 5)) + net_quantity = fields.Numeric("Net Quantity", digits=(16, 5)) + physical_amount = fields.Numeric("Physical Amount", digits=(16, 2)) + derivative_amount = fields.Numeric("Derivative Amount", digits=(16, 2)) + net_amount = fields.Numeric("Net Amount", digits=(16, 2)) + mtm = fields.Numeric("MTM", digits=(16, 2)) + + @classmethod + def table_query(cls): + ValuationLine = Pool().get('valuation.valuation.line') + val = ValuationLine.__table__() + + context = Transaction().context + where = val.type.in_( + PHYSICAL_VALUATION_TYPES + DERIVATIVE_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'] + + is_derivative = val.type.in_(DERIVATIVE_VALUATION_TYPES) + physical_quantity = Case( + (is_derivative, 0), else_=Coalesce(val.quantity, 0)) + derivative_quantity = Case( + (is_derivative, Coalesce(val.quantity, 0)), else_=0) + physical_amount = Case( + (is_derivative, 0), else_=Coalesce(val.amount, 0)) + derivative_amount = Case( + (is_derivative, Coalesce(val.amount, 0)), else_=0) + + group_by = [ + val.date, + val.product, + val.counterparty, + val.currency, + val.unit, + val.state, + val.strategy, + ] + + return val.select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + Min(val.id).as_('id'), + val.date.as_('valuation_date'), + val.product.as_('product'), + val.counterparty.as_('counterparty'), + val.currency.as_('currency'), + val.unit.as_('unit'), + val.state.as_('state'), + val.strategy.as_('strategy'), + Sum(physical_quantity).as_('physical_quantity'), + Sum(derivative_quantity).as_('derivative_quantity'), + Sum(Coalesce(val.quantity, 0)).as_('net_quantity'), + Sum(physical_amount).as_('physical_amount'), + Sum(derivative_amount).as_('derivative_amount'), + Sum(Coalesce(val.amount, 0)).as_('net_amount'), + Sum(Coalesce(val.mtm, 0)).as_('mtm'), + where=where, + group_by=group_by) diff --git a/modules/purchase_trade/ctrm_reporting.xml b/modules/purchase_trade/ctrm_reporting.xml index 983ea1f..865491b 100644 --- a/modules/purchase_trade/ctrm_reporting.xml +++ b/modules/purchase_trade/ctrm_reporting.xml @@ -11,7 +11,7 @@ ctrm_position_physical_list - 1.1 Physical Position + Physical Position ctrm.reporting.position.physical ctrm.reporting.position.physical.context @@ -31,7 +31,7 @@ ctrm_position_financial_list - 1.2 Financial Paper Position + Financial Position ctrm.reporting.position.financial ctrm.reporting.position.financial.context @@ -40,145 +40,166 @@ + + ctrm.reporting.position.net.context + form + ctrm_position_net_context_form + + + ctrm.reporting.position.net + tree + ctrm_position_net_list + + + Net Consolidated Position + ctrm.reporting.position.net + ctrm.reporting.position.net.context + + + + + + diff --git a/modules/purchase_trade/view/ctrm_position_financial_context_form.xml b/modules/purchase_trade/view/ctrm_position_financial_context_form.xml index d09fec2..120a09b 100644 --- a/modules/purchase_trade/view/ctrm_position_financial_context_form.xml +++ b/modules/purchase_trade/view/ctrm_position_financial_context_form.xml @@ -1,24 +1,18 @@
-