[IMP] Move sale_stock_workflow towards sale_workflow and make sure project_mrp tests pass

bzr revid: jco@openerp.com-20130910154822-u2if98d4r32rtibi
This commit is contained in:
Josse Colpaert 2013-09-10 17:48:22 +02:00
parent 83f30b55dc
commit d207edc369
16 changed files with 278 additions and 212 deletions

View File

@ -32,7 +32,7 @@ This application supports complete integration and production scheduling for sto
--> -->
<record id="route_warehouse0_manufacture" model='stock.location.route'> <record id="route_warehouse0_manufacture" model='stock.location.route'>
<field name="name">Manufacture</field> <field name="name">Your Company Manufacture</field>
<field name="sequence">5</field> <field name="sequence">5</field>
</record> </record>

View File

@ -49,7 +49,7 @@ 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.state == 'done': if self._is_procurement_task(cr, uid, procurement, context=context) and procurement.task_id and procurement.task_id.stage_id.closed:
return True return True
return super(procurement_order, self)._check(cr, uid, procurement, context=context) return super(procurement_order, self)._check(cr, uid, procurement, context=context)
@ -70,6 +70,35 @@ class procurement_order(osv.osv):
account = procurement.sale_line_id.order_id.project_id account = procurement.sale_line_id.order_id.project_id
project_ids = project_project.search(cr, uid, [('analytic_account_id', '=', account.id)]) project_ids = project_project.search(cr, uid, [('analytic_account_id', '=', account.id)])
projects = project_project.browse(cr, uid, project_ids, context=context) projects = project_project.browse(cr, uid, project_ids, context=context)
project = projects and projects[0] or False
return project
def _create_service_task(self, cr, uid, procurement, context=None):
project_task = self.pool.get('project.task')
project = self._get_project(cr, uid, procurement, context=context)
planned_hours = self._convert_qty_company_hours(cr, uid, procurement, context=context)
task_id = project_task.create(cr, uid, {
'name': '%s:%s' % (procurement.origin or '', procurement.product_id.name),
'date_deadline': procurement.date_planned,
'planned_hours': planned_hours,
'remaining_hours': planned_hours,
'partner_id': procurement.sale_line_id and procurement.sale_line_id.order_id.partner_id.id or False,
'user_id': procurement.product_id.product_manager.id,
'procurement_id': procurement.id,
'description': procurement.name + '\n',
'project_id': project and project.id or False,
'company_id': procurement.company_id.id,
},context=context)
self.write(cr, uid, [procurement.id], {'task_id': task_id, 'message':_('Task created.')}, context=context)
self.project_task_create_note(cr, uid, [procurement.id], context=context)
return task_id
def project_task_create_note(self, cr, uid, ids, context=None):
for procurement in self.browse(cr, uid, ids, context=context):
body = _("Task created")
self.message_post(cr, uid, [procurement.id], body=body, context=context)
if procurement.sale_line_id and procurement.sale_line_id.order_id:
procurement.sale_line_id.order_id.message_post(body=body)
@ -98,10 +127,10 @@ class project_task(osv.osv):
} }
def _validate_subflows(self, cr, uid, ids, context=None): def _validate_subflows(self, cr, uid, ids, context=None):
wf_service = netsvc.LocalService("workflow") proc_obj = self.pool.get("procurement.order")
for task in self.browse(cr, uid, ids): for task in self.browse(cr, uid, ids, context=context):
if task.procurement_id: if task.procurement_id:
wf_service.trg_write(uid, 'procurement.order', task.procurement_id.id, cr) proc_obj.check(cr, uid, [task.procurement_id.id], context=context)
def write(self, cr, uid, ids, values, context=None): def write(self, cr, uid, ids, values, context=None):
""" When closing tasks, validate subflows. """ """ When closing tasks, validate subflows. """
@ -124,9 +153,12 @@ class sale_order(osv.osv):
_inherit = 'sale.order' _inherit = 'sale.order'
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):
proc_data = super(sale_order, self)._prepare_order_line_procurement(cr, if not(line.product_id.type== "service" and not line.product_id.auto_create_task):
proc_data = super(sale_order, self)._prepare_order_line_procurement(cr,
uid, order, line, group_id = group_id, context=context) uid, order, line, group_id = group_id, context=context)
proc_data['sale_line_id'] = line.id proc_data['sale_line_id'] = line.id
else:
proc_data = False
return proc_data return proc_data
def _picked_rate(self, cr, uid, ids, name, arg, context=None): def _picked_rate(self, cr, uid, ids, name, arg, context=None):

