Price component filter domain & from to line/sale line

This commit is contained in:
2026-04-28 19:59:33 +02:00
parent ff2b897b7a
commit 1d6f3158c0
7 changed files with 79 additions and 24 deletions

View File

@@ -2,7 +2,7 @@
# this repository contains the full copyright notices and license terms.
from trytond.model import fields
from trytond.pool import Pool, PoolMeta
from trytond.pyson import Bool, Eval, Id, If
from trytond.pyson import Bool, Eval, Id
from trytond.model import (ModelSQL, ModelView)
from trytond.exceptions import UserError
from trytond.tools import is_full_text, lstrip_wildcard
@@ -333,12 +333,11 @@ class Pricing(ModelSQL,ModelView):
pricing_date = fields.Date("Date")
price_component = fields.Many2One(
'pricing.component', "Component",
domain=[If(Bool(Eval('line')),
('line', '=', Eval('line')),
If(Bool(Eval('sale_line')),
('sale_line', '=', Eval('sale_line')),
('id', '=', -1)))],
depends=['line', 'sale_line'])#, ondelete='CASCADE')
domain=[('id', 'in', Eval('available_components', []))],
depends=['available_components'])#, ondelete='CASCADE')
available_components = fields.Function(
fields.One2Many('pricing.component', '', "Available Components"),
'on_change_with_available_components')
quantity = fields.Numeric("Qt",digits='unit')
settl_price = fields.Numeric("Settl. price",digits='unit')
fixed_qt = fields.Numeric("Fixed qt",digits='unit', readonly=True)
@@ -368,14 +367,25 @@ class Pricing(ModelSQL,ModelView):
def default_quantity(cls):
return Decimal(0)
@classmethod
def default_settl_price(cls):
return Decimal(0)
@classmethod
def default_settl_price(cls):
return Decimal(0)
@classmethod
def default_eod_price(cls):
return Decimal(0)
@fields.depends('line', 'sale_line')
def on_change_with_available_components(self, name=None):
Component = Pool().get('pricing.component')
line = getattr(self, 'line', None)
if line:
return Component.search([('line', '=', line)])
sale_line = getattr(self, 'sale_line', None)
if sale_line:
return Component.search([('sale_line', '=', sale_line)])
return []
@staticmethod
def _weighted_average_price(fixed_qt, fixed_price, unfixed_qt, unfixed_price):
fixed_qt = Decimal(str(fixed_qt or 0))

View File

@@ -1101,6 +1101,22 @@ class Line(metaclass=PoolMeta):
and bool(line.to_del)
and line.from_del > line.to_del)
@classmethod
def _check_delivery_period_values(cls, lines, values=None):
values = values or {}
for line in lines:
from_del = values.get('from_del', getattr(line, 'from_del', None))
to_del = values.get('to_del', getattr(line, 'to_del', None))
if from_del and to_del and from_del > to_del:
raise UserError(
"Delivery period From date must be before To date.")
@classmethod
def create(cls, vlist):
for values in vlist:
cls._check_delivery_period_values([cls()], values)
return super().create(vlist)
def _check_delivery_period(self):
if self._has_invalid_delivery_period(self):
raise UserError(
@@ -1475,13 +1491,15 @@ class Line(metaclass=PoolMeta):
# Si delta négatif alors on decrease si c'est possible le lot_qt non shippé non matché et s'il n'y en a pas on envoie un
# message d'erreur 'Please unlink or unmatch lot'
Lot = Pool().get('lot.lot')
LotQt = Pool().get('lot.qt')
old_values = {}
for records, values in zip(args[::2], args[1::2]):
if 'quantity_theorical' in values:
for record in records:
old_values[record.id] = record.quantity_theorical
LotQt = Pool().get('lot.qt')
old_values = {}
for records, values in zip(args[::2], args[1::2]):
if {'from_del', 'to_del'} & set(values):
cls._check_delivery_period_values(records, values)
if 'quantity_theorical' in values:
for record in records:
old_values[record.id] = record.quantity_theorical
super().write(*args)

View File

@@ -1084,6 +1084,22 @@ class SaleLine(metaclass=PoolMeta):
and bool(line.to_del)
and line.from_del > line.to_del)
@classmethod
def _check_delivery_period_values(cls, lines, values=None):
values = values or {}
for line in lines:
from_del = values.get('from_del', getattr(line, 'from_del', None))
to_del = values.get('to_del', getattr(line, 'to_del', None))
if from_del and to_del and from_del > to_del:
raise UserError(
"Delivery period From date must be before To date.")
@classmethod
def create(cls, vlist):
for values in vlist:
cls._check_delivery_period_values([cls()], values)
return super().create(vlist)
def _check_delivery_period(self):
if self._has_invalid_delivery_period(self):
raise UserError(
@@ -1593,6 +1609,8 @@ class SaleLine(metaclass=PoolMeta):
old_values = {}
for records, values in zip(args[::2], args[1::2]):
if {'from_del', 'to_del'} & set(values):
cls._check_delivery_period_values(records, values)
if 'quantity_theorical' in values:
for record in records:
old_values[record.id] = record.quantity_theorical

View File

@@ -6,7 +6,7 @@ from decimal import Decimal
from unittest.mock import Mock, patch
from trytond.pool import Pool
from trytond.pyson import Bool, Eval, If
from trytond.pyson import Eval
from trytond.tests.test_tryton import ModuleTestCase, with_transaction
from trytond.exceptions import UserError
from trytond.modules.purchase_trade import valuation as valuation_module
@@ -528,11 +528,9 @@ class PurchaseTradeTestCase(ModuleTestCase):
'pricing component choices are limited to the purchase or sale line'
Pricing = Pool().get('pricing.pricing')
self.assertEqual(Pricing.price_component.domain, [If(Bool(Eval('line')),
('line', '=', Eval('line')),
If(Bool(Eval('sale_line')),
('sale_line', '=', Eval('sale_line')),
('id', '=', -1)))])
self.assertEqual(Pricing.price_component.domain, [
('id', 'in', Eval('available_components', [])),
])
def test_pricing_component_must_belong_to_pricing_owner(self):
'pricing rows reject components from another purchase or sale line'
@@ -589,6 +587,14 @@ class PurchaseTradeTestCase(ModuleTestCase):
purchase_line.on_change_from_del()
with self.assertRaises(UserError):
sale_line.on_change_to_del()
with self.assertRaises(UserError):
PurchaseLine._check_delivery_period_values([valid], {
'from_del': invalid.from_del,
})
with self.assertRaises(UserError):
SaleLine._check_delivery_period_values([valid], {
'to_del': datetime.date(2026, 3, 31),
})
def test_pricing_eod_uses_weighted_average_for_manual_rows(self):
'manual pricing eod uses the weighted average of fixed and unfixed legs'

View File

@@ -1,6 +1,7 @@
<form>
<field name="line" invisible="1"/>
<field name="sale_line" invisible="1"/>
<field name="available_components" invisible="1"/>
<label name="pricing_date"/>
<field name="pricing_date"/>
<label name="price_component"/>

View File

@@ -1,6 +1,7 @@
<tree>
<field name="line" tree_invisible="1"/>
<field name="sale_line" tree_invisible="1"/>
<field name="available_components" tree_invisible="1"/>
<field name="pricing_date"/>
<field name="price_component"/>
<field name="quantity"/>

View File

@@ -1,6 +1,7 @@
<tree>
<field name="line" tree_invisible="1"/>
<field name="sale_line" tree_invisible="1"/>
<field name="available_components" tree_invisible="1"/>
<field name="pricing_date"/>
<field name="price_component"/>
<field name="quantity"/>