From eda6864dab73ecd8c68022b19169f55b107ddb6a Mon Sep 17 00:00:00 2001 From: Leonardo Pistone Date: Tue, 17 Mar 2015 12:35:46 +0100 Subject: [PATCH] make stock_reserve_sale owner_aware --- stock_reserve_sale/__openerp__.py | 13 +++++-- stock_reserve_sale/test/sale_line_reserve.yml | 16 +++------ stock_reserve_sale/test/sale_reserve.yml | 18 +++++----- .../wizard/sale_stock_reserve.py | 35 +++++++++++++++++-- .../wizard/sale_stock_reserve_view.xml | 1 + 5 files changed, 55 insertions(+), 28 deletions(-) diff --git a/stock_reserve_sale/__openerp__.py b/stock_reserve_sale/__openerp__.py index be0ae3152..3fa481478 100644 --- a/stock_reserve_sale/__openerp__.py +++ b/stock_reserve_sale/__openerp__.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- ############################################################################## # -# Author: Guewen Baconnier -# Copyright 2013 Camptocamp SA +# Author: Guewen Baconnier, Leonardo Pistone +# Copyright 2013-2015 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 @@ -20,7 +20,7 @@ ############################################################################## {'name': 'Stock Reserve Sales', - 'version': '0.1', + 'version': '1.0', 'author': "Camptocamp,Odoo Community Association (OCA)", 'category': 'Warehouse', 'license': 'AGPL-3', @@ -48,6 +48,13 @@ If you want to prevent sales orders to be confirmed when the stock is insufficient at the order date, you may want to install the `sale_exception_nostock` module. +Additionally, if the sale_owner_stock_sourcing module is installed, the owner +specified on the sale order line will be proposed as owner of the reservation. +If you try to make a reservation for an order whose lines have different, you +will get a message suggesting to reserve each line individually. There is no +module dependency: this modules is fully functional even without ownership +management. + """, 'depends': ['sale_stock', 'stock_reserve', diff --git a/stock_reserve_sale/test/sale_line_reserve.yml b/stock_reserve_sale/test/sale_line_reserve.yml index 421d5da2f..0a798c3c2 100644 --- a/stock_reserve_sale/test/sale_line_reserve.yml +++ b/stock_reserve_sale/test/sale_line_reserve.yml @@ -41,18 +41,14 @@ order_id: sale_reserve_02 - And I create a stock reserve for this line -- - !record {model: sale.stock.reserve, id: wizard_reserve_02_01}: - note: Reservation for the sales order line -- - I call the wizard to reserve the products of the sales order - !python {model: sale.stock.reserve}: | active_id = ref('sale_line_reserve_02_01') context['active_id'] = active_id context['active_ids'] = [active_id] context['active_model'] = 'sale.order.line' - self.button_reserve(cr, uid, [ref('wizard_reserve_02_01')], context=context) + wizard_id = self.create(cr, uid, {}, context=context) + self.button_reserve(cr, uid, [wizard_id], context=context) - I check Virtual stock of yogurt after update reservation - @@ -83,18 +79,14 @@ product_uom: product.product_uom_unit - And I try to create a stock reserve for this MTO line -- - !record {model: sale.stock.reserve, id: wizard_reserve_02_02}: - note: Reservation for the sales order line -- - I call the wizard to reserve the products of the sales order - !python {model: sale.stock.reserve}: | active_id = ref('sale_line_reserve_02_02') context['active_id'] = active_id context['active_ids'] = [active_id] context['active_model'] = 'sale.order.line' - self.button_reserve(cr, uid, [ref('wizard_reserve_02_02')], context=context) + wizard_id = self.create(cr, uid, {}, context=context) + self.button_reserve(cr, uid, [wizard_id], context=context) - I should not have a stock reservation for a MTO line - diff --git a/stock_reserve_sale/test/sale_reserve.yml b/stock_reserve_sale/test/sale_reserve.yml index 2671f40e1..9afc4dff9 100644 --- a/stock_reserve_sale/test/sale_reserve.yml +++ b/stock_reserve_sale/test/sale_reserve.yml @@ -35,22 +35,20 @@ product_uom_qty: 4 - I call the wizard to reserve the products of the sales order -- - !record {model: sale.stock.reserve, id: wizard_reserve_01}: - note: Reservation for the sales order - !python {model: sale.stock.reserve}: | active_id = ref('sale_reserve_01') context['active_id'] = active_id context['active_ids'] = [active_id] context['active_model'] = 'sale.order' - self.button_reserve(cr, uid, [ref('wizard_reserve_01')], context=context) + wizard_id = self.create(cr, uid, {}, context=context) + self.button_reserve(cr, uid, [wizard_id], context=context) - I check Virtual stock of Gelato after update reservation - - !python {model: product.product}: | - product = self.browse(cr, uid, ref('product_gelato'), context=context) - assert product.virtual_available == 6, "Stock is not updated." + !python {model: product.product, id: product_gelato}: | + from nose.tools import * + assert_almost_equal(self.virtual_available, 6.0) - I release the sales order's reservations - @@ -59,6 +57,6 @@ - I check Virtual stock of Gelato after release of reservations - - !python {model: product.product}: | - product = self.browse(cr, uid, ref('product_gelato'), context=context) - assert product.virtual_available == 10, "Stock is not updated." + !python {model: product.product, id: product_gelato}: | + from nose.tools import * + assert_almost_equal(self.virtual_available, 10.0) diff --git a/stock_reserve_sale/wizard/sale_stock_reserve.py b/stock_reserve_sale/wizard/sale_stock_reserve.py index 2fc7d1ff1..67d9fb313 100644 --- a/stock_reserve_sale/wizard/sale_stock_reserve.py +++ b/stock_reserve_sale/wizard/sale_stock_reserve.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- ############################################################################## # -# Author: Guewen Baconnier -# Copyright 2013 Camptocamp SA +# Author: Guewen Baconnier, Leonardo Pistone +# Copyright 2013-2015 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 @@ -19,7 +19,7 @@ # ############################################################################## -from openerp import models, fields, api +from openerp import models, fields, api, exceptions class SaleStockReserve(models.TransientModel): @@ -33,6 +33,32 @@ class SaleStockReserve(models.TransientModel): def _default_location_dest_id(self): return self.env['stock.reservation']._default_location_dest_id() + def _default_owner(self): + """If sale_owner_stock_sourcing is installed, it adds an owner field + on sale order lines. Use it. + + """ + model = self.env[self.env.context['active_model']] + if model._name == 'sale.order': + lines = model.browse(self.env.context['active_id']).order_line + else: + lines = model.browse(self.env.context['active_ids']) + + try: + owners = set([l.stock_owner_id for l in lines]) + except AttributeError: + return self.env['res.partner'] + # module sale_owner_stock_sourcing not installed, fine + + if len(owners) == 1: + return owners.pop() + elif len(owners) > 1: + raise exceptions.Warning( + 'The lines have different owners. Please reserve them ' + 'individually with the reserve button on each one.') + + return self.env['res.partner'] + location_id = fields.Many2one( 'stock.location', 'Source Location', @@ -50,6 +76,8 @@ class SaleStockReserve(models.TransientModel): help="If a date is given, the reservations will be released " "at the end of the validity.") note = fields.Text('Notes') + owner_id = fields.Many2one('res.partner', 'Stock Owner', + default=_default_owner) @api.multi def _prepare_stock_reservation(self, line): @@ -67,6 +95,7 @@ class SaleStockReserve(models.TransientModel): 'product_uos': product_uos, 'price_unit': line.price_unit, 'sale_line_id': line.id, + 'restrict_partner_id': self.owner_id.id, } @api.multi diff --git a/stock_reserve_sale/wizard/sale_stock_reserve_view.xml b/stock_reserve_sale/wizard/sale_stock_reserve_view.xml index 5b3c39bcc..69b3fb4ff 100644 --- a/stock_reserve_sale/wizard/sale_stock_reserve_view.xml +++ b/stock_reserve_sale/wizard/sale_stock_reserve_view.xml @@ -16,6 +16,7 @@ +