View File

@ -10,7 +10,6 @@
<field name="product_uom" ref="product.product_uom_day"/> <field name="product_uom" ref="product.product_uom_day"/>
<field name="price_unit">150.0</field> <field name="price_unit">150.0</field>
<field name="product_uom_qty">5.0</field> <field name="product_uom_qty">5.0</field>
<field name="type">make_to_order</field>
</record> </record>
<record id="project.project_tt_deployment" model="project.task.type"> <record id="project.project_tt_deployment" model="project.task.type">

View File

@ -14,11 +14,14 @@
<record id="view_product_task_form" model="ir.ui.view"> <record id="view_product_task_form" model="ir.ui.view">
<field name="name">product.form.view.inherit</field> <field name="name">product.form.view.inherit</field>
<field name="model">product.product</field> <field name="model">product.product</field>
<field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/> <field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<field name="type" position="after"> <field name="type" position="after">
<field name="project_id" attrs="{'invisible':[('type','!=','service')]}" /> <field name="project_id" attrs="{'invisible':[('type','!=','service')]}" />
</field> </field>
<field name="standard_price" position="after">
<field name="auto_create_task"/>
</field>
</field> </field>
</record> </record>
<record id="task_type_edit_mrp_inherit" model="ir.ui.view"> <record id="task_type_edit_mrp_inherit" model="ir.ui.view">

View File

@ -1,18 +1,43 @@
-
Update product to automatically create tasks
-
!record {model: product.product, id: auto_task_service}:
auto_create_task: True
name: Advanced auto task Service
type: service
list_price: 150.0
standard_price: 100.0
uom_id: product.product_uom_day
uom_po_id: product.product_uom_day
-
Create a new sales order with a service product
-
!record {model: sale.order, id: sale_order_service}:
partner_id: base.res_partner_2
pricelist_id: product.list0
-
Associate a sale order line
-
!record {model: sale.order.line, id: service_line}:
product_id: auto_task_service
product_uom_qty: 50.0
name: Fixing the bugs
order_id: sale_order_service
- -
In order to test process to generate task automatic from procurement, I confirm sale order to sale service product. In order to test process to generate task automatic from procurement, I confirm sale order to sale service product.
- -
!workflow {model: sale.order, action: order_confirm, ref: sale.sale_order_3} !workflow {model: sale.order, action: order_confirm, ref: sale_order_service}
- -
I run the scheduler. I run the scheduler.
- -
!python {model: procurement.order}: | !python {model: procurement.order}: |
self.run_scheduler(cr, uid) self.run_scheduler(cr, uid)
- -
Now I check that task details after run procurement Now I check the details of the generated task
- -
!python {model: procurement.order}: | !python {model: procurement.order}: |
from datetime import datetime from datetime import datetime
procurement_ids = self.search(cr, uid, [('sale_line_id', '=', ref('line_services'))]) procurement_ids = self.search(cr, uid, [('sale_line_id', '=', ref('service_line'))])
assert procurement_ids, "Procurement is not generated for Service Order Line." assert procurement_ids, "Procurement is not generated for Service Order Line."
procurement = self.browse(cr, uid, procurement_ids[0], context=context) procurement = self.browse(cr, uid, procurement_ids[0], context=context)
assert procurement.state != 'done' , "Procurement should not be closed." assert procurement.state != 'done' , "Procurement should not be closed."
@ -34,14 +59,14 @@
I close that task. I close that task.
- -
!python {model: project.task}: | !python {model: project.task}: |
task_ids = self.search(cr, uid, [('sale_line_id', '=', ref('line_services'))]) task_ids = self.search(cr, uid, [('sale_line_id', '=', ref('service_line'))])
assert task_ids, "Task is not generated for Service Order Line." assert task_ids, "Task is not generated for Service Order Line."
self.write(cr, uid, task_ids, {'stage_id': ref('project.project_tt_deployment')}, context=context) self.write(cr, uid, task_ids, {'stage_id': ref('project.project_tt_deployment')}, context=context)
- -
I check procurement of Service Order Line after closed task. I check procurement of Service Order Line after closed task.
- -
!python {model: procurement.order}: | !python {model: procurement.order}: |
procurement_ids = self.search(cr, uid, [('sale_line_id', '=', ref('line_services'))]) procurement_ids = self.search(cr, uid, [('sale_line_id', '=', ref('service_line'))])
assert procurement_ids, "Procurement is not generated for Service Order Line." assert procurement_ids, "Procurement is not generated for Service Order Line."
procurement = self.browse(cr, uid, procurement_ids[0], context=context) procurement = self.browse(cr, uid, procurement_ids[0], context=context)
assert procurement.state == 'done' , "Procurement should be closed." assert procurement.state == 'done' , "Procurement should be closed."

