diff -r 9a0b5b830df9 trytond/trytond/modules/stock_supply/__init__.py --- a/trytond/trytond/modules/stock_supply/__init__.py Wed Jun 22 16:17:37 2016 +0200 +++ b/trytond/trytond/modules/stock_supply/__init__.py Wed Jun 22 17:05:42 2016 +0200 @@ -21,6 +21,7 @@ ShipmentInternal, CreateShipmentInternalStart, Location, + LocationLeadTime, module='stock_supply', type_='model') Pool.register( CreatePurchaseRequest, diff -r 9a0b5b830df9 trytond/trytond/modules/stock_supply/location.py --- a/trytond/trytond/modules/stock_supply/location.py Wed Jun 22 16:17:37 2016 +0200 +++ b/trytond/trytond/modules/stock_supply/location.py Wed Jun 22 17:05:42 2016 +0200 @@ -1,11 +1,13 @@ # This file is part of Tryton. The COPYRIGHT file at the top level of # this repository contains the full copyright notices and license terms. +import datetime + from trytond.pool import PoolMeta from trytond.model import fields from trytond.pyson import Eval -__all__ = ['Location'] +__all__ = ['Location', 'LocationLeadTime'] class Location: @@ -23,3 +25,17 @@ ], depends=['type', 'active'], help='Leave empty for no default provisioning') + + +class LocationLeadTime: + __metaclass__ = PoolMeta + __name__ = 'stock.location.lead_time' + + @classmethod + def get_max_lead_time(cls): + 'Return the biggest lead time' + lead_times = cls.search([]) + if lead_times: + return datetime.timedelta(max(r.lead_time for r in lead_times)) + else: + return datetime.timedelta(0) diff -r 9a0b5b830df9 trytond/trytond/modules/stock_supply/shipment.py --- a/trytond/trytond/modules/stock_supply/shipment.py Wed Jun 22 16:17:37 2016 +0200 +++ b/trytond/trytond/modules/stock_supply/shipment.py Wed Jun 22 17:05:42 2016 +0200 @@ -1,5 +1,7 @@ #This file is part of Tryton. The COPYRIGHT file at the top level of #this repository contains the full copyright notices and license terms. +import datetime + from sql import Table from sql.functions import Overlay, Position @@ -51,8 +53,11 @@ Date = pool.get('ir.date') User = pool.get('res.user') Move = pool.get('stock.move') + LeadTime = pool.get('stock.location.lead_time') + user_record = User(Transaction().user) today = Date.today() + lead_time = LeadTime.get_max_lead_time() # fetch quantities on order points order_points = OrderPoint.search([ ('type', '=', 'internal'), @@ -80,62 +85,73 @@ else: product_ids = id2product.keys() product_ids.sort() - # TODO Allow to compute for other future date - with Transaction().set_context(forecast=True, stock_date_end=today): - pbl = Product.products_by_location(id2location.keys(), - product_ids, with_childs=True) - # Create a list of move to create - moves = {} - for location in id2location.itervalues(): - for product_id in product_ids: - qty = pbl.get((location.id, product_id), 0) - op = product2op.get((location.id, product_id)) - if op: - min_qty, max_qty = op.min_quantity, op.max_quantity - provisioning_location = op.provisioning_location - elif location and location.provisioning_location: - min_qty, max_qty = 0, 0 - provisioning_location = location.provisioning_location - else: - continue - if qty < min_qty: - key = (provisioning_location.id, location.id, product_id) - moves[key] = max_qty - qty + internal_shipments = [] + date = today + end_date = date + lead_time + while date <= end_date: + shipments = [] + with Transaction().set_context(forecast=True, stock_date_end=date): + pbl = Product.products_by_location(id2location.keys(), + product_ids, with_childs=True) - # Group moves by {from,to}_location - to_create = {} - for key, qty in moves.iteritems(): - from_location, to_location, product = key - to_create.setdefault( - (from_location, to_location), []).append((product, qty)) - # Create shipments and moves - shipments = [] - for locations, moves in to_create.iteritems(): - from_location, to_location = locations - shipment = cls( - from_location=from_location, - to_location=to_location, - planned_date=today, - moves=[], - ) - for move in moves: - product_id, qty = move - product = id2product.setdefault( - product_id, Product(product_id)) - shipment.moves.append(Move( - from_location=from_location, - to_location=to_location, - planned_date=today, - product=product, - quantity=qty, - uom=product.default_uom, - company=user_record.company, - )) - shipment.save() - shipments.append(shipment) - cls.wait(shipments) - return shipments + # Create a list of moves to create + moves = {} + for location in id2location.itervalues(): + for product_id in product_ids: + qty = pbl.get((location.id, product_id), 0) + op = product2op.get((location.id, product_id)) + if op: + min_qty, max_qty = op.min_quantity, op.max_quantity + provisioning_location = op.provisioning_location + elif location and location.provisioning_location: + min_qty, max_qty = 0, 0 + provisioning_location = location.provisioning_location + else: + continue + if qty < min_qty: + key = ( + provisioning_location.id, location.id, product_id) + moves[key] = max_qty - qty + + # Group moves by {from,to}_location + to_create = {} + for key, qty in moves.iteritems(): + from_location, to_location, product = key + to_create.setdefault( + (from_location, to_location), []).append((product, qty)) + # Create shipments and moves + for locations, moves in to_create.iteritems(): + from_location, to_location = locations + shipment = cls( + from_location=from_location, + to_location=to_location, + planned_date=date, + ) + shipment_moves = [] + for move in moves: + product_id, qty = move + product = id2product.setdefault( + product_id, Product(product_id)) + shipment_moves.append(Move( + from_location=from_location, + to_location=to_location, + planned_date=date, + product=product, + quantity=qty, + uom=product.default_uom, + company=user_record.company, + )) + shipment.moves = shipment_moves + shipment.planned_start_date = ( + shipment.on_change_with_planned_start_date()) + shipments.append(shipment) + date += datetime.timedelta(1) + if shipments: + shipments = cls.create([s._save_values for s in shipments]) + cls.wait(shipments) + internal_shipments += shipments + return internal_shipments class CreateShipmentInternalStart(ModelView):