From 50a069816d19c0a609c6644f3491e711fce86802 Mon Sep 17 00:00:00 2001 From: Yannick Vaucher Date: Wed, 5 Nov 2014 18:44:12 +0100 Subject: [PATCH 1/2] port onchanges to API 8.0 to fix #22 --- .../model/logistic_requisition_source.py | 144 +++++++++--------- .../view/requisition_view.xml | 24 --- 2 files changed, 73 insertions(+), 95 deletions(-) diff --git a/framework_agreement_sourcing/model/logistic_requisition_source.py b/framework_agreement_sourcing/model/logistic_requisition_source.py index 7959ae7d..0e0f3e16 100644 --- a/framework_agreement_sourcing/model/logistic_requisition_source.py +++ b/framework_agreement_sourcing/model/logistic_requisition_source.py @@ -20,9 +20,9 @@ ############################################################################## from itertools import chain -from openerp.osv import orm, fields +from openerp import fields, api, osv +from openerp.osv import orm from openerp.tools.translate import _ -from openerp.addons.framework_agreement.utils import id_boilerplate class logistic_requisition_source(orm.Model): @@ -32,13 +32,15 @@ class logistic_requisition_source(orm.Model): _inherit = "logistic.requisition.source" _columns = { - 'framework_agreement_id': fields.many2one('framework.agreement', - 'Agreement'), - 'framework_agreement_po_id': fields.many2one('purchase.order', - 'Agreement Purchase'), - 'supplier_id': fields.related('framework_agreement_id', 'supplier_id', - type='many2one', relation='res.partner', - string='Agreement Supplier')} + 'framework_agreement_id': osv.fields.many2one('framework.agreement', + 'Agreement'), + 'framework_agreement_po_id': osv.fields.many2one( + 'purchase.order', + 'Agreement Purchase'), + 'supplier_id': osv.fields.related( + 'framework_agreement_id', 'supplier_id', + type='many2one', relation='res.partner', + string='Agreement Supplier')} def _get_procur_method_hook(self, cr, uid, context=None): """Adds framework agreement as a procurement method in selection @@ -260,27 +262,24 @@ def _is_sourced_fw_agreement(self, cr, uid, source, context=None): # predicate return bool(sources_ids) - # ---------------OpenERP tedious onchange management ---------------------- + # ---------------Odoo onchange management ---------------------- - def _get_date(self, cr, uid, requision_line_id, context=None): + @api.model + def _get_date(self): """helper to retrive date to be used by framework agreement when in source line context - :param source_id: requisition.line.source id that should + :param requisition_line_id: requisition.line id that should provide date :returns: date/datetime string """ - req_obj = self.pool['logistic.requisition.line'] - current = req_obj.browse(cr, uid, requision_line_id, context=context) now = fields.datetime.now() - return current.requisition_id.date or now + return self.requisition_id.date or now - @id_boilerplate - def onchange_sourcing_method(self, cr, uid, ids, method, req_line_id, - proposed_product_id, proposed_qty=0, - context=None): + @api.onchange('procurement_method') + def onchange_sourcing_method(self): """ Called when source method is set on a source line. @@ -289,50 +288,64 @@ def onchange_sourcing_method(self, cr, uid, ids, method, req_line_id, and raise quantity warning. """ - line_source = self.browse(cr, uid, ids, context=context) - res = {'value': {'framework_agreement_id': False}} - if (method != 'fw_agreement' or not proposed_product_id): - return res - currency = line_source.currency_id - agreement_obj = self.pool['framework.agreement'] - date = self._get_date(cr, uid, req_line_id, context=context) + if (self.procurement_method != 'fw_agreement' + or not self.proposed_product_id): + self.framework_agreement_id = False + return + agreement_obj = self.env['framework.agreement'] + date = self._get_date() agreement, enough_qty = agreement_obj.get_cheapest_agreement_for_qty( - cr, uid, proposed_product_id, date, proposed_qty, - currency=currency, context=context) + self.proposed_product_id.id, date, self.proposed_qty, + currency=self.currency_id) if not agreement: - return res - price = agreement.get_price(proposed_qty, currency=currency) - res['value'] = {'framework_agreement_id': agreement.id, - 'unit_cost': price, - 'total_cost': price * proposed_qty, - 'supplier_id': agreement.supplier_id.id} + self.framework_agreement_id = False + return + price = agreement.get_price(self.proposed_qty, + currency=self.currency_id) + vals = {'framework_agreement_id': agreement.id, + 'unit_cost': price, + 'total_cost': price * self.proposed_qty, + 'supplier_id': agreement.supplier_id.id} + self.write(vals) + res = {} if not enough_qty: - msg = _("You have ask for a quantity of %s \n" + msg = _("You have asked for a quantity of %s \n" " but there is only %s available" - " for current agreement") % (proposed_qty, + " for current agreement") % (self.proposed_qty, agreement.available_quantity) + res['warning'] = msg return res - @id_boilerplate - def onchange_quantity(self, cr, uid, ids, method, req_line_id, qty, - proposed_product_id, context=None): + @api.onchange('proposed_qty') + def onchange_quantity(self): """Raise a warning if agreed qty is not sufficient""" - line_source = self.browse(cr, uid, ids, context=context) - if (method != 'fw_agreement' or not proposed_product_id): - return {} - currency = line_source.currency_id - date = self._get_date(cr, uid, req_line_id, context=context) - return self.onchange_quantity_obs(cr, uid, ids, qty, date, - proposed_product_id, - currency=currency, - price_field='dummy', - context=context) - - @id_boilerplate - def onchange_product_id(self, cr, uid, ids, method, req_line_id, - proposed_product_id, proposed_qty, - context=None): + if (self.procurement_method != 'fw_agreement' + or not self.proposed_product_id): + return + agreement_obj = self.env['framework.agreement'] + date = self._get_date() + agreement, enough_qty = agreement_obj.get_cheapest_agreement_for_qty( + self.proposed_product_id.id, date, self.proposed_qty, + currency=self.currency_id) + if not agreement: + self.framework_agreement_id = False + return + self.framework_agreement_id = agreement.id + res = {} + if agreement.available_quantity < self.proposed_qty: + msg = {'title': _('Agreement Warning!'), + 'message': (_("You have ask for a quantity of %s \n" + " but there is only %s available" + " for current agreement") + % (self.proposed_qty, + agreement.available_quantity))} + + res['warning'] = msg + return res + + @api.onchange('proposed_product_id') + def onchange_product_id(self): """Call when product is set on a source line. If sourcing method is framework agreement @@ -340,20 +353,9 @@ def onchange_product_id(self, cr, uid, ids, method, req_line_id, and raise quantity warning. """ - if method != 'fw_agreement': - if proposed_product_id: - value = {'proposed_uom_id': ''} - if proposed_product_id: - prod_obj = self.pool.get('product.product') - prod = prod_obj.browse( - cr, uid, proposed_product_id, context=context) - value = { - 'proposed_uom_id': prod.uom_id.id, - } - return {'value': value} - return {} - - return self.onchange_sourcing_method(cr, uid, ids, method, req_line_id, - proposed_product_id, - proposed_qty=proposed_qty, - context=context) + if self.procurement_method != 'fw_agreement': + if self.proposed_product_id: + self.proposed_uom_id = self.proposed_product_id.uom_id or False + return + + return self.onchange_sourcing_method() diff --git a/framework_agreement_sourcing/view/requisition_view.xml b/framework_agreement_sourcing/view/requisition_view.xml index 9c59e0d2..ff44731e 100644 --- a/framework_agreement_sourcing/view/requisition_view.xml +++ b/framework_agreement_sourcing/view/requisition_view.xml @@ -40,29 +40,5 @@ - - ad agreement source line onchange - logistic.requisition.source - - - - - onchange_sourcing_method(procurement_method, requisition_line_id, proposed_product_id, proposed_qty) - - - - onchange_quantity(procurement_method, requisition_line_id, proposed_qty, proposed_product_id) - - - onchange_product_id(procurement_method, requisition_line_id, proposed_product_id, proposed_qty) - - - - - - From e350d69fdf89fd0a7fa74fc473578c3f17db2376 Mon Sep 17 00:00:00 2001 From: Yannick Vaucher Date: Thu, 6 Nov 2014 10:33:09 +0100 Subject: [PATCH 2/2] Add a second search when no agreement is found This restore former warning message when we can find an agreement with not enough quantities This allow to find and finish the framework agreement almost finished. As it is preferable to finish agreements completely instead of contracting new ones and be left with multiple remainings of agreements. --- .../model/logistic_requisition_source.py | 107 ++++++++++-------- 1 file changed, 61 insertions(+), 46 deletions(-) diff --git a/framework_agreement_sourcing/model/logistic_requisition_source.py b/framework_agreement_sourcing/model/logistic_requisition_source.py index 0e0f3e16..9f75e520 100644 --- a/framework_agreement_sourcing/model/logistic_requisition_source.py +++ b/framework_agreement_sourcing/model/logistic_requisition_source.py @@ -2,7 +2,7 @@ ############################################################################## # # Author: Nicolas Bessi -# Copyright 2013 Camptocamp SA +# Copyright 2013-2014 Camptocamp SA # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -278,6 +278,61 @@ def _get_date(self): now = fields.datetime.now() return self.requisition_id.date or now + @api.multi + def _check_enought_qty(self, agreement): + """ Raise a warning if quantity is not enough + to fullfil completely the sourcing + + :returns: dict with warning message + + """ + if self.proposed_qty > agreement.available_quantity: + msg = _("You have asked for a quantity of %s \n" + " but there is only %s available" + " for current agreement") % (self.proposed_qty, + agreement.available_quantity) + + return {'warning': {'message': msg}} + + @api.multi + def _get_best_agreement(self): + """ Search for an agreement with enough quantity + and if not find, search for an agreement without + specifying qty + + :returns: agreement record + + """ + agreement_obj = self.env['framework.agreement'] + date = self._get_date() + agreement, __ = agreement_obj.get_cheapest_agreement_for_qty( + self.proposed_product_id.id, date, qty=self.proposed_qty, + currency=self.currency_id) + if not agreement: + agreement, __ = agreement_obj.get_cheapest_agreement_for_qty( + self.proposed_product_id.id, date, qty=None, + currency=self.currency_id) + return agreement + + @api.multi + def _onchange_base_agreement_method(self): + """ When agreement method basics change, + we want to find a proper agreement, + update price and supplier based on this agreement. + + """ + agreement = self._get_best_agreement() + if not agreement: + self.framework_agreement_id = False + return + price = agreement.get_price(self.proposed_qty, + currency=self.currency_id) + self.framework_agreement_id = agreement.id + self.unit_cost = price + self.total_cost = price * self.proposed_qty + self.supplier_id = agreement.supplier_id.id + return self._check_enought_qty(agreement) + @api.onchange('procurement_method') def onchange_sourcing_method(self): """ @@ -292,30 +347,7 @@ def onchange_sourcing_method(self): or not self.proposed_product_id): self.framework_agreement_id = False return - agreement_obj = self.env['framework.agreement'] - date = self._get_date() - agreement, enough_qty = agreement_obj.get_cheapest_agreement_for_qty( - self.proposed_product_id.id, date, self.proposed_qty, - currency=self.currency_id) - if not agreement: - self.framework_agreement_id = False - return - price = agreement.get_price(self.proposed_qty, - currency=self.currency_id) - vals = {'framework_agreement_id': agreement.id, - 'unit_cost': price, - 'total_cost': price * self.proposed_qty, - 'supplier_id': agreement.supplier_id.id} - self.write(vals) - res = {} - if not enough_qty: - msg = _("You have asked for a quantity of %s \n" - " but there is only %s available" - " for current agreement") % (self.proposed_qty, - agreement.available_quantity) - - res['warning'] = msg - return res + return self._onchange_base_agreement_method() @api.onchange('proposed_qty') def onchange_quantity(self): @@ -323,26 +355,10 @@ def onchange_quantity(self): if (self.procurement_method != 'fw_agreement' or not self.proposed_product_id): return - agreement_obj = self.env['framework.agreement'] - date = self._get_date() - agreement, enough_qty = agreement_obj.get_cheapest_agreement_for_qty( - self.proposed_product_id.id, date, self.proposed_qty, - currency=self.currency_id) - if not agreement: - self.framework_agreement_id = False - return + agreement = self._get_best_agreement() self.framework_agreement_id = agreement.id - res = {} - if agreement.available_quantity < self.proposed_qty: - msg = {'title': _('Agreement Warning!'), - 'message': (_("You have ask for a quantity of %s \n" - " but there is only %s available" - " for current agreement") - % (self.proposed_qty, - agreement.available_quantity))} - - res['warning'] = msg - return res + if agreement: + return self._check_enought_qty(agreement) @api.onchange('proposed_product_id') def onchange_product_id(self): @@ -357,5 +373,4 @@ def onchange_product_id(self): if self.proposed_product_id: self.proposed_uom_id = self.proposed_product_id.uom_id or False return - - return self.onchange_sourcing_method() + return self._onchange_base_agreement_method()