View File

@ -152,7 +152,7 @@ class purchase_order(osv.osv):
def _get_picking_in(self, cr, uid, context=None): def _get_picking_in(self, cr, uid, context=None):
obj_data = self.pool.get('ir.model.data') obj_data = self.pool.get('ir.model.data')
return obj_data.get_object_reference(cr, uid, 'stock','picking_type_in')[1] return obj_data.get_object_reference(cr, uid, 'stock','picking_type_in') and obj_data.get_object_reference(cr, uid, 'stock','picking_type_in')[1] or False
STATE_SELECTION = [ STATE_SELECTION = [
('draft', 'Draft PO'), ('draft', 'Draft PO'),

View File

@ -71,7 +71,7 @@
--> -->
<record id="route_warehouse0_buy" model='stock.location.route'> <record id="route_warehouse0_buy" model='stock.location.route'>
<field name="name">Buy</field> <field name="name">Your Company Buy</field>
<field name="sequence">5</field> <field name="sequence">5</field>
</record> </record>

View File

@ -144,6 +144,7 @@ class purchase_requisition(osv.osv):
def _prepare_purchase_order(self, cr, uid, requisition, supplier, context=None): def _prepare_purchase_order(self, cr, uid, requisition, supplier, context=None):
supplier_pricelist = supplier.property_product_pricelist_purchase and supplier.property_product_pricelist_purchase.id or False supplier_pricelist = supplier.property_product_pricelist_purchase and supplier.property_product_pricelist_purchase.id or False
picking_type_in = self.pool.get("purchase.order")._get_picking_in(cr, uid, context=context)
return { return {
'origin': requisition.name, 'origin': requisition.name,
'date_order': requisition.date_end or fields.date.context_today(self, cr, uid, context=context), 'date_order': requisition.date_end or fields.date.context_today(self, cr, uid, context=context),
@ -154,6 +155,7 @@ class purchase_requisition(osv.osv):
'fiscal_position': supplier.property_account_position and supplier.property_account_position.id or False, 'fiscal_position': supplier.property_account_position and supplier.property_account_position.id or False,
'requisition_id': requisition.id, 'requisition_id': requisition.id,
'notes': requisition.description, 'notes': requisition.description,
'picking_type_id': picking_type_in,
} }
def _prepare_purchase_order_line(self, cr, uid, requisition, requisition_line, purchase_id, supplier, context=None): def _prepare_purchase_order_line(self, cr, uid, requisition, requisition_line, purchase_id, supplier, context=None):

View File

@ -169,10 +169,13 @@ class sale_order(osv.osv):
('waiting_date', 'Waiting Schedule'), ('waiting_date', 'Waiting Schedule'),
('progress', 'Sales Order'), ('progress', 'Sales Order'),
('manual', 'Sale to Invoice'), ('manual', 'Sale to Invoice'),
('shipping_except', 'Shipping Exception'),
('invoice_except', 'Invoice Exception'), ('invoice_except', 'Invoice Exception'),
('done', 'Done'), ('done', 'Done'),
], 'Status', readonly=True, track_visibility='onchange', ], 'Status', readonly=True, help="Gives the status of the quotation or sales order.\
help="Gives the status of the quotation or sales order. \nThe exception status is automatically set when a cancel operation occurs in the processing of a document linked to the sales order. \nThe 'Waiting Schedule' status is set when the invoice is confirmed but waiting for the scheduler to run on the order date.", select=True), \nThe exception status is automatically set when a cancel operation occurs \
in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception).\nThe 'Waiting Schedule' status is set when the invoice is confirmed\
but waiting for the scheduler to run on the order date.", select=True),
'date_order': fields.datetime('Date', required=True, readonly=True, select=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}), 'date_order': fields.datetime('Date', required=True, readonly=True, select=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}),
'create_date': fields.datetime('Creation Date', readonly=True, select=True, help="Date on which sales order is created."), 'create_date': fields.datetime('Creation Date', readonly=True, select=True, help="Date on which sales order is created."),
'date_confirm': fields.date('Confirmation Date', readonly=True, select=True, help="Date on which sales order is confirmed."), 'date_confirm': fields.date('Confirmation Date', readonly=True, select=True, help="Date on which sales order is confirmed."),
@ -668,9 +671,11 @@ class sale_order(osv.osv):
for line in order.order_line: for line in order.order_line:
if (line.state == 'done') or not line.product_id: if (line.state == 'done') or not line.product_id:
continue continue
proc_id = procurement_obj.create(cr, uid, 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_ids.append(proc_id) if vals:
proc_id = procurement_obj.create(cr, uid, vals, context=context)
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) procurement_obj.run(cr, uid, proc_ids, context=context)
@ -688,6 +693,61 @@ 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':
# 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 = 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
# TODO add a field price_unit_uos # TODO add a field price_unit_uos
# - update it on change product and unit price # - update it on change product and unit price
# - use it in report if there is a uos # - use it in report if there is a uos
@ -743,8 +803,6 @@ class sale_order_line(osv.osv):
'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10) 'sale.order.line': (lambda self,cr,uid,ids,ctx=None: ids, ['invoice_lines'], 10)
}), }),
'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}), 'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price'), readonly=True, states={'draft': [('readonly', False)]}),
'type': fields.selection([('make_to_stock', 'from stock'), ('make_to_order', 'on order')], 'Procurement Method', required=True, readonly=True, states={'draft': [('readonly', False)]},
help="From stock: When needed, the product is taken from the stock or we wait for replenishment.\nOn order: When needed, the product is purchased or produced."),
'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')), 'price_subtotal': fields.function(_amount_line, string='Subtotal', digits_compute= dp.get_precision('Account')),
'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}), 'tax_id': fields.many2many('account.tax', 'sale_order_tax', 'order_line_id', 'tax_id', 'Taxes', readonly=True, states={'draft': [('readonly', False)]}),
'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."), 'address_allotment_id': fields.many2one('res.partner', 'Allotment Partner',help="A partner to whom the particular product needs to be allotted."),
@ -774,7 +832,6 @@ class sale_order_line(osv.osv):
'product_uos_qty': 1, 'product_uos_qty': 1,
'sequence': 10, 'sequence': 10,
'state': 'draft', 'state': 'draft',
'type': 'make_to_stock',
'price_unit': 0.0, 'price_unit': 0.0,
'delay': 0.0, 'delay': 0.0,
} }

