From de76a64f7e310023ad94f35c5442cd57672ec88f Mon Sep 17 00:00:00 2001 From: Alexis de Lattre Date: Wed, 27 May 2015 11:02:07 +0200 Subject: [PATCH] Split procurement_suggest in 2 modules : procurement_suggest + procurement_suggest_purchase --- procurement_suggest/__openerp__.py | 5 +- .../wizard/procurement_suggest.py | 110 ++++++------------ .../wizard/procurement_suggest_view.xml | 22 ++-- procurement_suggest_purchase/__init__.py | 3 + procurement_suggest_purchase/__openerp__.py | 45 +++++++ .../wizard/__init__.py | 3 + .../wizard/procurement_suggest.py | 75 ++++++++++++ .../wizard/procurement_suggest_view.xml | 27 +++++ 8 files changed, 199 insertions(+), 91 deletions(-) create mode 100644 procurement_suggest_purchase/__init__.py create mode 100644 procurement_suggest_purchase/__openerp__.py create mode 100644 procurement_suggest_purchase/wizard/__init__.py create mode 100644 procurement_suggest_purchase/wizard/procurement_suggest.py create mode 100644 procurement_suggest_purchase/wizard/procurement_suggest_view.xml diff --git a/procurement_suggest/__openerp__.py b/procurement_suggest/__openerp__.py index fa4dea0..26412ae 100644 --- a/procurement_suggest/__openerp__.py +++ b/procurement_suggest/__openerp__.py @@ -33,14 +33,11 @@ Procurement Suggest TODO -Roadmap : split the module in 2 and move the purchase-specific part in a module -that has a dependancy on this module and purchase. This module will then not have a depandancy on purchase any more. - This module has been written by Alexis de Lattre from Akretion . """, 'author': 'Akretion', 'website': 'http://www.akretion.com', - 'depends': ['stock', 'purchase'], + 'depends': ['stock'], 'data': [ 'stock_view.xml', 'wizard/procurement_suggest_view.xml', diff --git a/procurement_suggest/wizard/procurement_suggest.py b/procurement_suggest/wizard/procurement_suggest.py index 53c781b..bf20ef1 100644 --- a/procurement_suggest/wizard/procurement_suggest.py +++ b/procurement_suggest/wizard/procurement_suggest.py @@ -40,14 +40,6 @@ class ProcurementSuggestionGenerate(models.TransientModel): @api.model def _prepare_suggest_line(self, orderpoint): - porderline_id = False - if orderpoint.product_id.seller_id: - porderlines = self.env['purchase.order.line'].search([ - ('state', 'not in', ('draft', 'cancel')), - ('product_id', '=', orderpoint.product_id.id)], - order='id desc', limit=1) - # I cannot filter on 'date_order' because it is not a stored field - porderline_id = porderlines and porderlines[0].id or False sline = { 'product_id': orderpoint.product_id.id, 'seller_id': orderpoint.product_id.seller_id.id or False, @@ -55,7 +47,6 @@ class ProcurementSuggestionGenerate(models.TransientModel): 'incoming_qty': orderpoint.product_id.incoming_qty, 'outgoing_qty': orderpoint.product_id.outgoing_qty, 'orderpoint_id': orderpoint.id, - 'last_po_line_id': porderline_id, } return sline @@ -82,6 +73,7 @@ class ProcurementSuggestionGenerate(models.TransientModel): p_suggest_lines = [] lines = {} # key = product_id ; value = {'min_qty', ...} for op in ops: + # TODO : take into account the running procurements ? if op.product_id.virtual_available < op.product_min_qty: if op.product_id.id in lines: raise Warning( @@ -130,89 +122,55 @@ class ProcurementSuggest(models.TransientModel): outgoing_qty = fields.Float( string='Outgoing Quantity', readonly=True, digits=dp.get_precision('Product Unit of Measure')) - last_po_line_id = fields.Many2one( - 'purchase.order.line', string='Last Purchase Order Line', - readonly=True) - last_po_date = fields.Datetime( - related='last_po_line_id.order_id.date_order', - string='Date of the last PO', readonly=True) - last_po_qty = fields.Float( - related='last_po_line_id.product_qty', readonly=True, - string='Quantity of the Last Order') orderpoint_id = fields.Many2one( 'stock.warehouse.orderpoint', string='Re-ordering Rule', readonly=True) + uom_id = fields.Many2one( + 'product.uom', related='product_id.uom_id', readonly=True) + # on orderpoids, uom_id is a related field of product_id.uom_id + # so I do the same here min_qty = fields.Float( string="Min Quantity", readonly=True, related='orderpoint_id.product_min_qty', digits=dp.get_precision('Product Unit of Measure')) - qty_to_order = fields.Float( - string='Quantity to Order', + procurement_qty = fields.Float( + string='Procurement Quantity', digits=dp.get_precision('Product Unit of Measure')) -class ProcurementSuggestPoCreate(models.TransientModel): - _name = 'procurement.suggest.po.create' - _description = 'ProcurementSuggestPoCreate' +class ProcurementCreateFromSuggest(models.TransientModel): + _name = 'procurement.create.from.suggest' + _description = 'Create Procurements from Procurement Suggestions' @api.model - def _prepare_purchase_order_vals(self, partner, po_lines): - polo = self.pool['purchase.order.line'] - ponull = self.env['purchase.order'].browse(False) - po_vals = {'partner_id': partner.id} - partner_change_dict = ponull.onchange_partner_id(partner.id) - po_vals.update(partner_change_dict['value']) - picking_type_id = self.env['purchase.order']._get_picking_in() - picking_type_dict = ponull.onchange_picking_type_id(picking_type_id) - po_vals.update(picking_type_dict['value']) - order_lines = [] - for product, qty_to_order in po_lines: - product_change_res = polo.onchange_product_id( - self._cr, self._uid, [], - partner.property_product_pricelist_purchase.id, - product.id, qty_to_order, False, partner.id, - fiscal_position_id=partner.property_account_position.id, - context=self.env.context) - product_change_vals = product_change_res['value'] - taxes_id_vals = [] - if product_change_vals.get('taxes_id'): - for tax_id in product_change_vals['taxes_id']: - taxes_id_vals.append((4, tax_id)) - product_change_vals['taxes_id'] = taxes_id_vals - order_lines.append( - [0, 0, dict(product_change_vals, product_id=product.id)]) - po_vals['order_line'] = order_lines - return po_vals + def _prepare_procurement_order(self, proc_suggest): + proc_vals = { + 'name': u'INT: ' + unicode(self.env.user.login), + 'product_id': proc_suggest.product_id.id, + 'product_qty': proc_suggest.procurement_qty, + 'product_uom': proc_suggest.uom_id.id, + 'location_id': proc_suggest.orderpoint_id.location_id.id, + 'company_id': proc_suggest.orderpoint_id.company_id.id, + 'origin': _('Procurement Suggest'), + } + return proc_vals @api.multi - def create_po(self): + def create_proc(self): self.ensure_one() - # group by supplier - po_to_create = {} # key = seller_id, value = [(product, qty)] psuggest_ids = self.env.context.get('active_ids') + poo = self.env['procurement.order'] + new_procs = poo.browse(False) for line in self.env['procurement.suggest'].browse(psuggest_ids): - if not line.qty_to_order: - continue - if line.seller_id in po_to_create: - po_to_create[line.seller_id].append( - (line.product_id, line.qty_to_order)) - else: - po_to_create[line.seller_id] = [ - (line.product_id, line.qty_to_order)] - new_po_ids = [] - for seller, po_lines in po_to_create.iteritems(): - po_vals = self._prepare_purchase_order_vals( - seller, po_lines) - new_po = self.env['purchase.order'].create(po_vals) - new_po_ids.append(new_po.id) - - if not new_po_ids: - raise Warning(_('No purchase orders created')) + if line.procurement_qty: + vals = self._prepare_procurement_order(line) + new_procs += poo.create(vals) + if new_procs: + new_procs.signal_workflow('button_confirm') + new_procs.run() + else: + raise Warning(_('All requested quantities are null.')) action = self.env['ir.actions.act_window'].for_xml_id( - 'purchase', 'purchase_rfq') - action.update({ - 'nodestroy': False, - 'target': 'current', - 'domain': [('id', 'in', new_po_ids)], - }) + 'procurement', 'procurement_action') + action['domain'] = [('id', 'in', new_procs.ids)] return action diff --git a/procurement_suggest/wizard/procurement_suggest_view.xml b/procurement_suggest/wizard/procurement_suggest_view.xml index a00dce4..8b4b397 100644 --- a/procurement_suggest/wizard/procurement_suggest_view.xml +++ b/procurement_suggest/wizard/procurement_suggest_view.xml @@ -50,9 +50,8 @@ - - - + + @@ -77,29 +76,30 @@ procurement.suggest tree new + 500 - - procurement_suggest_po_create.form - procurement.suggest.po.create + + procurement_create_from_suggest.form + procurement.create.from.suggest

- This wizard will create Purchase Orders. + This wizard will create procurements and confirm them, so that it creates purchase orders or manufacturing orders.

-
- diff --git a/procurement_suggest_purchase/__init__.py b/procurement_suggest_purchase/__init__.py new file mode 100644 index 0000000..9809b86 --- /dev/null +++ b/procurement_suggest_purchase/__init__.py @@ -0,0 +1,3 @@ +# -*- encoding: utf-8 -*- + +from . import wizard diff --git a/procurement_suggest_purchase/__openerp__.py b/procurement_suggest_purchase/__openerp__.py new file mode 100644 index 0000000..24a20e9 --- /dev/null +++ b/procurement_suggest_purchase/__openerp__.py @@ -0,0 +1,45 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Procurement Suggest Purchase module for Odoo +# Copyright (C) 2015 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# 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 . +# +############################################################################## + + +{ + 'name': 'Procurement Suggest Purchase', + 'version': '0.1', + 'category': 'Procurements', + 'license': 'AGPL-3', + 'summary': 'Usability enhancements to procurement suggest for purchase', + 'description': """ +Procurement Suggest Purchase +============================ + +TODO + +This module has been written by Alexis de Lattre from Akretion . + """, + 'author': 'Akretion', + 'website': 'http://www.akretion.com', + 'depends': ['purchase', 'procurement_suggest'], + 'data': [ + 'wizard/procurement_suggest_view.xml', + ], + 'installable': True, +} diff --git a/procurement_suggest_purchase/wizard/__init__.py b/procurement_suggest_purchase/wizard/__init__.py new file mode 100644 index 0000000..ecb4ed5 --- /dev/null +++ b/procurement_suggest_purchase/wizard/__init__.py @@ -0,0 +1,3 @@ +# -*- encoding: utf-8 -*- + +from . import procurement_suggest diff --git a/procurement_suggest_purchase/wizard/procurement_suggest.py b/procurement_suggest_purchase/wizard/procurement_suggest.py new file mode 100644 index 0000000..21f64ac --- /dev/null +++ b/procurement_suggest_purchase/wizard/procurement_suggest.py @@ -0,0 +1,75 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Procurement Suggest Purchase module for Odoo +# Copyright (C) 2015 Akretion (http://www.akretion.com) +# @author Alexis de Lattre +# +# 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 import models, fields, api + + +class ProcurementSuggestionGenerate(models.TransientModel): + _inherit = 'procurement.suggest.generate' + + @api.model + def _prepare_suggest_line(self, orderpoint): + sline = super(ProcurementSuggestionGenerate, self).\ + _prepare_suggest_line(orderpoint) + porderline_id = False + if orderpoint.product_id.seller_id: + porderlines = self.env['purchase.order.line'].search([ + ('state', 'not in', ('draft', 'cancel')), + ('product_id', '=', orderpoint.product_id.id)], + order='id desc', limit=1) + # I cannot filter on 'date_order' because it is not a stored field + porderline_id = porderlines and porderlines[0].id or False + sline['last_po_line_id'] = porderline_id + return sline + + +class ProcurementSuggest(models.TransientModel): + _inherit = 'procurement.suggest' + + last_po_line_id = fields.Many2one( + 'purchase.order.line', string='Last Purchase Order Line', + readonly=True) + last_po_date = fields.Datetime( + related='last_po_line_id.order_id.date_order', + string='Date of the last PO', readonly=True) + last_po_qty = fields.Float( + related='last_po_line_id.product_qty', readonly=True, + string='Quantity of the Last Order') + + +class ProcurementCreateFromSuggest(models.TransientModel): + _inherit = 'procurement.create.from.suggest' + + @api.multi + def create_proc(self): + action = super(ProcurementCreateFromSuggest, self).create_proc() + poo = self.env['procurement.order'] + new_procs = poo.browse(action['domain'][0][2]) + po_ids = [] + for proc in new_procs: + if proc.purchase_id and proc.purchase_id.id not in po_ids: + po_ids.append(proc.purchase_id.id) + if po_ids: + action = self.env['ir.actions.act_window'].for_xml_id( + 'purchase', 'purchase_rfq') + action['domain'] = [('id', 'in', po_ids)] + return action diff --git a/procurement_suggest_purchase/wizard/procurement_suggest_view.xml b/procurement_suggest_purchase/wizard/procurement_suggest_view.xml new file mode 100644 index 0000000..b9f1e1d --- /dev/null +++ b/procurement_suggest_purchase/wizard/procurement_suggest_view.xml @@ -0,0 +1,27 @@ + + + + + + + + + + procurement_suggest.tree + procurement.suggest + + + + + + + + + + + +