From af7cf8a2263f92235d0c3c28218fe207d1d6da45 Mon Sep 17 00:00:00 2001 From: "Quentin (OpenERP)" Date: Wed, 10 Jul 2013 17:00:42 +0200 Subject: [PATCH] [WIP] procurement, project_mrp bzr revid: qdp-launchpad@openerp.com-20130710150042-djynhii0hrib2rlk --- addons/procurement/procurement.py | 23 ++++-- addons/project_mrp/__init__.py | 1 - addons/project_mrp/project_mrp.py | 75 +++++++++++++---- addons/project_mrp/project_procurement.py | 98 ----------------------- addons/purchase/purchase.py | 12 +-- addons/sale_stock/sale_stock.py | 3 +- 6 files changed, 83 insertions(+), 129 deletions(-) delete mode 100644 addons/project_mrp/project_procurement.py diff --git a/addons/procurement/procurement.py b/addons/procurement/procurement.py index 282680aff36..d3bb42208a7 100644 --- a/addons/procurement/procurement.py +++ b/addons/procurement/procurement.py @@ -142,10 +142,8 @@ class procurement_order(osv.osv): return {} def run(self, cr, uid, ids, context=None): - for procurement in self.browse(cr, uid, ids, context=context or {}): - rule = self.pool.get("procurement.rule").browse(cr, uid, self._assign(cr, uid, procurement, context=context), context=context) - if rule: - self.write(cr, uid, [procurement.id], {'rule_id': rule.id}, context=context) + for procurement in self.browse(cr, uid, ids, context=context): + if self._assign(cr, uid, procurement, context=context): procurement.refresh() self._run(cr, uid, procurement, context=context or {}) self.write(cr, uid, [procurement.id], {'state': 'running'}, context=context) @@ -166,14 +164,27 @@ class procurement_order(osv.osv): # # Method to overwrite in different procurement modules # - def _assign(self, cr, uid, procurement, context=None): - '''This method returns a procurement.rule that depicts what to go with the given procurement + def _find_suitable_rule(self, cr, uid, procurement, context=None): + '''This method returns a procurement.rule that depicts what to do with the given procurement in order to complete its needs. It returns False if no suiting rule is found. :param procurement: browse record :rtype: int or False ''' return False + def _assign(self, cr, uid, procurement, context=None): + '''This method check what to do with the given procurement in order to complete its needs. + It returns False if no solution is found, otherwise it stores the matching rule (if any) and + returns True. + :param procurement: browse record + :rtype: boolean + ''' + rule_id = self._find_suitable_rule(cr, uid, procurement, context=context) + if rule_id: + self.write(cr, uid, [procurement.id], {'rule_id': rule_id}, context=context) + return True + return False + def _run(self, cr, uid, procurement, context=None): '''This method implements the resolution of the given procurement :param procurement: browse record diff --git a/addons/project_mrp/__init__.py b/addons/project_mrp/__init__.py index df4f0fa8a52..c0c3172c29f 100644 --- a/addons/project_mrp/__init__.py +++ b/addons/project_mrp/__init__.py @@ -19,7 +19,6 @@ # ############################################################################## -import project_procurement import project_mrp # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/project_mrp/project_mrp.py b/addons/project_mrp/project_mrp.py index bb25b4aae24..081a34380bb 100644 --- a/addons/project_mrp/project_mrp.py +++ b/addons/project_mrp/project_mrp.py @@ -21,6 +21,56 @@ from openerp.osv import fields, osv from openerp import netsvc +from openerp.tools.translate import _ + +class procurement_order(osv.osv): + _name = "procurement.order" + _inherit = "procurement.order" + _columns = { + 'task_id': fields.many2one('project.task', 'Task'), + 'sale_line_id': fields.many2one('sale.order.line', 'Sales order line') + } + + def _is_procurement_task(self, cr, uid, procurement, context=None): + return procurement.product_id.type == 'service' and procurement.product_it.auto_create_task or False + + def _assign(self, cr, uid, procurement, context=None): + res = super(procurement_order, self)._assign(cr, uid, procurement, context=context) + if not res: + #if there isn't any specific procurement.rule defined for the product, we may want to create a task + if self._is_procurement_task(cr, uid, procurement, context=context): + return True + return res + + def _run(self, cr, uid, procurement, context=None): + if self._is_procurement_task(cr, uid, procurement, context=context) and not procurement.task_id: + #create a task for the procurement + return self._create_service_task(cr, uid, procurement, context=context) + return super(procurement_order, self)._run(cr, uid, procurement, context=context) + + 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': + return True + return super(procurement_order, self)._check(cr, uid, procurement, context=context) + + def _convert_qty_company_hours(self, cr, uid, procurement, context=None): + product_uom = self.pool.get('product.uom') + company_time_uom_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.project_time_mode_id + if procurement.product_uom.id != company_time_uom_id.id and procurement.product_uom.category_id.id == company_time_uom_id.category_id.id: + planned_hours = product_uom._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, company_time_uom_id.id) + else: + planned_hours = procurement.product_qty + return planned_hours + + def _get_project(self, cr, uid, procurement, context=None): + project_project = self.pool.get('project.project') + project = procurement.product_id.project_id + if not project and procurement.sale_line_id: + # find the project corresponding to the analytic account of the sales order + account = procurement.sale_line_id.order_id.project_id + project_ids = project_project.search(cr, uid, [('analytic_account_id', '=', account.id)]) + projects = project_project.browse(cr, uid, project_ids, context=context) + class project_task(osv.osv): _name = "project.task" @@ -30,30 +80,21 @@ class project_task(osv.osv): 'sale_line_id': fields.related('procurement_id', 'sale_line_id', type='many2one', relation='sale.order.line', store=True, string='Sales Order Line'), } - def _validate_subflows(self, cr, uid, ids): - wf_service = netsvc.LocalService("workflow") - for task in self.browse(cr, uid, ids): - if task.procurement_id: - wf_service.trg_write(uid, 'procurement.order', task.procurement_id.id, cr) - - def do_close(self, cr, uid, ids, *args, **kwargs): - res = super(project_task, self).do_close(cr, uid, ids, *args, **kwargs) - self._validate_subflows(cr, uid, ids) - return res - - def do_cancel(self, cr, uid, ids, *args, **kwargs): - res = super(project_task, self).do_cancel(cr, uid, ids, *args, **kwargs) - self._validate_subflows(cr, uid, ids) - return res + #TODO handle the task cancellation + #def do_cancel(self, cr, uid, ids, *args, **kwargs): + # res = super(project_task, self).do_cancel(cr, uid, ids, *args, **kwargs) + # self._validate_subflows(cr, uid, ids) + # return res class product_product(osv.osv): _inherit = "product.product" _columns = { - 'project_id': fields.many2one('project.project', 'Project', ondelete='set null',) + 'project_id': fields.many2one('project.project', 'Project', ondelete='set null',), + 'auto_create_task': fields.boolean('Create Task Automatically', help="Thick this option if you want to create a task automatically each time this product is sold"), } class sale_order(osv.osv): - _inherit ='sale.order' + _inherit = 'sale.order' def _prepare_order_line_procurement(self, cr, uid, order, line, move_id, date_planned, context=None): proc_data = super(sale_order, self)._prepare_order_line_procurement(cr, diff --git a/addons/project_mrp/project_procurement.py b/addons/project_mrp/project_procurement.py deleted file mode 100644 index f4b4a28db46..00000000000 --- a/addons/project_mrp/project_procurement.py +++ /dev/null @@ -1,98 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# OpenERP, Open Source Management Solution -# Copyright (C) 2004-2010 Tiny SPRL (). -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -############################################################################## - -from openerp.osv import fields, osv -from openerp.tools.translate import _ - -class procurement_order(osv.osv): - _name = "procurement.order" - _inherit = "procurement.order" - _columns = { - 'task_id': fields.many2one('project.task', 'Task'), - 'sale_line_id': fields.many2one('sale.order.line', 'Sales order line') - } - - def action_check_finished(self, cr, uid, ids): - res = super(procurement_order, self).action_check_finished(cr, uid, ids) - return res and self.check_task_done(cr, uid, ids) - - def check_task_done(self, cr, uid, ids, context=None): - """ Checks if task is done or not. - @return: True or False. - """ - for p in self.browse(cr, uid, ids, context=context): - if (p.product_id.type=='service') and (p.procure_method=='make_to_order') and p.task_id and (p.task_id.state not in ('done', 'cancelled')): - return False - return True - - def check_produce_service(self, cr, uid, procurement, context=None): - return True - - def _convert_qty_company_hours(self, cr, uid, procurement, context=None): - product_uom = self.pool.get('product.uom') - company_time_uom_id = self.pool.get('res.users').browse(cr, uid, uid).company_id.project_time_mode_id - if procurement.product_uom.id != company_time_uom_id.id and procurement.product_uom.category_id.id == company_time_uom_id.category_id.id: - planned_hours = product_uom._compute_qty(cr, uid, procurement.product_uom.id, procurement.product_qty, company_time_uom_id.id) - else: - planned_hours = procurement.product_qty - return planned_hours - - def _get_project(self, cr, uid, procurement, context=None): - project_project = self.pool.get('project.project') - project = procurement.product_id.project_id - if not project and procurement.sale_line_id: - # find the project corresponding to the analytic account of the sales order - account = procurement.sale_line_id.order_id.project_id - project_ids = project_project.search(cr, uid, [('analytic_account_id', '=', account.id)]) - projects = project_project.browse(cr, uid, project_ids, context=context) - project = projects and projects[0] or False - return project - - def action_produce_assign_service(self, cr, uid, ids, context=None): - project_task = self.pool.get('project.task') - for procurement in self.browse(cr, uid, ids, context=context): - 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' + (procurement.note or ''), - '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, 'state': 'running', 'message':_('Task created.')}, context=context) - self.project_task_create_note(cr, uid, ids, 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) - - -# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 08bcaa52f3b..f0d796ff31e 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -1034,14 +1034,14 @@ class procurement_order(osv.osv): 'purchase_id': fields.many2one('purchase.order', 'Purchase Order'), } - def _assign(self, cr, uid, procurement, context=None): - rule = super(procurement_order, self)._assign(cr, uid, procurement, context=context) - if not rule: + def _find_suitable_rule(self, cr, uid, procurement, context=None): + rule_id = super(procurement_order, self)._find_suitable_rule(cr, uid, procurement, context=context) + if not rule_id: #if there isn't any specific procurement.rule defined for the product, we try to directly supply it from a supplier if procurement.product_id.supply_method == 'buy' and self._check_supplier_info(cr, uid, [procurement.id], context=context): - rule = self.pool.get('procurement.rule').search(cr, uid, [('action', '=', 'buy'), ('location_id', '=', procurement.location_id.id)], context=context) - rule = rule and rule[0] or False - return rule + rule_id = self.pool.get('procurement.rule').search(cr, uid, [('action', '=', 'buy'), ('location_id', '=', procurement.location_id.id)], context=context) + rule_id = rule_id and rule_id[0] or False + return rule_id def _run(self, cr, uid, procurement, context=None): if procurement.rule_id and procurement.rule_id.action == 'buy': diff --git a/addons/sale_stock/sale_stock.py b/addons/sale_stock/sale_stock.py index a3b489e2766..38a8d77ebbc 100644 --- a/addons/sale_stock/sale_stock.py +++ b/addons/sale_stock/sale_stock.py @@ -55,7 +55,7 @@ class sale_order(osv.osv): ('shipping_except', 'Shipping Exception'), ('invoice_except', 'Invoice Exception'), ('done', 'Done'), - ], 'Status', readonly=True,help="Gives the status of the quotation or sales order.\ + ], '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), @@ -494,3 +494,4 @@ class sale_advance_payment_inv(osv.osv_memory): } sale_line_obj.create(cr, uid, vals, context=context) return result +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: