Files
tradon/modules/purchase_trade/ctrm_reporting.py
2026-05-24 19:32:03 +02:00

1987 lines
79 KiB
Python

from sql import Literal, Null, Union, Window
from sql.aggregate import Count, 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))
class CTRMShippingLogisticsContext(ModelView):
"CTRM Shipping Logistics Context"
__name__ = 'ctrm.reporting.operations.shipping.context'
from_date = fields.Date("From Date")
to_date = fields.Date("To Date")
supplier = fields.Many2One('party.party', "Supplier")
warehouse = fields.Many2One('stock.location', "Warehouse")
transport_type = fields.Selection([
(None, ''),
('vessel', 'Vessel'),
('truck', 'Truck'),
('other', 'Other'),
], "Transport Type")
vessel = fields.Many2One('trade.vessel', "Vessel")
state = fields.Char("State")
class CTRMShippingLogistics(ModelSQL, ModelView):
"CTRM Shipping Logistics"
__name__ = 'ctrm.reporting.operations.shipping'
shipment = fields.Many2One('stock.shipment.in', "Shipment")
reference = fields.Char("Reference")
supplier = fields.Many2One('party.party', "Supplier")
warehouse = fields.Many2One('stock.location', "Warehouse")
from_location = fields.Many2One('stock.location', "From")
to_location = fields.Many2One('stock.location', "To")
transport_type = fields.Selection([
(None, ''),
('vessel', 'Vessel'),
('truck', 'Truck'),
('other', 'Other'),
], "Transport Type")
vessel = fields.Many2One('trade.vessel', "Vessel")
state = fields.Char("State")
planned_date = fields.Date("Planned Date")
effective_date = fields.Date("Effective Date")
estimated_loading = fields.Date("Estimated Loading")
eta_pol = fields.Date("ETA POL")
eta = fields.Date("ETA")
etd = fields.Date("ETD")
discharged_date = fields.Date("Discharged Date")
booking = fields.Char("Booking")
bl_number = fields.Char("BL Number")
product = fields.Many2One('product.product', "Product")
quantity = fields.Numeric("Quantity", digits=(16, 5))
unit = fields.Many2One('product.uom', "Unit")
lot_count = fields.Integer("Lots")
@classmethod
def table_query(cls):
ShipmentIn = Pool().get('stock.shipment.in')
Lot = Pool().get('lot.lot')
shipment = ShipmentIn.__table__()
lot = Lot.__table__()
lot_query = lot.select(
lot.lot_shipment_in.as_('shipment'),
Count(lot.id).as_('lot_count'),
Sum(Coalesce(lot.lot_qt, 0)).as_('quantity'),
Max(lot.lot_product).as_('product'),
Max(lot.lot_unit_line).as_('unit'),
where=((lot.lot_shipment_in != Null)
& (lot.lot_type == 'physic')),
group_by=[lot.lot_shipment_in])
context = Transaction().context
logistics_date = Coalesce(
shipment.etad, shipment.eta, shipment.planned_date)
where = shipment.id != Null
if context.get('from_date'):
where &= logistics_date >= context['from_date']
if context.get('to_date'):
where &= logistics_date <= context['to_date']
if context.get('supplier'):
where &= shipment.supplier == context['supplier']
if context.get('warehouse'):
where &= shipment.warehouse == context['warehouse']
if context.get('transport_type'):
where &= shipment.transport_type == context['transport_type']
if context.get('vessel'):
where &= shipment.vessel == context['vessel']
if context.get('state'):
where &= shipment.state == context['state']
return (
shipment
.join(lot_query, 'LEFT',
condition=lot_query.shipment == shipment.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
shipment.id.as_('id'),
shipment.id.as_('shipment'),
shipment.ref.as_('reference'),
shipment.supplier.as_('supplier'),
shipment.warehouse.as_('warehouse'),
shipment.from_location.as_('from_location'),
shipment.to_location.as_('to_location'),
shipment.transport_type.as_('transport_type'),
shipment.vessel.as_('vessel'),
shipment.state.as_('state'),
shipment.planned_date.as_('planned_date'),
shipment.effective_date.as_('effective_date'),
shipment.etl.as_('estimated_loading'),
shipment.eta.as_('eta_pol'),
shipment.etad.as_('eta'),
shipment.etd.as_('etd'),
shipment.unloaded.as_('discharged_date'),
shipment.booking.as_('booking'),
shipment.bl_number.as_('bl_number'),
lot_query.product.as_('product'),
Coalesce(lot_query.quantity, 0).as_('quantity'),
lot_query.unit.as_('unit'),
Coalesce(lot_query.lot_count, 0).as_('lot_count'),
where=where))
class CTRMInventoryContext(ModelView):
"CTRM Inventory Context"
__name__ = 'ctrm.reporting.operations.inventory.context'
product = fields.Many2One('product.product', "Product")
supplier = fields.Many2One('party.party', "Supplier")
client = fields.Many2One('party.party', "Client")
warehouse = fields.Many2One('stock.location', "Warehouse")
lot_status = fields.Selection([
(None, ''),
('forecast', 'Forecast'),
('loading', 'Loading'),
('transit', 'Transit'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Status")
availability = fields.Selection([
(None, ''),
('available', 'Available'),
('reserved', 'Reserved'),
('locked', 'Locked'),
('prov', 'Prov. inv'),
('invoiced', 'Invoiced'),
], "Availability")
class CTRMInventory(ModelSQL, ModelView):
"CTRM Inventory"
__name__ = 'ctrm.reporting.operations.inventory'
lot = fields.Many2One('lot.lot', "Lot")
product = fields.Many2One('product.product', "Product")
supplier = fields.Many2One('party.party', "Supplier")
client = fields.Many2One('party.party', "Client")
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")
lot_status = fields.Selection([
(None, ''),
('forecast', 'Forecast'),
('loading', 'Loading'),
('transit', 'Transit'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Status")
availability = fields.Selection([
(None, ''),
('available', 'Available'),
('reserved', 'Reserved'),
('locked', 'Locked'),
('prov', 'Prov. inv'),
('invoiced', 'Invoiced'),
], "Availability")
warehouse = fields.Many2One('stock.location', "Warehouse")
from_location = fields.Many2One('stock.location', "From")
to_location = fields.Many2One('stock.location', "To")
shipment_in = fields.Many2One('stock.shipment.in', "Shipment In")
shipment_out = fields.Many2One('stock.shipment.out', "Shipment Out")
shipment_internal = fields.Many2One(
'stock.shipment.internal', "Shipment Internal")
container = fields.Char("Container")
quantity = fields.Numeric("Quantity", digits=(16, 5))
unit = fields.Many2One('product.uom', "Unit")
@classmethod
def table_query(cls):
pool = Pool()
Lot = pool.get('lot.lot')
PurchaseLine = pool.get('purchase.line')
Purchase = pool.get('purchase.purchase')
SaleLine = pool.get('sale.line')
Sale = pool.get('sale.sale')
ShipmentIn = pool.get('stock.shipment.in')
lot = Lot.__table__()
purchase_line = PurchaseLine.__table__()
purchase = Purchase.__table__()
sale_line = SaleLine.__table__()
sale = Sale.__table__()
shipment_in = ShipmentIn.__table__()
context = Transaction().context
warehouse = shipment_in.warehouse
from_location = shipment_in.from_location
to_location = shipment_in.to_location
where = lot.lot_type == 'physic'
if context.get('product'):
where &= lot.lot_product == context['product']
if context.get('supplier'):
where &= purchase.party == context['supplier']
if context.get('client'):
where &= sale.party == context['client']
if context.get('warehouse'):
where &= warehouse == context['warehouse']
if context.get('lot_status'):
where &= lot.lot_status == context['lot_status']
if context.get('availability'):
where &= lot.lot_av == context['availability']
return (
lot
.join(purchase_line, 'LEFT',
condition=lot.line == purchase_line.id)
.join(purchase, 'LEFT',
condition=purchase_line.purchase == purchase.id)
.join(sale_line, 'LEFT',
condition=lot.sale_line == sale_line.id)
.join(sale, 'LEFT',
condition=sale_line.sale == sale.id)
.join(shipment_in, 'LEFT',
condition=lot.lot_shipment_in == shipment_in.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
lot.id.as_('id'),
lot.id.as_('lot'),
lot.lot_product.as_('product'),
purchase.party.as_('supplier'),
sale.party.as_('client'),
purchase.id.as_('purchase'),
lot.line.as_('purchase_line'),
sale.id.as_('sale'),
lot.sale_line.as_('sale_line'),
lot.lot_status.as_('lot_status'),
lot.lot_av.as_('availability'),
warehouse.as_('warehouse'),
from_location.as_('from_location'),
to_location.as_('to_location'),
lot.lot_shipment_in.as_('shipment_in'),
lot.lot_shipment_out.as_('shipment_out'),
lot.lot_shipment_internal.as_('shipment_internal'),
lot.lot_container.as_('container'),
Coalesce(lot.lot_qt, 0).as_('quantity'),
lot.lot_unit_line.as_('unit'),
where=where))
class CTRMContractPerformanceContext(ModelView):
"CTRM Contract Performance Context"
__name__ = 'ctrm.reporting.operations.contract.context'
side = fields.Selection([
(None, ''),
('purchase', 'Purchase'),
('sale', 'Sale'),
], "Side")
product = fields.Many2One('product.product', "Product")
counterparty = fields.Many2One('party.party', "Counterparty")
delivery_period = fields.Many2One('product.month', "Delivery Period")
status = fields.Selection([
(None, ''),
('under', 'Under delivery'),
('in_tolerance', 'In tolerance'),
('over', 'Over delivery'),
], "Status")
open_only = fields.Boolean("Open Only")
class CTRMContractPerformance(ModelSQL, ModelView):
"CTRM Contract Performance"
__name__ = 'ctrm.reporting.operations.contract'
side = fields.Selection([
('purchase', 'Purchase'),
('sale', 'Sale'),
], "Side")
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")
counterparty = fields.Many2One('party.party', "Counterparty")
product = fields.Many2One('product.product', "Product")
delivery_period = fields.Many2One('product.month', "Delivery Period")
from_date = fields.Date("From")
to_date = fields.Date("To")
contract_quantity = fields.Numeric("Contract Quantity", digits=(16, 5))
actual_quantity = fields.Numeric("Actual Quantity", digits=(16, 5))
variance_quantity = fields.Numeric("Variance", digits=(16, 5))
tolerance_min = fields.Numeric("Tolerance Min %", digits=(16, 5))
tolerance_max = fields.Numeric("Tolerance Max %", digits=(16, 5))
status = fields.Selection([
('under', 'Under delivery'),
('in_tolerance', 'In tolerance'),
('over', 'Over delivery'),
], "Status")
finished = fields.Boolean("Finished")
unit = fields.Many2One('product.uom', "Unit")
lot_count = fields.Integer("Lots")
@classmethod
def table_query(cls):
pool = Pool()
Lot = pool.get('lot.lot')
PurchaseLine = pool.get('purchase.line')
Purchase = pool.get('purchase.purchase')
SaleLine = pool.get('sale.line')
Sale = pool.get('sale.sale')
lot = Lot.__table__()
purchase_line = PurchaseLine.__table__()
purchase = Purchase.__table__()
sale_line = SaleLine.__table__()
sale = Sale.__table__()
purchase_contract_quantity = Coalesce(
purchase_line.quantity_theorical, purchase_line.quantity, 0)
purchase_tolerance_min = Coalesce(
purchase_line.tol_min, purchase.tol_min, 0)
purchase_tolerance_max = Coalesce(
purchase_line.tol_max, purchase.tol_max, 0)
purchase_actual_quantity = Sum(Coalesce(lot.lot_qt, 0))
purchase_min_quantity = purchase_contract_quantity * (
Literal(1) - (purchase_tolerance_min / Literal(100)))
purchase_max_quantity = purchase_contract_quantity * (
Literal(1) + (purchase_tolerance_max / Literal(100)))
purchase_status = Case(
(purchase_actual_quantity < purchase_min_quantity, 'under'),
(purchase_actual_quantity > purchase_max_quantity, 'over'),
else_='in_tolerance')
sale_contract_quantity = Coalesce(
sale_line.quantity_theorical, sale_line.quantity, 0)
sale_tolerance_min = Coalesce(sale_line.tol_min, sale.tol_min, 0)
sale_tolerance_max = Coalesce(sale_line.tol_max, sale.tol_max, 0)
sale_actual_quantity = Sum(Coalesce(lot.lot_qt, 0))
sale_min_quantity = sale_contract_quantity * (
Literal(1) - (sale_tolerance_min / Literal(100)))
sale_max_quantity = sale_contract_quantity * (
Literal(1) + (sale_tolerance_max / Literal(100)))
sale_status = Case(
(sale_actual_quantity < sale_min_quantity, 'under'),
(sale_actual_quantity > sale_max_quantity, 'over'),
else_='in_tolerance')
context = Transaction().context
purchase_where = (lot.lot_type == 'physic') & (lot.line != Null)
if context.get('product'):
purchase_where &= purchase_line.product == context['product']
if context.get('counterparty'):
purchase_where &= purchase.party == context['counterparty']
if context.get('delivery_period'):
purchase_where &= purchase_line.del_period == (
context['delivery_period'])
if context.get('open_only'):
purchase_where &= purchase_line.finished == False
purchase_query = (
lot
.join(purchase_line, condition=lot.line == purchase_line.id)
.join(purchase, condition=purchase_line.purchase == purchase.id)
.select(
Literal('purchase').as_('side'),
purchase.id.as_('purchase'),
lot.line.as_('purchase_line'),
Literal(None).as_('sale'),
Literal(None).as_('sale_line'),
purchase.party.as_('counterparty'),
purchase_line.product.as_('product'),
purchase_line.del_period.as_('delivery_period'),
purchase_line.from_del.as_('from_date'),
purchase_line.to_del.as_('to_date'),
purchase_contract_quantity.as_('contract_quantity'),
purchase_actual_quantity.as_('actual_quantity'),
(purchase_actual_quantity - purchase_contract_quantity).as_(
'variance_quantity'),
purchase_tolerance_min.as_('tolerance_min'),
purchase_tolerance_max.as_('tolerance_max'),
purchase_status.as_('status'),
purchase_line.finished.as_('finished'),
purchase_line.unit.as_('unit'),
Count(lot.id).as_('lot_count'),
where=purchase_where,
group_by=[
purchase.id,
lot.line,
purchase.party,
purchase_line.product,
purchase_line.del_period,
purchase_line.from_del,
purchase_line.to_del,
purchase_contract_quantity,
purchase_tolerance_min,
purchase_tolerance_max,
purchase_line.finished,
purchase_line.unit,
]))
sale_where = (lot.lot_type == 'physic') & (lot.sale_line != Null)
if context.get('product'):
sale_where &= sale_line.product == context['product']
if context.get('counterparty'):
sale_where &= sale.party == context['counterparty']
if context.get('delivery_period'):
sale_where &= sale_line.del_period == context['delivery_period']
if context.get('open_only'):
sale_where &= sale_line.finished == False
sale_query = (
lot
.join(sale_line, condition=lot.sale_line == sale_line.id)
.join(sale, condition=sale_line.sale == sale.id)
.select(
Literal('sale').as_('side'),
Literal(None).as_('purchase'),
Literal(None).as_('purchase_line'),
sale.id.as_('sale'),
lot.sale_line.as_('sale_line'),
sale.party.as_('counterparty'),
sale_line.product.as_('product'),
sale_line.del_period.as_('delivery_period'),
sale_line.from_del.as_('from_date'),
sale_line.to_del.as_('to_date'),
sale_contract_quantity.as_('contract_quantity'),
sale_actual_quantity.as_('actual_quantity'),
(sale_actual_quantity - sale_contract_quantity).as_(
'variance_quantity'),
sale_tolerance_min.as_('tolerance_min'),
sale_tolerance_max.as_('tolerance_max'),
sale_status.as_('status'),
sale_line.finished.as_('finished'),
sale_line.unit.as_('unit'),
Count(lot.id).as_('lot_count'),
where=sale_where,
group_by=[
sale.id,
lot.sale_line,
sale.party,
sale_line.product,
sale_line.del_period,
sale_line.from_del,
sale_line.to_del,
sale_contract_quantity,
sale_tolerance_min,
sale_tolerance_max,
sale_line.finished,
sale_line.unit,
]))
side = context.get('side')
if side == 'purchase':
grouped = Union(purchase_query, purchase_query, all_=False)
elif side == 'sale':
grouped = Union(sale_query, sale_query, all_=False)
else:
grouped = Union(purchase_query, sale_query, all_=True)
report_id = RowNumber(window=Window([],
order_by=[grouped.side, grouped.purchase_line,
grouped.sale_line]))
outer_where = grouped.side != Null
if context.get('status'):
outer_where &= grouped.status == context['status']
return grouped.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
report_id.as_('id'),
grouped.side.as_('side'),
grouped.purchase.as_('purchase'),
grouped.purchase_line.as_('purchase_line'),
grouped.sale.as_('sale'),
grouped.sale_line.as_('sale_line'),
grouped.counterparty.as_('counterparty'),
grouped.product.as_('product'),
grouped.delivery_period.as_('delivery_period'),
grouped.from_date.as_('from_date'),
grouped.to_date.as_('to_date'),
grouped.contract_quantity.as_('contract_quantity'),
grouped.actual_quantity.as_('actual_quantity'),
grouped.variance_quantity.as_('variance_quantity'),
grouped.tolerance_min.as_('tolerance_min'),
grouped.tolerance_max.as_('tolerance_max'),
grouped.status.as_('status'),
grouped.finished.as_('finished'),
grouped.unit.as_('unit'),
grouped.lot_count.as_('lot_count'),
where=outer_where)
class CTRMSchedulingContext(ModelView):
"CTRM Scheduling Context"
__name__ = 'ctrm.reporting.operations.scheduling.context'
from_date = fields.Date("From Date")
to_date = fields.Date("To Date")
product = fields.Many2One('product.product', "Product")
counterparty = fields.Many2One('party.party', "Counterparty")
warehouse = fields.Many2One('stock.location', "Warehouse")
shipment_state = fields.Char("Shipment State")
lot_status = fields.Selection([
(None, ''),
('forecast', 'Forecast'),
('loading', 'Loading'),
('transit', 'Transit'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Lot Status")
class CTRMScheduling(ModelSQL, ModelView):
"CTRM Scheduling"
__name__ = 'ctrm.reporting.operations.scheduling'
lot = fields.Many2One('lot.lot', "Lot")
product = fields.Many2One('product.product', "Product")
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")
counterparty = fields.Many2One('party.party', "Counterparty")
shipment_in = fields.Many2One('stock.shipment.in', "Shipment")
warehouse = fields.Many2One('stock.location', "Warehouse")
from_location = fields.Many2One('stock.location', "From")
to_location = fields.Many2One('stock.location', "To")
delivery_period = fields.Many2One('product.month', "Delivery Period")
contract_from = fields.Date("Contract From")
contract_to = fields.Date("Contract To")
scheduled_date = fields.Date("Scheduled Date")
eta = fields.Date("ETA")
etd = fields.Date("ETD")
actual_date = fields.Date("Actual Date")
lot_status = fields.Selection([
(None, ''),
('forecast', 'Forecast'),
('loading', 'Loading'),
('transit', 'Transit'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Lot Status")
shipment_state = fields.Char("Shipment State")
quantity = fields.Numeric("Quantity", digits=(16, 5))
unit = fields.Many2One('product.uom', "Unit")
@classmethod
def table_query(cls):
pool = Pool()
Lot = pool.get('lot.lot')
PurchaseLine = pool.get('purchase.line')
Purchase = pool.get('purchase.purchase')
SaleLine = pool.get('sale.line')
Sale = pool.get('sale.sale')
ShipmentIn = pool.get('stock.shipment.in')
lot = Lot.__table__()
purchase_line = PurchaseLine.__table__()
purchase = Purchase.__table__()
sale_line = SaleLine.__table__()
sale = Sale.__table__()
shipment = ShipmentIn.__table__()
counterparty = Case(
(lot.line != Null, purchase.party), else_=sale.party)
delivery_period = Coalesce(
purchase_line.del_period, sale_line.del_period)
contract_from = Coalesce(purchase_line.from_del, sale_line.from_del)
contract_to = Coalesce(purchase_line.to_del, sale_line.to_del)
scheduled_date = Coalesce(
shipment.etad, shipment.eta, shipment.planned_date,
contract_from)
context = Transaction().context
where = lot.lot_type == 'physic'
if context.get('from_date'):
where &= scheduled_date >= context['from_date']
if context.get('to_date'):
where &= scheduled_date <= context['to_date']
if context.get('product'):
where &= lot.lot_product == context['product']
if context.get('counterparty'):
where &= counterparty == context['counterparty']
if context.get('warehouse'):
where &= shipment.warehouse == context['warehouse']
if context.get('shipment_state'):
where &= shipment.state == context['shipment_state']
if context.get('lot_status'):
where &= lot.lot_status == context['lot_status']
return (
lot
.join(purchase_line, 'LEFT',
condition=lot.line == purchase_line.id)
.join(purchase, 'LEFT',
condition=purchase_line.purchase == purchase.id)
.join(sale_line, 'LEFT',
condition=lot.sale_line == sale_line.id)
.join(sale, 'LEFT',
condition=sale_line.sale == sale.id)
.join(shipment, 'LEFT',
condition=lot.lot_shipment_in == shipment.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
lot.id.as_('id'),
lot.id.as_('lot'),
lot.lot_product.as_('product'),
purchase.id.as_('purchase'),
lot.line.as_('purchase_line'),
sale.id.as_('sale'),
lot.sale_line.as_('sale_line'),
counterparty.as_('counterparty'),
lot.lot_shipment_in.as_('shipment_in'),
shipment.warehouse.as_('warehouse'),
shipment.from_location.as_('from_location'),
shipment.to_location.as_('to_location'),
delivery_period.as_('delivery_period'),
contract_from.as_('contract_from'),
contract_to.as_('contract_to'),
scheduled_date.as_('scheduled_date'),
shipment.etad.as_('eta'),
shipment.etd.as_('etd'),
shipment.effective_date.as_('actual_date'),
lot.lot_status.as_('lot_status'),
shipment.state.as_('shipment_state'),
Coalesce(lot.lot_qt, 0).as_('quantity'),
lot.lot_unit_line.as_('unit'),
where=where))
class CTRMFinanceDateContextMixin:
from_date = fields.Date("From Date")
to_date = fields.Date("To Date")
party = fields.Many2One('party.party', "Party")
currency = fields.Many2One('currency.currency', "Currency")
@classmethod
def default_to_date(cls):
Date = Pool().get('ir.date')
return Date.today()
class CTRMAccrualsContext(CTRMFinanceDateContextMixin, ModelView):
"CTRM Accruals Context"
__name__ = 'ctrm.reporting.finance.accruals.context'
product = fields.Many2One('product.product', "Product")
purchase = fields.Many2One('purchase.purchase', "Purchase")
sale = fields.Many2One('sale.sale', "Sale")
type = fields.Selection([
(None, ''),
('physical', 'Physical'),
('fee', 'Fee'),
('derivative', 'Derivative'),
], "Accrual Type")
class CTRMAccruals(ModelSQL, ModelView):
"CTRM Accruals"
__name__ = 'ctrm.reporting.finance.accruals'
valuation_date = fields.Date("Valuation Date")
accrual_type = fields.Selection([
('physical', 'Physical'),
('fee', 'Fee'),
('derivative', 'Derivative'),
], "Accrual Type")
lot = fields.Many2One('lot.lot', "Lot")
product = fields.Many2One('product.product', "Product")
party = fields.Many2One('party.party', "Party")
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")
quantity = fields.Numeric("Quantity", digits=(16, 5))
unit = fields.Many2One('product.uom', "Unit")
amount = fields.Numeric("Amount", digits=(16, 2))
currency = fields.Many2One('currency.currency', "Currency")
state = fields.Char("State")
@classmethod
def table_query(cls):
pool = Pool()
ValuationLine = pool.get('valuation.valuation.line')
Lot = pool.get('lot.lot')
val = ValuationLine.__table__()
lot = Lot.__table__()
accrual_type = Case(
(val.type == 'derivative', 'derivative'),
(val.type.in_(['line fee', 'pur. fee', 'sale fee',
'shipment fee']), 'fee'),
else_='physical')
context = Transaction().context
where = (
val.type.in_(ALL_VALUATION_TYPES)
& ((val.lot == Null)
| ((lot.invoice_line == Null)
& (lot.sale_invoice_line == Null))))
if context.get('from_date'):
where &= val.date >= context['from_date']
if context.get('to_date'):
where &= val.date <= context['to_date']
if context.get('party'):
where &= val.counterparty == context['party']
if context.get('currency'):
where &= val.currency == context['currency']
if context.get('product'):
where &= val.product == context['product']
if context.get('purchase'):
where &= val.purchase == context['purchase']
if context.get('sale'):
where &= val.sale == context['sale']
if context.get('type'):
where &= accrual_type == context['type']
return (
val
.join(lot, 'LEFT', condition=val.lot == lot.id)
.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'),
accrual_type.as_('accrual_type'),
val.lot.as_('lot'),
val.product.as_('product'),
val.counterparty.as_('party'),
val.purchase.as_('purchase'),
val.line.as_('purchase_line'),
val.sale.as_('sale'),
val.sale_line.as_('sale_line'),
val.reference.as_('reference'),
val.quantity.as_('quantity'),
val.unit.as_('unit'),
val.amount.as_('amount'),
val.currency.as_('currency'),
val.state.as_('state'),
where=where))
class CTRMSettlementsContext(CTRMFinanceDateContextMixin, ModelView):
"CTRM Settlements Context"
__name__ = 'ctrm.reporting.finance.settlements.context'
invoice_type = fields.Selection([
(None, ''),
('in', 'Supplier'),
('out', 'Customer'),
], "Invoice Type")
state = fields.Selection([
(None, ''),
('draft', 'Draft'),
('validated', 'Validated'),
('posted', 'Posted'),
('paid', 'Paid'),
('cancelled', 'Cancelled'),
], "State")
payment_status = fields.Selection([
(None, ''),
('not', 'Not Paid'),
('partial', 'Partially Paid'),
('paid', 'Paid'),
], "Payment Status")
class CTRMSettlements(ModelSQL, ModelView):
"CTRM Settlements and Invoicing"
__name__ = 'ctrm.reporting.finance.settlements'
invoice = fields.Many2One('account.invoice', "Invoice")
invoice_type = fields.Selection([
('in', 'Supplier'),
('out', 'Customer'),
], "Invoice Type")
number = fields.Char("Number")
reference = fields.Char("Reference")
invoice_date = fields.Date("Invoice Date")
party = fields.Many2One('party.party', "Party")
state = fields.Char("State")
currency = fields.Many2One('currency.currency', "Currency")
invoice_amount = fields.Numeric("Invoice Amount", digits=(16, 2))
paid_amount = fields.Numeric("Paid Amount", digits=(16, 2))
open_amount = fields.Numeric("Open Amount", digits=(16, 2))
payment_status = fields.Selection([
('not', 'Not Paid'),
('partial', 'Partially Paid'),
('paid', 'Paid'),
], "Payment Status")
move = fields.Many2One('account.move', "Move")
reconciliation = fields.Integer("Reconciliation")
@classmethod
def table_query(cls):
pool = Pool()
Invoice = pool.get('account.invoice')
InvoicePayment = pool.get('account.invoice-account.move.line')
MoveLine = pool.get('account.move.line')
invoice = Invoice.__table__()
invoice_payment = InvoicePayment.__table__()
line = MoveLine.__table__()
amount = Coalesce(invoice.total_amount_cache, 0)
paid = Coalesce(Sum(line.amount_second_currency), 0)
open_amount = amount - paid
payment_status = Case(
(open_amount == 0, 'paid'),
(paid != 0, 'partial'),
else_='not')
context = Transaction().context
where = invoice.id != Null
if context.get('from_date'):
where &= invoice.invoice_date >= context['from_date']
if context.get('to_date'):
where &= invoice.invoice_date <= context['to_date']
if context.get('party'):
where &= invoice.party == context['party']
if context.get('currency'):
where &= invoice.currency == context['currency']
if context.get('invoice_type'):
where &= invoice.type == context['invoice_type']
if context.get('state'):
where &= invoice.state == context['state']
grouped = (
invoice
.join(invoice_payment, 'LEFT',
condition=invoice_payment.invoice == invoice.id)
.join(line, 'LEFT',
condition=line.id == invoice_payment.line)
.select(
invoice.id.as_('id'),
invoice.id.as_('invoice'),
invoice.type.as_('invoice_type'),
invoice.number.as_('number'),
invoice.reference.as_('reference'),
invoice.invoice_date.as_('invoice_date'),
invoice.party.as_('party'),
invoice.state.as_('state'),
invoice.currency.as_('currency'),
amount.as_('invoice_amount'),
paid.as_('paid_amount'),
open_amount.as_('open_amount'),
payment_status.as_('payment_status'),
invoice.move.as_('move'),
Max(line.reconciliation).as_('reconciliation'),
where=where,
group_by=[
invoice.id, invoice.type, invoice.number,
invoice.reference, invoice.invoice_date, invoice.party,
invoice.state, invoice.currency,
invoice.total_amount_cache, invoice.move,
]))
outer_where = grouped.id != Null
if context.get('payment_status'):
outer_where &= grouped.payment_status == context['payment_status']
return grouped.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
grouped.id.as_('id'),
grouped.invoice.as_('invoice'),
grouped.invoice_type.as_('invoice_type'),
grouped.number.as_('number'),
grouped.reference.as_('reference'),
grouped.invoice_date.as_('invoice_date'),
grouped.party.as_('party'),
grouped.state.as_('state'),
grouped.currency.as_('currency'),
grouped.invoice_amount.as_('invoice_amount'),
grouped.paid_amount.as_('paid_amount'),
grouped.open_amount.as_('open_amount'),
grouped.payment_status.as_('payment_status'),
grouped.move.as_('move'),
grouped.reconciliation.as_('reconciliation'),
where=outer_where)
class CTRMCashFlowContext(CTRMFinanceDateContextMixin, ModelView):
"CTRM Cash Flow Context"
__name__ = 'ctrm.reporting.finance.cashflow.context'
overdue_only = fields.Boolean("Overdue Only")
class CTRMCashFlow(ModelSQL, ModelView):
"CTRM Cash Flow Forecast"
__name__ = 'ctrm.reporting.finance.cashflow'
move_line = fields.Many2One('account.move.line', "Move Line")
move = fields.Many2One('account.move', "Move")
due_date = fields.Date("Due Date")
posting_date = fields.Date("Posting Date")
party = fields.Many2One('party.party', "Party")
account = fields.Many2One('account.account', "Account")
currency = fields.Many2One('currency.currency', "Currency")
amount = fields.Numeric("Amount", digits=(16, 2))
debit = fields.Numeric("Debit", digits=(16, 2))
credit = fields.Numeric("Credit", digits=(16, 2))
second_currency = fields.Many2One('currency.currency', "Second Currency")
amount_second_currency = fields.Numeric(
"Amount Second Currency", digits=(16, 2))
description = fields.Char("Description")
reference = fields.Char("Reference")
journal = fields.Many2One('account.journal', "Journal")
@classmethod
def table_query(cls):
pool = Pool()
MoveLine = pool.get('account.move.line')
Move = pool.get('account.move')
Company = pool.get('company.company')
line = MoveLine.__table__()
move = Move.__table__()
company = Company.__table__()
currency = Coalesce(line.second_currency, company.currency)
amount = Coalesce(line.debit, 0) - Coalesce(line.credit, 0)
context = Transaction().context
where = (
(line.reconciliation == Null)
& (line.maturity_date != Null))
if context.get('from_date'):
where &= line.maturity_date >= context['from_date']
if context.get('to_date'):
where &= line.maturity_date <= context['to_date']
if context.get('party'):
where &= line.party == context['party']
if context.get('currency'):
where &= currency == context['currency']
if context.get('overdue_only'):
Date = Pool().get('ir.date')
where &= line.maturity_date < Date.today()
return (
line
.join(move, condition=line.move == move.id)
.join(company, condition=move.company == company.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
line.id.as_('id'),
line.id.as_('move_line'),
line.move.as_('move'),
line.maturity_date.as_('due_date'),
move.date.as_('posting_date'),
line.party.as_('party'),
line.account.as_('account'),
currency.as_('currency'),
amount.as_('amount'),
line.debit.as_('debit'),
line.credit.as_('credit'),
line.second_currency.as_('second_currency'),
line.amount_second_currency.as_('amount_second_currency'),
line.description.as_('description'),
Coalesce(line.ext_ref, move.ext_ref).as_('reference'),
move.journal.as_('journal'),
where=where))
class CTRMGLReconciliationContext(CTRMFinanceDateContextMixin, ModelView):
"CTRM GL Reconciliation Context"
__name__ = 'ctrm.reporting.finance.gl.context'
account = fields.Many2One('account.account', "Account")
lot = fields.Many2One('lot.lot', "Lot")
unreconciled_only = fields.Boolean("Unreconciled Only")
class CTRMGLReconciliation(ModelSQL, ModelView):
"CTRM GL Reconciliation"
__name__ = 'ctrm.reporting.finance.gl'
move_line = fields.Many2One('account.move.line', "Move Line")
move = fields.Many2One('account.move', "Move")
posting_date = fields.Date("Posting Date")
journal = fields.Many2One('account.journal', "Journal")
account = fields.Many2One('account.account', "Account")
party = fields.Many2One('party.party', "Party")
lot = fields.Many2One('lot.lot', "Lot")
fee = fields.Many2One('fee.fee', "Fee")
invoice = fields.Many2One('account.invoice', "Invoice")
currency = fields.Many2One('currency.currency', "Currency")
debit = fields.Numeric("Debit", digits=(16, 2))
credit = fields.Numeric("Credit", digits=(16, 2))
balance = fields.Numeric("Balance", digits=(16, 2))
second_currency = fields.Many2One('currency.currency', "Second Currency")
amount_second_currency = fields.Numeric(
"Amount Second Currency", digits=(16, 2))
reconciliation = fields.Integer("Reconciliation")
move_state = fields.Char("Move State")
description = fields.Char("Description")
reference = fields.Char("Reference")
@classmethod
def table_query(cls):
pool = Pool()
MoveLine = pool.get('account.move.line')
Move = pool.get('account.move')
Invoice = pool.get('account.invoice')
Company = pool.get('company.company')
line = MoveLine.__table__()
move = Move.__table__()
invoice = Invoice.__table__()
company = Company.__table__()
currency = Coalesce(line.second_currency, company.currency)
balance = Coalesce(line.debit, 0) - Coalesce(line.credit, 0)
context = Transaction().context
where = (line.lot != Null) | (line.fee != Null) | (invoice.id != Null)
if context.get('from_date'):
where &= move.date >= context['from_date']
if context.get('to_date'):
where &= move.date <= context['to_date']
if context.get('party'):
where &= line.party == context['party']
if context.get('currency'):
where &= currency == context['currency']
if context.get('account'):
where &= line.account == context['account']
if context.get('lot'):
where &= line.lot == context['lot']
if context.get('unreconciled_only'):
where &= line.reconciliation == Null
return (
line
.join(move, condition=line.move == move.id)
.join(company, condition=move.company == company.id)
.join(invoice, 'LEFT', condition=invoice.move == move.id)
.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
line.id.as_('id'),
line.id.as_('move_line'),
line.move.as_('move'),
move.date.as_('posting_date'),
move.journal.as_('journal'),
line.account.as_('account'),
line.party.as_('party'),
line.lot.as_('lot'),
line.fee.as_('fee'),
invoice.id.as_('invoice'),
currency.as_('currency'),
line.debit.as_('debit'),
line.credit.as_('credit'),
balance.as_('balance'),
line.second_currency.as_('second_currency'),
line.amount_second_currency.as_('amount_second_currency'),
line.reconciliation.as_('reconciliation'),
move.state.as_('move_state'),
line.description.as_('description'),
Coalesce(line.ext_ref, move.ext_ref).as_('reference'),
where=where))