diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py
index 35bcda9..ebf1891 100755
--- a/modules/purchase_trade/stock.py
+++ b/modules/purchase_trade/stock.py
@@ -1758,6 +1758,58 @@ class ShipmentIn(metaclass=PoolMeta):
price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
return quantity * price
+ @classmethod
+ def _report_lot_quantity_for_line(cls, lot, line):
+ get_quantity = getattr(lot, 'get_current_quantity_converted', None)
+ unit = getattr(line, 'unit', None)
+ if callable(get_quantity):
+ try:
+ return Decimal(str(get_quantity(unit=unit) or 0))
+ except TypeError:
+ try:
+ return Decimal(str(get_quantity() or 0))
+ except TypeError:
+ pass
+
+ quantity = Decimal(str(getattr(lot, 'lot_quantity', 0) or 0))
+ from_unit = getattr(lot, 'lot_unit_line', None)
+ if quantity and from_unit and unit and from_unit != unit:
+ try:
+ Uom = Pool().get('product.uom')
+ quantity = Decimal(str(
+ Uom.compute_qty(from_unit, float(quantity), unit) or 0))
+ except KeyError:
+ pass
+ return quantity
+
+ def _get_report_linkage_lot_quantities_by_line(self, lines, get_line):
+ line_keys = {self._report_record_key(line) for line in lines}
+ quantities = {}
+ for lot in self._get_report_linkage_lots():
+ if getattr(lot, 'lot_type', None) != 'physic':
+ continue
+ line = get_line(lot)
+ if not line:
+ continue
+ key = self._report_record_key(line)
+ if key not in line_keys:
+ continue
+ quantities[key] = (
+ quantities.get(key, Decimal('0'))
+ + self._report_lot_quantity_for_line(lot, line))
+ return quantities
+
+ def _report_linkage_line_quantity(self, line, lot_quantities):
+ key = self._report_record_key(line)
+ if key in lot_quantities:
+ return lot_quantities[key]
+ return self._report_line_quantity(line)
+
+ def _report_linkage_line_amount(self, line, lot_quantities):
+ quantity = self._report_linkage_line_quantity(line, lot_quantities)
+ price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
+ return quantity * price
+
def _get_report_linkage_product(self):
lines = (
self._get_report_linkage_purchase_lines()
@@ -1924,9 +1976,16 @@ class ShipmentIn(metaclass=PoolMeta):
def _get_report_linkage_summary_rows(self):
purchase_lines = self._get_report_linkage_purchase_lines()
sale_lines = self._get_report_linkage_sale_lines()
+ purchase_quantities = self._get_report_linkage_lot_quantities_by_line(
+ purchase_lines, self._report_linkage_lot_purchase_line)
+ sale_quantities = self._get_report_linkage_lot_quantities_by_line(
+ sale_lines, self._report_linkage_lot_sale_line)
purchase_total = -sum(
- self._report_line_amount(line) for line in purchase_lines)
- sale_total = sum(self._report_line_amount(line) for line in sale_lines)
+ self._report_linkage_line_amount(line, purchase_quantities)
+ for line in purchase_lines)
+ sale_total = sum(
+ self._report_linkage_line_amount(line, sale_quantities)
+ for line in sale_lines)
rows = []
if purchase_lines:
@@ -1971,22 +2030,30 @@ class ShipmentIn(metaclass=PoolMeta):
rows = []
purchase_lines = self._get_report_linkage_purchase_lines()
sale_lines = self._get_report_linkage_sale_lines()
+ purchase_quantities = self._get_report_linkage_lot_quantities_by_line(
+ purchase_lines, self._report_linkage_lot_purchase_line)
+ sale_quantities = self._get_report_linkage_lot_quantities_by_line(
+ sale_lines, self._report_linkage_lot_sale_line)
if purchase_lines:
rows.append(('Purchase', '', '', '', '', '', '', '', '', ''))
for line in purchase_lines:
purchase = getattr(line, 'purchase', None)
rows.append(self._get_report_linkage_movement_row(
- 'Deal', purchase, line))
+ 'Deal', purchase, line, purchase_quantities))
if sale_lines:
rows.append(('Sale', '', '', '', '', '', '', '', '', ''))
for line in sale_lines:
sale = getattr(line, 'sale', None)
rows.append(self._get_report_linkage_movement_row(
- 'Deal', sale, line))
+ 'Deal', sale, line, sale_quantities))
if purchase_lines or sale_lines:
balance = (
- sum(self._report_line_quantity(line) for line in purchase_lines)
- - sum(self._report_line_quantity(line) for line in sale_lines))
+ sum(self._report_linkage_line_quantity(
+ line, purchase_quantities)
+ for line in purchase_lines)
+ - sum(self._report_linkage_line_quantity(
+ line, sale_quantities)
+ for line in sale_lines))
unit = self._report_unit_symbol(
purchase_lines[0] if purchase_lines else sale_lines[0])
rows.append((
@@ -1997,10 +2064,13 @@ class ShipmentIn(metaclass=PoolMeta):
'', '', '', '', ''))
return rows
- def _get_report_linkage_movement_row(self, kind, trade, line):
+ def _get_report_linkage_movement_row(
+ self, kind, trade, line, lot_quantities=None):
+ lot_quantities = lot_quantities or {}
product = getattr(line, 'product', None)
quantity = ' '.join(part for part in [
- self._format_report_quantity(self._report_line_quantity(line)),
+ self._format_report_quantity(
+ self._report_linkage_line_quantity(line, lot_quantities)),
(self._report_unit_symbol(line) or '').upper()] if part)
incoterm = getattr(trade, 'incoterm', None)
period = getattr(line, 'period_at', None) or ''
@@ -2046,15 +2116,24 @@ class ShipmentIn(metaclass=PoolMeta):
def _get_report_linkage_detail_rows(self):
rows = []
- for line in self._get_report_linkage_sale_lines():
+ sale_lines = self._get_report_linkage_sale_lines()
+ purchase_lines = self._get_report_linkage_purchase_lines()
+ sale_quantities = self._get_report_linkage_lot_quantities_by_line(
+ sale_lines, self._report_linkage_lot_sale_line)
+ purchase_quantities = self._get_report_linkage_lot_quantities_by_line(
+ purchase_lines, self._report_linkage_lot_purchase_line)
+ for line in sale_lines:
sale = getattr(line, 'sale', None)
rows.append(self._get_report_linkage_detail_row(
- 'A', 'Deal revenue', sale, line, self._report_line_amount(line)))
- for line in self._get_report_linkage_purchase_lines():
+ 'A', 'Deal revenue', sale, line,
+ self._report_linkage_line_amount(line, sale_quantities),
+ sale_quantities))
+ for line in purchase_lines:
purchase = getattr(line, 'purchase', None)
rows.append(self._get_report_linkage_detail_row(
'A', 'Deal expense', purchase, line,
- -self._report_line_amount(line)))
+ -self._report_linkage_line_amount(line, purchase_quantities),
+ purchase_quantities))
for pair in self._get_report_linkage_fee_pairs():
rows.append(self._get_report_linkage_fee_detail_row(pair))
estimated_total = sum((row[6] for row in rows), Decimal('0'))
@@ -2068,11 +2147,14 @@ class ShipmentIn(metaclass=PoolMeta):
validated_total, 'pnl'))
return rows
- def _get_report_linkage_detail_row(self, group, label, trade, line, amount):
+ def _get_report_linkage_detail_row(
+ self, group, label, trade, line, amount, lot_quantities=None):
+ lot_quantities = lot_quantities or {}
currency = self._report_currency_code(trade)
unit = self._report_unit_symbol(line).upper()
unit_price = self._report_price(getattr(line, 'unit_price', 0))
- quantity = self._format_report_quantity(self._report_line_quantity(line))
+ quantity = self._format_report_quantity(
+ self._report_linkage_line_quantity(line, lot_quantities))
return (
group,
label,
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index e7ae0e4..9a5ee16 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -7531,9 +7531,21 @@ description
lot = SimpleNamespace(
id=101,
lot_type='physic',
+ lot_quantity=Decimal('40'),
+ lot_unit_line=unit,
line=purchase_line,
sale_line=sale_line)
- shipment.incoming_moves = [SimpleNamespace(lot=lot)]
+ other_lot = SimpleNamespace(
+ id=102,
+ lot_type='physic',
+ lot_quantity=Decimal('20'),
+ lot_unit_line=unit,
+ line=purchase_line,
+ sale_line=sale_line)
+ shipment.incoming_moves = [
+ SimpleNamespace(lot=lot),
+ SimpleNamespace(lot=other_lot),
+ ]
shipment.vessel = SimpleNamespace(vessel_name='MV ATLANTIC')
self.assertEqual(
@@ -7545,8 +7557,8 @@ description
shipment.report_linkage_bl_date, 'Thursday, April 30, 2026')
self.assertIn('Purchases', shipment.report_linkage_summary_groups)
self.assertIn('Sales', shipment.report_linkage_summary_groups)
- self.assertIn('-8,000.000', shipment.report_linkage_summary_estimated)
- self.assertIn('10,000.000', shipment.report_linkage_summary_estimated)
+ self.assertIn('-4,800.000', shipment.report_linkage_summary_estimated)
+ self.assertIn('6,000.000', shipment.report_linkage_summary_estimated)
summary_rows = shipment._get_report_linkage_summary_rows()
freight_rows = [
row for row in summary_rows
@@ -7555,7 +7567,11 @@ description
self.assertEqual(freight_rows[0][2], Decimal('-25'))
self.assertIn('P-10', shipment.report_linkage_movement_references)
self.assertIn('S-20', shipment.report_linkage_movement_references)
- self.assertIn('100 MT', shipment.report_linkage_movement_quantities)
+ self.assertIn('60 MT', shipment.report_linkage_movement_quantities)
+ detail_rows = shipment._get_report_linkage_detail_rows()
+ deal_rows = [row for row in detail_rows if row[8] == 'line']
+ self.assertTrue(deal_rows)
+ self.assertTrue(all(row[5] == '60' for row in deal_rows))
self.assertIn('80.000 USD/MT', shipment.report_linkage_pricing_input_prices)
self.assertIn('100.000 USD/MT', shipment.report_linkage_pricing_input_prices)
diff --git a/modules/purchase_trade/view/purchase_line_form.xml b/modules/purchase_trade/view/purchase_line_form.xml
index a2e0571..7e5dc8d 100755
--- a/modules/purchase_trade/view/purchase_line_form.xml
+++ b/modules/purchase_trade/view/purchase_line_form.xml
@@ -140,7 +140,7 @@ this repository contains the full copyright notices and license terms. -->
colspan="12" col="1" panel="card" icon="tryton-list"
xalign="0" yalign="0"
col_widths="1fr">
-
diff --git a/modules/purchase_trade/view/sale_line_form.xml b/modules/purchase_trade/view/sale_line_form.xml
index aeb486a..e149d30 100755
--- a/modules/purchase_trade/view/sale_line_form.xml
+++ b/modules/purchase_trade/view/sale_line_form.xml
@@ -138,7 +138,7 @@ this repository contains the full copyright notices and license terms. -->
colspan="12" col="1" panel="card" icon="tryton-list"
xalign="0" yalign="0"
col_widths="1fr">
-