This commit is contained in:
2026-05-24 17:53:33 +02:00
parent 50636c1294
commit 1dc8803287
5 changed files with 261 additions and 39 deletions

View File

@@ -60,6 +60,8 @@ def register():
global_reporting.GRConfiguration,
ctrm_reporting.CTRMPhysicalPosition,
ctrm_reporting.CTRMPhysicalPositionContext,
ctrm_reporting.CTRMFinancialPosition,
ctrm_reporting.CTRMFinancialPositionContext,
configuration.Configuration,
pricing.ImportPricesStart,
pricing.ImportPricesResult,

View File

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

View File

@@ -20,6 +20,26 @@
<field name="view" ref="ctrm_position_physical_view_list"/>
<field name="act_window" ref="act_ctrm_position_physical"/>
</record>
<record model="ir.ui.view" id="ctrm_position_financial_context_view_form">
<field name="model">ctrm.reporting.position.financial.context</field>
<field name="type">form</field>
<field name="name">ctrm_position_financial_context_form</field>
</record>
<record model="ir.ui.view" id="ctrm_position_financial_view_list">
<field name="model">ctrm.reporting.position.financial</field>
<field name="type">tree</field>
<field name="name">ctrm_position_financial_list</field>
</record>
<record model="ir.action.act_window" id="act_ctrm_position_financial">
<field name="name">1.2 Financial Paper Position</field>
<field name="res_model">ctrm.reporting.position.financial</field>
<field name="context_model">ctrm.reporting.position.financial.context</field>
</record>
<record model="ir.action.act_window.view" id="act_ctrm_position_financial_view">
<field name="sequence" eval="10"/>
<field name="view" ref="ctrm_position_financial_view_list"/>
<field name="act_window" ref="act_ctrm_position_financial"/>
</record>
<menuitem
name="1. Positions"
@@ -36,6 +56,7 @@
name="1.2 Financial Paper Position"
parent="menu_ctrm_positions"
sequence="20"
action="act_ctrm_position_financial"
id="menu_ctrm_position_financial"/>
<menuitem
name="1.3 Net Consolidated Position"

View File

@@ -0,0 +1,24 @@
<form>
<label name="trade_from"/>
<field name="trade_from"/>
<label name="trade_to"/>
<field name="trade_to"/>
<label name="maturity_from"/>
<field name="maturity_from"/>
<label name="maturity_to"/>
<field name="maturity_to"/>
<label name="product"/>
<field name="product"/>
<label name="party"/>
<field name="party"/>
<label name="purchase"/>
<field name="purchase"/>
<label name="sale"/>
<field name="sale"/>
<label name="direction"/>
<field name="direction"/>
<label name="state"/>
<field name="state"/>
<label name="open_only"/>
<field name="open_only"/>
</form>

View File

@@ -0,0 +1,17 @@
<tree>
<field name="trade_date"/>
<field name="maturity_date"/>
<field name="product" width="140"/>
<field name="party" width="120"/>
<field name="purchase" width="100"/>
<field name="purchase_line" width="120"/>
<field name="sale" width="100"/>
<field name="sale_line" width="120"/>
<field name="price_index" width="120"/>
<field name="direction"/>
<field name="state"/>
<field name="contract_count" sum="1"/>
<field name="open_qty" sum="1"/>
<field name="entry_price"/>
<field name="exit_price"/>
</tree>