diff --git a/modules/purchase_trade/fee.py b/modules/purchase_trade/fee.py index c2a7502..f0ea47f 100755 --- a/modules/purchase_trade/fee.py +++ b/modules/purchase_trade/fee.py @@ -8,7 +8,7 @@ from trytond.tools import is_full_text, lstrip_wildcard from trytond.transaction import Transaction, inactive_records from decimal import getcontext, Decimal, ROUND_UP, ROUND_HALF_UP from sql.aggregate import Count, Max, Min, Sum, Avg, BoolOr -from sql.conditionals import Case +from sql.conditionals import Case, Coalesce from sql import Column, Literal, Null from sql.functions import CurrentTimestamp, DateTrunc from trytond.wizard import Button, StateTransition, StateView, Wizard @@ -1515,10 +1515,10 @@ class FeeLots(ModelSQL,ModelView): class FeeReport( ModelSQL, ModelView): - "Fee Report" - __name__ = 'fee.report' - r_purchase_line = fields.Many2One('purchase.line', "Purchase line") - r_sale_line = fields.Many2One('sale.line', "Sale line") + "Fee Report" + __name__ = 'fee.report' + r_purchase_line = fields.Many2One('purchase.line', "Purchase line") + r_sale_line = fields.Many2One('sale.line', "Sale line") r_shipment_in = fields.Many2One('stock.shipment.in', "Shipment in") r_shipment_out = fields.Many2One('stock.shipment.out', "Shipment out") r_shipment_internal = fields.Many2One('stock.shipment.internal', "Shipment internal") @@ -1540,9 +1540,10 @@ class FeeReport( ('pcost', '% cost price'), ], 'Mode', required=True) - r_fee_quantity = fields.Function(fields.Numeric("Qt",digits=(1,4)),'get_quantity') - r_fee_unit = fields.Function(fields.Many2One('product.uom',"Unit"),'get_unit') - r_purchase = fields.Many2One('purchase.purchase',"Purchase", ondelete='CASCADE') + r_fee_quantity = fields.Function(fields.Numeric("Qt",digits=(1,4)),'get_quantity') + r_fee_unit = fields.Function(fields.Many2One('product.uom',"Unit"),'get_unit') + r_purchase = fields.Many2One('purchase.purchase',"Purchase", ondelete='CASCADE') + r_sale = fields.Many2One('sale.sale',"Sale", ondelete='CASCADE') r_fee_amount = fields.Function(fields.Numeric("Amount", digits=(1,4)),'get_amount') r_inv = fields.Function(fields.Many2One('account.invoice',"Invoice"),'get_invoice') r_dn_cn = fields.Function(fields.Many2One('account.invoice',"DN/CN"), @@ -1617,16 +1618,26 @@ class FeeReport( @classmethod def table_query(cls): - FeeReport = Pool().get('fee.fee') - fr = FeeReport.__table__() - Purchase = Pool().get('purchase.purchase') - pu = Purchase.__table__() - PurchaseLine = Pool().get('purchase.line') - pl = PurchaseLine.__table__() - Sale = Pool().get('sale.sale') - sa = Sale.__table__() - SaleLine = Pool().get('sale.line') - sl = SaleLine.__table__() + FeeReport = Pool().get('fee.fee') + fr = FeeReport.__table__() + FeeLots = Pool().get('fee.lots') + fl = FeeLots.__table__() + PurchaseLine = Pool().get('purchase.line') + pl = PurchaseLine.__table__() + SaleLine = Pool().get('sale.line') + sl = SaleLine.__table__() + + fee_lot_lines = ( + fl + .join(pl, 'LEFT', condition=fl.line == pl.id) + .join(sl, 'LEFT', condition=fl.sale_line == sl.id) + .select( + fl.fee.as_('fee'), + Min(fl.line).as_('purchase_line'), + Min(pl.purchase).as_('purchase'), + Min(fl.sale_line).as_('sale_line'), + Min(sl.sale).as_('sale'), + group_by=[fl.fee])) context = Transaction().context party = context.get('party') @@ -1644,10 +1655,13 @@ class FeeReport( wh &= (fr.fee_counterparty == party) if fee_type: wh &= (fr.fee_type == fee_type) - if purchase: - wh &= (pu.id == purchase) - if sale: - wh &= (sa.id == sale) + purchase_expr = Coalesce(fee_lot_lines.purchase, fr.purchase) + purchase_line_expr = Coalesce(fee_lot_lines.purchase_line, fr.line) + sale_expr = fee_lot_lines.sale + if purchase: + wh &= (purchase_expr == purchase) + if sale: + wh &= (sale_expr == sale) if shipment_in: wh &= (fr.shipment_in == shipment_in) if invoice_status == 'not_invoiced': @@ -1656,30 +1670,33 @@ class FeeReport( wh &= ((fr.state == 'invoiced') & (fr.dn_cn == Null)) elif invoice_status == 'invoiced_with_dn_cn': wh &= ((fr.state == 'invoiced') & (fr.dn_cn != Null)) - # if shipment_out: - # wh &= (fr.shipment_out == shipment_out) - - query = fr.join(pl,'LEFT',condition=fr.line == pl.id).join(pu,'LEFT', condition=pl.purchase == pu.id).select( - Literal(0).as_('create_uid'), - CurrentTimestamp().as_('create_date'), - Literal(None).as_('write_uid'), - Literal(None).as_('write_date'), - fr.id.as_('id'), - fr.line.as_('r_purchase_line'), - Literal(None).as_('r_sale_line'), - fr.shipment_in.as_('r_shipment_in'), - Literal(None).as_('r_shipment_out'), - fr.shipment_internal.as_('r_shipment_internal'), - fr.product.as_('r_fee_type'), - fr.supplier.as_('r_fee_counterparty'), + # if shipment_out: + # wh &= (fr.shipment_out == shipment_out) + + query = fr.join( + fee_lot_lines, 'LEFT', condition=fr.id == fee_lot_lines.fee + ).select( + Literal(0).as_('create_uid'), + CurrentTimestamp().as_('create_date'), + Literal(None).as_('write_uid'), + Literal(None).as_('write_date'), + fr.id.as_('id'), + purchase_line_expr.as_('r_purchase_line'), + fee_lot_lines.sale_line.as_('r_sale_line'), + fr.shipment_in.as_('r_shipment_in'), + Literal(None).as_('r_shipment_out'), + fr.shipment_internal.as_('r_shipment_internal'), + fr.product.as_('r_fee_type'), + fr.supplier.as_('r_fee_counterparty'), fr.type.as_('r_type'), - fr.p_r.as_('r_fee_paystatus'), - fr.mode.as_('r_mode'), - fr.state.as_('r_state'), - fr.purchase.as_('r_purchase'), - #fr.amount.as_('r_fee_amount'), - fr.price.as_('r_fee_price'), - fr.currency.as_('r_fee_currency'), + fr.p_r.as_('r_fee_paystatus'), + fr.mode.as_('r_mode'), + fr.state.as_('r_state'), + purchase_expr.as_('r_purchase'), + sale_expr.as_('r_sale'), + #fr.amount.as_('r_fee_amount'), + fr.price.as_('r_fee_price'), + fr.currency.as_('r_fee_currency'), #fr.fee_lots.as_('r_fee_lots'), #fr.lots.as_('r_lots'), where=wh) diff --git a/modules/purchase_trade/fee.xml b/modules/purchase_trade/fee.xml index d95a602..55dfeb8 100755 --- a/modules/purchase_trade/fee.xml +++ b/modules/purchase_trade/fee.xml @@ -159,5 +159,9 @@ this repository contains the full copyright notices and license terms. --> action="act_fee_report_form" sequence="10" id="menu_fee_report_form"/> + + + + diff --git a/modules/purchase_trade/pricing.py b/modules/purchase_trade/pricing.py index ff1ebf6..545b4ba 100755 --- a/modules/purchase_trade/pricing.py +++ b/modules/purchase_trade/pricing.py @@ -612,24 +612,24 @@ class MtmStrategy(ModelSQL, ModelView): if comp.price_source_type == 'curve' and comp.price_index: value = Decimal( - comp.price_index.get_price( - dt, - line.unit, - self.currency, - last=scenario.use_last_price - ) - ) + comp.price_index.get_price( + dt, + line.unit, + self.currency, + relative_last=scenario.use_last_price + ) + ) elif comp.price_source_type == 'matrix' and comp.price_matrix: value = self._get_matrix_price(comp, line, dt) elif comp.price_source_type == 'fixed': - value = Decimal(comp.get_price( - dt, - line.unit, - self.currency, - last=scenario.use_last_price - )) + value = Decimal(comp.get_price( + dt, + line.unit, + self.currency, + relative_last=scenario.use_last_price + )) if comp.ratio: value *= Decimal(comp.ratio) / Decimal(100) diff --git a/modules/purchase_trade/tests/test_module.py b/modules/purchase_trade/tests/test_module.py index 2b7a281..d105461 100644 --- a/modules/purchase_trade/tests/test_module.py +++ b/modules/purchase_trade/tests/test_module.py @@ -709,6 +709,11 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual( strategy.get_mtm(line, Decimal('10')), Decimal('250.00')) + strategy.components[0].price_index.get_price.assert_called_once_with( + '2026-03-29', + line.unit, + strategy.currency, + relative_last=True) @with_transaction() def test_get_mtm_uses_fixed_pricing_component(self): @@ -1205,6 +1210,7 @@ class PurchaseTradeTestCase(ModuleTestCase): def test_get_strategy_mtm_price_applies_component_ratio(self): 'strategy mtm price applies component ratios' + price_index = Mock(get_price=Mock(return_value=Decimal('100'))) strategy = Mock( scenario=Mock( valuation_date='2026-03-29', @@ -1214,7 +1220,7 @@ class PurchaseTradeTestCase(ModuleTestCase): ) strategy.components = [Mock( price_source_type='curve', - price_index=Mock(get_price=Mock(return_value=Decimal('100'))), + price_index=price_index, price_matrix=None, ratio=Decimal('25'), )] @@ -1223,6 +1229,11 @@ class PurchaseTradeTestCase(ModuleTestCase): self.assertEqual( valuation_module.Valuation._get_strategy_mtm_price(strategy, line), Decimal('25.0000')) + price_index.get_price.assert_called_once_with( + '2026-03-29', + line.unit, + strategy.currency, + relative_last=True) def test_get_strategy_mtm_price_keeps_signed_component_spread(self): 'strategy mtm price keeps signed spread between different components' diff --git a/modules/purchase_trade/valuation.py b/modules/purchase_trade/valuation.py index 5b68559..db43d13 100644 --- a/modules/purchase_trade/valuation.py +++ b/modules/purchase_trade/valuation.py @@ -522,7 +522,7 @@ class ValuationBase(ModelSQL): scenario.valuation_date, line.unit, strategy.currency, - last=scenario.use_last_price + relative_last=scenario.use_last_price )) elif comp.price_source_type == 'matrix' and comp.price_matrix: value = Decimal(strategy._get_matrix_price( @@ -533,7 +533,7 @@ class ValuationBase(ModelSQL): scenario.valuation_date, line.unit, strategy.currency, - last=scenario.use_last_price + relative_last=scenario.use_last_price )) if comp.ratio: @@ -583,7 +583,7 @@ class ValuationBase(ModelSQL): scenario.valuation_date, line.unit, strategy.currency, - last=scenario.use_last_price)) + relative_last=scenario.use_last_price)) previous = cls._previous_curve_price( component.price_index, scenario.valuation_date, diff --git a/modules/purchase_trade/view/fee_report_list.xml b/modules/purchase_trade/view/fee_report_list.xml index 39a813d..b0e35dc 100755 --- a/modules/purchase_trade/view/fee_report_list.xml +++ b/modules/purchase_trade/view/fee_report_list.xml @@ -1,6 +1,8 @@