Bug pnl fee

This commit is contained in:
2026-05-14 14:31:23 +02:00
parent 82a30f246d
commit 20a4e20e91
8 changed files with 603 additions and 36 deletions

View File

@@ -136,6 +136,22 @@ class ValuationBase(ModelSQL):
values['sale'] = sale_line.sale.id
values['sale_line'] = sale_line.id
@staticmethod
def _record_id(record):
return getattr(record, 'id', record)
@classmethod
def _unique_lots(cls, lots):
unique = []
seen = set()
for lot in lots:
lot_id = cls._record_id(lot)
if not lot or lot_id in seen:
continue
unique.append(lot)
seen.add(lot_id)
return tuple(unique)
@classmethod
def _filter_values_by_types(cls, values, selected_types):
if selected_types is None:
@@ -166,6 +182,105 @@ class ValuationBase(ModelSQL):
if valuation_lines:
ValuationLine.delete(valuation_lines)
@classmethod
def _value_key(cls, value):
return (
value.get('sale_line') or None,
None if value.get('sale_line') else value.get('line'),
value.get('lot'),
value.get('type'),
value.get('reference'),
value.get('counterparty'),
value.get('product'),
value.get('state'),
value.get('strategy'),
)
@classmethod
def _dedupe_values(cls, values):
unique = []
seen = set()
for value in values:
key = cls._value_key(value)
if key in seen:
continue
unique.append(value)
seen.add(key)
return unique
@classmethod
def _snapshot_identity_domain(cls, value):
domain = [
('lot', '=', value.get('lot')),
('type', '=', value.get('type')),
('reference', '=', value.get('reference')),
('counterparty', '=', value.get('counterparty')),
('product', '=', value.get('product')),
('state', '=', value.get('state')),
('strategy', '=', value.get('strategy')),
]
if value.get('sale_line'):
domain.append(('sale_line', '=', value.get('sale_line')))
elif value.get('line'):
domain.append(('line', '=', value.get('line')))
elif value.get('sale'):
domain.append(('sale', '=', value.get('sale')))
elif value.get('purchase'):
domain.append(('purchase', '=', value.get('purchase')))
return domain
@classmethod
def _delete_existing_snapshot_values(cls, values):
if not values:
return
Date = Pool().get('ir.date')
Valuation = Pool().get('valuation.valuation')
ValuationLine = Pool().get('valuation.valuation.line')
seen = set()
for value in values:
if not value.get('lot') or not value.get('type'):
continue
key = cls._value_key(value)
if key in seen:
continue
seen.add(key)
valuation_line_domain = cls._snapshot_identity_domain(value)
valuation_domain = list(valuation_line_domain)
valuation_domain.append(('date', '=', Date.today()))
valuations = Valuation.search(valuation_domain)
if valuations:
Valuation.delete(valuations)
valuation_lines = ValuationLine.search(valuation_line_domain)
if valuation_lines:
ValuationLine.delete(valuation_lines)
@classmethod
def _matched_purchase_lines_from_sale_line(cls, sale_line):
getter = getattr(sale_line, 'get_matched_lines', None)
if not callable(getter):
return []
purchase_lines = []
seen = set()
matched_lines = getter() or []
try:
iterator = iter(matched_lines)
except TypeError:
return []
for matched_line in iterator:
lot_p = getattr(matched_line, 'lot_p', None)
line = getattr(lot_p, 'line', None)
line_id = cls._record_id(line)
if line and line_id not in seen:
purchase_lines.append(line)
seen.add(line_id)
return purchase_lines
@classmethod
def _delete_existing_sale_line(cls, sale_line, selected_types=None):
Date = Pool().get('ir.date')
@@ -748,7 +863,7 @@ class ValuationBase(ModelSQL):
and not cls._ignore_finished_open_lot(line, s.lot_s)
and not cls._ignore_finished_open_lot(s.lot_s.sale_line, s.lot_s)
)
all_lots = cls._valuation_lots(line) + sale_open_lots
all_lots = cls._unique_lots(cls._valuation_lots(line) + sale_open_lots)
for lot in all_lots:
if cls._ignore_empty_open_fee_lot(lot):
continue
@@ -955,6 +1070,8 @@ class ValuationBase(ModelSQL):
values.extend(cls.create_pnl_price_from_line(line))
values.extend(cls.create_pnl_der_from_line(line))
values = cls._filter_values_by_types(values, selected_types)
values = cls._dedupe_values(values)
cls._delete_existing_snapshot_values(values)
if values:
Valuation = Pool().get('valuation.valuation')
@@ -964,6 +1081,13 @@ class ValuationBase(ModelSQL):
@classmethod
def generate_from_sale_line(cls, sale_line, valuation_type='all'):
matched_purchase_lines = cls._matched_purchase_lines_from_sale_line(
sale_line)
if matched_purchase_lines:
for line in matched_purchase_lines:
cls.generate(line, valuation_type=valuation_type)
return
selected_types = cls._get_generate_types(valuation_type)
cls._delete_existing_sale_line(sale_line, selected_types=selected_types)
values = []
@@ -971,6 +1095,8 @@ class ValuationBase(ModelSQL):
values.extend(cls.create_pnl_price_from_sale_line(sale_line))
values.extend(cls.create_pnl_der_from_sale_line(sale_line))
values = cls._filter_values_by_types(values, selected_types)
values = cls._dedupe_values(values)
cls._delete_existing_snapshot_values(values)
if values:
Valuation = Pool().get('valuation.valuation')