Linkage report

This commit is contained in:
2026-08-05 18:09:23 +02:00
parent 2bcbf169cf
commit 3bb2811e76
4 changed files with 118 additions and 20 deletions

View File

@@ -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,

View File

@@ -7531,9 +7531,21 @@ description</t></is></c>
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</t></is></c>
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</t></is></c>
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)

View File

@@ -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">
<field name="fees" colspan="1" mode="tree,form" height="180"
<field name="fees" colspan="1" mode="tree,form" height="270"
view_ids="purchase_trade.fee_view_tree_sequence,purchase_trade.fee_view_form"/>
<button name="apply_default_fees" icon="tryton-launch"/>
</group>

View File

@@ -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">
<field name="fees" colspan="1" mode="tree,form" height="180"
<field name="fees" colspan="1" mode="tree,form" height="270"
view_ids="purchase_trade.fee_view_tree_sequence,purchase_trade.fee_view_form"/>
<button name="apply_default_fees" icon="tryton-launch"/>
</group>