first commit
This commit is contained in:
120
modules/sale_supply_production/production.py
Normal file
120
modules/sale_supply_production/production.py
Normal file
@@ -0,0 +1,120 @@
|
||||
# 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)
|
||||
Reference in New Issue
Block a user