[FIX] sale, project_mrp, sale_stock: fixed problems related to the procurement workflow
bzr revid: qdp-launchpad@openerp.com-20130917064359-jwque36uwouac61p
This commit is contained in:
parent
4e25eccad5
commit
e12c9ab5ec
|
@ -20,7 +20,6 @@
|
||||||
##############################################################################
|
##############################################################################
|
||||||
|
|
||||||
from openerp.osv import fields, osv
|
from openerp.osv import fields, osv
|
||||||
from openerp import netsvc
|
|
||||||
from openerp.tools.translate import _
|
from openerp.tools.translate import _
|
||||||
|
|
||||||
class procurement_order(osv.osv):
|
class procurement_order(osv.osv):
|
||||||
|
@ -49,8 +48,8 @@ class procurement_order(osv.osv):
|
||||||
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
|
return super(procurement_order, self)._run(cr, uid, procurement, context=context)
|
||||||
|
|
||||||
def _check(self, cr, uid, procurement, context=None):
|
def _check(self, cr, uid, procurement, context=None):
|
||||||
if self._is_procurement_task(cr, uid, procurement, context=context) and procurement.task_id and procurement.task_id.stage_id.closed:
|
if self._is_procurement_task(cr, uid, procurement, context=context):
|
||||||
return True
|
return procurement.task_id and procurement.task_id.stage_id.closed or False
|
||||||
return super(procurement_order, self)._check(cr, uid, procurement, context=context)
|
return super(procurement_order, self)._check(cr, uid, procurement, context=context)
|
||||||
|
|
||||||
def _convert_qty_company_hours(self, cr, uid, procurement, context=None):
|
def _convert_qty_company_hours(self, cr, uid, procurement, context=None):
|
||||||
|
@ -149,25 +148,20 @@ class product_product(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class sale_order_line(osv.osv):
|
||||||
|
_inherit = 'sale.order.line'
|
||||||
|
|
||||||
|
def need_procurement(self, cr, uid, ids, context=None):
|
||||||
|
#when sale is installed alone, there is no need to create procurements, but with project_mrp
|
||||||
|
#we must create a procurement for each service that has the auto_create_task boolean set to True.
|
||||||
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
|
if line.product_id and line.product_id.type == 'service' and line.product_id.auto_create_task:
|
||||||
|
return True
|
||||||
|
return super(sale_order_line, self).need_procurement(cr, uid, ids, context=context)
|
||||||
|
|
||||||
class sale_order(osv.osv):
|
class sale_order(osv.osv):
|
||||||
_inherit = 'sale.order'
|
_inherit = 'sale.order'
|
||||||
|
|
||||||
def _can_create_procurement(self, cr, uid, ids, context=None):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None):
|
|
||||||
proc_data = super(sale_order, self)._prepare_order_line_procurement(cr,
|
|
||||||
uid, order, line, group_id = group_id, context=context)
|
|
||||||
if not(line.product_id.type== "service" and not line.product_id.auto_create_task):
|
|
||||||
proc_data['sale_line_id'] = line.id
|
|
||||||
return proc_data
|
|
||||||
|
|
||||||
def _check_create_procurement(self, cr, uid, order, line, context=None):
|
|
||||||
create = super(sale_order, self)._check_create_procurement(cr, uid, order, line, context=context)
|
|
||||||
if (line.product_id.type== "service" and not line.product_id.auto_create_task):
|
|
||||||
create = False
|
|
||||||
return create
|
|
||||||
|
|
||||||
def _picked_rate(self, cr, uid, ids, name, arg, context=None):
|
def _picked_rate(self, cr, uid, ids, name, arg, context=None):
|
||||||
if not ids:
|
if not ids:
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -622,6 +622,8 @@ class sale_order(osv.osv):
|
||||||
}
|
}
|
||||||
|
|
||||||
def action_done(self, cr, uid, ids, context=None):
|
def action_done(self, cr, uid, ids, context=None):
|
||||||
|
for order in self.browse(cr, uid, ids, context=context):
|
||||||
|
self.pool.get('sale.order.line').write(cr, uid, [line.id for line in order.order_line], {'state': 'done'}, context=context)
|
||||||
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
|
return self.write(cr, uid, ids, {'state': 'done'}, context=context)
|
||||||
|
|
||||||
def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None):
|
def _prepare_order_line_procurement(self, cr, uid, order, line, group_id=False, context=None):
|
||||||
|
@ -646,15 +648,16 @@ class sale_order(osv.osv):
|
||||||
return date_planned
|
return date_planned
|
||||||
|
|
||||||
def _prepare_procurement_group(self, cr, uid, order, context=None):
|
def _prepare_procurement_group(self, cr, uid, order, context=None):
|
||||||
return {
|
return {'name': order.name, 'partner_id': order.partner_shipping_id.id}
|
||||||
'name': order.name, 'partner_id': order.partner_shipping_id.id,
|
|
||||||
}
|
|
||||||
|
|
||||||
def _check_create_procurement(self, cr, uid, order, line, context=None):
|
def procurement_needed(self, cr, uid, ids, context=None):
|
||||||
return True
|
#when sale is installed only, there is no need to create procurements, that's only
|
||||||
|
#further installed modules (project_mrp, sale_stock) that will change this.
|
||||||
def _can_create_procurement(self, cr, uid, ids, context=None):
|
sale_line_obj = self.pool.get('sale.order.line')
|
||||||
return False
|
res = []
|
||||||
|
for order in self.browse(cr, uid, ids, context=context):
|
||||||
|
res.append(sale_line_obj.need_procurement(cr, uid, [line.id for line in order.order_line], context=context))
|
||||||
|
return any(res)
|
||||||
|
|
||||||
def action_ship_create(self, cr, uid, ids, context=None):
|
def action_ship_create(self, cr, uid, ids, context=None):
|
||||||
"""Create the required procurements to supply sales order lines, also connecting
|
"""Create the required procurements to supply sales order lines, also connecting
|
||||||
|
@ -668,21 +671,23 @@ class sale_order(osv.osv):
|
||||||
:return: True
|
:return: True
|
||||||
"""
|
"""
|
||||||
procurement_obj = self.pool.get('procurement.order')
|
procurement_obj = self.pool.get('procurement.order')
|
||||||
|
sale_line_obj = self.pool.get('sale.order.line')
|
||||||
for order in self.browse(cr, uid, ids, context=context):
|
for order in self.browse(cr, uid, ids, context=context):
|
||||||
proc_ids = []
|
proc_ids = []
|
||||||
vals = self._prepare_procurement_group(cr, uid, order, context=context)
|
vals = self._prepare_procurement_group(cr, uid, order, context=context)
|
||||||
group_id = self.pool.get("procurement.group").create(cr, uid, vals, context=context)
|
group_id = self.pool.get("procurement.group").create(cr, uid, vals, context=context)
|
||||||
|
|
||||||
order.write({'procurement_group_id': group_id}, context=context)
|
order.write({'procurement_group_id': group_id}, context=context)
|
||||||
for line in order.order_line:
|
for line in order.order_line:
|
||||||
if (line.state == 'done') or not line.product_id:
|
if sale_line_obj.need_procurement(cr, uid, [line.id], context=context):
|
||||||
continue
|
if (line.state == 'done') or not line.product_id:
|
||||||
if self._can_create_procurement(cr, uid, ids, context=context) and self._check_create_procurement(cr, uid, order, line, context=context):
|
continue
|
||||||
vals = self._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context)
|
vals = self._prepare_order_line_procurement(cr, uid, order, line, group_id=group_id, context=context)
|
||||||
proc_id = procurement_obj.create(cr, uid, vals, context=context)
|
proc_id = procurement_obj.create(cr, uid, vals, context=context)
|
||||||
proc_ids.append(proc_id)
|
proc_ids.append(proc_id)
|
||||||
#Confirm procurement order such that rules will be applied on it
|
#Confirm procurement order such that rules will be applied on it
|
||||||
procurement_obj.run(cr, uid, proc_ids, context=context)
|
#note that the workflow ensure proc_ids isn't an empty list
|
||||||
|
procurement_obj.run(cr, uid, proc_ids, context=context)
|
||||||
# FP NOTE: do we need this? isn't it the workflow that should set this
|
# FP NOTE: do we need this? isn't it the workflow that should set this
|
||||||
val = {}
|
val = {}
|
||||||
if order.state == 'shipping_except':
|
if order.state == 'shipping_except':
|
||||||
|
@ -697,14 +702,6 @@ class sale_order(osv.osv):
|
||||||
order.write(val)
|
order.write(val)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def action_ship_end(self, cr, uid, ids, context=None):
|
|
||||||
for order in self.browse(cr, uid, ids, context=context):
|
|
||||||
for line in order.order_line:
|
|
||||||
if line.state == 'exception':
|
|
||||||
self.pool.get('sale.order.line').write(cr, uid, [line.id], {'state': 'done'}, context=context)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# if mode == 'finished':
|
# if mode == 'finished':
|
||||||
# returns True if all lines are done, False otherwise
|
# returns True if all lines are done, False otherwise
|
||||||
# if mode == 'canceled':
|
# if mode == 'canceled':
|
||||||
|
@ -715,18 +712,12 @@ class sale_order(osv.osv):
|
||||||
canceled = False
|
canceled = False
|
||||||
write_done_ids = []
|
write_done_ids = []
|
||||||
write_cancel_ids = []
|
write_cancel_ids = []
|
||||||
if not self._can_create_procurement(cr, uid, ids, context={}):
|
|
||||||
for order in self.browse(cr, uid, ids, context={}):
|
|
||||||
for line in order.order_line:
|
|
||||||
write_done_ids.append(line.id)
|
|
||||||
self.pool.get('sale.order.line').write(cr, uid, write_done_ids, {'state': 'done'})
|
|
||||||
return True
|
|
||||||
for order in self.browse(cr, uid, ids, context={}):
|
for order in self.browse(cr, uid, ids, context={}):
|
||||||
|
|
||||||
#TODO: Need to rethink what happens when cancelling
|
#TODO: Need to rethink what happens when cancelling
|
||||||
for line in order.order_line:
|
for line in order.order_line:
|
||||||
states = [x.state for x in line.procurement_ids]
|
states = [x.state for x in line.procurement_ids]
|
||||||
cancel = all([x == 'cancel' for x in states])
|
cancel = states and all([x == 'cancel' for x in states])
|
||||||
doneorcancel = all([x in ('done', 'cancel') for x in states])
|
doneorcancel = all([x in ('done', 'cancel') for x in states])
|
||||||
if cancel:
|
if cancel:
|
||||||
canceled = True
|
canceled = True
|
||||||
|
@ -764,6 +755,11 @@ class sale_order(osv.osv):
|
||||||
# - use it in report if there is a uos
|
# - use it in report if there is a uos
|
||||||
class sale_order_line(osv.osv):
|
class sale_order_line(osv.osv):
|
||||||
|
|
||||||
|
def need_procurement(self, cr, uid, ids, context=None):
|
||||||
|
#when sale is installed only, there is no need to create procurements, that's only
|
||||||
|
#further installed modules (project_mrp, sale_stock) that will change this.
|
||||||
|
return False
|
||||||
|
|
||||||
def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
|
def _amount_line(self, cr, uid, ids, field_name, arg, context=None):
|
||||||
tax_obj = self.pool.get('account.tax')
|
tax_obj = self.pool.get('account.tax')
|
||||||
cur_obj = self.pool.get('res.currency')
|
cur_obj = self.pool.get('res.currency')
|
||||||
|
@ -1145,4 +1141,4 @@ class procurement_order(osv.osv):
|
||||||
_columns = {
|
_columns = {
|
||||||
'sale_line_id': fields.many2one('sale.order.line', string='Sale Order Line'),
|
'sale_line_id': fields.many2one('sale.order.line', string='Sale Order Line'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -191,8 +191,7 @@
|
||||||
<record id="act_ship_end" model="workflow.activity">
|
<record id="act_ship_end" model="workflow.activity">
|
||||||
<field name="wkf_id" ref="sale.wkf_sale"/>
|
<field name="wkf_id" ref="sale.wkf_sale"/>
|
||||||
<field name="name">ship_end</field>
|
<field name="name">ship_end</field>
|
||||||
<field name="kind">function</field>
|
<field name="kind">dummy</field>
|
||||||
<field name="action">action_ship_end()</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="act_ship_cancel" model="workflow.activity">
|
<record id="act_ship_cancel" model="workflow.activity">
|
||||||
|
@ -240,7 +239,12 @@
|
||||||
<record id="trans_wait_ship_ship" model="workflow.transition">
|
<record id="trans_wait_ship_ship" model="workflow.transition">
|
||||||
<field name="act_from" ref="act_wait_ship"/>
|
<field name="act_from" ref="act_wait_ship"/>
|
||||||
<field name="act_to" ref="act_ship"/>
|
<field name="act_to" ref="act_ship"/>
|
||||||
<field name="condition">(order_policy!='prepaid') or invoiced</field>
|
<field name="condition">procurement_needed() and ((order_policy!='prepaid') or invoiced)</field>
|
||||||
|
</record>
|
||||||
|
<record id="trans_wait_ship_done" model="workflow.transition">
|
||||||
|
<field name="act_from" ref="act_wait_ship"/>
|
||||||
|
<field name="act_to" ref="act_ship_end"/>
|
||||||
|
<field name="condition">not procurement_needed()</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="trans_ship_end_done" model="workflow.transition">
|
<record id="trans_ship_end_done" model="workflow.transition">
|
||||||
|
|
|
@ -31,9 +31,6 @@ from openerp import SUPERUSER_ID
|
||||||
class sale_order(osv.osv):
|
class sale_order(osv.osv):
|
||||||
_inherit = "sale.order"
|
_inherit = "sale.order"
|
||||||
|
|
||||||
def _can_create_procurement(self, cr, uid, ids, context=None):
|
|
||||||
return True
|
|
||||||
|
|
||||||
def copy(self, cr, uid, id, default=None, context=None):
|
def copy(self, cr, uid, id, default=None, context=None):
|
||||||
if not default:
|
if not default:
|
||||||
default = {}
|
default = {}
|
||||||
|
@ -203,8 +200,6 @@ class sale_order(osv.osv):
|
||||||
self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context)
|
self.write(cr, uid, [o.id], {'order_policy': 'manual'}, context=context)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
def _get_date_planned(self, cr, uid, order, line, start_date, context=None):
|
||||||
date_planned = super(sale_order, self)._get_date_planned(cr, uid, order, line, start_date, context=context)
|
date_planned = super(sale_order, self)._get_date_planned(cr, uid, order, line, start_date, context=context)
|
||||||
date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
date_planned = (date_planned - timedelta(days=order.company_id.security_lead)).strftime(DEFAULT_SERVER_DATETIME_FORMAT)
|
||||||
|
@ -240,10 +235,17 @@ class sale_order(osv.osv):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class sale_order_line(osv.osv):
|
class sale_order_line(osv.osv):
|
||||||
_inherit = 'sale.order.line'
|
_inherit = 'sale.order.line'
|
||||||
|
|
||||||
|
def need_procurement(self, cr, uid, ids, context=None):
|
||||||
|
#when sale is installed alone, there is no need to create procurements, but with sale_stock
|
||||||
|
#we must create a procurement for each product that is not a service.
|
||||||
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
|
if line.product_id and line.product_id.type != 'service':
|
||||||
|
return True
|
||||||
|
return super(sale_order_line, self).need_procurement(cr, uid, ids, context=context)
|
||||||
|
|
||||||
def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
|
def _number_packages(self, cr, uid, ids, field_name, arg, context=None):
|
||||||
res = {}
|
res = {}
|
||||||
for line in self.browse(cr, uid, ids, context=context):
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
|
@ -262,7 +264,6 @@ class sale_order_line(osv.osv):
|
||||||
'product_packaging': False,
|
'product_packaging': False,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def button_cancel(self, cr, uid, ids, context=None):
|
def button_cancel(self, cr, uid, ids, context=None):
|
||||||
res = super(sale_order_line, self).button_cancel(cr, uid, ids, context=context)
|
res = super(sale_order_line, self).button_cancel(cr, uid, ids, context=context)
|
||||||
for line in self.browse(cr, uid, ids, context=context):
|
for line in self.browse(cr, uid, ids, context=context):
|
||||||
|
@ -407,4 +408,4 @@ class stock_move(osv.osv):
|
||||||
res['account_analytic_id'] = sale_line.order_id.project_id and sale_line.order_id.project_id.id or False
|
res['account_analytic_id'] = sale_line.order_id.project_id and sale_line.order_id.project_id.id or False
|
||||||
res['price_unit'] = sale_line.price_unit
|
res['price_unit'] = sale_line.price_unit
|
||||||
res['discount'] = sale_line.discount
|
res['discount'] = sale_line.discount
|
||||||
return res
|
return res
|
||||||
|
|
|
@ -64,9 +64,7 @@
|
||||||
Check one quant was created in Customers location with 200 pieces and one move in the history_ids
|
Check one quant was created in Customers location with 200 pieces and one move in the history_ids
|
||||||
-
|
-
|
||||||
!python {model: stock.quant}: |
|
!python {model: stock.quant}: |
|
||||||
quant_id = self.search(cr, uid, [('product_id', '=', ref("drop_shop_product"))])
|
quant_ids = self.search(cr, uid, [('location_id', '=', ref('stock.stock_location_customers')),('qty', '=', 200), ('product_id', '=', ref("drop_shop_product"))])
|
||||||
print quant_id, [(x.qty, x.product_id.name) for x in self.browse(cr, uid, quant_id)]
|
assert quant_ids, 'No Quant found'
|
||||||
quant_id = self.search(cr, uid, [('location_id', '=', ref('stock.stock_location_customers')),('qty', '=', 200), ('product_id', '=', ref("drop_shop_product"))])
|
assert len(quant_ids) == 1
|
||||||
print quant_id, [(x.qty, x.product_id.name) for x in self.browse(cr, uid, quant_id)]
|
assert len(self.browse(cr, uid, quant_ids)[0].history_ids) == 1
|
||||||
assert len(self.browse(cr, uid, quant_id)[0].history_ids) == 1
|
|
||||||
assert len(quant_id) == 1
|
|
||||||
|
|
Loading…
Reference in New Issue