From c2f3d3995f1b5db0b95a1e76c07fc7893d32744b Mon Sep 17 00:00:00 2001 From: laurentbarontini Date: Mon, 8 Jun 2026 19:52:14 +0200 Subject: [PATCH] Purchase design --- modules/purchase_trade/purchase.py | 125 ++++++++++++++++-- modules/purchase_trade/view/purchase_form.xml | 23 +--- 2 files changed, 123 insertions(+), 25 deletions(-) diff --git a/modules/purchase_trade/purchase.py b/modules/purchase_trade/purchase.py index f8e4d55..17b79f3 100755 --- a/modules/purchase_trade/purchase.py +++ b/modules/purchase_trade/purchase.py @@ -330,9 +330,11 @@ class Purchase(metaclass=PoolMeta): forex = fields.One2Many('forex.cover.physical.contract','contract',"Forex",readonly=True) plan = fields.Many2One('workflow.plan',"Name") estimated_date = fields.One2Many('pricing.estimated','purchase',"Estimated date") - group_pnl = fields.Boolean("Group Pnl") - viewer = fields.Function(fields.Text(""),'get_viewer') - doc_template = fields.Many2One('doc.template',"Template") + group_pnl = fields.Boolean("Group Pnl") + viewer = fields.Function(fields.Text(""),'get_viewer') + execution_summary_viewer = fields.Function( + fields.Text(""), 'get_execution_summary_viewer') + doc_template = fields.Many2One('doc.template',"Template") required_documents = fields.Many2Many( 'contract.document.type', 'purchase', 'doc_type', 'Required Documents') analytic_dimensions = fields.One2Many( @@ -638,7 +640,7 @@ class Purchase(metaclass=PoolMeta): } return "d3:" + json.dumps(data) - def get_viewer(self, name=None): + def get_viewer(self, name=None): country_start = '' dep_name = '' arr_name = '' @@ -690,10 +692,117 @@ class Purchase(metaclass=PoolMeta): "departures": [departure], "arrivals": [arrival] } - - return "d3:" + json.dumps(data) - - def getLots(self): + + return "d3:" + json.dumps(data) + + def _execution_summary_quantity(self, value): + if value is None: + return 0.0 + try: + return float(value) + except (TypeError, ValueError): + return 0.0 + + def get_execution_summary_viewer(self, name=None): + LotQt = Pool().get('lot.qt') + rows = [] + totals = defaultdict(float) + + for line in (self.lines or []): + if getattr(line, 'type', 'line') != 'line': + continue + + quantity = self._execution_summary_quantity( + getattr(line, 'quantity_theorical', None) + or getattr(line, 'quantity', None)) + matched = 0.0 + shipped = 0.0 + lots_count = 0 + shipped_routes = [] + line_lots = list(getattr(line, 'lots', None) or []) + lot_ids = [lot.id for lot in line_lots if getattr(lot, 'id', None)] + lot_qts = LotQt.search([('lot_p', 'in', lot_ids)]) if lot_ids else [] + + for lqt in lot_qts: + lots_count += 1 + lot_quantity = self._execution_summary_quantity( + getattr(lqt, 'lot_quantity', None) + or getattr(lqt, 'lot_qt', None)) + if getattr(lqt, 'lot_s', None): + matched += lot_quantity + shipment = ( + getattr(lqt, 'lot_shipment_in', None) + or getattr(lqt, 'lot_shipment_internal', None) + or getattr(lqt, 'lot_shipment_out', None)) + if shipment: + shipped += lot_quantity + route_from = getattr( + getattr(shipment, 'from_location', None), + 'rec_name', None) + route_to = getattr( + getattr(shipment, 'to_location', None), + 'rec_name', None) + if route_from or route_to: + shipped_routes.append( + '%s -> %s' % (route_from or '-', route_to or '-')) + + if not lot_qts: + for lot in line_lots: + lots_count += 1 + lot_quantity = self._execution_summary_quantity( + getattr(lot, 'lot_qt', None)) + if getattr(lot, 'lot_s', None) or getattr(lot, 'sale_line', None): + matched += lot_quantity + shipment = ( + getattr(lot, 'lot_shipment_in', None) + or getattr(lot, 'lot_shipment_internal', None) + or getattr(lot, 'lot_shipment_out', None)) + if shipment: + shipped += lot_quantity + route_from = getattr( + getattr(shipment, 'from_location', None), + 'rec_name', None) + route_to = getattr( + getattr(shipment, 'to_location', None), + 'rec_name', None) + if route_from or route_to: + shipped_routes.append( + '%s -> %s' % (route_from or '-', route_to or '-')) + + unit = getattr(getattr(line, 'unit', None), 'rec_name', '') or '' + product = getattr(getattr(line, 'product', None), 'rec_name', '') or '' + route = (shipped_routes[0] if shipped_routes else '%s -> %s' % ( + getattr(getattr(self, 'from_location', None), 'rec_name', None) + or '-', + getattr(getattr(self, 'to_location', None), 'rec_name', None) + or '-')) + + rows.append({ + 'product': product, + 'quantity': quantity, + 'matched': matched, + 'shipped': shipped, + 'open': max(quantity - shipped, 0.0), + 'unit': unit, + 'lots': lots_count, + 'route': route, + }) + totals['quantity'] += quantity + totals['matched'] += matched + totals['shipped'] += shipped + totals['open'] += max(quantity - shipped, 0.0) + totals['lines'] += 1 + + data = { + 'type': 'execution-summary', + 'title': 'Execution snapshot', + 'unit': rows[0]['unit'] if rows else '', + 'totals': dict(totals), + 'rows': rows[:4], + } + return "d3:" + json.dumps(data) + + def getLots(self): if self.lines: if self.lines.lots: return [l for l in self.lines.lots] diff --git a/modules/purchase_trade/view/purchase_form.xml b/modules/purchase_trade/view/purchase_form.xml index 0b248ac..e4f9a58 100755 --- a/modules/purchase_trade/view/purchase_form.xml +++ b/modules/purchase_trade/view/purchase_form.xml @@ -79,7 +79,7 @@ this repository contains the full copyright notices and license terms. --> + col_widths="105px,120px,105px,120px,135px,200px"> @@ -101,22 +101,11 @@ this repository contains the full copyright notices and license terms. --> -