Add Long and Short detail report

This commit is contained in:
2026-07-29 18:08:22 +02:00
parent 27d2a81b31
commit 3235a1ba57
5 changed files with 646 additions and 1 deletions

View File

@@ -72,6 +72,8 @@ def register():
ctrm_reporting.CTRMLongShortCommodityDirection,
ctrm_reporting.CTRMLongShortPeriodProduct,
ctrm_reporting.CTRMLongShortPricingStatus,
ctrm_reporting.CTRMLongShortDetail,
ctrm_reporting.CTRMLongShortDetailContext,
ctrm_reporting.CTRMRealizedPnl,
ctrm_reporting.CTRMRealizedPnlContext,
ctrm_reporting.CTRMMtmPnl,

View File

@@ -3,7 +3,7 @@ import datetime
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 sql.functions import Abs, CurrentTimestamp, RowNumber
from trytond.model import ModelSQL, ModelView, fields
from trytond.pool import Pool
@@ -818,6 +818,481 @@ class CTRMLongShortPricingStatus(
line_pricing=True)
class CTRMLongShortDetailContext(CTRMOpenPositionContext):
"CTRM Long & Short Detail Context"
__name__ = 'ctrm.reporting.position.long_short.detail.context'
asof = fields.Date("From Date")
todate = fields.Date("To Date")
purchase = fields.Many2One('purchase.purchase', "Purchase")
sale = fields.Many2One('sale.sale', "Sale")
supplier = fields.Many2One('party.party', "Supplier")
client = fields.Many2One('party.party', "Client")
reference = fields.Char("Reference")
shipment = fields.Many2One('stock.shipment.in', "Shipment")
vessel = fields.Many2One('trade.vessel', "Vessel")
location = fields.Many2One('stock.location', "Location")
dimension = fields.Many2One('analytic.dimension.value', "Dimension")
matching_status = fields.Selection([
('all', 'All'),
('matched', 'Matched'),
('not matched', 'Not Matched'),
], "Matching")
shipping_status = fields.Selection([
('all', 'All'),
('unshipped', 'Unshipped'),
('planned', 'Planned'),
('scheduled', 'Scheduled'),
('shipped', 'Shipped'),
('received', 'Received'),
], "Shipping Status")
lot_status = fields.Selection([
('all', 'All'),
('forecast', 'Forecast'),
('loading', 'Loading'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Where")
lot_origin = fields.Selection([
('all', 'All'),
('open', 'Open'),
('physic', 'Physic'),
], "Open/Physic")
availability = fields.Selection([
('all', 'All'),
('available', 'Available'),
('reserved', 'Reserved'),
('locked', 'Locked'),
], "Availability")
display_finished = fields.Boolean("Finished")
@classmethod
def default_matching_status(cls):
return 'all'
@classmethod
def default_shipping_status(cls):
return 'all'
@classmethod
def default_lot_status(cls):
return 'all'
@classmethod
def default_lot_origin(cls):
return 'all'
@classmethod
def default_availability(cls):
return 'all'
class CTRMLongShortDetail(ModelSQL, ModelView):
"CTRM Long & Short Detail"
__name__ = 'ctrm.reporting.position.long_short.detail'
contract_type = fields.Selection([
('purchase', 'Purchase'),
('sale', 'Sale'),
], "Contract Type", readonly=True)
contract_reference = fields.Char("Contract No.", readonly=True)
purchase = fields.Many2One(
'purchase.purchase', "Purchase", readonly=True)
purchase_line = fields.Many2One(
'purchase.line', "Purchase Line", readonly=True)
sale = fields.Many2One('sale.sale', "Sale", readonly=True)
sale_line = fields.Many2One('sale.line', "Sale Line", readonly=True)
counterparty = fields.Many2One(
'party.party', "Counterparty", readonly=True)
lot = fields.Many2One('lot.lot', "Lot", readonly=True)
lot_name = fields.Char("Lot Name", readonly=True)
lot_type = fields.Selection([
('virtual', 'Open'),
('physic', 'Physic'),
('loss', 'Loss'),
], "Qt Type", readonly=True)
shipping_status = fields.Selection([
('unshipped', 'Unshipped'),
('planned', 'Planned'),
('scheduled', 'Scheduled'),
('shipped', 'Shipped'),
('received', 'Received'),
], "Shipping Status", readonly=True)
lot_status = fields.Selection([
(None, ''),
('forecast', 'Forecast'),
('loading', 'Loading'),
('transit', 'Transit'),
('destination', 'Destination'),
('stock', 'Stock'),
('delivered', 'Delivered'),
], "Where", readonly=True)
availability = fields.Selection([
('available', 'Available'),
('reserved', 'Reserved'),
('locked', 'Locked'),
], "Availability", readonly=True)
product = fields.Many2One(
'product.product', "Product", readonly=True)
commodity = fields.Many2One(
'product.category', "Commodity", readonly=True)
attributes_name = fields.Function(
fields.Char("Attributes", readonly=True), 'get_line_display')
specification = fields.Function(
fields.Char("Specification", readonly=True), 'get_line_display')
incoterm = fields.Many2One(
'incoterm.incoterm', "Incoterm", readonly=True)
incoterm_location = fields.Many2One(
'party.address', "Incoterm Place", readonly=True)
from_location = fields.Many2One(
'stock.location', "From", readonly=True)
to_location = fields.Many2One(
'stock.location', "To", readonly=True)
delivery_period = fields.Many2One(
'product.month', "Shipment Pd", readonly=True)
from_date = fields.Date("From Date", readonly=True)
to_date = fields.Date("To Date", readonly=True)
shipment_in = fields.Many2One(
'stock.shipment.in', "Shipment", readonly=True)
vessel = fields.Many2One('trade.vessel', "Vessel", readonly=True)
bl_date = fields.Date("BL Date", readonly=True)
bl_number = fields.Char("BL Number", readonly=True)
etd = fields.Date("ETD", readonly=True)
eta = fields.Date("ETA", readonly=True)
actual_date = fields.Date("Actual Date", readonly=True)
strategy = fields.Many2One(
'mtm.strategy', "Strategy", readonly=True)
pricing = fields.Selection([
('fixed', 'Fixed'),
('unfixed', 'Unfixed'),
], "Pricing", readonly=True)
price_type = fields.Selection([
('cash', 'Cash Price'),
('priced', 'Priced'),
('basis', 'Basis'),
('efp', 'EFP'),
], "Price Type", readonly=True)
unit_price = fields.Numeric(
"Unit Price", digits=(16, 4), readonly=True)
currency = fields.Many2One(
'currency.currency', "Currency", readonly=True)
currency_symbol = fields.Function(
fields.Char("Currency Symbol"), 'get_currency_symbol')
quantity = fields.Numeric("Quantity", digits=(16, 3), readonly=True)
unit = fields.Many2One('product.uom', "Unit", readonly=True)
amount = fields.Numeric("Value", digits=(16, 2), readonly=True)
direction = fields.Selection([
('long', 'LONG'),
('short', 'SHORT'),
], "Direction", readonly=True)
def _line(self):
if self.contract_type == 'purchase':
return self.purchase_line
return self.sale_line
def get_line_display(self, name=None):
line = self._line()
if not line:
return None
return getattr(line, name, None)
def get_currency_symbol(self, name=None):
currency = getattr(self, 'currency', None)
return (
getattr(currency, 'symbol', None)
or getattr(currency, 'code', None)
or getattr(currency, 'rec_name', None))
@classmethod
def _category_query(cls):
Product = Pool().get('product.product')
Template = Pool().get('product.template')
TemplateCategory = Pool().get('product.template-product.category')
product = Product.__table__()
template = Template.__table__()
template_category = TemplateCategory.__table__()
return (
product
.join(template, condition=product.template == template.id)
.join(template_category, 'LEFT',
condition=template_category.template == template.id)
.select(
product.id.as_('product'),
Max(template_category.category).as_('commodity'),
where=template.type != 'service',
group_by=[product.id]))
@classmethod
def _strategy_query(cls, strategy_table, line_column):
return strategy_table.select(
line_column.as_('line'),
Max(strategy_table.strategy).as_('strategy'),
group_by=[line_column])
@classmethod
def _line_pricing(cls, price_type):
return Case(
(price_type.in_(['cash', 'priced']), 'fixed'),
else_='unfixed')
@classmethod
def _detail_source(cls):
context = Transaction().context
LotQt = Pool().get('lot.qt')
return LotQt.getQuery(
purchase=context.get('purchase'),
sale=context.get('sale'),
shipment=context.get('shipment'),
type=context.get('matching_status'),
state=context.get('availability'),
qttype=None,
supplier=context.get('supplier'),
client=context.get('client'),
ps='all',
lot_status=context.get('lot_status'),
group='all',
product=context.get('product'),
location=context.get('location'),
origin=context.get('lot_origin'),
finished=context.get('display_finished'),
shipping_status=context.get('shipping_status'),
asof=context.get('asof'),
todate=context.get('todate'),
dimension=context.get('dimension'),
strategy=context.get('strategy'),
vessel=context.get('vessel'),
reference=context.get('reference'))
@classmethod
def _apply_common_filters(cls, where, product, commodity, pricing,
direction, period, prefix, counterparty, side):
context = Transaction().context
if context.get('commodity'):
where &= commodity == context['commodity']
if context.get('pricing_status'):
where &= pricing == context['pricing_status']
if context.get('direction'):
if context['direction'] == 'flat':
where &= Literal(False)
elif context['direction'] != direction:
where &= Literal(False)
if context.get('shipment_period'):
where &= period == context['shipment_period']
where = CTRMLongShortMixin._apply_period_filter(
where, period, prefix)
if context.get('counterparty'):
where &= counterparty == context['counterparty']
return where
@classmethod
def table_query(cls):
pool = Pool()
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')
PurchaseStrategy = pool.get('purchase.strategy')
SaleStrategy = pool.get('sale.strategy')
purchase_line = PurchaseLine.__table__()
purchase = Purchase.__table__()
sale_line = SaleLine.__table__()
sale = Sale.__table__()
shipment = ShipmentIn.__table__()
purchase_strategy_table = PurchaseStrategy.__table__()
sale_strategy_table = SaleStrategy.__table__()
purchase_strategy = cls._strategy_query(
purchase_strategy_table, purchase_strategy_table.line)
sale_strategy = cls._strategy_query(
sale_strategy_table, sale_strategy_table.sale_line)
purchase_category = cls._category_query()
sale_category = cls._category_query()
purchase_source = cls._detail_source()
sale_source = cls._detail_source()
purchase_quantity = Abs(Coalesce(purchase_source.r_tot, 0))
purchase_pricing = cls._line_pricing(purchase_line.price_type)
purchase_where = (
(purchase_source.r_line != Null)
& (purchase_line.product != Null))
purchase_where = cls._apply_common_filters(
purchase_where, purchase_line.product, purchase_category.commodity,
purchase_pricing, 'long', purchase_line.del_period, 'purchase',
purchase.party, 'purchase')
purchase_query = (
purchase_source
.join(purchase_line,
condition=purchase_source.r_line == purchase_line.id)
.join(purchase, condition=purchase_line.purchase == purchase.id)
.join(purchase_category, 'LEFT',
condition=purchase_category.product == purchase_line.product)
.join(shipment, 'LEFT',
condition=purchase_source.r_lot_shipment_in == shipment.id)
.join(purchase_strategy, 'LEFT',
condition=purchase_strategy.line == purchase_line.id)
.select(
(purchase_source.id * 2).as_('id'),
Literal('purchase').as_('contract_type'),
Coalesce(purchase.reference, purchase.our_reference).as_(
'contract_reference'),
purchase.id.as_('purchase'),
purchase_line.id.as_('purchase_line'),
Literal(None).as_('sale'),
Literal(None).as_('sale_line'),
purchase.party.as_('counterparty'),
purchase_source.r_lot_p.as_('lot'),
purchase_source.r_lot_name.as_('lot_name'),
purchase_source.r_lot_type.as_('lot_type'),
purchase_source.r_shipping_status.as_('shipping_status'),
purchase_source.r_lot_status.as_('lot_status'),
purchase_source.r_lot_av.as_('availability'),
purchase_line.product.as_('product'),
purchase_category.commodity.as_('commodity'),
purchase.incoterm.as_('incoterm'),
purchase.incoterm_location.as_('incoterm_location'),
purchase_source.r_from_l.as_('from_location'),
purchase_source.r_from_t.as_('to_location'),
purchase_line.del_period.as_('delivery_period'),
purchase_line.from_del.as_('from_date'),
purchase_line.to_del.as_('to_date'),
purchase_source.r_lot_shipment_in.as_('shipment_in'),
purchase_source.r_vessel.as_('vessel'),
purchase_source.r_bl_date.as_('bl_date'),
purchase_source.r_bl_number.as_('bl_number'),
shipment.etd.as_('etd'),
Coalesce(shipment.etad, shipment.eta).as_('eta'),
shipment.effective_date.as_('actual_date'),
purchase_strategy.strategy.as_('strategy'),
purchase_pricing.as_('pricing'),
purchase_line.price_type.as_('price_type'),
purchase_line.unit_price.as_('unit_price'),
purchase.currency.as_('currency'),
purchase_quantity.as_('quantity'),
purchase_line.unit.as_('unit'),
(purchase_quantity * Coalesce(
purchase_line.unit_price, 0)).as_('amount'),
Literal('long').as_('direction'),
where=purchase_where))
sale_quantity = Abs(Coalesce(sale_source.r_tot, 0))
sale_pricing = cls._line_pricing(sale_line.price_type)
sale_where = (
(sale_source.r_sale_line != Null)
& (sale_line.product != Null))
sale_where = cls._apply_common_filters(
sale_where, sale_line.product, sale_category.commodity,
sale_pricing, 'short', sale_line.del_period, 'sale',
sale.party, 'sale')
sale_query = (
sale_source
.join(sale_line,
condition=sale_source.r_sale_line == sale_line.id)
.join(sale, condition=sale_line.sale == sale.id)
.join(sale_category, 'LEFT',
condition=sale_category.product == sale_line.product)
.join(shipment, 'LEFT',
condition=sale_source.r_lot_shipment_in == shipment.id)
.join(sale_strategy, 'LEFT',
condition=sale_strategy.line == sale_line.id)
.select(
(sale_source.id * 2 + 1).as_('id'),
Literal('sale').as_('contract_type'),
Coalesce(sale.reference, sale.our_reference).as_(
'contract_reference'),
Literal(None).as_('purchase'),
Literal(None).as_('purchase_line'),
sale.id.as_('sale'),
sale_line.id.as_('sale_line'),
sale.party.as_('counterparty'),
sale_source.r_lot_p.as_('lot'),
sale_source.r_lot_name.as_('lot_name'),
sale_source.r_lot_type.as_('lot_type'),
sale_source.r_shipping_status.as_('shipping_status'),
sale_source.r_lot_status.as_('lot_status'),
sale_source.r_lot_av.as_('availability'),
sale_line.product.as_('product'),
sale_category.commodity.as_('commodity'),
sale.incoterm.as_('incoterm'),
sale.incoterm_location.as_('incoterm_location'),
sale_source.r_from_l.as_('from_location'),
sale_source.r_from_t.as_('to_location'),
sale_line.del_period.as_('delivery_period'),
sale_line.from_del.as_('from_date'),
sale_line.to_del.as_('to_date'),
sale_source.r_lot_shipment_in.as_('shipment_in'),
sale_source.r_vessel.as_('vessel'),
sale_source.r_bl_date.as_('bl_date'),
sale_source.r_bl_number.as_('bl_number'),
shipment.etd.as_('etd'),
Coalesce(shipment.etad, shipment.eta).as_('eta'),
shipment.effective_date.as_('actual_date'),
sale_strategy.strategy.as_('strategy'),
sale_pricing.as_('pricing'),
sale_line.price_type.as_('price_type'),
sale_line.unit_price.as_('unit_price'),
sale.currency.as_('currency'),
sale_quantity.as_('quantity'),
sale_line.unit.as_('unit'),
(sale_quantity * Coalesce(
sale_line.unit_price, 0)).as_('amount'),
Literal('short').as_('direction'),
where=sale_where))
detail = Union(purchase_query, sale_query, all_=True)
return detail.select(
Literal(0).as_('create_uid'),
CurrentTimestamp().as_('create_date'),
Literal(None).as_('write_uid'),
Literal(None).as_('write_date'),
detail.id.as_('id'),
detail.contract_type.as_('contract_type'),
detail.contract_reference.as_('contract_reference'),
detail.purchase.as_('purchase'),
detail.purchase_line.as_('purchase_line'),
detail.sale.as_('sale'),
detail.sale_line.as_('sale_line'),
detail.counterparty.as_('counterparty'),
detail.lot.as_('lot'),
detail.lot_name.as_('lot_name'),
detail.lot_type.as_('lot_type'),
detail.shipping_status.as_('shipping_status'),
detail.lot_status.as_('lot_status'),
detail.availability.as_('availability'),
detail.product.as_('product'),
detail.commodity.as_('commodity'),
detail.incoterm.as_('incoterm'),
detail.incoterm_location.as_('incoterm_location'),
detail.from_location.as_('from_location'),
detail.to_location.as_('to_location'),
detail.delivery_period.as_('delivery_period'),
detail.from_date.as_('from_date'),
detail.to_date.as_('to_date'),
detail.shipment_in.as_('shipment_in'),
detail.vessel.as_('vessel'),
detail.bl_date.as_('bl_date'),
detail.bl_number.as_('bl_number'),
detail.etd.as_('etd'),
detail.eta.as_('eta'),
detail.actual_date.as_('actual_date'),
detail.strategy.as_('strategy'),
detail.pricing.as_('pricing'),
detail.price_type.as_('price_type'),
detail.unit_price.as_('unit_price'),
detail.currency.as_('currency'),
detail.quantity.as_('quantity'),
detail.unit.as_('unit'),
detail.amount.as_('amount'),
detail.direction.as_('direction'),
order_by=[
detail.delivery_period, detail.product, detail.contract_type,
detail.contract_reference, detail.lot_name])
class CTRMPnlContextMixin:
date = fields.Date("Valuation Date")
product = fields.Many2One('product.product', "Product")

View File

@@ -55,6 +55,16 @@
<field name="type">tree</field>
<field name="name">ctrm_open_position_list</field>
</record>
<record model="ir.ui.view" id="ctrm_long_short_detail_context_view_form">
<field name="model">ctrm.reporting.position.long_short.detail.context</field>
<field name="type">form</field>
<field name="name">ctrm_long_short_detail_context_form</field>
</record>
<record model="ir.ui.view" id="ctrm_long_short_detail_view_list">
<field name="model">ctrm.reporting.position.long_short.detail</field>
<field name="type">tree</field>
<field name="name">ctrm_long_short_detail_list</field>
</record>
<record model="ir.ui.view" id="ctrm_long_short_product_strategy_view_list">
<field name="model">ctrm.reporting.position.long_short.product_strategy</field>
<field name="type">tree</field>
@@ -86,6 +96,16 @@
<field name="view" ref="ctrm_open_position_view_list"/>
<field name="act_window" ref="act_ctrm_open_position"/>
</record>
<record model="ir.action.act_window" id="act_ctrm_long_short_detail">
<field name="name">Long &amp; Short Detail</field>
<field name="res_model">ctrm.reporting.position.long_short.detail</field>
<field name="context_model">ctrm.reporting.position.long_short.detail.context</field>
</record>
<record model="ir.action.act_window.view" id="act_ctrm_long_short_detail_view">
<field name="sequence" eval="10"/>
<field name="view" ref="ctrm_long_short_detail_view_list"/>
<field name="act_window" ref="act_ctrm_long_short_detail"/>
</record>
<record model="ir.action.act_window" id="act_ctrm_long_short_product_strategy">
<field name="name">Long &amp; Short by Product &amp; Strategy</field>
<field name="res_model">ctrm.reporting.position.long_short.product_strategy</field>
@@ -162,6 +182,12 @@
action="act_ctrm_open_position"
sequence="20"
id="menu_ctrm_positions_long_short"/>
<menuitem
name="Long &amp; Short Detail"
parent="menu_ctrm_positions_physical_group"
action="act_ctrm_long_short_detail"
sequence="25"
id="menu_ctrm_positions_long_short_detail"/>
<menuitem
name="By Product &amp; Strategy"
parent="menu_ctrm_positions_physical_group"

View File

@@ -0,0 +1,94 @@
<form col="12"
col_widths="1fr,1fr,1fr,1fr,1fr,1fr,1fr,1fr,1fr,1fr,1fr,1fr">
<group id="detail_common_filters" string="Common filters"
colspan="12" col="8" panel="summary"
col_widths="min-content,1fr,min-content,1fr,min-content,1fr,min-content,1fr">
<label name="valuation_date"/>
<field name="valuation_date"/>
<label name="commodity"/>
<field name="commodity"/>
<label name="product"/>
<field name="product"/>
<label name="pricing_status"/>
<field name="pricing_status"/>
<label name="shipment_period"/>
<field name="shipment_period"/>
<label name="strategy"/>
<field name="strategy"/>
<label name="counterparty"/>
<field name="counterparty"/>
<label name="direction"/>
<field name="direction"/>
</group>
<group id="detail_status_filters" string="Lot &amp; logistics"
colspan="12" col="12" panel="card" icon="tryton-archive"
col_widths="min-content,1fr,min-content,1fr,min-content,1fr,min-content,1fr,min-content,1fr,min-content,1fr">
<label name="asof"/>
<field name="asof"/>
<label name="todate"/>
<field name="todate"/>
<label name="shipping_status"/>
<field name="shipping_status"/>
<label name="lot_status"/>
<field name="lot_status"/>
<label name="lot_origin"/>
<field name="lot_origin"/>
<label name="matching_status"/>
<field name="matching_status"/>
<label name="shipment"/>
<field name="shipment"/>
<label name="vessel"/>
<field name="vessel"/>
<label name="location"/>
<field name="location"/>
<label name="dimension"/>
<field name="dimension"/>
<label name="availability"/>
<field name="availability"/>
<label name="display_finished"/>
<field name="display_finished"/>
</group>
<group id="detail_purchase_filters" string="Purchase side"
colspan="6" col="4" panel="card"
col_widths="min-content,1fr,min-content,1fr">
<label name="supplier"/>
<field name="supplier"/>
<label name="purchase"/>
<field name="purchase"/>
<label name="purchase_period_mode"/>
<field name="purchase_period_mode"/>
<label name="purchase_period"/>
<field name="purchase_period"/>
<label name="purchase_period_from"/>
<field name="purchase_period_from"/>
<label name="purchase_period_to"/>
<field name="purchase_period_to"/>
</group>
<group id="detail_sale_filters" string="Sale side"
colspan="6" col="4" panel="card"
col_widths="min-content,1fr,min-content,1fr">
<label name="client"/>
<field name="client"/>
<label name="sale"/>
<field name="sale"/>
<label name="sale_period_mode"/>
<field name="sale_period_mode"/>
<label name="sale_period"/>
<field name="sale_period"/>
<label name="sale_period_from"/>
<field name="sale_period_from"/>
<label name="sale_period_to"/>
<field name="sale_period_to"/>
</group>
<group id="detail_reference_filters" string="Reference"
colspan="12" col="2" panel="card" icon="tryton-search">
<label name="reference"/>
<field name="reference"/>
</group>
</form>

View File

@@ -0,0 +1,48 @@
<tree>
<field name="contract_type" widget="badge"
badge_colors="purchase:#16a34a,sale:#ef4444" width="95"/>
<field name="contract_reference" width="130"/>
<field name="purchase" width="120" optional="1"/>
<field name="sale" width="120" optional="1"/>
<field name="counterparty" width="140"/>
<field name="lot_name" width="110"/>
<field name="lot" width="90" optional="1"/>
<field name="lot_type" widget="badge"
badge_colors="virtual:#2563eb,physic:#8b5cf6,loss:#64748b"
width="80"/>
<field name="shipping_status" widget="badge"
badge_colors="shipped:#16a34a,unshipped:#ef4444,planned:#06b6d4,scheduled:#f59e0b,received:#64748b"
width="120"/>
<field name="lot_status" width="90"/>
<field name="availability" width="95" optional="1"/>
<field name="product" width="190"/>
<field name="attributes_name" width="160"/>
<field name="specification" width="160" optional="1"/>
<field name="commodity" width="120" optional="1"/>
<field name="incoterm" width="80"/>
<field name="incoterm_location" width="140"/>
<field name="from_location" width="110"/>
<field name="to_location" width="110"/>
<field name="delivery_period" width="100"/>
<field name="from_date" width="95" optional="1"/>
<field name="to_date" width="95" optional="1"/>
<field name="shipment_in" width="120" optional="1"/>
<field name="vessel" width="120" optional="1"/>
<field name="bl_date" width="90" optional="1"/>
<field name="bl_number" width="100" optional="1"/>
<field name="etd" width="90" optional="1"/>
<field name="eta" width="90" optional="1"/>
<field name="actual_date" width="95" optional="1"/>
<field name="strategy" width="130" optional="1"/>
<field name="pricing" widget="badge"
badge_colors="fixed:#16a34a,unfixed:#f59e0b" width="80"/>
<field name="price_type" width="90"/>
<field name="unit_price" symbol="currency_symbol" width="100"/>
<field name="quantity" symbol="unit" sum="1" width="110"/>
<field name="unit" optional="1" width="70"/>
<field name="amount" symbol="currency_symbol" sum="1" width="120"/>
<field name="currency" optional="1" width="70"/>
<field name="currency_symbol" tree_invisible="1"/>
<field name="direction" widget="badge"
badge_colors="long:#16a34a,short:#ef4444" width="80"/>
</tree>