View File

@ -150,7 +150,6 @@
</group> </group>
<group> <group>
<field name="tax_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','&lt;&gt;','purchase')]"/> <field name="tax_id" widget="many2many_tags" domain="[('parent_id','=',False),('type_tax_use','&lt;&gt;','purchase')]"/>
<field name="type"/>
<field name="th_weight"/> <field name="th_weight"/>
<!-- we should put a config wizard for these two fields --> <!-- we should put a config wizard for these two fields -->
<field name="address_allotment_id"/> <field name="address_allotment_id"/>

View File

@ -162,5 +162,124 @@
<field name="act_to" ref="act_done"/> <field name="act_to" ref="act_done"/>
</record> </record>
<!--
Procurements creation and checking branch
-->
<!-- Activity -->
<record id="act_wait_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">wait_ship</field>
</record>
<record id="act_cancel3" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">cancel3</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship</field>
<field name="kind">function</field>
<field name="action">action_ship_create()</field>
</record>
<record id="act_ship_end" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_end</field>
<field name="kind">function</field>
<field name="action">action_ship_end()</field>
</record>
<record id="act_ship_cancel" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_cancel</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_ship_except" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_except</field>
<field name="kind">function</field>
<field name="action">write({'state':'shipping_except'})</field>
</record>
<!-- Transition -->
<record id="trans_router_wait_ship" model="workflow.transition">
<field name="act_from" ref="sale.act_router"/>
<field name="act_to" ref="act_wait_ship"/>
</record>
<record id="trans_router_wait_invoice_shipping" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice_end"/>
<field name="condition">(order_policy=='picking')</field>
</record>
<record id="trans_wait_invoice_invoice" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice"/>
<field name="condition">order_policy=='prepaid'</field>
</record>
<record id="trans_wait_ship_cancel3" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_cancel3"/>
<field name="signal">cancel</field>
</record>
<record id="trans_wait_ship_ship" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_ship"/>
<field name="condition">(order_policy!='prepaid') or invoiced</field>
</record>
<record id="trans_ship_end_done" model="workflow.transition">
<field name="act_from" ref="act_ship_end"/>
<field name="act_to" ref="sale.act_done"/>
</record>
<record id="trans_ship_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_end"/>
<field name="trigger_model">procurement.order</field>
<field name="trigger_expr_id">procurement_lines_get()</field>
<field name="condition">test_state('finished')</field>
</record>
<record id="trans_ship_ship_except" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_except"/>
<field name="condition">test_state('canceled')</field>
</record>
<record id="trans_ship_except_ship" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship"/>
<field name="signal">ship_recreate</field>
</record>
<record id="trans_ship_except_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_end"/>
<field name="signal">ship_corrected</field>
</record>
<record id="trans_ship_except_ship_cancel" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_cancel"/>
<field name="signal">ship_cancel</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -91,20 +91,6 @@ class sale_order(osv.osv):
return vals return vals
_columns = { _columns = {
'state': fields.selection([
('draft', 'Draft Quotation'),
('sent', 'Quotation Sent'),
('cancel', 'Cancelled'),
('waiting_date', 'Waiting Schedule'),
('progress', 'Sales Order'),
('manual', 'Sale to Invoice'),
('shipping_except', 'Shipping Exception'),
('invoice_except', 'Invoice Exception'),
('done', 'Done'),
], 'Status', readonly=True, help="Gives the status of the quotation or sales order.\
\nThe exception status is automatically set when a cancel operation occurs \
in the invoice validation (Invoice Exception) or in the picking list process (Shipping Exception).\nThe 'Waiting Schedule' status is set when the invoice is confirmed\
but waiting for the scheduler to run on the order date.", select=True),
'incoterm': fields.many2one('stock.incoterms', 'Incoterm', help="International Commercial Terms are a series of predefined commercial terms used in international transactions."), 'incoterm': fields.many2one('stock.incoterms', 'Incoterm', help="International Commercial Terms are a series of predefined commercial terms used in international transactions."),
'picking_policy': fields.selection([('direct', 'Deliver each product when available'), ('one', 'Deliver all products at once')], 'picking_policy': fields.selection([('direct', 'Deliver each product when available'), ('one', 'Deliver all products at once')],
'Shipping Policy', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]}, 'Shipping Policy', required=True, readonly=True, states={'draft': [('readonly', False)], 'sent': [('readonly', False)]},
@ -212,41 +198,7 @@ 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
# 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 = 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 _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)
@ -258,8 +210,8 @@ class sale_order(osv.osv):
res.update({'move_type': order.picking_policy}) res.update({'move_type': order.picking_policy})
return res return res
def action_ship_end(self, cr, uid, ids, context=None): def action_ship_end(self, cr, uid, ids, context=None):
super(sale_order, self).action_ship_end(cr, uid, ids, context=context)
for order in self.browse(cr, uid, ids, context=context): for order in self.browse(cr, uid, ids, context=context):
val = {'shipped': True} val = {'shipped': True}
if order.state == 'shipping_except': if order.state == 'shipping_except':
@ -269,15 +221,12 @@ class sale_order(osv.osv):
if (not line.invoiced) and (line.state not in ('cancel', 'draft')): if (not line.invoiced) and (line.state not in ('cancel', 'draft')):
val['state'] = 'manual' val['state'] = 'manual'
break break
for line in order.order_line:
towrite = []
if line.state == 'exception':
towrite.append(line.id)
if towrite:
self.pool.get('sale.order.line').write(cr, uid, towrite, {'state': 'done'}, context=context)
res = self.write(cr, uid, [order.id], val) res = self.write(cr, uid, [order.id], val)
return True return True
def has_stockable_products(self, cr, uid, ids, *args): def has_stockable_products(self, cr, uid, ids, *args):
for order in self.browse(cr, uid, ids): for order in self.browse(cr, uid, ids):
for order_line in order.order_line: for order_line in order.order_line:
@ -285,12 +234,7 @@ class sale_order(osv.osv):
return True return True
return False return False
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
class sale_order_line(osv.osv): class sale_order_line(osv.osv):
_inherit = 'sale.order.line' _inherit = 'sale.order.line'
@ -397,7 +341,6 @@ class sale_order_line(osv.osv):
#update of result obtained in super function #update of result obtained in super function
product_obj = product_obj.browse(cr, uid, product, context=context) product_obj = product_obj.browse(cr, uid, product, context=context)
res['value']['delay'] = (product_obj.sale_delay or 0.0) res['value']['delay'] = (product_obj.sale_delay or 0.0)
#res['value']['type'] = product_obj.procure_method
#check if product is available, and if not: raise an error #check if product is available, and if not: raise an error
uom2 = False uom2 = False

View File

@ -45,7 +45,7 @@
<field name="shipped"/> <field name="shipped"/>
<field name="invoice_exists" invisible="1"/> <field name="invoice_exists" invisible="1"/>
</field> </field>
<xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='type']" position="before"> <xpath expr="//page[@string='Order Lines']/field[@name='order_line']/form[@string='Sales Order Lines']/group/group/field[@name='tax_id']" position="after">
<label for="delay"/> <label for="delay"/>
<div> <div>
<field name="delay" class="oe_inline"/> days <field name="delay" class="oe_inline"/> days

View File

@ -1,119 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<openerp> <openerp>
<data> <data>
<!-- Activity -->
<record id="act_wait_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">wait_ship</field>
</record>
<record id="act_cancel3" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">cancel3</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<record id="act_ship" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship</field>
<field name="kind">function</field>
<field name="action">action_ship_create()</field>
</record>
<record id="act_ship_except" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_except</field>
<field name="kind">function</field>
<field name="action">write({'state':'shipping_except'})</field>
</record>
<record id="act_ship_end" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_end</field>
<field name="kind">function</field>
<field name="action">action_ship_end()</field>
</record>
<record id="act_ship_cancel" model="workflow.activity">
<field name="wkf_id" ref="sale.wkf_sale"/>
<field name="name">ship_cancel</field>
<field name="flow_stop">True</field>
<field name="kind">stopall</field>
<field name="action">action_cancel()</field>
</record>
<!-- Transistion -->
<record id="trans_router_wait_ship" model="workflow.transition">
<field name="act_from" ref="sale.act_router"/>
<field name="act_to" ref="act_wait_ship"/>
</record>
<record id="trans_router_wait_invoice_shipping" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice_end"/>
<field name="condition">(order_policy=='picking')</field>
</record>
<record id="trans_wait_invoice_invoice" model="workflow.transition">
<field name="act_from" ref="sale.act_wait_invoice"/>
<field name="act_to" ref="sale.act_invoice"/>
<field name="condition">order_policy=='prepaid'</field>
</record>
<record id="trans_wait_ship_cancel3" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_cancel3"/>
<field name="signal">cancel</field>
</record>
<record id="trans_wait_ship_ship" model="workflow.transition">
<field name="act_from" ref="act_wait_ship"/>
<field name="act_to" ref="act_ship"/>
<field name="condition">(order_policy!='prepaid') or invoiced</field>
</record>
<record id="trans_ship_end_done" model="workflow.transition">
<field name="act_from" ref="act_ship_end"/>
<field name="act_to" ref="sale.act_done"/>
</record>
<record id="trans_ship_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_end"/>
<field name="trigger_model">procurement.order</field>
<field name="trigger_expr_id">procurement_lines_get()</field>
<field name="condition">test_state('finished')</field>
</record>
<record id="trans_ship_ship_except" model="workflow.transition">
<field name="act_from" ref="act_ship"/>
<field name="act_to" ref="act_ship_except"/>
<field name="condition">test_state('canceled')</field>
</record>
<record id="trans_ship_except_ship" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship"/>
<field name="signal">ship_recreate</field>
</record>
<record id="trans_ship_except_ship_end" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_end"/>
<field name="signal">ship_corrected</field>
</record>
<record id="trans_ship_except_ship_cancel" model="workflow.transition">
<field name="act_from" ref="act_ship_except"/>
<field name="act_to" ref="act_ship_cancel"/>
<field name="signal">ship_cancel</field>
</record>
</data> </data>
</openerp> </openerp>

View File

@ -1599,18 +1599,19 @@
<field name="name">Orderpoints</field> <field name="name">Orderpoints</field>
<field name="res_model">stock.warehouse.orderpoint</field> <field name="res_model">stock.warehouse.orderpoint</field>
</record> </record>
<!-->
<record model="ir.ui.view" id="product_template_form_view_procurement"> <record model="ir.ui.view" id="product_template_form_view_procurement">
<field name="name">product.template.procurement</field> <field name="name">product.template.procurement</field>
<field name="model">product.product</field> <field name="model">product.product</field>
<field name="inherit_id" ref="product.product_template_form_view"/> <field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='type']" position="after"> <xpath expr="//field[@name='standard_price']" position="after" >
<field name="route_ids" widget="many2many_tags"/> <group name="procurement_help" col="1" groups="base.group_user">
<field name="route_ids" widget="many2many_tags"/>
</group>
</xpath> </xpath>
</field> </field>
</record> </record>-->
<record id="product_search_form_view_procurment" model="ir.ui.view"> <record id="product_search_form_view_procurment" model="ir.ui.view">
<field name="name">product.search.procurment.form</field> <field name="name">product.search.procurment.form</field>
<field name="model">product.product</field> <field name="model">product.product</field>
@ -1628,9 +1629,11 @@
<field name="inherit_id" ref="product.product_normal_form_view"/> <field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//group[@name='general']" position="after" > <xpath expr="//group[@name='general']" position="after" >
<group name="procurement_help" class="oe_grey" col="1" groups="base.group_user"> <newline/>
<!--TODO: Should write explanation for different routes--> <group>
<field name="route_ids" widget="many2many_tags"/>
</group> </group>
<newline/>
</xpath> </xpath>
<xpath expr="//div[@name='buttons']" position="inside"> <xpath expr="//div[@name='buttons']" position="inside">
@ -1639,10 +1642,6 @@
<button string="Orderpoints" name="%(product_open_orderpoint)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}"/> <button string="Orderpoints" name="%(product_open_orderpoint)d" type="action" attrs="{'invisible':[('type', '=', 'service')]}"/>
</xpath> </xpath>
<xpath expr="//field[@name='type']" position="after">
<field name="route_ids" widget="many2many_tags"/>
</xpath>
<group name="procurement_uom" position="before"> <group name="procurement_uom" position="before">
<group name="delay" string="Delays"> <group name="delay" string="Delays">
<label for="produce_delay" attrs="{'invisible':[('type','=','service')]}"/> <label for="produce_delay" attrs="{'invisible':[('type','=','service')]}"/>

View File

@ -190,6 +190,7 @@ class stock_picking(osv.osv):
company = move.company_id company = move.company_id
origin = move.picking_id.name origin = move.picking_id.name
partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context) partner, user_id, currency_id = move_obj._get_master_data(cr, uid, move, company, context=context)
key = (partner.id, currency_id, company.id, user_id) key = (partner.id, currency_id, company.id, user_id)
if key not in invoices: if key not in invoices: