# 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)