[MERGE] merged the branch of jco with simplification of negative quants treatment, using a list of fallback domains and recomputing the state of move if we took some quants that were preeviously reserved for something else
bzr revid: qdp-launchpad@openerp.com-20140422145954-89jfnqw34u703h98
This commit is contained in:
+1
-1
@@ -800,7 +800,7 @@ class mrp_production(osv.osv):
|
||||
|
||||
q = min(move.product_qty, qty)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, scheduled.product_id, q, domain=[('qty', '>', 0.0)],
|
||||
prefered_domain=[('reservation_id', '=', move.id)], fallback_domain=[('reservation_id', '=', False)], context=context)
|
||||
prefered_domain_list=[[('reservation_id', '=', move.id)], [('reservation_id', '=', False)]], context=context)
|
||||
for quant, quant_qty in quants:
|
||||
if quant:
|
||||
lot_id = quant.lot_id.id
|
||||
|
||||
+53
-51
@@ -368,7 +368,9 @@ class stock_quant(osv.osv):
|
||||
to_move_quants.append(quant)
|
||||
quants_reconcile.append(quant)
|
||||
if to_move_quants:
|
||||
to_recompute_move_ids = [x.reservation_id.id for x in to_move_quants if x.reservation_id and x.reservation_id.id != move.id]
|
||||
self.move_quants_write(cr, uid, to_move_quants, move, location_to, dest_package_id, context=context)
|
||||
self.pool.get('stock.move').recalculate_move_state(cr, uid, to_recompute_move_ids, context=context)
|
||||
if location_to.usage == 'internal':
|
||||
if self.search(cr, uid, [('product_id', '=', move.product_id.id), ('qty','<', 0)], limit=1, context=context):
|
||||
for quant in quants_reconcile:
|
||||
@@ -381,34 +383,31 @@ class stock_quant(osv.osv):
|
||||
'package_id': dest_package_id}
|
||||
self.write(cr, SUPERUSER_ID, [q.id for q in quants], vals, context=context)
|
||||
|
||||
def quants_get_prefered_domain(self, cr, uid, location, product, qty, domain=None, prefered_domain=False, fallback_domain=False, restrict_lot_id=False, restrict_partner_id=False, context=None):
|
||||
def quants_get_prefered_domain(self, cr, uid, location, product, qty, domain=None, prefered_domain_list=[], restrict_lot_id=False, restrict_partner_id=False, context=None):
|
||||
''' This function tries to find quants in the given location for the given domain, by trying to first limit
|
||||
the choice on the quants that match the prefered_domain as well. But if the qty requested is not reached
|
||||
it tries to find the remaining quantity by using the fallback_domain.
|
||||
the choice on the quants that match the first item of prefered_domain_list as well. But if the qty requested is not reached
|
||||
it tries to find the remaining quantity by looping on the prefered_domain_list (tries with the second item and so on).
|
||||
Make sure the quants aren't found twice => all the domains of prefered_domain_list should be orthogonal
|
||||
'''
|
||||
if domain is None:
|
||||
domain = []
|
||||
quants = [(None, qty)]
|
||||
#don't look for quants in location that are of type production, supplier or inventory.
|
||||
if location.usage in ['inventory', 'production', 'supplier']:
|
||||
return [(None, qty)]
|
||||
if prefered_domain and fallback_domain:
|
||||
if domain is None:
|
||||
domain = []
|
||||
quants = self.quants_get(cr, uid, location, product, qty, domain=domain + prefered_domain, restrict_lot_id=restrict_lot_id, restrict_partner_id=restrict_partner_id, context=context)
|
||||
res_qty = qty
|
||||
quant_ids = []
|
||||
for quant in quants:
|
||||
if quant[0]:
|
||||
quant_ids.append(quant[0].id)
|
||||
res_qty -= quant[1]
|
||||
return quants
|
||||
res_qty = qty
|
||||
if not prefered_domain_list:
|
||||
return self.quants_get(cr, uid, location, product, qty, domain=domain, restrict_lot_id=restrict_lot_id, restrict_partner_id=restrict_partner_id, context=context)
|
||||
for prefered_domain in prefered_domain_list:
|
||||
if res_qty > 0:
|
||||
#try to replace the last tuple (None, res_qty) with something that wasn't chosen at first because of the prefered order
|
||||
quants.pop()
|
||||
#make sure the quants aren't found twice (if the prefered_domain and the fallback_domain aren't orthogonal
|
||||
domain += [('id', 'not in', quant_ids)]
|
||||
unprefered_quants = self.quants_get(cr, uid, location, product, res_qty, domain=domain + fallback_domain, restrict_lot_id=restrict_lot_id, restrict_partner_id=restrict_partner_id, context=context)
|
||||
for quant in unprefered_quants:
|
||||
quants.append(quant)
|
||||
return quants
|
||||
return self.quants_get(cr, uid, location, product, qty, domain=domain, restrict_lot_id=restrict_lot_id, restrict_partner_id=restrict_partner_id, context=context)
|
||||
tmp_quants = self.quants_get(cr, uid, location, product, res_qty, domain=domain + prefered_domain, restrict_lot_id=restrict_lot_id, restrict_partner_id=restrict_partner_id, context=context)
|
||||
for quant in tmp_quants:
|
||||
if quant[0]:
|
||||
res_qty -= quant[1]
|
||||
quants += unprefered_quants
|
||||
return quants
|
||||
|
||||
def quants_get(self, cr, uid, location, product, qty, domain=None, restrict_lot_id=False, restrict_partner_id=False, context=None):
|
||||
"""
|
||||
@@ -510,8 +509,6 @@ class stock_quant(osv.osv):
|
||||
dom += [('lot_id', '=', quant.lot_id.id)]
|
||||
dom += [('owner_id', '=', quant.owner_id.id)]
|
||||
dom += [('package_id', '=', quant.package_id.id)]
|
||||
if move.move_dest_id:
|
||||
dom += [('negative_move_id', '=', move.move_dest_id.id)]
|
||||
quants = self.quants_get(cr, uid, quant.location_id, quant.product_id, quant.qty, dom, context=context)
|
||||
for quant_neg, qty in quants:
|
||||
if not quant_neg:
|
||||
@@ -1725,7 +1722,10 @@ class stock_move(osv.osv):
|
||||
if move.state in ('done', 'cancel'):
|
||||
raise osv.except_osv(_('Operation Forbidden!'), _('Cannot unreserve a done move'))
|
||||
quant_obj.quants_unreserve(cr, uid, move, context=context)
|
||||
self.write(cr, uid, [move.id], {'state': 'confirmed'}, context=context)
|
||||
if self.find_move_ancestors(cr, uid, move, context=context):
|
||||
self.write(cr, uid, [move.id], {'state': 'waiting'}, context=context)
|
||||
else:
|
||||
self.write(cr, uid, [move.id], {'state': 'confirmed'}, context=context)
|
||||
|
||||
def _prepare_procurement_from_move(self, cr, uid, move, context=None):
|
||||
origin = (move.group_id and (move.group_id.name + ":") or "") + (move.rule_id and move.rule_id.name or "/")
|
||||
@@ -2026,8 +2026,7 @@ class stock_move(osv.osv):
|
||||
""" Changes the state to assigned.
|
||||
@return: True
|
||||
"""
|
||||
#when a MTO move availability is forced, it shouldn't be treated anymore as a MTO so we break the link with ancestors (to avoid further problems in re-reservation)
|
||||
return self.write(cr, uid, ids, {'state': 'assigned', 'procure_method': 'make_to_stock', 'move_orig_ids': [(6, 0, [])]}, context=context)
|
||||
return self.write(cr, uid, ids, {'state': 'assigned'}, context=context)
|
||||
|
||||
def check_tracking(self, cr, uid, move, lot_id, context=None):
|
||||
""" Checks if serial number is assigned to stock move or not and raise an error if it had to.
|
||||
@@ -2092,7 +2091,7 @@ class stock_move(osv.osv):
|
||||
domain = main_domain[move.id] + self.pool.get('stock.move.operation.link').get_specific_domain(cr, uid, record, context=context)
|
||||
qty = record.qty
|
||||
if qty:
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, qty, domain=domain, prefered_domain=[], fallback_domain=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, qty, domain=domain, prefered_domain_list=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quant_obj.quants_reserve(cr, uid, quants, move, record, context=context)
|
||||
for move in todo_moves:
|
||||
move.refresh()
|
||||
@@ -2100,7 +2099,7 @@ class stock_move(osv.osv):
|
||||
if move.state != 'assigned':
|
||||
qty_already_assigned = move.reserved_availability
|
||||
qty = move.product_qty - qty_already_assigned
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain[move.id], prefered_domain=[], fallback_domain=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain[move.id], prefered_domain_list=[], restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quant_obj.quants_reserve(cr, uid, quants, move, context=context)
|
||||
|
||||
#force assignation of consumable products and incoming from supplier/inventory/production
|
||||
@@ -2148,18 +2147,22 @@ class stock_move(osv.osv):
|
||||
move2 = not move2.move_orig_ids and move2.split_from or False
|
||||
return ancestors
|
||||
|
||||
def check_quants_history(self, cr, uid, move, quants, context=None):
|
||||
#raise an error in the case the move is chained MTO and the selected quants were not properly chained (manual change in pack operations) because:
|
||||
#1) users must be wanred they break the MTO flow
|
||||
#2) if left as it, it will create negative quants complex to reconcile as we allow to take quants only from ancestors,
|
||||
# and we allow reconciliation only of negative quants created by next move when receiving a chained quant.
|
||||
ancestors = self.find_move_ancestors(cr, uid, move, context=context)
|
||||
if move.state == 'waiting' and not ancestors:
|
||||
raise osv.except_osv(_('Error'), _('You cannot the requested operation. As the move is chained you are supposed to take the same products as in the previous step. Please use the values proposed or force the availability of the move to break the link and process it as you like.'))
|
||||
if ancestors:
|
||||
for q, dummy in quants:
|
||||
if not q or not (set(ancestors) & set([m.id for m in q.history_ids])):
|
||||
raise osv.except_osv(_('Error'), _('You cannot the requested operation. As the move is chained you are supposed to take the same products as in the previous step. Please use the values proposed or force the availability of the move to break the link and process it as you like.'))
|
||||
def recalculate_move_state(self, cr, uid, move_ids, context=None):
|
||||
'''Recompute the state of moves given because their reserved quants were used to fulfill another operation'''
|
||||
for move in self.browse(cr, uid, move_ids, context=context):
|
||||
vals = {}
|
||||
reserved_quant_ids = move.reserved_quant_ids
|
||||
if len(reserved_quant_ids) > 0 and not move.partially_available:
|
||||
vals['partially_available'] = True
|
||||
if len(reserved_quant_ids) == 0 and move.partially_available:
|
||||
vals['partially_available'] = False
|
||||
if move.state == 'assigned':
|
||||
if self.find_move_ancestors(cr, uid, move, context=context):
|
||||
vals['state'] = 'waiting'
|
||||
else:
|
||||
vals['state'] = 'confirmed'
|
||||
if vals:
|
||||
self.write(cr, uid, [move.id], vals, context=context)
|
||||
|
||||
def action_done(self, cr, uid, ids, context=None):
|
||||
""" Process completly the moves given as ids and if all moves are done, it will finish the picking.
|
||||
@@ -2193,9 +2196,11 @@ class stock_move(osv.osv):
|
||||
self.check_tracking(cr, uid, move, ops.package_id.id or ops.lot_id.id, context=context)
|
||||
prefered_domain = [('reservation_id', '=', move.id)]
|
||||
fallback_domain = [('reservation_id', '=', False)]
|
||||
fallback_domain2 = ['&', ('reservation_id', '!=', move.id), ('reservation_id', '!=', False)]
|
||||
prefered_domain_list = [prefered_domain] + [fallback_domain] + [fallback_domain2]
|
||||
dom = main_domain + self.pool.get('stock.move.operation.link').get_specific_domain(cr, uid, record, context=context)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, record.qty, domain=dom, prefered_domain=prefered_domain,
|
||||
fallback_domain=fallback_domain, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, ops.location_id, move.product_id, record.qty, domain=dom, prefered_domain_list=prefered_domain_list,
|
||||
restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
if ops.result_package_id.id:
|
||||
#if a result package is given, all quants go there
|
||||
quant_dest_package_id = ops.result_package_id.id
|
||||
@@ -2216,9 +2221,11 @@ class stock_move(osv.osv):
|
||||
main_domain = [('qty', '>', 0)]
|
||||
prefered_domain = [('reservation_id', '=', move.id)]
|
||||
fallback_domain = [('reservation_id', '=', False)]
|
||||
fallback_domain2 = ['&', ('reservation_id', '!=', move.id), ('reservation_id', '!=', False)]
|
||||
prefered_domain_list = [prefered_domain] + [fallback_domain] + [fallback_domain2]
|
||||
self.check_tracking(cr, uid, move, move.restrict_lot_id.id, context=context)
|
||||
qty = move_qty[move.id]
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain=prefered_domain, fallback_domain=fallback_domain, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quants = quant_obj.quants_get_prefered_domain(cr, uid, move.location_id, move.product_id, qty, domain=main_domain, prefered_domain_list=prefered_domain_list, restrict_lot_id=move.restrict_lot_id.id, restrict_partner_id=move.restrict_partner_id.id, context=context)
|
||||
quant_obj.quants_move(cr, uid, quants, move, move.location_dest_id, lot_id=move.restrict_lot_id.id, owner_id=move.restrict_partner_id.id, context=context)
|
||||
#unreserve the quants and make them available for other operations/moves
|
||||
quant_obj.quants_unreserve(cr, uid, move, context=context)
|
||||
@@ -3517,14 +3524,9 @@ class stock_package(osv.osv):
|
||||
while parent.parent_id:
|
||||
parent = parent.parent_id
|
||||
quant_ids = self.get_content(cr, uid, [parent.id], context=context)
|
||||
quants = quant_obj.browse(cr, uid, quant_ids, context=context)
|
||||
normal_quants = [x for x in quants if not x.propagated_from_id if x.qty > 0]
|
||||
propagated_quants = [x for x in quants if x.propagated_from_id if x.qty > 0]
|
||||
location_id = normal_quants and normal_quants[0].location_id.id or False
|
||||
prop_loc_id = propagated_quants and propagated_quants[0].location_id.id or False
|
||||
all_normal = all([quant.location_id.id == location_id for quant in normal_quants])
|
||||
all_propagated = all([quant.location_id.id == prop_loc_id for quant in propagated_quants])
|
||||
if not all_normal or not all_propagated:
|
||||
quants = [x for x in quant_obj.browse(cr, uid, quant_ids, context=context) if x.qty > 0]
|
||||
location_id = quants and quants[0].location_id.id or False
|
||||
if not [quant.location_id.id == location_id for quant in quants]:
|
||||
raise osv.except_osv(_('Error'), _('Everything inside a package should be in the same location'))
|
||||
return True
|
||||
|
||||
|
||||
@@ -95,7 +95,6 @@
|
||||
pack_ids2 = [x.id for x in picking2.pack_operation_ids]
|
||||
stock_pack.write(cr, uid, pack_ids1, {'picking_id': picking2.id})
|
||||
stock_pack.write(cr, uid, pack_ids2, {'picking_id': picking1.id})
|
||||
picking1.refresh()
|
||||
-
|
||||
Process this picking
|
||||
-
|
||||
@@ -106,7 +105,12 @@
|
||||
-
|
||||
!python {model: stock.quant}: |
|
||||
reco_id = self.search(cr ,uid , [('product_id','=',ref('product_wise')), ('qty', '<', 0.0)], context=context)
|
||||
assert len(reco_id) > 0, 'This should have created a negative quant'
|
||||
assert len(reco_id) == 0, 'This should not have created a negative quant'
|
||||
-
|
||||
Check the other delivery order has changed its state back to partially available
|
||||
-
|
||||
!python {model: stock.picking}: |
|
||||
assert self.browse(cr, uid, ref('delivery_order_wise2')).state == 'partially_available', "Delivery order 2 should be back in confirmed state"
|
||||
-
|
||||
Process the second picking
|
||||
-
|
||||
@@ -117,4 +121,4 @@
|
||||
-
|
||||
!python {model: stock.quant}: |
|
||||
reco_id = self.search(cr ,uid , [('product_id','=',ref('product_wise'))], context=context)
|
||||
assert all([x.location_id.id==ref('stock_location_customers') and x.qty > 0.0 for x in self.browse(cr, uid, reco_id)]), "Negative quant or wrong location detected"
|
||||
assert all([x.location_id.id==ref('stock_location_customers') and x.qty > 0.0 for x in self.browse(cr, uid, reco_id)]), "Negative quant or wrong location detected"
|
||||
Reference in New Issue
Block a user