899 lines
35 KiB
Python
899 lines
35 KiB
Python
from sql import Literal, Null, Window
|
|
from sql.aggregate import Max, Min, Sum
|
|
from sql.conditionals import Case, Coalesce
|
|
from sql.functions import CurrentTimestamp, RowNumber
|
|
|
|
from trytond.model import ModelSQL, ModelView, fields
|
|
from trytond.pool import Pool
|
|
from trytond.transaction import Transaction
|
|
|
|
|
|
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']
|
|
ALL_VALUATION_TYPES = PHYSICAL_VALUATION_TYPES + DERIVATIVE_VALUATION_TYPES
|
|
|
|
|
|
class CTRMValuationContextMixin:
|
|
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 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")
|
|
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):
|
|
ValuationLine = Pool().get('valuation.valuation.line')
|
|
val = ValuationLine.__table__()
|
|
|
|
context = Transaction().context
|
|
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']
|
|
|
|
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.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(
|
|
CTRMValuationContextMixin, ModelView):
|
|
"CTRM Financial Position Context"
|
|
__name__ = 'ctrm.reporting.position.financial.context'
|
|
|
|
|
|
class CTRMFinancialPosition(ModelSQL, ModelView):
|
|
"CTRM Financial Position"
|
|
__name__ = 'ctrm.reporting.position.financial'
|
|
|
|
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")
|
|
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):
|
|
ValuationLine = Pool().get('valuation.valuation.line')
|
|
val = ValuationLine.__table__()
|
|
|
|
context = Transaction().context
|
|
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']
|
|
|
|
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.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)
|
|
|
|
|
|
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)
|
|
|
|
|
|
class CTRMPnlExplainContext(CTRMPnlContextMixin, ModelView):
|
|
"CTRM P&L Explain Context"
|
|
__name__ = 'ctrm.reporting.pnl.explain.context'
|
|
|
|
|
|
class CTRMPnlExplain(ModelSQL, ModelView):
|
|
"CTRM P&L Explain"
|
|
__name__ = 'ctrm.reporting.pnl.explain'
|
|
|
|
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_pnl = fields.Numeric("Physical P&L", digits=(16, 2))
|
|
fee_pnl = fields.Numeric("Fee P&L", digits=(16, 2))
|
|
derivative_pnl = fields.Numeric("Derivative P&L", digits=(16, 2))
|
|
mtm_delta = fields.Numeric("MTM Delta", digits=(16, 2))
|
|
total_pnl = fields.Numeric("Total P&L", digits=(16, 2))
|
|
|
|
@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']
|
|
|
|
is_fee = val.type.in_([
|
|
'line fee',
|
|
'pur. fee',
|
|
'sale fee',
|
|
'shipment fee',
|
|
])
|
|
is_derivative = val.type.in_(DERIVATIVE_VALUATION_TYPES)
|
|
physical_pnl = Case(
|
|
(is_fee | is_derivative, 0), else_=Coalesce(val.amount, 0))
|
|
fee_pnl = Case((is_fee, Coalesce(val.amount, 0)), else_=0)
|
|
derivative_pnl = Case(
|
|
(is_derivative, Coalesce(val.amount, 0)), else_=0)
|
|
mtm_delta = Coalesce(val.mtm, 0) - Coalesce(val.amount, 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_pnl).as_('physical_pnl'),
|
|
Sum(fee_pnl).as_('fee_pnl'),
|
|
Sum(derivative_pnl).as_('derivative_pnl'),
|
|
Sum(mtm_delta).as_('mtm_delta'),
|
|
Sum(Coalesce(val.amount, 0)).as_('total_pnl'),
|
|
where=where,
|
|
group_by=group_by)
|
|
|
|
|
|
class CTRMPnlDimensionContext(CTRMPnlContextMixin, ModelView):
|
|
"CTRM P&L by Dimension Context"
|
|
__name__ = 'ctrm.reporting.pnl.dimension.context'
|
|
|
|
dimension = fields.Many2One('analytic.dimension', "Dimension")
|
|
value = fields.Many2One('analytic.dimension.value', "Value")
|
|
|
|
|
|
class CTRMPnlDimension(ModelSQL, ModelView):
|
|
"CTRM P&L by Dimension"
|
|
__name__ = 'ctrm.reporting.pnl.dimension'
|
|
|
|
valuation_date = fields.Date("Valuation Date")
|
|
dimension = fields.Many2One('analytic.dimension', "Dimension")
|
|
value = fields.Many2One('analytic.dimension.value', "Value")
|
|
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")
|
|
quantity = fields.Numeric("Quantity", digits=(16, 5))
|
|
amount = fields.Numeric("Amount", digits=(16, 2))
|
|
mtm = fields.Numeric("MTM", digits=(16, 2))
|
|
mtm_delta = fields.Numeric("MTM Delta", digits=(16, 2))
|
|
|
|
@classmethod
|
|
def table_query(cls):
|
|
ValuationLine = Pool().get('valuation.valuation.line')
|
|
Assignment = Pool().get('analytic.dimension.assignment')
|
|
val = ValuationLine.__table__()
|
|
purchase_assignment = Assignment.__table__()
|
|
sale_assignment = Assignment.__table__()
|
|
|
|
context = Transaction().context
|
|
dimension_expr = Coalesce(
|
|
sale_assignment.dimension, purchase_assignment.dimension)
|
|
value_expr = Coalesce(sale_assignment.value, purchase_assignment.value)
|
|
|
|
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 context.get('dimension'):
|
|
where &= dimension_expr == context['dimension']
|
|
if context.get('value'):
|
|
where &= value_expr == context['value']
|
|
|
|
group_by = [
|
|
val.date,
|
|
dimension_expr,
|
|
value_expr,
|
|
val.product,
|
|
val.counterparty,
|
|
val.currency,
|
|
val.unit,
|
|
val.state,
|
|
val.strategy,
|
|
]
|
|
grouped = (
|
|
val
|
|
.join(purchase_assignment, 'LEFT',
|
|
condition=purchase_assignment.purchase == val.purchase)
|
|
.join(sale_assignment, 'LEFT',
|
|
condition=sale_assignment.sale == val.sale)
|
|
.select(
|
|
val.date.as_('valuation_date'),
|
|
dimension_expr.as_('dimension'),
|
|
value_expr.as_('value'),
|
|
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(Coalesce(val.quantity, 0)).as_('quantity'),
|
|
Sum(Coalesce(val.amount, 0)).as_('amount'),
|
|
Sum(Coalesce(val.mtm, 0)).as_('mtm'),
|
|
Sum(Coalesce(val.mtm, 0) - Coalesce(val.amount, 0)).as_(
|
|
'mtm_delta'),
|
|
where=where,
|
|
group_by=group_by))
|
|
|
|
row_number = RowNumber(window=Window([],
|
|
order_by=[
|
|
grouped.valuation_date.asc,
|
|
grouped.dimension.asc,
|
|
grouped.value.asc,
|
|
grouped.product.asc,
|
|
grouped.counterparty.asc,
|
|
grouped.currency.asc,
|
|
grouped.unit.asc,
|
|
grouped.state.asc,
|
|
grouped.strategy.asc,
|
|
]))
|
|
|
|
return grouped.select(
|
|
Literal(0).as_('create_uid'),
|
|
CurrentTimestamp().as_('create_date'),
|
|
Literal(None).as_('write_uid'),
|
|
Literal(None).as_('write_date'),
|
|
row_number.as_('id'),
|
|
grouped.valuation_date.as_('valuation_date'),
|
|
grouped.dimension.as_('dimension'),
|
|
grouped.value.as_('value'),
|
|
grouped.product.as_('product'),
|
|
grouped.counterparty.as_('counterparty'),
|
|
grouped.currency.as_('currency'),
|
|
grouped.unit.as_('unit'),
|
|
grouped.state.as_('state'),
|
|
grouped.strategy.as_('strategy'),
|
|
grouped.quantity.as_('quantity'),
|
|
grouped.amount.as_('amount'),
|
|
grouped.mtm.as_('mtm'),
|
|
grouped.mtm_delta.as_('mtm_delta'))
|
|
|
|
|
|
class CTRMCreditRiskContext(ModelView):
|
|
"CTRM Credit Risk Context"
|
|
__name__ = 'ctrm.reporting.risk.credit.context'
|
|
|
|
party = fields.Many2One('party.party', "Party")
|
|
currency = fields.Many2One('currency.currency', "Credit Currency")
|
|
risk_level = fields.Selection([
|
|
(None, ''),
|
|
('low', 'Low'),
|
|
('medium', 'Medium'),
|
|
('high', 'High'),
|
|
], "Risk Level")
|
|
over_limit_only = fields.Boolean("Over Limit Only")
|
|
|
|
|
|
class CTRMCreditRisk(ModelSQL, ModelView):
|
|
"CTRM Credit Risk"
|
|
__name__ = 'ctrm.reporting.risk.credit'
|
|
|
|
party = fields.Many2One('party.party', "Party")
|
|
credit_limit = fields.Numeric("Credit Limit", digits=(16, 2))
|
|
credit_currency = fields.Many2One(
|
|
'currency.currency', "Credit Currency")
|
|
open_exposure = fields.Numeric("Open Exposure", digits=(16, 2))
|
|
internal_limit = fields.Numeric("Internal Limit", digits=(16, 2))
|
|
insurance_limit = fields.Numeric("Insurance Limit", digits=(16, 2))
|
|
available_credit = fields.Numeric("Available Credit", digits=(16, 2))
|
|
utilization = fields.Numeric("Utilization %", digits=(16, 2))
|
|
risk_level = fields.Selection([
|
|
(None, ''),
|
|
('low', 'Low'),
|
|
('medium', 'Medium'),
|
|
('high', 'High'),
|
|
], "Risk Level")
|
|
status = fields.Char("Status")
|
|
|
|
@classmethod
|
|
def table_query(cls):
|
|
Party = Pool().get('party.party')
|
|
MoveLine = Pool().get('account.move.line')
|
|
InternalLimit = Pool().get('party.internal.limit')
|
|
InsuranceLimit = Pool().get('party.insurance.limit')
|
|
|
|
party = Party.__table__()
|
|
move_line = MoveLine.__table__()
|
|
internal_limit = InternalLimit.__table__()
|
|
insurance_limit = InsuranceLimit.__table__()
|
|
|
|
exposure_query = move_line.select(
|
|
move_line.party.as_('party'),
|
|
Sum(Coalesce(move_line.debit, 0)
|
|
- Coalesce(move_line.credit, 0)).as_('open_exposure'),
|
|
where=((move_line.party != Null)
|
|
& (move_line.reconciliation == Null)),
|
|
group_by=[move_line.party])
|
|
internal_query = internal_limit.select(
|
|
internal_limit.party.as_('party'),
|
|
Sum(Coalesce(internal_limit.amount, 0)).as_('internal_limit'),
|
|
group_by=[internal_limit.party])
|
|
insurance_query = insurance_limit.select(
|
|
insurance_limit.party.as_('party'),
|
|
Sum(Coalesce(insurance_limit.amount, 0)).as_('insurance_limit'),
|
|
group_by=[insurance_limit.party])
|
|
|
|
exposure = Coalesce(exposure_query.open_exposure, 0)
|
|
limit = Coalesce(party.credit_limit, 0)
|
|
utilization = Case(
|
|
(limit != 0, (exposure / limit) * 100),
|
|
else_=0)
|
|
available_credit = limit - exposure
|
|
status = Case(
|
|
(exposure > limit, 'Over limit'),
|
|
(exposure > limit * 0.8, 'Warning'),
|
|
else_='OK')
|
|
|
|
context = Transaction().context
|
|
where = (
|
|
(party.credit_limit != Null)
|
|
| (exposure_query.open_exposure != Null)
|
|
| (internal_query.internal_limit != Null)
|
|
| (insurance_query.insurance_limit != Null))
|
|
if context.get('party'):
|
|
where &= party.id == context['party']
|
|
if context.get('currency'):
|
|
where &= party.credit_currency == context['currency']
|
|
if context.get('risk_level'):
|
|
where &= party.risk_level == context['risk_level']
|
|
if context.get('over_limit_only'):
|
|
where &= exposure > limit
|
|
|
|
return (
|
|
party
|
|
.join(exposure_query, 'LEFT',
|
|
condition=exposure_query.party == party.id)
|
|
.join(internal_query, 'LEFT',
|
|
condition=internal_query.party == party.id)
|
|
.join(insurance_query, 'LEFT',
|
|
condition=insurance_query.party == party.id)
|
|
.select(
|
|
Literal(0).as_('create_uid'),
|
|
CurrentTimestamp().as_('create_date'),
|
|
Literal(None).as_('write_uid'),
|
|
Literal(None).as_('write_date'),
|
|
party.id.as_('id'),
|
|
party.id.as_('party'),
|
|
party.credit_limit.as_('credit_limit'),
|
|
party.credit_currency.as_('credit_currency'),
|
|
exposure.as_('open_exposure'),
|
|
Coalesce(internal_query.internal_limit, 0).as_(
|
|
'internal_limit'),
|
|
Coalesce(insurance_query.insurance_limit, 0).as_(
|
|
'insurance_limit'),
|
|
available_credit.as_('available_credit'),
|
|
utilization.as_('utilization'),
|
|
party.risk_level.as_('risk_level'),
|
|
status.as_('status'),
|
|
where=where))
|