From 20f51de50f03d9f041e127b7e0a9a878844738f2 Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Sun, 24 May 2026 19:04:58 +0200 Subject: [PATCH] GR --- modules/purchase_trade/__init__.py | 4 + modules/purchase_trade/ctrm_reporting.py | 266 +++++++++++++++++- modules/purchase_trade/ctrm_reporting.xml | 42 +++ .../view/ctrm_inventory_context_form.xml | 14 + .../view/ctrm_inventory_list.xml | 19 ++ .../ctrm_shipping_logistics_context_form.xml | 16 ++ .../view/ctrm_shipping_logistics_list.xml | 20 ++ 7 files changed, 380 insertions(+), 1 deletion(-) create mode 100644 modules/purchase_trade/view/ctrm_inventory_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_inventory_list.xml create mode 100644 modules/purchase_trade/view/ctrm_shipping_logistics_context_form.xml create mode 100644 modules/purchase_trade/view/ctrm_shipping_logistics_list.xml diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py index ee2ed4e..aa496be 100755 --- a/modules/purchase_trade/__init__.py +++ b/modules/purchase_trade/__init__.py @@ -74,6 +74,10 @@ def register(): ctrm_reporting.CTRMPnlDimensionContext, ctrm_reporting.CTRMCreditRisk, ctrm_reporting.CTRMCreditRiskContext, + ctrm_reporting.CTRMShippingLogistics, + ctrm_reporting.CTRMShippingLogisticsContext, + ctrm_reporting.CTRMInventory, + ctrm_reporting.CTRMInventoryContext, configuration.Configuration, pricing.ImportPricesStart, pricing.ImportPricesResult, diff --git a/modules/purchase_trade/ctrm_reporting.py b/modules/purchase_trade/ctrm_reporting.py index bb70a84..4404472 100644 --- a/modules/purchase_trade/ctrm_reporting.py +++ b/modules/purchase_trade/ctrm_reporting.py @@ -1,5 +1,5 @@ from sql import Literal, Null, Window -from sql.aggregate import Max, Min, Sum +from sql.aggregate import Count, Max, Min, Sum from sql.conditionals import Case, Coalesce from sql.functions import CurrentTimestamp, RowNumber @@ -896,3 +896,267 @@ class CTRMCreditRisk(ModelSQL, ModelView): 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)) diff --git a/modules/purchase_trade/ctrm_reporting.xml b/modules/purchase_trade/ctrm_reporting.xml index c9ac973..e4dc7c7 100644 --- a/modules/purchase_trade/ctrm_reporting.xml +++ b/modules/purchase_trade/ctrm_reporting.xml @@ -160,6 +160,46 @@ + + ctrm.reporting.operations.shipping.context + form + ctrm_shipping_logistics_context_form + + + ctrm.reporting.operations.shipping + tree + ctrm_shipping_logistics_list + + + Shipping Logistics + ctrm.reporting.operations.shipping + ctrm.reporting.operations.shipping.context + + + + + + + + ctrm.reporting.operations.inventory.context + form + ctrm_inventory_context_form + + + ctrm.reporting.operations.inventory + tree + ctrm_inventory_list + + + Inventory + ctrm.reporting.operations.inventory + ctrm.reporting.operations.inventory.context + + + + + + +