120 lines
4.2 KiB
Python
120 lines
4.2 KiB
Python
#The COPYRIGHT file at the top level of this repository contains the full
|
|
# copyright notices and license terms.
|
|
import datetime
|
|
import operator
|
|
from trytond.model import ModelView, fields
|
|
from trytond.transaction import Transaction
|
|
from trytond.pool import Pool, PoolMeta
|
|
from trytond.pyson import Eval, And
|
|
|
|
__all__ = ['PurchaseRequest']
|
|
|
|
_STATES = {
|
|
'readonly': ~Eval('state').in_(['draft', 'pending']),
|
|
}
|
|
|
|
|
|
class PurchaseRequest(metaclass=PoolMeta):
|
|
__name__ = 'purchase.request'
|
|
|
|
pending = fields.Boolean('Pending', readonly=True)
|
|
|
|
@classmethod
|
|
def __setup__(cls):
|
|
super(PurchaseRequest, cls).__setup__()
|
|
pending = ('pending', 'Pending')
|
|
if pending not in cls.state.selection:
|
|
cls.state.selection.append(pending)
|
|
# set new attributes at all purchase request fields
|
|
for fname in dir(cls):
|
|
field = getattr(cls, fname)
|
|
if hasattr(field, 'states'):
|
|
if field.states.get('readonly'):
|
|
field.states['readonly'] = And(field.states['readonly'],
|
|
_STATES['readonly'])
|
|
else:
|
|
field.states['readonly'] = _STATES['readonly']
|
|
field.depends.add('state')
|
|
cls._buttons.update({
|
|
'draft': {
|
|
'invisible': Eval('state') != 'pending',
|
|
'icon': 'tryton-back',
|
|
},
|
|
'to_pending': {
|
|
'invisible': Eval('state') != 'draft',
|
|
'icon': 'tryton-forward',
|
|
},
|
|
})
|
|
|
|
@staticmethod
|
|
def default_pending():
|
|
return False
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
def draft(cls, requests):
|
|
cls.write(requests, {'pending': False})
|
|
cls.update_state(requests)
|
|
|
|
@classmethod
|
|
@ModelView.button
|
|
def to_pending(cls, requests):
|
|
cls.write(requests, {'pending': True})
|
|
cls.update_state(requests)
|
|
|
|
def get_state(self):
|
|
if self.pending and not self.purchase_line:
|
|
return 'pending'
|
|
return super(PurchaseRequest, self).get_state()
|
|
|
|
@classmethod
|
|
def generate_requests(cls, products=None, warehouses=None):
|
|
with Transaction().set_context(generate_requests=True):
|
|
return super(PurchaseRequest, cls).generate_requests(products,
|
|
warehouses)
|
|
|
|
@classmethod
|
|
def compare_requests(cls, new_requests, company):
|
|
pool = Pool()
|
|
Uom = pool.get('product.uom')
|
|
Request = pool.get('purchase.request')
|
|
requests = Request.search([
|
|
('purchase_line', '=', None),
|
|
('pending', '=', True),
|
|
('product', '!=', None),
|
|
])
|
|
# Fetch data from existing requests
|
|
existing_req = {}
|
|
for request in requests:
|
|
existing_req.setdefault(
|
|
(request.product.id, request.warehouse.id),
|
|
[]).append({
|
|
'supply_date': (
|
|
request.supply_date or datetime.date.max),
|
|
'quantity': request.quantity,
|
|
'unit': request.unit,
|
|
})
|
|
|
|
new_requests = super(PurchaseRequest, cls).compare_requests(
|
|
new_requests, company)
|
|
new_requests.sort(key=operator.attrgetter('supply_date'))
|
|
for new_req in new_requests:
|
|
for old_req in existing_req.get(
|
|
(new_req.product.id, new_req.warehouse.id), []):
|
|
if old_req['supply_date'] <= new_req.supply_date:
|
|
quantity = Uom.compute_qty(old_req['unit'],
|
|
old_req['quantity'], new_req.unit)
|
|
new_req.quantity = max(0.0, new_req.quantity - quantity)
|
|
new_req.computed_quantity = new_req.quantity
|
|
old_req['quantity'] = Uom.compute_qty(new_req.unit,
|
|
max(0.0, quantity - new_req.quantity), old_req['unit'])
|
|
else:
|
|
break
|
|
return new_requests
|
|
|
|
@classmethod
|
|
def delete(cls, requests):
|
|
if Transaction().context.get('generate_requests', False):
|
|
requests = [r for r in requests if not r.pending]
|
|
super(PurchaseRequest, cls).delete(requests)
|