diff --git a/modules/purchase_trade/__init__.py b/modules/purchase_trade/__init__.py
index f52d2fe..d13a854 100755
--- a/modules/purchase_trade/__init__.py
+++ b/modules/purchase_trade/__init__.py
@@ -204,13 +204,12 @@ def register():
stock.ImportSoFStart,
stock.RevaluateStart,
stock.Account,
- stock.AccountMoveLine,
- stock.AccountMove,
- stock.ContainerType,
- stock.ShipmentContainer,
+ stock.AccountMoveLine,
+ stock.AccountMove,
+ stock.ContainerType,
+ stock.ShipmentContainer,
lot.Lot,
lot.LotQt,
- stock.LotQt,
lot.LotReport,
lot.LotContext,
lot.LotShippingStart,
@@ -366,7 +365,6 @@ def register():
stock.ShipmentCOOReport,
stock.ShipmentPackingListReport,
stock.ShipmentLinkageReport,
- stock.LotQtLinkageReport,
stock.LotReportLinkageReport,
module='purchase_trade', type_='report')
diff --git a/modules/purchase_trade/lot.py b/modules/purchase_trade/lot.py
index ab48007..19a9ce8 100755
--- a/modules/purchase_trade/lot.py
+++ b/modules/purchase_trade/lot.py
@@ -4233,7 +4233,7 @@ class LotUnship(Wizard):
lot = Lot(r.id)
if lqt and r.r_lot_type == 'virtual':
shipment = None
- qt = lqt.lot_quantity
+ qt = Decimal(str(lqt.lot_quantity or 0))
mode = 'both'
if not lqt.lot_p:
lot = lqt.lot_s
@@ -4246,17 +4246,21 @@ class LotUnship(Wizard):
shipment = lqt.lot_shipment_internal
elif lqt.lot_shipment_out:
shipment = lqt.lot_shipment_out
- #Decrease forecasted virtual part shipped
- lot.updateVirtualPart(-qt,lqt.lot_shipment_origin,lqt.lot_s,mode)
- #Increase forecasted virtual part non shipped
- if lqt.is_planned_transport():
- LotQt.restore_planned_open_quantity(lqt, qt)
- elif not lot.updateVirtualPart(qt,None,lqt.lot_s,mode):
- lot.createVirtualPart(qt,None,lqt.lot_s,mode)
+ if not shipment:
+ continue
if lqt.lot_p and lqt.lot_p.line:
affected_lines.append(lqt.lot_p.line)
if lqt.lot_s and lqt.lot_s.sale_line:
affected_lines.append(lqt.lot_s.sale_line)
+ # Restore the selected scheduled quantity only once, then
+ # remove its shipment-linked lot.qt so it cannot be
+ # unlinked again from the shipment planned tab.
+ if qt:
+ if lqt.is_planned_transport():
+ LotQt.restore_planned_open_quantity(lqt, qt)
+ elif not lot.updateVirtualPart(qt,None,lqt.lot_s,mode):
+ lot.createVirtualPart(qt,None,lqt.lot_s,mode)
+ LotQt.delete([lqt])
if lot and r.r_lot_type == 'physic':
lot = Lot(r.r_lot_p)
if lot.lot_type == 'physic':
diff --git a/modules/purchase_trade/stock.py b/modules/purchase_trade/stock.py
index 4bcd10f..ffd8929 100755
--- a/modules/purchase_trade/stock.py
+++ b/modules/purchase_trade/stock.py
@@ -1721,6 +1721,8 @@ class ShipmentIn(metaclass=PoolMeta):
getattr(product, 'name', None)
or cls._report_rec_name(product)
or 'Fee')
+ if label.startswith('[') and '] ' in label:
+ label = label.split('] ', 1)[1]
return label
def _get_report_linkage_summary_rows(self):
@@ -1732,9 +1734,11 @@ class ShipmentIn(metaclass=PoolMeta):
rows = []
if purchase_lines:
- rows.append(('Purchases', '', purchase_total, purchase_total))
+ rows.append((
+ 'Purchases', '', purchase_total, purchase_total,
+ 'major'))
if sale_lines:
- rows.append(('Sales', '', sale_total, sale_total))
+ rows.append(('Sales', '', sale_total, sale_total, 'major'))
fee_total = Decimal('0')
fee_rows = {}
@@ -1744,12 +1748,12 @@ class ShipmentIn(metaclass=PoolMeta):
fee_total += amount
fee_rows[label] = fee_rows.get(label, Decimal('0')) + amount
for label, amount in fee_rows.items():
- rows.append(('Costs', label, amount, amount))
+ rows.append(('Costs', label, amount, amount, 'cost'))
if rows:
- rows.append(('Costs', 'Total', fee_total, fee_total))
+ rows.append(('Costs', 'Total', fee_total, fee_total, 'cost'))
pnl = purchase_total + sale_total + fee_total
- rows.append(('P&L', '', pnl, pnl))
+ rows.append(('P&L', '', pnl, pnl, 'pnl'))
return rows
def _get_report_linkage_movement_rows(self):
@@ -1842,10 +1846,10 @@ class ShipmentIn(metaclass=PoolMeta):
-self._report_line_amount(line)))
for fee in self._get_report_linkage_fees():
rows.append(self._get_report_linkage_fee_detail_row(fee))
- total = sum((row[-1] for row in rows), Decimal('0'))
+ total = sum((row[7] for row in rows), Decimal('0'))
if rows:
- rows.append(('A', 'Total', '', '', '', '', total, total))
- rows.append(('P&L', '', '', '', '', '', total, total))
+ rows.append(('A', 'Total', '', '', '', '', total, total, 'total'))
+ rows.append(('P&L', '', '', '', '', '', total, total, 'pnl'))
return rows
def _get_report_linkage_detail_row(self, group, label, trade, line, amount):
@@ -1865,6 +1869,7 @@ class ShipmentIn(metaclass=PoolMeta):
quantity,
amount,
amount,
+ 'line',
)
def _get_report_linkage_fee_detail_row(self, fee):
@@ -1886,7 +1891,7 @@ class ShipmentIn(metaclass=PoolMeta):
quantity = self._report_line_quantity(trade_line)
return (
'A',
- self._report_rec_name(product) or 'Fee',
+ self._report_linkage_fee_label(fee),
self._report_rec_name(getattr(fee, 'supplier', None)),
self._report_number(trade),
' '.join(part for part in [
@@ -1896,6 +1901,7 @@ class ShipmentIn(metaclass=PoolMeta):
self._format_report_quantity(quantity or 0),
amount,
amount,
+ 'fee',
)
@classmethod
@@ -2013,7 +2019,7 @@ class ShipmentIn(metaclass=PoolMeta):
def report_linkage_summary_rows(self):
return self._report_table_rows(
self._get_report_linkage_summary_rows(),
- ('group', 'cost_type', 'estimated', 'validated'),
+ ('group', 'cost_type', 'estimated', 'validated', 'kind'),
{'estimated', 'validated'})
@property
@@ -2166,7 +2172,7 @@ class ShipmentIn(metaclass=PoolMeta):
return self._report_table_rows(
self._get_report_linkage_detail_rows(),
('group', 'cost_type', 'counterpart', 'source', 'unit_price',
- 'quantity', 'estimated', 'validated'),
+ 'quantity', 'estimated', 'validated', 'kind'),
{'estimated', 'validated'})
def get_rec_name(self, name=None):
@@ -2892,214 +2898,6 @@ class FindVessel(Wizard):
return action, {}
-class LotQt(metaclass=PoolMeta):
- __name__ = 'lot.qt'
-
- @staticmethod
- def _report_record_key(record):
- return ShipmentIn._report_record_key(record)
-
- @classmethod
- def _report_unique_records(cls, records):
- return ShipmentIn._report_unique_records(records)
-
- @staticmethod
- def _report_linkage_lot_purchase_line(lot):
- return ShipmentIn._report_linkage_lot_purchase_line(lot)
-
- @staticmethod
- def _report_linkage_lot_sale_line(lot):
- return ShipmentIn._report_linkage_lot_sale_line(lot)
-
- @staticmethod
- def _report_rec_name(record):
- return ShipmentIn._report_rec_name(record)
-
- @classmethod
- def _report_number(cls, record):
- return ShipmentIn._report_number(record)
-
- @staticmethod
- def _report_date(value):
- return ShipmentIn._report_date(value)
-
- @staticmethod
- def _report_amount(value):
- return ShipmentIn._report_amount(value)
-
- @staticmethod
- def _report_price(value):
- return ShipmentIn._report_price(value)
-
- @classmethod
- def _report_currency_code(cls, record):
- return ShipmentIn._report_currency_code(record)
-
- @classmethod
- def _report_unit_symbol(cls, line):
- return ShipmentIn._report_unit_symbol(line)
-
- @classmethod
- def _report_line_quantity(cls, line):
- return ShipmentIn._report_line_quantity(line)
-
- @classmethod
- def _report_line_amount(cls, line):
- return ShipmentIn._report_line_amount(line)
-
- @classmethod
- def _report_fee_amount(cls, fee):
- return ShipmentIn._report_fee_amount(fee)
-
- @classmethod
- def _report_linkage_fee_label(cls, fee):
- return ShipmentIn._report_linkage_fee_label(fee)
-
- @classmethod
- def _report_column(cls, rows, index, amount=False):
- return ShipmentIn._report_column(rows, index, amount=amount)
-
- @classmethod
- def _report_table_rows(cls, rows, names, amount_names=()):
- return ShipmentIn._report_table_rows(rows, names, amount_names)
-
- @staticmethod
- def _format_report_quantity(value, digits='0.001'):
- return ShipmentIn._format_report_quantity(value, digits=digits)
-
- @staticmethod
- def _get_report_unit_text(unit):
- return ShipmentIn._get_report_unit_text(unit)
-
- def _get_report_primary_move(self):
- return getattr(self, 'lot_move', None)
-
- def _get_report_linkage_lots(self):
- return self._report_unique_records((
- getattr(self, 'lot_p', None),
- getattr(self, 'lot_s', None),
- ))
-
- _get_report_linkage_purchase_lines = (
- ShipmentIn._get_report_linkage_purchase_lines)
- _get_report_linkage_sale_lines = ShipmentIn._get_report_linkage_sale_lines
- _get_report_linkage_purchase = ShipmentIn._get_report_linkage_purchase
- _get_report_linkage_sale = ShipmentIn._get_report_linkage_sale
- _get_report_linkage_product = ShipmentIn._get_report_linkage_product
-
- def _get_report_linkage_fees(self):
- fees = []
- seen = set()
-
- def add_fee(fee):
- if not fee:
- return
- key = self._report_record_key(fee)
- if key in seen:
- return
- seen.add(key)
- fees.append(fee)
-
- shipment = getattr(self, 'lot_shipment_in', None)
- for fee in getattr(shipment, 'fees', []) or []:
- add_fee(fee)
- for line in (
- self._get_report_linkage_purchase_lines()
- + self._get_report_linkage_sale_lines()):
- for fee in getattr(line, 'fees', []) or []:
- add_fee(fee)
- return fees
-
- _get_report_linkage_summary_rows = (
- ShipmentIn._get_report_linkage_summary_rows)
- _get_report_linkage_movement_rows = (
- ShipmentIn._get_report_linkage_movement_rows)
- _get_report_linkage_movement_row = (
- ShipmentIn._get_report_linkage_movement_row)
- _get_report_linkage_pricing_rows = (
- ShipmentIn._get_report_linkage_pricing_rows)
- _get_report_linkage_detail_rows = (
- ShipmentIn._get_report_linkage_detail_rows)
- _get_report_linkage_detail_row = (
- ShipmentIn._get_report_linkage_detail_row)
- _get_report_linkage_fee_detail_row = (
- ShipmentIn._get_report_linkage_fee_detail_row)
-
- report_linkage_title = ShipmentIn.report_linkage_title
- report_linkage_desk = ShipmentIn.report_linkage_desk
- report_linkage_book = ShipmentIn.report_linkage_book
- report_linkage_strategy = ShipmentIn.report_linkage_strategy
-
- @property
- def report_linkage_bl_date(self):
- shipment = getattr(self, 'lot_shipment_in', None)
- bl_date = getattr(shipment, 'bl_date', None)
- if not bl_date:
- move = getattr(self, 'lot_move', None)
- bl_date = getattr(move, 'bldate', None)
- return bl_date and bl_date.strftime('%A, %B %d, %Y') or ''
-
- report_linkage_trading_unit = ShipmentIn.report_linkage_trading_unit
- report_linkage_finance_user = ShipmentIn.report_linkage_finance_user
- report_linkage_summary_groups = ShipmentIn.report_linkage_summary_groups
- report_linkage_summary_cost_types = (
- ShipmentIn.report_linkage_summary_cost_types)
- report_linkage_summary_estimated = (
- ShipmentIn.report_linkage_summary_estimated)
- report_linkage_summary_validated = (
- ShipmentIn.report_linkage_summary_validated)
- report_linkage_summary_rows = ShipmentIn.report_linkage_summary_rows
- report_linkage_movement_types = ShipmentIn.report_linkage_movement_types
- report_linkage_movement_references = (
- ShipmentIn.report_linkage_movement_references)
- report_linkage_movement_counterparts = (
- ShipmentIn.report_linkage_movement_counterparts)
- report_linkage_movement_commodities = (
- ShipmentIn.report_linkage_movement_commodities)
- report_linkage_movement_quantities = (
- ShipmentIn.report_linkage_movement_quantities)
- report_linkage_movement_deliveries = (
- ShipmentIn.report_linkage_movement_deliveries)
- report_linkage_movement_basis = ShipmentIn.report_linkage_movement_basis
- report_linkage_movement_periods = (
- ShipmentIn.report_linkage_movement_periods)
- report_linkage_movement_from_dates = (
- ShipmentIn.report_linkage_movement_from_dates)
- report_linkage_movement_to_dates = (
- ShipmentIn.report_linkage_movement_to_dates)
- report_linkage_movement_rows = ShipmentIn.report_linkage_movement_rows
- report_linkage_bank_deal = ShipmentIn.report_linkage_bank_deal
- report_linkage_bank_type = ShipmentIn.report_linkage_bank_type
- report_linkage_bank_name = ShipmentIn.report_linkage_bank_name
- report_linkage_lc_type = ShipmentIn.report_linkage_lc_type
- report_linkage_lc_number = ShipmentIn.report_linkage_lc_number
- report_linkage_lc_amount = ShipmentIn.report_linkage_lc_amount
- report_linkage_lc_expiry_date = ShipmentIn.report_linkage_lc_expiry_date
- report_linkage_pricing_deals = ShipmentIn.report_linkage_pricing_deals
- report_linkage_pricing_sides = ShipmentIn.report_linkage_pricing_sides
- report_linkage_pricing_types = ShipmentIn.report_linkage_pricing_types
- report_linkage_pricing_symbols = ShipmentIn.report_linkage_pricing_symbols
- report_linkage_pricing_periods = ShipmentIn.report_linkage_pricing_periods
- report_linkage_pricing_input_prices = (
- ShipmentIn.report_linkage_pricing_input_prices)
- report_linkage_pricing_rows = ShipmentIn.report_linkage_pricing_rows
- report_linkage_detail_groups = ShipmentIn.report_linkage_detail_groups
- report_linkage_detail_cost_types = (
- ShipmentIn.report_linkage_detail_cost_types)
- report_linkage_detail_counterparts = (
- ShipmentIn.report_linkage_detail_counterparts)
- report_linkage_detail_sources = ShipmentIn.report_linkage_detail_sources
- report_linkage_detail_unit_prices = (
- ShipmentIn.report_linkage_detail_unit_prices)
- report_linkage_detail_quantities = (
- ShipmentIn.report_linkage_detail_quantities)
- report_linkage_detail_estimated = (
- ShipmentIn.report_linkage_detail_estimated)
- report_linkage_detail_validated = (
- ShipmentIn.report_linkage_detail_validated)
- report_linkage_detail_rows = ShipmentIn.report_linkage_detail_rows
-
-
class ShipmentOut(metaclass=PoolMeta):
__name__ = 'stock.shipment.out'
@@ -4633,9 +4431,7 @@ class ShipmentLinkageReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
'shipment_linkage_report_template', 'stock')
-class LotQtLinkageReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
- __name__ = 'lot.qt.linkage'
-
+class LinkageTemplateReport(ShipmentTemplateReportMixin, BaseSupplierShipping):
@classmethod
def _resolve_configured_report_path(cls, action):
return cls._resolve_template_path(
@@ -4852,7 +4648,7 @@ class LotReportLinkageRecord:
report_linkage_detail_rows = ShipmentIn.report_linkage_detail_rows
-class LotReportLinkageReport(LotQtLinkageReport):
+class LotReportLinkageReport(LinkageTemplateReport):
__name__ = 'lot.report.linkage'
@classmethod
diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py
index 8bf2beb..2bd1d48 100644
--- a/modules/purchase_trade/tests/test_module.py
+++ b/modules/purchase_trade/tests/test_module.py
@@ -706,6 +706,9 @@ class PurchaseTradeTestCase(ModuleTestCase):
lot_quantity=Decimal('40'),
lot_p=lot,
lot_s=sale_lot,
+ lot_shipment_in=Mock(),
+ lot_shipment_internal=None,
+ lot_shipment_out=None,
lot_shipment_origin='stock.shipment.in,12',
)
lqt.is_planned_transport.return_value = True
@@ -724,14 +727,53 @@ class PurchaseTradeTestCase(ModuleTestCase):
state = wizard.transition_start()
self.assertEqual(state, 'end')
- lot.updateVirtualPart.assert_called_once_with(
- Decimal('-40'), 'stock.shipment.in,12', sale_lot, 'both')
+ lot.updateVirtualPart.assert_not_called()
LotQt.restore_planned_open_quantity.assert_called_once_with(
lqt, Decimal('40'))
+ LotQt.delete.assert_called_once_with([lqt])
lot.createVirtualPart.assert_not_called()
Lot.assert_lines_quantity_consistency.assert_called_once_with([
purchase_line, sale_line])
+ def test_lot_unship_deletes_zero_scheduled_lotqt_without_restore(self):
+ 'unlinking a residual zero scheduled lot.qt only cleans the shipment tab'
+ wizard = lot_module.LotUnship()
+ wizard.records = [Mock(id=10000007, r_lot_type='virtual')]
+ purchase_line = Mock()
+ sale_line = Mock()
+ lot = Mock(line=purchase_line)
+ sale_lot = Mock(sale_line=sale_line)
+ lqt = Mock(
+ lot_quantity=Decimal('0'),
+ lot_p=lot,
+ lot_s=sale_lot,
+ lot_shipment_in=Mock(),
+ lot_shipment_internal=None,
+ lot_shipment_out=None,
+ )
+ lqt.is_planned_transport.return_value = True
+ Lot = Mock()
+ Lot.return_value = Mock()
+ Lot.skip_quantity_consistency.return_value.__enter__ = Mock()
+ Lot.skip_quantity_consistency.return_value.__exit__ = Mock()
+ LotQt = Mock()
+ LotQt.return_value = lqt
+ Move = Mock()
+
+ pool = Mock()
+ pool.get.side_effect = [Lot, LotQt, Move]
+ with patch('trytond.modules.purchase_trade.lot.Pool',
+ return_value=pool):
+ state = wizard.transition_start()
+
+ self.assertEqual(state, 'end')
+ LotQt.restore_planned_open_quantity.assert_not_called()
+ lot.updateVirtualPart.assert_not_called()
+ lot.createVirtualPart.assert_not_called()
+ LotQt.delete.assert_called_once_with([lqt])
+ Lot.assert_lines_quantity_consistency.assert_called_once_with([
+ purchase_line, sale_line])
+
def test_add_physical_lots_requires_linked_transport(self):
'physical lots can only be added from a scheduled quantity'
LotQt = Pool().get('lot.qt')
@@ -6795,7 +6837,7 @@ description
shipment.bl_date = datetime.date(2026, 4, 30)
freight_product = SimpleNamespace(
rec_name='[Maritime Freight] Maritime freight',
- name='Maritime freight')
+ name='[Maritime Freight] Maritime freight')
shipment.fees = [
SimpleNamespace(
id=201, product=freight_product, price=Decimal('10'),
@@ -6890,83 +6932,9 @@ description
self.assertIn('80.000 USD/MT', shipment.report_linkage_pricing_input_prices)
self.assertIn('100.000 USD/MT', shipment.report_linkage_pricing_input_prices)
- def test_lotqt_linkage_helpers_use_single_matching(self):
- 'lot.qt linkage helpers expose only the selected matching'
- LotQt = Pool().get('lot.qt')
- lotqt = LotQt()
-
- currency = SimpleNamespace(code='USD')
- unit = SimpleNamespace(symbol='MT')
- product = SimpleNamespace(
- rec_name='Sulphuric Acid',
- name='Sulphuric Acid',
- code='H2SO4')
- purchase = SimpleNamespace(
- id=1,
- number='P-10',
- reference='26.0001',
- currency=currency,
- party=SimpleNamespace(rec_name='SUPPLIER SA'),
- to_location=SimpleNamespace(rec_name='Odda'),
- incoterm=SimpleNamespace(code='FOB'),
- operator=SimpleNamespace(rec_name='Operator A'))
- sale = SimpleNamespace(
- id=2,
- number='S-20',
- reference='26.0001',
- currency=currency,
- party=SimpleNamespace(rec_name='CLIENT SA'),
- to_location=SimpleNamespace(rec_name='Mejillones'),
- incoterm=SimpleNamespace(code='CFR'))
- period = SimpleNamespace(rec_name='Chile FY26')
- purchase_line = SimpleNamespace(
- id=11,
- product=product,
- purchase=purchase,
- quantity_theorical=Decimal('100'),
- quantity=Decimal('100'),
- unit_price=Decimal('80'),
- unit=unit,
- price_type='fixed',
- del_period=period,
- period_at='laycan',
- from_del=datetime.date(2026, 4, 30),
- to_del=datetime.date(2026, 5, 8),
- fees=[],
- mtm=[])
- sale_line = SimpleNamespace(
- id=12,
- product=product,
- sale=sale,
- quantity_theorical=Decimal('100'),
- quantity=Decimal('100'),
- unit_price=Decimal('100'),
- unit=unit,
- price_type='fixed',
- del_period=period,
- period_at='laycan',
- from_del=datetime.date(2026, 4, 30),
- to_del=datetime.date(2026, 4, 30),
- fees=[],
- mtm=[])
- lotqt.lot_p = SimpleNamespace(id=101, line=purchase_line)
- lotqt.lot_s = SimpleNamespace(id=102, sale_line=sale_line)
- lotqt.lot_shipment_in = SimpleNamespace(
- bl_date=datetime.date(2026, 4, 30),
- fees=[])
-
- self.assertEqual(
- lotqt.report_linkage_title, 'Linkage P-10/S-20 26.0001')
- self.assertEqual(lotqt.report_linkage_desk, 'Sulphuric Acid')
- self.assertEqual(lotqt.report_linkage_book, 'H2SO4 Chile FY26')
- self.assertEqual(
- lotqt.report_linkage_bl_date, 'Thursday, April 30, 2026')
- self.assertIn('Purchases', lotqt.report_linkage_summary_groups)
- self.assertIn('Sales', lotqt.report_linkage_summary_groups)
- self.assertIn('P-10', lotqt.report_linkage_movement_references)
- self.assertIn('S-20', lotqt.report_linkage_movement_references)
- self.assertIn('80.000 USD/MT', lotqt.report_linkage_pricing_input_prices)
- self.assertIn('100.000 USD/MT', lotqt.report_linkage_pricing_input_prices)
+ def test_linkage_report_does_not_extend_lotqt_model(self):
+ 'linkage report must not alter the lot.qt ORM model'
+ self.assertFalse(hasattr(stock_module, 'LotQt'))
def test_lot_report_linkage_rejects_non_physical_lines(self):
'lot.report linkage report is only available for physical lines'
diff --git a/modules/purchase_trade/view/purchase_form.xml b/modules/purchase_trade/view/purchase_form.xml
index 66717fb..ff24cba 100755
--- a/modules/purchase_trade/view/purchase_form.xml
+++ b/modules/purchase_trade/view/purchase_form.xml
@@ -53,8 +53,9 @@ this repository contains the full copyright notices and license terms. -->
+
+
-
+
+
-
+
+
@@ -1184,30 +1186,34 @@
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
+
+
+
-
-
+
+
+
@@ -1226,7 +1232,7 @@
<shipment.report_linkage_title or ''>
-/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM
DAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsN
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAAR
CAAyAqADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA
@@ -1432,12 +1438,20 @@
GroupCost TypeEstimatedValidated
<for each="row in shipment.report_linkage_summary_rows">
+<if test="row['kind'] == 'pnl'">
+<row['group']><row['cost_type']><row['estimated']><row['validated']>
+</if>
+<if test="row['kind'] == 'cost'">
+<row['group']><row['cost_type']><row['estimated']><row['validated']>
+</if>
+<if test="row['kind'] != 'pnl' and row['kind'] != 'cost'">
<row['group']><row['cost_type']><row['estimated']><row['validated']>
+</if>
</for>
-
+
3- Loading and Discharge movements
@@ -1472,7 +1486,7 @@
<shipment.report_linkage_title or ''>
-/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM
+/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoM
DAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsN
FBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAAR
CAAyAqADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAA
@@ -1678,14 +1692,18 @@
GroupCost TypeCounterpartSourceUnit PriceQuantityEstimatedValidated
<for each="row in shipment.report_linkage_detail_rows">
+<if test="row['kind'] == 'pnl'">
+<row['group']><row['cost_type']><row['counterpart']><row['source']><row['unit_price']><row['quantity']><row['estimated']><row['validated']>
+</if>
+<if test="row['kind'] != 'pnl'">
<row['group']><row['cost_type']><row['counterpart']><row['source']><row['unit_price']><row['quantity']><row['estimated']><row['validated']>
+</if>
</for>
-OliverGyslerJeremieCOLLOTStephaneMonnard
-SteveZaccarini
+OliverGyslerJeremieCOLLOTStephaneMonnardSteveZaccarini
</for>