diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py
index 4fe654a..8386f94 100755
--- a/modules/purchase_trade/stock.py
+++ b/modules/purchase_trade/stock.py
@@ -844,10 +844,12 @@ class ShipmentIn(metaclass=PoolMeta):
instructions = fields.Text("Instructions")
add_bl = fields.Boolean("Add BL")
add_invoice = fields.Boolean("Add invoice")
- returned_id = fields.Char("Returned ID")
- result = fields.Char("Result",readonly=True)
- agent = fields.Many2One('party.party',"Booking Agent")
- service_order_key = fields.Integer("Service Order Key")
+ 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')
+ agent = fields.Many2One('party.party',"Booking Agent")
+ service_order_key = fields.Integer("Service Order Key")
@classmethod
def __setup__(cls):
@@ -3049,9 +3051,39 @@ class ShipmentIn(metaclass=PoolMeta):
if self.vessel:
return f"imo:{self.vessel.vessel_imo}"
- def get_sh(self, name):
- return self.id
-
+ def get_sh(self, name):
+ return self.id
+
+ def get_sale_invoice_numbers(self, name=None):
+ invoices = []
+ 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))
+
@classmethod
def default_transport_type(cls):
return 'vessel'
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index 1d77c7f..33fee0e 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -7417,6 +7417,35 @@ 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),
+ ])
+
+ self.assertEqual(
+ stock_module.ShipmentIn.get_sale_invoice_numbers(shipment),
+ 'SINV-001, SPRO-002')
+
def test_shipment_insurance_amount_fallback_uses_lot_and_incoming_moves(self):
'insurance amount falls back to lot unit price and shipment quantities'
ShipmentIn = Pool().get('stock.shipment.in')
diff --git a/modules/purchase_trade/view/shipment_in_tree.xml b/modules/purchase_trade/view/shipment_in_tree.xml
index f4f59a1..b034f17 100644
--- a/modules/purchase_trade/view/shipment_in_tree.xml
+++ b/modules/purchase_trade/view/shipment_in_tree.xml
@@ -7,6 +7,9 @@ this repository contains the full copyright notices and license terms. -->
+
+
+