Supply schedule: use a cron instead of a wizard
This commit is contained in:
1 parent
751b87f555
commit
d8def452f0
4 files changed
+300
-310
No files matched your search
@@ -35,6 +35,286 @@ class PurchaseRequest(OSV):
|
||||
context=context)[0]
|
||||
return False
|
||||
|
||||
|
||||
def generate_requests(self, cursor, user, context=None):
|
||||
"""
|
||||
For each product compute the purchase request that must be
|
||||
create today to meet product outputs.
|
||||
"""
|
||||
order_point_obj = self.pool.get('stock.order_point')
|
||||
purchase_request_obj = self.pool.get('stock.purchase_request')
|
||||
product_obj = self.pool.get('product.product')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
user_obj = self.pool.get('res.user')
|
||||
company = user_obj.browse(cursor, user, user, context=context).company
|
||||
|
||||
# fetch warehouses:
|
||||
warehouse_ids = location_obj.search(
|
||||
cursor, user, [('type','=','warehouse')], context=context)
|
||||
# fetch order points
|
||||
order_point_ids = order_point_obj.search(
|
||||
cursor, user, [], context=context)
|
||||
# index them by product
|
||||
product2ops = {}
|
||||
for order_point in order_point_obj.browse(
|
||||
cursor, user, order_point_ids, context=context):
|
||||
product2ops[
|
||||
(order_point.location.id, order_point.product.id)
|
||||
] = order_point
|
||||
|
||||
# fetch stockable products
|
||||
product_ids = product_obj.search(
|
||||
cursor, user, [('type', '=', 'stockable')], context=context)
|
||||
#aggregate product by minimum supply date
|
||||
date2products = {}
|
||||
for product in product_obj.browse(cursor, user, product_ids,
|
||||
context=context):
|
||||
min_date, max_date = self.get_supply_dates(
|
||||
cursor, user, product, context=context)
|
||||
date2products.setdefault(min_date, []).append((product, max_date))
|
||||
|
||||
# compute requests
|
||||
local_context = context and context.copy() or {}
|
||||
new_requests = []
|
||||
for min_date in date2products:
|
||||
product_ids = [ x[0].id for x in date2products[min_date] ]
|
||||
local_context.update(
|
||||
{'stock_date_end': min_date or datetime.date.max})
|
||||
pbl = product_obj.products_by_location(
|
||||
cursor, user, warehouse_ids, product_ids, with_childs=True,
|
||||
skip_zero=False, context=local_context)
|
||||
for product, max_date in date2products[min_date]:
|
||||
for warehouse_id in warehouse_ids:
|
||||
qty = pbl.pop((warehouse_id, product.id))
|
||||
order_point = product2ops.get((warehouse_id, product.id))
|
||||
# Search for shortage between min-max
|
||||
shortage_date, product_quantity = self.get_shortage(
|
||||
cursor, user, warehouse_id, product.id, min_date,
|
||||
max_date, min_date_qty=qty, order_point=order_point,
|
||||
context=context)
|
||||
|
||||
if shortage_date == None or product_quantity == None:
|
||||
continue
|
||||
# generate request values
|
||||
request_val = self.compute_request(
|
||||
cursor, user, product, warehouse_id, shortage_date,
|
||||
product_quantity, company, order_point, context=context)
|
||||
new_requests.append(request_val)
|
||||
|
||||
self.create_requests(cursor, user, new_requests, context=context)
|
||||
return {}
|
||||
|
||||
def create_requests(self, cursor, user, new_requests, context=None):
|
||||
"""
|
||||
Compare new_requests with already existing request and avoid
|
||||
to re-create existing requests.
|
||||
"""
|
||||
# delete purchase request without a purchase line
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
request_obj = self.pool.get('stock.purchase_request')
|
||||
product_supplier_obj = self.pool.get('purchase.product_supplier')
|
||||
req_ids = request_obj.search(
|
||||
cursor, user, [('purchase_line', '=', False)], context=context)
|
||||
request_obj.delete(cursor, user, req_ids, context=context)
|
||||
|
||||
req_ids = request_obj.search(cursor, user, [], context=context)
|
||||
requests = request_obj.browse(cursor, user, req_ids, context=context)
|
||||
# Fetch delivery_times for each (product,supplier)
|
||||
sup_delivery_time = {}
|
||||
for request in requests:
|
||||
product, supplier = None, None
|
||||
if request.purchase_line:
|
||||
product = request.purchase_line.product.id
|
||||
supplier = request.purchase_line.purchase.party.id
|
||||
else:
|
||||
product = request.product.id
|
||||
supplier = request.party and request.party.id
|
||||
if not supplier:
|
||||
continue
|
||||
sup_delivery_time[product, supplier] = None
|
||||
|
||||
prod_sup_ids = product_supplier_obj.search(
|
||||
cursor, user,
|
||||
['OR', ] + [
|
||||
['AND', ('product', '=', x[0]), ('party', '=', x[1])] \
|
||||
for x in sup_delivery_time.iterkeys()
|
||||
],
|
||||
context=context)
|
||||
for prod_sup in product_supplier_obj.browse(cursor, user, prod_sup_ids,
|
||||
context=context):
|
||||
sup_delivery_time[prod_sup.product.id, prod_sup.party.id] = \
|
||||
prod_sup.delivery_time
|
||||
|
||||
# Fetch data from existing requests
|
||||
existing_req = {}
|
||||
for request in requests:
|
||||
if request.purchase_line:
|
||||
product = request.purchase_line.product
|
||||
warehouse = request.purchase_line.purchase.warehouse
|
||||
purchase_date = request.purchase_line.purchase.purchase_date
|
||||
qty = line.quantity
|
||||
uom = line.unit
|
||||
supplier = line.purchase.party
|
||||
else:
|
||||
product = request.product
|
||||
warehouse = request.warehouse
|
||||
purchase_date = request.purchase_date
|
||||
qty = request.quantity
|
||||
uom = request.uom
|
||||
supplier = request.party
|
||||
|
||||
delivery_time = sup_delivery_time.get((product.id, supplier.id))
|
||||
if delivery_time:
|
||||
supply_date = purchase_date + \
|
||||
datetime.timedelta(delivery_time)
|
||||
else:
|
||||
supply_date = datetime.date.max
|
||||
|
||||
existing_req.setdefault((product.id, warehouse.id), []).append(
|
||||
{'supply_date': supply_date, 'quantity': qty, 'uom': uom})
|
||||
|
||||
for i in existing_req.itervalues():
|
||||
i.sort
|
||||
|
||||
# Update new requests to take existing requests into account
|
||||
new_requests.sort(lambda r,s: cmp(r['supply_date'],s['supply_date']))
|
||||
for new_req in new_requests:
|
||||
for old_req in existing_req.get((new_req['product'].id,
|
||||
new_req['warehouse']), []):
|
||||
if old_req['supply_date'] <= new_req['supply_date']:
|
||||
quantity = uom_obj.compute_qty(
|
||||
cursor, user, old_req['uom'], old_req['quantity'],
|
||||
new_req['uom'], context=context)
|
||||
new_req['quantity'] = max(0.0, new_req['quantity'] - quantity)
|
||||
old_req['quantity'] = uom_obj.compute_qty(
|
||||
cursor, user, new_req['uom'],
|
||||
max(0.0, quantity - new_req['quantity']),
|
||||
old_req['uom'], context=context)
|
||||
else:
|
||||
break
|
||||
|
||||
for new_req in new_requests:
|
||||
if new_req['supply_date'] == datetime.date.max:
|
||||
new_req['supply_date'] = None
|
||||
if new_req['quantity'] > 0.0:
|
||||
new_req.update({'product': new_req['product'].id,
|
||||
'party': new_req['party'] and new_req['party'].id,
|
||||
'uom': new_req['uom'].id,
|
||||
'company': new_req['company'].id
|
||||
})
|
||||
request_obj.create(cursor, user, new_req, context=context)
|
||||
|
||||
def get_supply_dates(self, cursor, user, product, context=None):
|
||||
"""
|
||||
Return for the given product min and max values for the
|
||||
earliest supply dates across all available suppliers.
|
||||
"""
|
||||
min_date = None
|
||||
max_date = None
|
||||
today = datetime.date.today()
|
||||
product_supplier_obj = self.pool.get('purchase.product_supplier')
|
||||
|
||||
for product_supplier in product.product_suppliers:
|
||||
supply_date = product_supplier_obj.compute_supply_date(
|
||||
cursor, user, product_supplier, date=today, context=context)
|
||||
if (not min_date) or supply_date < min_date:
|
||||
min_date = supply_date
|
||||
if (not max_date) or supply_date > max_date:
|
||||
max_date = supply_date
|
||||
|
||||
if not min_date:
|
||||
min_date = datetime.date.max
|
||||
max_date = datetime.date.max
|
||||
|
||||
return (min_date, max_date)
|
||||
|
||||
def compute_request(self, cursor, user, product, location_id, shortage_date,
|
||||
product_quantity, company, order_point=None,
|
||||
context=None):
|
||||
"""
|
||||
Return the value of the purchase request which will answer to
|
||||
the needed quantity at the given date. I.e: the latest
|
||||
purchase date, the expected supply date and the prefered
|
||||
supplier.
|
||||
"""
|
||||
supplier = None
|
||||
seq = None
|
||||
on_time = False
|
||||
today = datetime.date.today()
|
||||
max_quantity = order_point and order_point.max_quantity or 0.0
|
||||
for product_supplier in product.product_suppliers:
|
||||
supply_date = today + datetime.timedelta(product_supplier.delivery_time)
|
||||
sup_on_time = supply_date < shortage_date
|
||||
if not supplier:
|
||||
supplier = product_supplier.party
|
||||
on_time = sup_on_time
|
||||
seq = product_supplier.sequence
|
||||
continue
|
||||
|
||||
if (sup_on_time, product_supplier.sequence) < (on_time, seq):
|
||||
supplier = product_supplier.party
|
||||
on_time = sup_on_time
|
||||
seq = product_supplier.sequence
|
||||
|
||||
if supplier and product_supplier.delivery_time:
|
||||
purchase_date = \
|
||||
shortage_date - datetime.timedelta(product_supplier.delivery_time)
|
||||
else:
|
||||
purchase_date = today
|
||||
|
||||
return {'product': product,
|
||||
'party': supplier and supplier or None,
|
||||
'quantity': max_quantity - product_quantity,
|
||||
'uom': product.default_uom,
|
||||
'purchase_date': purchase_date,
|
||||
'supply_date': shortage_date,
|
||||
'stock_level': product_quantity,
|
||||
'company': company,
|
||||
'warehouse': location_id,
|
||||
}
|
||||
|
||||
def get_shortage(self, cursor, user, location_id, product_id, min_date,
|
||||
max_date, min_date_qty, order_point=None,context=None):
|
||||
"""
|
||||
Compute stock quantities between the two given dates. If given
|
||||
the order point, one date will be lacking in products this
|
||||
date is returned alongside the stock level at this date.
|
||||
|
||||
If no dates are given, the stock is computed for an infinire
|
||||
date and the shortage date is today.
|
||||
"""
|
||||
product_obj = self.pool.get('product.product')
|
||||
min_quantity = order_point and order_point.min_quantity or 0.0
|
||||
|
||||
if not min_date:
|
||||
if min_date_qty < min_quantity:
|
||||
return (
|
||||
datetime.date.today(), min_date_qty)
|
||||
else:
|
||||
return (None, None)
|
||||
if not max_date: max_date = min_date
|
||||
|
||||
current_date = min_date
|
||||
current_stock = min_date_qty
|
||||
while current_date <= max_date:
|
||||
if current_stock < min_quantity:
|
||||
return current_date, current_stock
|
||||
|
||||
local_context = context and context.copy() or {}
|
||||
local_context['stock_date_start'] = current_date
|
||||
local_context['stock_date_end'] = current_date
|
||||
res = product_obj.products_by_location(
|
||||
cursor, user, [location_id],
|
||||
[product_id], with_childs=True, skip_zero=False,
|
||||
context=context)
|
||||
for qty in res.itervalues():
|
||||
current_stock += qty
|
||||
if current_date == datetime.date.max:
|
||||
break
|
||||
current_date += datetime.timedelta(1)
|
||||
|
||||
return (None, None)
|
||||
|
||||
PurchaseRequest()
|
||||
|
||||
|
||||
|
||||
@@ -109,5 +109,25 @@
|
||||
<field name="operand">User/Current Company</field>
|
||||
<field name="rule_group" ref="rule_group_purchase_request"/>
|
||||
</record>
|
||||
|
||||
<record model="res.user" id="user_generate_request">
|
||||
<field name="login">user_cron_purchase_request</field>
|
||||
<field name="name">User Purchase Request</field>
|
||||
<field name="signature"></field>
|
||||
</record>
|
||||
|
||||
<record model="ir.cron" id="cron_generate_request">
|
||||
<field name="name">Generate Purchase Requests</field>
|
||||
<field name="user" ref="user_generate_request"/>
|
||||
<field name="active" eval="True"/>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
<field name="doall" eval="False"/>
|
||||
<field name="model">stock.purchase_request</field>
|
||||
<field name="function">generate_requests</field>
|
||||
<field name="priority">5</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</tryton>
|
||||
@@ -1,298 +0,0 @@
|
||||
from trytond.wizard import Wizard, WizardOSV
|
||||
import datetime
|
||||
# * Generate for X day in advance ?
|
||||
# * Provide a way to choose how mutch day before the shortage the suplly
|
||||
# must be planned
|
||||
|
||||
class GeneratePurchaseRequest(Wizard):
|
||||
'Generate Purchase Requests'
|
||||
_name = 'stock.generate_purchase_request'
|
||||
states = {
|
||||
'init': {
|
||||
'result': {
|
||||
'type': 'action',
|
||||
'action': 'generate_requests',
|
||||
'state': 'end',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def generate_requests(self, cursor, user, data, context=None):
|
||||
"""
|
||||
For each product compute the purchase request that must be
|
||||
create today to meet product outputs.
|
||||
"""
|
||||
order_point_obj = self.pool.get('stock.order_point')
|
||||
purchase_request_obj = self.pool.get('stock.purchase_request')
|
||||
product_obj = self.pool.get('product.product')
|
||||
location_obj = self.pool.get('stock.location')
|
||||
user_obj = self.pool.get('res.user')
|
||||
company = user_obj.browse(cursor, user, user, context=context).company
|
||||
# fetch warehouses:
|
||||
warehouse_ids = location_obj.search(
|
||||
cursor, user, [('type','=','warehouse')], context=context)
|
||||
|
||||
# fetch order points
|
||||
order_point_ids = order_point_obj.search(
|
||||
cursor, user, [], context=context)
|
||||
# index them by product
|
||||
product2ops = {}
|
||||
for order_point in order_point_obj.browse(cursor, user, order_point_ids,
|
||||
context=context):
|
||||
product2ops[
|
||||
(order_point.location.id, order_point.product.id)] = order_point
|
||||
|
||||
# fetch stockable products
|
||||
product_ids = product_obj.search(
|
||||
cursor, user, [('type', '=', 'stockable')], context=context)
|
||||
#aggregate product by minimum supply date
|
||||
date2products = {}
|
||||
for product in product_obj.browse(cursor, user, product_ids,
|
||||
context=context):
|
||||
min_date, max_date = self.get_supply_dates(
|
||||
cursor, user, product, context=context)
|
||||
date2products.setdefault(min_date, []).append((product, max_date))
|
||||
|
||||
# compute requests
|
||||
local_context = context.copy()
|
||||
new_requests = []
|
||||
for min_date in date2products:
|
||||
product_ids = [ x[0].id for x in date2products[min_date] ]
|
||||
local_context.update({'stock_date_end': min_date or datetime.date.max})
|
||||
pbl = product_obj.products_by_location(
|
||||
cursor, user, warehouse_ids, product_ids, with_childs=True,
|
||||
skip_zero=False, context=local_context)
|
||||
for product, max_date in date2products[min_date]:
|
||||
for warehouse_id in warehouse_ids:
|
||||
qty = pbl.pop((warehouse_id, product.id))
|
||||
order_point = product2ops.get((warehouse_id, product.id))
|
||||
# Search for shortage between min-max
|
||||
shortage_date, product_quantity = self.get_shortage(
|
||||
cursor, user, warehouse_id, product.id, min_date,
|
||||
max_date, min_date_qty=qty, order_point=order_point,
|
||||
context=context)
|
||||
|
||||
if shortage_date == None or product_quantity == None:
|
||||
continue
|
||||
# generate request values
|
||||
request_val = self.compute_request(
|
||||
cursor, user, product, warehouse_id, shortage_date,
|
||||
product_quantity, company, order_point, context=context)
|
||||
new_requests.append(request_val)
|
||||
|
||||
self.create_requests(cursor, user, new_requests, context=context)
|
||||
return {}
|
||||
|
||||
def create_requests(self, cursor, user, new_requests, context=None):
|
||||
"""
|
||||
Compare new_requests with already existing request and avoid
|
||||
to re-create existing requests.
|
||||
"""
|
||||
# delete purchase request without a purchase line
|
||||
uom_obj = self.pool.get('product.uom')
|
||||
request_obj = self.pool.get('stock.purchase_request')
|
||||
product_supplier_obj = self.pool.get('purchase.product_supplier')
|
||||
req_ids = request_obj.search(
|
||||
cursor, user, [('purchase_line', '=', False)], context=context)
|
||||
request_obj.delete(cursor, user, req_ids, context=context)
|
||||
|
||||
req_ids = request_obj.search(cursor, user, [], context=context)
|
||||
requests = request_obj.browse(cursor, user, req_ids, context=context)
|
||||
# Fetch delivery_times for each (product,supplier)
|
||||
sup_delivery_time = {}
|
||||
for request in requests:
|
||||
product, supplier = None, None
|
||||
if request.purchase_line:
|
||||
product = request.purchase_line.product.id
|
||||
supplier = request.purchase_line.purchase.party.id
|
||||
else:
|
||||
product = request.product.id
|
||||
supplier = request.party and request.party.id
|
||||
if not supplier:
|
||||
continue
|
||||
sup_delivery_time[product, supplier] = None
|
||||
|
||||
prod_sup_ids = product_supplier_obj.search(
|
||||
cursor, user,
|
||||
['OR', ] + [
|
||||
['AND', ('product', '=', x[0]), ('party', '=', x[1])] \
|
||||
for x in sup_delivery_time.iterkeys()
|
||||
],
|
||||
context=context)
|
||||
for prod_sup in product_supplier_obj.browse(cursor, user, prod_sup_ids,
|
||||
context=context):
|
||||
sup_delivery_time[prod_sup.product.id, prod_sup.party.id] = \
|
||||
prod_sup.delivery_time
|
||||
|
||||
# Fetch data from existing requests
|
||||
existing_req = {}
|
||||
for request in requests:
|
||||
if request.purchase_line:
|
||||
product = request.purchase_line.product
|
||||
warehouse = request.purchase_line.purchase.warehouse
|
||||
purchase_date = request.purchase_line.purchase.purchase_date
|
||||
qty = line.quantity
|
||||
uom = line.unit
|
||||
supplier = line.purchase.party
|
||||
else:
|
||||
product = request.product
|
||||
warehouse = request.warehouse
|
||||
purchase_date = request.purchase_date
|
||||
qty = request.quantity
|
||||
uom = request.uom
|
||||
supplier = request.party
|
||||
|
||||
delivery_time = sup_delivery_time.get((product.id, supplier.id))
|
||||
if delivery_time:
|
||||
supply_date = purchase_date + \
|
||||
datetime.timedelta(delivery_time)
|
||||
else:
|
||||
supply_date = datetime.date.max
|
||||
|
||||
existing_req.setdefault((product.id, warehouse.id), []).append(
|
||||
{'supply_date': supply_date, 'quantity': qty, 'uom': uom})
|
||||
|
||||
for i in existing_req.itervalues():
|
||||
i.sort
|
||||
|
||||
# Update new requests to take existing requests into account
|
||||
new_requests.sort(lambda r,s: cmp(r['supply_date'],s['supply_date']))
|
||||
for new_req in new_requests:
|
||||
for old_req in existing_req.get((new_req['product'].id,
|
||||
new_req['warehouse']), []):
|
||||
if old_req['supply_date'] <= new_req['supply_date']:
|
||||
quantity = uom_obj.compute_qty(
|
||||
cursor, user, old_req['uom'], old_req['quantity'],
|
||||
new_req['uom'], context=context)
|
||||
new_req['quantity'] = max(0.0, new_req['quantity'] - quantity)
|
||||
old_req['quantity'] = uom_obj.compute_qty(
|
||||
cursor, user, new_req['uom'],
|
||||
max(0.0, quantity - new_req['quantity']),
|
||||
old_req['uom'], context=context)
|
||||
else:
|
||||
break
|
||||
|
||||
for new_req in new_requests:
|
||||
if new_req['supply_date'] == datetime.date.max:
|
||||
new_req['supply_date'] = None
|
||||
if new_req['quantity'] > 0.0:
|
||||
new_req.update({'product': new_req['product'].id,
|
||||
'party': new_req['party'] and new_req['party'].id,
|
||||
'uom': new_req['uom'].id,
|
||||
'company': new_req['company'].id
|
||||
})
|
||||
request_obj.create(cursor, user, new_req, context=context)
|
||||
|
||||
def get_supply_dates(self, cursor, user, product, context=None):
|
||||
"""
|
||||
Return for the given product min and max values for the
|
||||
earliest supply dates across all available suppliers.
|
||||
"""
|
||||
min_date = None
|
||||
max_date = None
|
||||
today = datetime.date.today()
|
||||
product_supplier_obj = self.pool.get('purchase.product_supplier')
|
||||
|
||||
for product_supplier in product.product_suppliers:
|
||||
supply_date = product_supplier_obj.compute_supply_date(
|
||||
cursor, user, product_supplier, date=today, context=context)
|
||||
if (not min_date) or supply_date < min_date:
|
||||
min_date = supply_date
|
||||
if (not max_date) or supply_date > max_date:
|
||||
max_date = supply_date
|
||||
|
||||
if not min_date:
|
||||
min_date = datetime.date.max
|
||||
max_date = datetime.date.max
|
||||
|
||||
return (min_date, max_date)
|
||||
|
||||
def compute_request(self, cursor, user, product, location_id, shortage_date,
|
||||
product_quantity, company, order_point=None,
|
||||
context=None):
|
||||
"""
|
||||
Return the value of the purchase request which will answer to
|
||||
the needed quantity at the given date. I.e: the latest
|
||||
purchase date, the expected supply date and the prefered
|
||||
supplier.
|
||||
"""
|
||||
supplier = None
|
||||
seq = None
|
||||
on_time = False
|
||||
today = datetime.date.today()
|
||||
max_quantity = order_point and order_point.max_quantity or 0.0
|
||||
for product_supplier in product.product_suppliers:
|
||||
supply_date = today + datetime.timedelta(product_supplier.delivery_time)
|
||||
sup_on_time = supply_date < shortage_date
|
||||
if not supplier:
|
||||
supplier = product_supplier.party
|
||||
on_time = sup_on_time
|
||||
seq = product_supplier.sequence
|
||||
continue
|
||||
|
||||
if (sup_on_time, product_supplier.sequence) < (on_time, seq):
|
||||
supplier = product_supplier.party
|
||||
on_time = sup_on_time
|
||||
seq = product_supplier.sequence
|
||||
|
||||
if supplier and product_supplier.delivery_time:
|
||||
purchase_date = \
|
||||
shortage_date - datetime.timedelta(product_supplier.delivery_time)
|
||||
else:
|
||||
purchase_date = today
|
||||
|
||||
return {'product': product,
|
||||
'party': supplier and supplier or None,
|
||||
'quantity': max_quantity - product_quantity,
|
||||
'uom': product.default_uom,
|
||||
'purchase_date': purchase_date,
|
||||
'supply_date': shortage_date,
|
||||
'stock_level': product_quantity,
|
||||
'company': company,
|
||||
'warehouse': location_id,
|
||||
}
|
||||
|
||||
def get_shortage(self, cursor, user, location_id, product_id, min_date,
|
||||
max_date, min_date_qty, order_point=None,context=None):
|
||||
"""
|
||||
Compute stock quantities between the two given dates. If given
|
||||
the order point, one date will be lacking in products this
|
||||
date is returned alongside the stock level at this date.
|
||||
|
||||
If no dates are given, the stock is computed for an infinire
|
||||
date and the shortage date is today.
|
||||
"""
|
||||
product_obj = self.pool.get('product.product')
|
||||
min_quantity = order_point and order_point.min_quantity or 0.0
|
||||
|
||||
if not min_date:
|
||||
if min_date_qty < min_quantity:
|
||||
return (
|
||||
datetime.date.today(), min_date_qty)
|
||||
else:
|
||||
return (None, None)
|
||||
if not max_date: max_date = min_date
|
||||
|
||||
current_date = min_date
|
||||
current_stock = min_date_qty
|
||||
while current_date <= max_date:
|
||||
if current_stock < min_quantity:
|
||||
return current_date, current_stock
|
||||
|
||||
local_context = context.copy()
|
||||
local_context['stock_date_start'] = current_date
|
||||
local_context['stock_date_end'] = current_date
|
||||
res = product_obj.products_by_location(
|
||||
cursor, user, [location_id],
|
||||
[product_id], with_childs=True, skip_zero=False,
|
||||
context=context)
|
||||
for qty in res.itervalues():
|
||||
current_stock += qty
|
||||
if current_date == datetime.date.max:
|
||||
break
|
||||
current_date += datetime.timedelta(1)
|
||||
|
||||
return (None, None)
|
||||
|
||||
GeneratePurchaseRequest()
|
||||
@@ -1,12 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file is part of Tryton. The COPYRIGHT file at the top level of this repository contains the full copyright notices and license terms. -->
|
||||
<tryton>
|
||||
<data>
|
||||
<record model="ir.action.wizard" id="act_generate_purchase_request">
|
||||
<field name="name">Generate Purchase Requests</field>
|
||||
<field name="wiz_name">stock.generate_purchase_request</field>
|
||||
</record>
|
||||
<menuitem parent="purchase.menu_purchase" action="act_generate_purchase_request"
|
||||
id="menu_generate_purchase_request"/>
|
||||
</data>
|
||||
</tryton>
|
||||
Reference in new issue
Block a user