diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py index 8386f94..35bcda9 100755 --- a/modules/purchase_trade/stock.py +++ b/modules/purchase_trade/stock.py @@ -846,8 +846,8 @@ class ShipmentIn(metaclass=PoolMeta): add_invoice = fields.Boolean("Add invoice") returned_id = fields.Char("Returned ID") result = fields.Char("Result",readonly=True) - sale_invoice_numbers = fields.Function( - fields.Char("Sale Invoice"), 'get_sale_invoice_numbers') + sale_invoice_ref = fields.Function( + fields.Char("Sale invoice ref."), 'get_sale_invoice_ref') agent = fields.Many2One('party.party',"Booking Agent") service_order_key = fields.Integer("Service Order Key") @@ -3054,35 +3054,41 @@ class ShipmentIn(metaclass=PoolMeta): def get_sh(self, name): return self.id - def get_sale_invoice_numbers(self, name=None): - invoices = [] + def get_sale_invoice_ref(self, name=None): + invoice_ref = self._sale_invoice_ref_from_instructions() + if invoice_ref: + return invoice_ref + return self._sale_invoice_ref_from_fintrade() + + def _sale_invoice_ref_from_instructions(self): + instructions = self.html_to_text(self.instructions or '') + match = re.search( + r'Invoice\s+Nb:\s*([^|\r\n]+)', instructions, re.IGNORECASE) + if match: + return match.group(1).strip() + + def _sale_invoice_ref_from_fintrade(self): + if not self.reference: + return None + try: + booking_number = int(self.reference) + except (TypeError, ValueError): + return None + t = Table('freight_booking_lots') + cursor = Transaction().connection.cursor() + query = t.select( + t.SALE_INVOICE, + where=(t.BOOKING_NUMBER == booking_number), + group_by=[t.SALE_INVOICE]) + cursor.execute(*query) + refs = [] seen = set() - - def add_invoice(invoice): - invoice_id = getattr(invoice, 'id', None) - key = invoice_id or id(invoice) - if not invoice or key in seen: - return - seen.add(key) - invoices.append( - getattr(invoice, 'rec_name', None) - or getattr(invoice, 'number', None) - or getattr(invoice, 'reference', None) - or str(invoice_id or '')) - - for lotqt in self.lotqt or []: - lots = [ - getattr(lotqt, 'lot_p', None), - getattr(lotqt, 'lot_s', None), - ] - for lot in lots: - if not lot or getattr(lot, 'lot_type', None) != 'physic': - continue - invoice_line = ( - getattr(lot, 'sale_invoice_line', None) - or getattr(lot, 'sale_invoice_line_prov', None)) - add_invoice(getattr(invoice_line, 'invoice', None)) - return ', '.join(filter(None, invoices)) + for row in cursor.fetchall(): + ref = str(row[0] or '').strip() + if ref and ref not in seen: + refs.append(ref) + seen.add(ref) + return ', '.join(refs) @classmethod def default_transport_type(cls): diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 33fee0e..e7ae0e4 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -7417,34 +7417,22 @@ description shipment.report_insurance_issue_place_and_date, 'GENEVA, 06-04-2026') - def test_shipment_sale_invoice_numbers_use_physical_lot_invoices(self): - 'shipment tree helper lists sale invoices linked to physical lots' - final_invoice = SimpleNamespace(id=1, rec_name='SINV-001') - provisional_invoice = SimpleNamespace(id=2, rec_name='SPRO-002') - final_line = SimpleNamespace(invoice=final_invoice) - provisional_line = SimpleNamespace(invoice=provisional_invoice) - physical_final = SimpleNamespace( - lot_type='physic', - sale_invoice_line=final_line, - sale_invoice_line_prov=provisional_line) - physical_provisional = SimpleNamespace( - lot_type='physic', - sale_invoice_line=None, - sale_invoice_line_prov=provisional_line) - virtual = SimpleNamespace( - lot_type='virtual', - sale_invoice_line=SimpleNamespace( - invoice=SimpleNamespace(id=3, rec_name='IGNORED')), - sale_invoice_line_prov=None) - shipment = SimpleNamespace(lotqt=[ - SimpleNamespace(lot_p=physical_final, lot_s=virtual), - SimpleNamespace(lot_p=physical_provisional, lot_s=None), - SimpleNamespace(lot_p=physical_final, lot_s=None), - ]) + def test_shipment_sale_invoice_ref_uses_weight_report_message(self): + 'shipment tree helper reads the sale invoice ref from instructions' + shipment = SimpleNamespace( + instructions=( + '
Customer: CLIENT | ' + 'Invoice Nb: 4661 | ' + 'Invoice Date: 2026-07-28
'), + html_to_text=Mock(side_effect=lambda html_content: + stock_module.ShipmentIn.html_to_text( + SimpleNamespace(), html_content)), + _sale_invoice_ref_from_fintrade=Mock(return_value='IGNORED')) self.assertEqual( - stock_module.ShipmentIn.get_sale_invoice_numbers(shipment), - 'SINV-001, SPRO-002') + stock_module.ShipmentIn.get_sale_invoice_ref(shipment), + '4661') + shipment._sale_invoice_ref_from_fintrade.assert_not_called() def test_shipment_insurance_amount_fallback_uses_lot_and_incoming_moves(self): 'insurance amount falls back to lot unit price and shipment quantities' diff --git a/modules/purchase_trade/view/shipment_in_tree.xml b/modules/purchase_trade/view/shipment_in_tree.xml index b034f17..49c51e9 100644 --- a/modules/purchase_trade/view/shipment_in_tree.xml +++ b/modules/purchase_trade/view/shipment_in_tree.xml @@ -9,7 +9,7 @@ this repository contains the full copyright notices and license terms. -->