[ADD] First implementation of reserving quants while assigning and creating/moving when done
bzr revid: jco@openerp.com-20130619145406-jtllflivgeyi3aqh
This commit is contained in:
parent
80f71be202
commit
67d66e0d5f
|
@ -367,6 +367,12 @@ class stock_location(osv.osv):
|
|||
states = ['done']
|
||||
return self._product_all_get(cr, uid, id, product_ids, context, ['confirmed', 'waiting', 'assigned', 'done'])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def _product_reserve(self, cr, uid, ids, product_id, product_qty, context=None, lock=False):
|
||||
"""
|
||||
Attempt to find a quantity ``product_qty`` (in the product's default uom or the uom passed in ``context``) of product ``product_id``
|
||||
|
@ -478,6 +484,7 @@ class stock_quant(osv.osv):
|
|||
_name = "stock.quant"
|
||||
_description = "Quants"
|
||||
_columns = {
|
||||
'product_id': fields.many2one("product.product", "Product", required=True),
|
||||
'location_id': fields.many2one("stock.location", "Location", required=True),
|
||||
'qty': fields.float("Quantity", required=True), #should be in units of the product UoM
|
||||
'pack_id': fields.many2one("stock.quant.package"),
|
||||
|
@ -486,38 +493,69 @@ class stock_quant(osv.osv):
|
|||
'history_ids': fields.many2many("stock.move", "quant", "move", string="Moves History"),
|
||||
'price_unit': fields.float("Cost price"),
|
||||
'create_date': fields.date("Created date or date the quant entered the system"),
|
||||
#Maybe add date of last move
|
||||
#Might add date of last change of location also
|
||||
}
|
||||
|
||||
def split_and_assign_quants(self, cr, uid, ids, move, qty, context=None):
|
||||
def split_and_assign_quant(self, cr, uid, ids, move, qty, context=None):
|
||||
"""
|
||||
This method will split off the quants with the specified quantity
|
||||
and assign the move to this quant by using reserved_id
|
||||
|
||||
Should be triggered when assigning the move
|
||||
Should be executed on one id
|
||||
Should be executed on move only
|
||||
"""
|
||||
assert len(ids) == 1, _("Only split one quant at a time")
|
||||
#quant =
|
||||
#if (move.):
|
||||
|
||||
|
||||
|
||||
def split_and_assign_quants(self, cr, uid, quant_tuples, move, context=None):
|
||||
"""
|
||||
This method will split off the quants with the specified quantity
|
||||
and assign the move to this quant by using reserved_id
|
||||
|
||||
Should be triggered when assigning the move
|
||||
Should be executed on move only
|
||||
:param quant_tuples: are the tuples from choose_quants (quant_id, qty)
|
||||
"""
|
||||
quants_to_reserve = []
|
||||
for quant_tuple in quant_tuples:
|
||||
|
||||
quant = self.browse(cr, uid, quant_tuple[0], context=context)
|
||||
if quant_tuple[1] == quant.qty:
|
||||
quants_to_reserve.append(quant.id)
|
||||
else:
|
||||
#Split demanded qty frrm quant and add new quant to reserved
|
||||
new_quant = self.copy(cr, uid, quant.id, default={'qty': quant_tuple[1]}, context=context)
|
||||
new_qty = quant.qty - quant_tuple[1]
|
||||
self.write(cr, uid, quant.id, {'qty': new_qty}, context=context)
|
||||
quants_to_reserve.append(new_quant)
|
||||
self.write(cr, uid, quants_to_reserve, {'reservation_id': move.id}, context=context)
|
||||
self.pool.get("stock.move").write(cr, uid, [move.id], {'reserved_quant_ids': [(4, x) for x in quants_to_reserve]}, context=context)
|
||||
|
||||
|
||||
def move_quants(self, cr, uid, ids, move, context=None):
|
||||
"""
|
||||
Change location of quants
|
||||
When a move is done, the quants will already have been split because of the previous method
|
||||
=> you only need to change the location of the quant
|
||||
-> At the same time the reservations will be removed
|
||||
:param move: browse_record
|
||||
"""
|
||||
self.write(cr, uid, ids, {'location_id': move.location_dest_id.id}, context=context)
|
||||
self.write(cr, uid, ids, {'location_id': move.location_dest_id.id,
|
||||
'reservation_id': False}, context=context)
|
||||
self.pool.get("stock.move").write(cr, uid, [move.id], {"reserved_quant_ids": [(5, 0)]}, context=context)
|
||||
|
||||
|
||||
def choose_quants(self, cr, uid, ids, location_id, product_id, qty, context=None):
|
||||
def choose_quants(self, cr, uid, location_id, product_id, qty, context=None):
|
||||
"""
|
||||
Use the removal strategies of product to search for the correct quants
|
||||
|
||||
:param location_id: child_of this location_id
|
||||
:param product_id: id of product
|
||||
:param qty in UoM of product
|
||||
:returns: tuples of (quants, qty)
|
||||
:returns: tuples of (quant_id, qty)
|
||||
"""
|
||||
#TODO Normally, you should check the removal strategy now
|
||||
#But we will assume it is FIFO for the moment
|
||||
|
@ -543,7 +581,7 @@ class stock_quant_package(osv.osv):
|
|||
"""
|
||||
_name = "stock.quant.package"
|
||||
_columns = {
|
||||
'quant_ids':fields.one2many("stock.quant", "Quants"),
|
||||
'quant_ids':fields.one2many("stock.quant", "pack_id", "Quants"),
|
||||
'name': fields.char('Pack Reference', required = True),
|
||||
}
|
||||
|
||||
|
@ -2205,6 +2243,8 @@ class stock_move(osv.osv):
|
|||
done = []
|
||||
count = 0
|
||||
pickings = {}
|
||||
quant_obj = self.pool.get("stock.quant")
|
||||
uom_obj = self.pool.get("product.uom")
|
||||
if context is None:
|
||||
context = {}
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
|
@ -2215,7 +2255,27 @@ class stock_move(osv.osv):
|
|||
continue
|
||||
if move.state in ('confirmed', 'waiting'):
|
||||
# Important: we must pass lock=True to _product_reserve() to avoid race conditions and double reservations
|
||||
res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True)
|
||||
#res = self.pool.get('stock.location')._product_reserve(cr, uid, [move.location_id.id], move.product_id.id, move.product_qty, {'uom': move.product_uom.id}, lock=True)
|
||||
|
||||
#Convert UoM qty -> check rounding now in product_reserver
|
||||
qty = uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id)
|
||||
res2 = quant_obj.choose_quants(cr, uid, move.location_id.id, move.product_id.id, qty, context=context)
|
||||
|
||||
#Should group quants by location:
|
||||
quants = {}
|
||||
qtys = {}
|
||||
qty = {}
|
||||
for tuple in res2:
|
||||
quant = quant_obj.browse(cr, uid, tuple[0], context=context) #should be out of the loop
|
||||
if quant.location_id.id not in quants:
|
||||
quants[quant.location_id.id] = []
|
||||
qtys[quant.location_id.id] = []
|
||||
qty[quant.location_id.id] = 0
|
||||
quants[quant.location_id.id] += [quant.id]
|
||||
qtys[quant.location_id.id] += [tuple[1]]
|
||||
qty[quant.location_id.id] += tuple[1]
|
||||
|
||||
res = [(qty[key], key) for key in quants.keys()]
|
||||
if res:
|
||||
#_product_available_test depends on the next status for correct functioning
|
||||
#the test does not work correctly if the same product occurs multiple times
|
||||
|
@ -2227,11 +2287,13 @@ class stock_move(osv.osv):
|
|||
r = res.pop(0)
|
||||
product_uos_qty = self.pool.get('stock.move').onchange_quantity(cr, uid, ids, move.product_id.id, r[0], move.product_id.uom_id.id, move.product_id.uos_id.id)['value']['product_uos_qty']
|
||||
cr.execute('update stock_move set location_id=%s, product_qty=%s, product_uos_qty=%s where id=%s', (r[1], r[0],product_uos_qty, move.id))
|
||||
|
||||
#assign and split quants
|
||||
quant_obj.split_and_assign_quants(cr, uid, zip(quants[r[1]], qtys[r[1]]), move, context=context)
|
||||
while res:
|
||||
r = res.pop(0)
|
||||
move_id = self.copy(cr, uid, move.id, {'product_uos_qty': product_uos_qty, 'product_qty': r[0], 'location_id': r[1]})
|
||||
done.append(move_id)
|
||||
quant_obj.split_and_assign_quants(cr, uid, zip(quants[r[1]], qtys[r[1]]), self.browse(cr, uid, move_id, context=context), context=context)
|
||||
if done:
|
||||
count += len(done)
|
||||
self.write(cr, uid, done, {'state': 'assigned'})
|
||||
|
@ -2441,14 +2503,14 @@ class stock_move(osv.osv):
|
|||
'line_id': move_lines,
|
||||
'ref': move.picking_id and move.picking_id.name})
|
||||
|
||||
def split_quants_for_pack(self, cr, uid, ids, context=None):
|
||||
def _get_quants_from_pack(self, cr, uid, ids, context=None):
|
||||
"""
|
||||
Suppose for the moment we don't have any packaging
|
||||
"""
|
||||
res = {}
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
#Split according to pack wizard if necessary
|
||||
res[move.id] = move.reserved_quant_ids
|
||||
res[move.id] = [x.id for x in move.reserved_quant_ids]
|
||||
return res
|
||||
|
||||
|
||||
|
@ -2470,13 +2532,25 @@ class stock_move(osv.osv):
|
|||
self.action_confirm(cr, uid, todo, context=context)
|
||||
todo = []
|
||||
|
||||
uom_obj = self.pool.get("product.uom")
|
||||
#Do price calc on move
|
||||
quants = {}
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
quants = self.split_quants_for_pack(cr, uid, [move.id], context=context)
|
||||
|
||||
self.pool.get("stock.quant").move_quants(cr, uid, quants[move.id], context=context)
|
||||
#Do price calculation on move -> SHould PASS Quants here
|
||||
matchresults = self.price_calculation(cr, uid, ids, context=context)
|
||||
quants.update(self._get_quants_from_pack(cr, uid, [move.id], context=context))
|
||||
if (move.location_id.usage in ['supplier']):
|
||||
#Create quants
|
||||
vals = {'product_id': move.product_id.id,
|
||||
'location_id': move.location_dest_id.id,
|
||||
'qty': uom_obj._compute_qty(cr, uid, move.product_uom.id, move.product_qty, move.product_id.uom_id.id),
|
||||
'create_date': fields.date.context_today(self, cr, uid, context=context),
|
||||
'price_unit': move.price_unit,
|
||||
}
|
||||
quant_id = self.pool.get("stock.quant").create(cr, uid, vals, context=context)
|
||||
quants[move.id].append(quant_id)
|
||||
else:
|
||||
self.pool.get("stock.quant").move_quants(cr, uid, quants[move.id], move, context=context)
|
||||
#Do price calculation on move -> Should pass Quants here -> is a dictionary
|
||||
matchresults = self.price_calculation(cr, uid, ids, quants, context=context)
|
||||
|
||||
for move in self.browse(cr, uid, ids, context=context):
|
||||
if move.state in ['done','cancel']:
|
||||
|
@ -2799,7 +2873,7 @@ class stock_move(osv.osv):
|
|||
product_obj.write(cr, uid, [product.id], {'standard_price': total_price / amount}, context=context)
|
||||
return res
|
||||
|
||||
def price_calculation(self, cr, uid, ids, context=None):
|
||||
def price_calculation(self, cr, uid, ids, quants, context=None):
|
||||
'''
|
||||
This method puts the right price on the stock move,
|
||||
adapts the price on the product when necessary
|
||||
|
|
Loading…
Reference in New Issue