Mtm bug
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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"/>
|
||||
<record model="ir.ui.menu" id="menu_fee_report_form">
|
||||
<field name="parent" ref="menu_fees"/>
|
||||
<field name="sequence" eval="10"/>
|
||||
</record>
|
||||
</data>
|
||||
</tryton>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<tree>
|
||||
<button name="invoice" string="Action"/>
|
||||
<field name="r_purchase_line" width="90"/>
|
||||
<field name="r_purchase_line" width="90" tree_invisible="1"/>
|
||||
<field name="r_purchase" width="100"/>
|
||||
<field name="r_sale" width="100"/>
|
||||
<field name="r_shipment_origin" width="120"/>
|
||||
<field name="r_fee_type" width="120"/>
|
||||
<field name="r_fee_counterparty" width="100"/>
|
||||
|
||||
Reference in New Issue
Block a user