Files
tradon/modules/sale_supply_production/production.py
2026-03-14 09:42:12 +00:00

121 lines
3.8 KiB
Python

# This file is part of Tryton. The COPYRIGHT file at the top level of
# this repository contains the full copyright notices and license terms.
from collections import defaultdict
from functools import wraps
from trytond.i18n import gettext
from trytond.model import Model, ModelView, Workflow
from trytond.model.exceptions import AccessError
from trytond.pool import Pool, PoolMeta
from trytond.tools import grouped_slice
from trytond.transaction import Transaction, without_check_access
def process_sale_supply(func):
@wraps(func)
def wrapper(cls, productions):
pool = Pool()
Sale = pool.get('sale.sale')
transaction = Transaction()
context = transaction.context
sales = set()
with without_check_access():
for sub_productions in grouped_slice(productions):
ids = [p.id for p in sub_productions]
sales.update([s.id for s in Sale.search([
('lines.productions', 'in', ids),
])])
result = func(cls, productions)
if sales:
with transaction.set_context(
queue_batch=context.get('queue_batch', True)):
Sale.__queue__.process(sales)
return result
return wrapper
class Production(metaclass=PoolMeta):
__name__ = 'production'
@classmethod
def _get_origin(cls):
return super()._get_origin() | {'sale.line'}
@classmethod
@process_sale_supply
def on_delete(cls, productions):
return super().on_delete(productions)
@classmethod
@ModelView.button
@Workflow.transition('cancelled')
@process_sale_supply
def cancel(cls, productions):
super().cancel(productions)
@classmethod
@ModelView.button
@Workflow.transition('draft')
def draft(cls, productions):
pool = Pool()
SaleLine = pool.get('sale.line')
for production in productions:
if (production.state == 'cancelled'
and isinstance(production.origin, SaleLine)):
raise AccessError(
gettext('sale_supply_production'
'.msg_production_reset_draft',
production=production.rec_name))
super().draft(productions)
@classmethod
@ModelView.button
@Workflow.transition('running')
@process_sale_supply
def run(cls, productions):
super().run(productions)
@classmethod
@ModelView.button
@Workflow.transition('done')
@process_sale_supply
def do(cls, productions):
super().do(productions)
for production in productions:
production.assign_supplied()
def assign_supplied(self, grouping=('product',), filter_=None):
pool = Pool()
SaleLine = pool.get('sale.line')
if isinstance(self.origin, SaleLine):
sale_line = self.origin
else:
return
def filter_func(move):
if filter_ is None:
return True
for fieldname, values in filter_:
value = getattr(move, fieldname)
if isinstance(value, Model):
value = value.id
if value not in values:
return False
def get_key(move):
key = (move.to_location.id,)
for field in grouping:
value = getattr(move, field)
if isinstance(value, Model):
value = value.id
key += (value,)
return key
pbl = defaultdict(lambda: defaultdict(int))
for move in filter(filter_func, self.outputs):
pbl[move.product][get_key(move)] += move.internal_quantity
sale_line.assign_supplied(pbl[sale_line.product], grouping=grouping)