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))