diff --git a/purchase_request.py b/purchase_request.py index 0ec1e5fa4a..a68503b470 100644 --- a/purchase_request.py +++ b/purchase_request.py @@ -84,21 +84,21 @@ class PurchaseRequest(metaclass=PoolMeta): ], order=[('id', 'ASC')]) product_ids = [p.id for p in products] # aggregate product by minimum supply date - date2products = {} + date2products = defaultdict(list) for product in products: min_date, max_date = cls.get_supply_dates( product, company=company.id) - date2products.setdefault((min_date, max_date), []).append(product) + date2products[min_date, max_date].append(product) # compute requests new_requests = [] - for dates, dates_products in date2products.items(): - min_date, max_date = dates + for (min_date, max_date), dates_products in date2products.items(): for sub_products in grouped_slice(dates_products): sub_products = list(sub_products) product_ids = [p.id for p in sub_products] - with Transaction().set_context(forecast=True, - stock_date_end=min_date or datetime.date.max): + with Transaction().set_context( + forecast=True, + stock_date_end=min_date): pbl = Product.products_by_location(warehouse_ids, with_childs=True, grouping_filter=(product_ids,)) for warehouse_id in warehouse_ids: @@ -111,8 +111,9 @@ class PurchaseRequest(metaclass=PoolMeta): p.id for p in sub_products if (warehouse_id, p.id) not in product2ops_other] # Search for shortage between min-max - shortages = cls.get_shortage(warehouse_id, product_ids, - min_date, max_date, min_date_qties=min_date_qties, + shortages = cls.get_shortage( + warehouse_id, product_ids, min_date, max_date, + min_date_qties=min_date_qties, order_points=product2ops) for product in sub_products: @@ -307,18 +308,30 @@ class PurchaseRequest(metaclass=PoolMeta): res_dates = {} res_qties = {} - min_quantities = {} + min_quantities = defaultdict(float) for product_id in product_ids: order_point = order_points.get((location_id, product_id)) if order_point: min_quantities[product_id] = order_point.min_quantity - else: - min_quantities[product_id] = 0.0 + + with Transaction().set_context( + forecast=True, + stock_date_start=min_date, + stock_date_end=max_date): + pbl = Product.products_by_location( + [location_id], with_childs=True, + grouping=('date', 'product'), + grouping_filter=(None, product_ids)) + pbl_dates = defaultdict(dict) + for key, qty in pbl.items(): + date, product_id = key[1:] + pbl_dates[date][product_id] = qty current_date = min_date current_qties = min_date_qties.copy() + products_to_check = product_ids.copy() while (current_date < max_date) or (current_date == min_date): - for product_id in product_ids: + for product_id in products_to_check: current_qty = current_qties[product_id] min_quantity = min_quantities[product_id] res_qty = res_qties.get(product_id) @@ -333,15 +346,10 @@ class PurchaseRequest(metaclass=PoolMeta): break current_date += datetime.timedelta(1) - # Update current quantities with next moves - with Transaction().set_context(forecast=True, - stock_date_start=current_date, - stock_date_end=current_date): - pbl = Product.products_by_location([location_id], - with_childs=True, grouping_filter=(product_ids,)) - for key, qty in pbl.items(): - _, product_id = key + pbl = pbl_dates[current_date] + products_to_check.clear() + for product_id, qty in pbl.items(): current_qties[product_id] += qty + products_to_check.append(product_id) - return dict((x, (res_dates.get(x), res_qties.get(x))) - for x in product_ids) + return {x: (res_dates.get(x), res_qties.get(x)) for x in product_ids} diff --git a/tests/scenario_stock_supply_purchase_request.rst b/tests/scenario_stock_supply_purchase_request.rst index 04f0fb0e46..0244427d38 100644 --- a/tests/scenario_stock_supply_purchase_request.rst +++ b/tests/scenario_stock_supply_purchase_request.rst @@ -38,6 +38,13 @@ Create parties:: >>> supplier = Party(name='Supplier') >>> supplier.save() +Configure supply period:: + + >>> PurchaseConfig = Model.get('purchase.configuration') + >>> purchase_config = PurchaseConfig(1) + >>> purchase_config.supply_period = datetime.timedelta(days=30) + >>> purchase_config.save() + Create stock admin user:: >>> User = Model.get('res.user') @@ -107,6 +114,15 @@ Create product:: >>> template.save() >>> product, = template.products +Define a product supplier:: + + >>> set_user(purchase_user) + >>> ProductSupplier = Model.get('purchase.product_supplier') + >>> product_supplier = ProductSupplier(template=template) + >>> product_supplier.party = supplier + >>> product_supplier.lead_time = datetime.timedelta(days=1) + >>> product_supplier.save() + Get stock locations:: >>> set_user(stock_admin_user) @@ -117,7 +133,7 @@ Get stock locations:: >>> output_loc, = Location.find([('code', '=', 'OUT')]) >>> storage_loc, = Location.find([('code', '=', 'STO')]) -Create a need for missing product:: +Create needs for missing product:: >>> set_user(stock_user) >>> ShipmentOut = Model.get('stock.shipment.out') @@ -138,6 +154,10 @@ Create a need for missing product:: >>> move.currency = company.currency >>> shipment_out.click('wait') + >>> shipment_out, = shipment_out.duplicate( + ... default={'planned_date': today + datetime.timedelta(days=10)}) + >>> shipment_out.click('wait') + There is no purchase request:: >>> PurchaseRequest = Model.get('purchase.request') @@ -158,7 +178,7 @@ There is now a draft purchase request:: >>> pr.product == product True >>> pr.quantity - 1.0 + 2.0 Create an order point with negative minimal quantity:: @@ -168,22 +188,22 @@ Create an order point with negative minimal quantity:: >>> order_point.type = 'purchase' >>> order_point.product = product >>> order_point.warehouse_location = warehouse_loc - >>> order_point.min_quantity = -1 + >>> order_point.min_quantity = -2 >>> order_point.target_quantity = 10 >>> order_point.save() -Create production request:: +Create purchase request:: >>> create_pr = Wizard('stock.supply') >>> create_pr.execute('create_') -There is no more production request:: +There is no more purchase request:: >>> set_user(purchase_user) >>> PurchaseRequest.find([]) [] -Set a postive minimal quantity on order point create purchase request:: +Set a positive minimal quantity on order point create purchase request:: >>> set_user(stock_admin_user) >>> order_point.min_quantity = 5 @@ -198,7 +218,7 @@ There is now a draft purchase request:: >>> pr.product == product True >>> pr.quantity - 11.0 + 12.0 Using zero as minimal quantity on order point also creates purchase request:: @@ -215,13 +235,11 @@ There is now a draft purchase request:: >>> pr.product == product True >>> pr.quantity - 11.0 + 12.0 Re-run with purchased request:: >>> create_purchase = Wizard('purchase.request.create_purchase', [pr]) - >>> create_purchase.form.party = supplier - >>> create_purchase.execute('start') >>> pr.state 'purchased'