Linkage report
This commit is contained in:
@@ -1758,6 +1758,58 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
|
price = Decimal(str(getattr(line, 'unit_price', 0) or 0))
|
||||||
return quantity * price
|
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):
|
def _get_report_linkage_product(self):
|
||||||
lines = (
|
lines = (
|
||||||
self._get_report_linkage_purchase_lines()
|
self._get_report_linkage_purchase_lines()
|
||||||
@@ -1924,9 +1976,16 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
def _get_report_linkage_summary_rows(self):
|
def _get_report_linkage_summary_rows(self):
|
||||||
purchase_lines = self._get_report_linkage_purchase_lines()
|
purchase_lines = self._get_report_linkage_purchase_lines()
|
||||||
sale_lines = self._get_report_linkage_sale_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(
|
purchase_total = -sum(
|
||||||
self._report_line_amount(line) for line in purchase_lines)
|
self._report_linkage_line_amount(line, purchase_quantities)
|
||||||
sale_total = sum(self._report_line_amount(line) for line in sale_lines)
|
for line in purchase_lines)
|
||||||
|
sale_total = sum(
|
||||||
|
self._report_linkage_line_amount(line, sale_quantities)
|
||||||
|
for line in sale_lines)
|
||||||
|
|
||||||
rows = []
|
rows = []
|
||||||
if purchase_lines:
|
if purchase_lines:
|
||||||
@@ -1971,22 +2030,30 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
rows = []
|
rows = []
|
||||||
purchase_lines = self._get_report_linkage_purchase_lines()
|
purchase_lines = self._get_report_linkage_purchase_lines()
|
||||||
sale_lines = self._get_report_linkage_sale_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:
|
if purchase_lines:
|
||||||
rows.append(('Purchase', '', '', '', '', '', '', '', '', ''))
|
rows.append(('Purchase', '', '', '', '', '', '', '', '', ''))
|
||||||
for line in purchase_lines:
|
for line in purchase_lines:
|
||||||
purchase = getattr(line, 'purchase', None)
|
purchase = getattr(line, 'purchase', None)
|
||||||
rows.append(self._get_report_linkage_movement_row(
|
rows.append(self._get_report_linkage_movement_row(
|
||||||
'Deal', purchase, line))
|
'Deal', purchase, line, purchase_quantities))
|
||||||
if sale_lines:
|
if sale_lines:
|
||||||
rows.append(('Sale', '', '', '', '', '', '', '', '', ''))
|
rows.append(('Sale', '', '', '', '', '', '', '', '', ''))
|
||||||
for line in sale_lines:
|
for line in sale_lines:
|
||||||
sale = getattr(line, 'sale', None)
|
sale = getattr(line, 'sale', None)
|
||||||
rows.append(self._get_report_linkage_movement_row(
|
rows.append(self._get_report_linkage_movement_row(
|
||||||
'Deal', sale, line))
|
'Deal', sale, line, sale_quantities))
|
||||||
if purchase_lines or sale_lines:
|
if purchase_lines or sale_lines:
|
||||||
balance = (
|
balance = (
|
||||||
sum(self._report_line_quantity(line) for line in purchase_lines)
|
sum(self._report_linkage_line_quantity(
|
||||||
- sum(self._report_line_quantity(line) for line in sale_lines))
|
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(
|
unit = self._report_unit_symbol(
|
||||||
purchase_lines[0] if purchase_lines else sale_lines[0])
|
purchase_lines[0] if purchase_lines else sale_lines[0])
|
||||||
rows.append((
|
rows.append((
|
||||||
@@ -1997,10 +2064,13 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
'', '', '', '', ''))
|
'', '', '', '', ''))
|
||||||
return rows
|
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)
|
product = getattr(line, 'product', None)
|
||||||
quantity = ' '.join(part for part in [
|
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)
|
(self._report_unit_symbol(line) or '').upper()] if part)
|
||||||
incoterm = getattr(trade, 'incoterm', None)
|
incoterm = getattr(trade, 'incoterm', None)
|
||||||
period = getattr(line, 'period_at', None) or ''
|
period = getattr(line, 'period_at', None) or ''
|
||||||
@@ -2046,15 +2116,24 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
|
|
||||||
def _get_report_linkage_detail_rows(self):
|
def _get_report_linkage_detail_rows(self):
|
||||||
rows = []
|
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)
|
sale = getattr(line, 'sale', None)
|
||||||
rows.append(self._get_report_linkage_detail_row(
|
rows.append(self._get_report_linkage_detail_row(
|
||||||
'A', 'Deal revenue', sale, line, self._report_line_amount(line)))
|
'A', 'Deal revenue', sale, line,
|
||||||
for line in self._get_report_linkage_purchase_lines():
|
self._report_linkage_line_amount(line, sale_quantities),
|
||||||
|
sale_quantities))
|
||||||
|
for line in purchase_lines:
|
||||||
purchase = getattr(line, 'purchase', None)
|
purchase = getattr(line, 'purchase', None)
|
||||||
rows.append(self._get_report_linkage_detail_row(
|
rows.append(self._get_report_linkage_detail_row(
|
||||||
'A', 'Deal expense', purchase, line,
|
'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():
|
for pair in self._get_report_linkage_fee_pairs():
|
||||||
rows.append(self._get_report_linkage_fee_detail_row(pair))
|
rows.append(self._get_report_linkage_fee_detail_row(pair))
|
||||||
estimated_total = sum((row[6] for row in rows), Decimal('0'))
|
estimated_total = sum((row[6] for row in rows), Decimal('0'))
|
||||||
@@ -2068,11 +2147,14 @@ class ShipmentIn(metaclass=PoolMeta):
|
|||||||
validated_total, 'pnl'))
|
validated_total, 'pnl'))
|
||||||
return rows
|
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)
|
currency = self._report_currency_code(trade)
|
||||||
unit = self._report_unit_symbol(line).upper()
|
unit = self._report_unit_symbol(line).upper()
|
||||||
unit_price = self._report_price(getattr(line, 'unit_price', 0))
|
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 (
|
return (
|
||||||
group,
|
group,
|
||||||
label,
|
label,
|
||||||
|
|||||||
@@ -7531,9 +7531,21 @@ description</t></is></c>
|
|||||||
lot = SimpleNamespace(
|
lot = SimpleNamespace(
|
||||||
id=101,
|
id=101,
|
||||||
lot_type='physic',
|
lot_type='physic',
|
||||||
|
lot_quantity=Decimal('40'),
|
||||||
|
lot_unit_line=unit,
|
||||||
line=purchase_line,
|
line=purchase_line,
|
||||||
sale_line=sale_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')
|
shipment.vessel = SimpleNamespace(vessel_name='MV ATLANTIC')
|
||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
@@ -7545,8 +7557,8 @@ description</t></is></c>
|
|||||||
shipment.report_linkage_bl_date, 'Thursday, April 30, 2026')
|
shipment.report_linkage_bl_date, 'Thursday, April 30, 2026')
|
||||||
self.assertIn('Purchases', shipment.report_linkage_summary_groups)
|
self.assertIn('Purchases', shipment.report_linkage_summary_groups)
|
||||||
self.assertIn('Sales', 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('-4,800.000', shipment.report_linkage_summary_estimated)
|
||||||
self.assertIn('10,000.000', shipment.report_linkage_summary_estimated)
|
self.assertIn('6,000.000', shipment.report_linkage_summary_estimated)
|
||||||
summary_rows = shipment._get_report_linkage_summary_rows()
|
summary_rows = shipment._get_report_linkage_summary_rows()
|
||||||
freight_rows = [
|
freight_rows = [
|
||||||
row for row in summary_rows
|
row for row in summary_rows
|
||||||
@@ -7555,7 +7567,11 @@ description</t></is></c>
|
|||||||
self.assertEqual(freight_rows[0][2], Decimal('-25'))
|
self.assertEqual(freight_rows[0][2], Decimal('-25'))
|
||||||
self.assertIn('P-10', shipment.report_linkage_movement_references)
|
self.assertIn('P-10', shipment.report_linkage_movement_references)
|
||||||
self.assertIn('S-20', 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('80.000 USD/MT', shipment.report_linkage_pricing_input_prices)
|
||||||
self.assertIn('100.000 USD/MT', shipment.report_linkage_pricing_input_prices)
|
self.assertIn('100.000 USD/MT', shipment.report_linkage_pricing_input_prices)
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
colspan="12" col="1" panel="card" icon="tryton-list"
|
colspan="12" col="1" panel="card" icon="tryton-list"
|
||||||
xalign="0" yalign="0"
|
xalign="0" yalign="0"
|
||||||
col_widths="1fr">
|
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"/>
|
view_ids="purchase_trade.fee_view_tree_sequence,purchase_trade.fee_view_form"/>
|
||||||
<button name="apply_default_fees" icon="tryton-launch"/>
|
<button name="apply_default_fees" icon="tryton-launch"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ this repository contains the full copyright notices and license terms. -->
|
|||||||
colspan="12" col="1" panel="card" icon="tryton-list"
|
colspan="12" col="1" panel="card" icon="tryton-list"
|
||||||
xalign="0" yalign="0"
|
xalign="0" yalign="0"
|
||||||
col_widths="1fr">
|
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"/>
|
view_ids="purchase_trade.fee_view_tree_sequence,purchase_trade.fee_view_form"/>
|
||||||
<button name="apply_default_fees" icon="tryton-launch"/>
|
<button name="apply_default_fees" icon="tryton-launch"/>
|
||||||
</group>
|
</group>
|
||||||
|
|||||||
Reference in New Issue
Block a user