diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py
index df8534e703d..2848858a088 100644
--- a/addons/procurement/procurement.py
+++ b/addons/procurement/procurement.py
@@ -195,7 +195,7 @@ class procurement_order(osv.osv):
def run(self, cr, uid, ids, context=None):
for procurement_id in ids:
- #we intentionnaly do the browse under the for loop to avoid caching all ids which would be ressource greedy
+ #we intentionnaly do the browse under the for loop to avoid caching all ids which would be resource greedy
#and useless as we'll make a refresh later that will invalidate all the cache (and thus the next iteration
#will fetch all the ids again)
procurement = self.browse(cr, uid, procurement_id, context=context)
diff --git a/addons/sale/sale.py b/addons/sale/sale.py
index 6cd6e815974..bdb87ad61f4 100644
--- a/addons/sale/sale.py
+++ b/addons/sale/sale.py
@@ -741,49 +741,7 @@ class sale_order(osv.osv):
order.write(val)
return True
- # if mode == 'finished':
- # returns True if all lines are done, False otherwise
- # if mode == 'canceled':
- # returns True if there is at least one canceled line, False otherwise
- def test_state(self, cr, uid, ids, mode, *args):
- assert mode in ('finished', 'canceled'), _("invalid mode for test_state")
- finished = True
- canceled = False
- write_done_ids = []
- write_cancel_ids = []
- for order in self.browse(cr, uid, ids, context={}):
- #TODO: Need to rethink what happens when cancelling
- for line in order.order_line:
- states = [x.state for x in line.procurement_ids]
- cancel = states and all([x == 'cancel' for x in states])
- doneorcancel = all([x in ('done', 'cancel') for x in states])
- if cancel:
- canceled = True
- if line.state != 'exception':
- write_cancel_ids.append(line.id)
- if not doneorcancel:
- finished = False
- if doneorcancel and not cancel:
- write_done_ids.append(line.id)
-
- if write_done_ids:
- self.pool.get('sale.order.line').write(cr, uid, write_done_ids, {'state': 'done'})
- if write_cancel_ids:
- self.pool.get('sale.order.line').write(cr, uid, write_cancel_ids, {'state': 'exception'})
-
- if mode == 'finished':
- return finished
- elif mode == 'canceled':
- return canceled
-
-
- def procurement_lines_get(self, cr, uid, ids, *args):
- res = []
- for order in self.browse(cr, uid, ids, context={}):
- for line in order.order_line:
- res += [x.id for x in line.procurement_ids]
- return res
def onchange_fiscal_position(self, cr, uid, ids, fiscal_position, order_lines, context=None):
'''Update taxes of order lines for each line where a product is defined
@@ -828,6 +786,20 @@ class sale_order(osv.osv):
order_line.append(line)
return {'value': {'order_line': order_line}}
+ def test_procurements_done(self, cr, uid, ids, context=None):
+ for sale in self.browse(cr, uid, ids, context=context):
+ for line in sale.order_line:
+ if not all([x.state == 'done' for x in line.procurement_ids]):
+ return False
+ return True
+
+ def test_procurements_except(self, cr, uid, ids, context=None):
+ for sale in self.browse(cr, uid, ids, context=context):
+ for line in sale.order_line:
+ if any([x.state == 'cancel' for x in line.procurement_ids]):
+ return True
+ return False
+
# TODO add a field price_unit_uos
# - update it on change product and unit price
@@ -924,6 +896,8 @@ class sale_order_line(osv.osv):
'delay': 0.0,
}
+
+
def _get_line_qty(self, cr, uid, line, context=None):
if line.product_uos:
return line.product_uos_qty or 0.0
@@ -1268,6 +1242,20 @@ class procurement_order(osv.osv):
'sale_line_id': fields.many2one('sale.order.line', string='Sale Order Line'),
}
+ def write(self, cr, uid, ids, vals, context=None):
+ if isinstance(ids, (int, long)):
+ ids = [ids]
+ res = super(procurement_order, self).write(cr, uid, ids, vals, context=context)
+ from openerp import workflow
+ if vals.get('state') in ['done', 'cancel', 'exception']:
+ for proc in self.browse(cr, uid, ids, context=context):
+ if proc.sale_line_id and proc.sale_line_id.order_id and proc.move_ids:
+ order_id = proc.sale_line_id.order_id.id
+ if self.pool.get('sale.order').test_procurements_done(cr, uid, [order_id], context=context):
+ workflow.trg_validate(uid, 'sale.order', order_id, 'ship_end', cr)
+ if self.pool.get('sale.order').test_procurements_except(cr, uid, [order_id], context=context):
+ workflow.trg_validate(uid, 'sale.order', order_id, 'ship_except', cr)
+ return res
class product_product(osv.Model):
_inherit = 'product.product'
diff --git a/addons/sale/sale_workflow.xml b/addons/sale/sale_workflow.xml
index 831a0a9d12c..1dd093f4e1d 100644
--- a/addons/sale/sale_workflow.xml
+++ b/addons/sale/sale_workflow.xml
@@ -262,9 +262,7 @@
- procurement.order
- procurement_lines_get()
- test_state('finished')
+ ship_end
diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py
index 20bac48c562..ffe96dd6cb3 100644
--- a/addons/sale_stock/sale_stock.py
+++ b/addons/sale_stock/sale_stock.py
@@ -350,15 +350,6 @@ class sale_order_line(osv.osv):
class stock_move(osv.osv):
_inherit = 'stock.move'
- def action_cancel(self, cr, uid, ids, context=None):
- sale_ids = []
- for move in self.browse(cr, uid, ids, context=context):
- if move.procurement_id and move.procurement_id.sale_line_id:
- sale_ids.append(move.procurement_id.sale_line_id.order_id.id)
- if sale_ids:
- self.pool.get('sale.order').signal_workflow(cr, uid, sale_ids, 'ship_except')
- return super(stock_move, self).action_cancel(cr, uid, ids, context=context)
-
def _create_invoice_line_from_vals(self, cr, uid, move, invoice_line_vals, context=None):
invoice_line_id = super(stock_move, self)._create_invoice_line_from_vals(cr, uid, move, invoice_line_vals, context=context)
if move.procurement_id and move.procurement_id.sale_line_id:
diff --git a/addons/stock/procurement.py b/addons/stock/procurement.py
index b8d7a03c9f2..2024b016ef3 100644
--- a/addons/stock/procurement.py
+++ b/addons/stock/procurement.py
@@ -222,27 +222,18 @@ class procurement_order(osv.osv):
'''
if procurement.rule_id and procurement.rule_id.action == 'move':
uom_obj = self.pool.get('product.uom')
- done_test_list = []
- done_cancel_test_list = []
- qty_done = 0
- for move in procurement.move_ids:
- done_test_list.append(move.state == 'done')
- done_cancel_test_list.append(move.state in ('done', 'cancel'))
- qty_done += move.product_qty if move.state == 'done' else 0
- qty_done = uom_obj._compute_qty(cr, uid, procurement.product_id.uom_id.id, qty_done, procurement.product_uom.id)
- at_least_one_done = any(done_test_list)
+ cancel_test_list = [x.state == 'cancel' for x in procurement.move_ids]
+ done_cancel_test_list = [x.state in ('done', 'cancel') for x in procurement.move_ids]
+ at_least_one_cancel = any(cancel_test_list)
all_done_or_cancel = all(done_cancel_test_list)
+ all_cancel = all(cancel_test_list)
if not all_done_or_cancel:
return False
- elif all_done_or_cancel and procurement.product_qty == qty_done:
+ elif all_done_or_cancel and not all_cancel:
return True
- elif at_least_one_done:
- #some move cancelled and some validated
- self.message_post(cr, uid, [procurement.id], body=_('Some stock moves have been cancelled for this procurement. Run the procurement again to trigger a move for the remaining quantity or change the procurement quantity to finish it directly'), context=context)
- else:
- #all move are cancelled
+ elif all_cancel:
self.message_post(cr, uid, [procurement.id], body=_('All stock moves have been cancelled for this procurement.'), context=context)
- self.write(cr, uid, [procurement.id], {'state': 'exception'}, context=context)
+ self.write(cr, uid, [procurement.id], {'state': 'cancel'}, context=context)
return False
return super(procurement_order, self)._check(cr, uid, procurement, context)
diff --git a/addons/stock/stock.py b/addons/stock/stock.py
index 938a759da46..2a316fa3461 100644
--- a/addons/stock/stock.py
+++ b/addons/stock/stock.py
@@ -2148,20 +2148,18 @@ class stock_move(osv.osv):
if move.propagate:
procurement_ids = procurement_obj.search(cr, uid, [('move_dest_id', '=', move.id)], context=context)
procurement_obj.cancel(cr, uid, procurement_ids, context=context)
- elif move.move_dest_id:
- #cancel chained moves
- if move.propagate:
- self.action_cancel(cr, uid, [move.move_dest_id.id], context=context)
- # If we have a long chain of moves to be cancelled, it is easier for the user to handle
- # only the last procurement which will go into exception, instead of all procurements
- # along the chain going into exception. We need to check if there are no split moves not cancelled however
- if move.procurement_id:
- proc = move.procurement_id
- if all([x.state == 'cancel' for x in proc.move_ids if x.id != move.id]):
- procurement_obj.write(cr, uid, [proc.id], {'state': 'cancel'})
-
- elif move.move_dest_id.state == 'waiting':
- self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}, context=context)
+ else:
+ if move.move_dest_id:
+ if move.propagate:
+ self.action_cancel(cr, uid, [move.move_dest_id.id], context=context)
+ elif move.move_dest_id.state == 'waiting':
+ #If waiting, the chain will be broken and we are not sure if we can still wait for it (=> could take from stock instead)
+ self.write(cr, uid, [move.move_dest_id.id], {'state': 'confirmed'}, context=context)
+ if move.procurement_id:
+ # Does the same as procurement check, only eliminating a refresh
+ proc = move.procurement_id
+ if all([x.state == 'cancel' for x in proc.move_ids if x.id != move.id]):
+ procurement_obj.write(cr, uid, [proc.id], {'state': 'cancel'})
return self.write(cr, uid, ids, {'state': 'cancel', 'move_dest_id': False}, context=context)
def _check_package_from_moves(self, cr, uid, ids, context=None):
@@ -3934,7 +3932,8 @@ class stock_warehouse_orderpoint(osv.osv):
continue
procurement_qty = uom_obj._compute_qty_obj(cr, uid, procurement.product_uom, procurement.product_qty, procurement.product_id.uom_id, context=context)
for move in procurement.move_ids:
- if move.state not in ('draft', 'cancel'):
+ #need to add the moves in draft as they aren't in the virtual quantity + moves that have not been created yet
+ if move.state not in ('draft'):
#if move is already confirmed, assigned or done, the virtual stock is already taking this into account so it shouldn't be deducted
procurement_qty -= move.product_qty
qty += procurement_qty
@@ -3950,7 +3949,6 @@ class stock_warehouse_orderpoint(osv.osv):
for rule in self.browse(cr, uid, ids, context=context):
if rule.product_id.uom_id.category_id.id != rule.product_uom.category_id.id:
return False
-
return True
def action_view_proc_to_process(self, cr, uid, ids, context=None):