Merge pull request #41 from lepistone/reserve-owner

make stock_reserve and stock_reserve_sale owner_aware
This commit is contained in:
Joël Grand-Guillaume
2015-04-24 10:44:25 +02:00
7 changed files with 62 additions and 28 deletions

View File

@@ -43,11 +43,15 @@ stock below the minimum, the orderpoint will be triggered and new
purchase orders will be generated. It also implies that the max may be
exceeded if the reservations are canceled.
If ownership of stock is active in the stock settings, you can specify the
owner on the reservation.
Contributors
------------
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Leonardo Pistone <leonardo.pistone@camptocamp.com>
""",
'depends': ['stock',

View File

@@ -36,6 +36,7 @@
<field name="company_id"
groups="base.group_multi_company"
widget="selection"/>
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
</group>
<group name="location" string="Locations"
groups="stock.group_locations">
@@ -63,6 +64,7 @@
<field name="product_uom_qty" sum="Total" />
<field name="product_uom" />
<field name="date_validity" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
<field name="state"/>
<button name="reserve" type="object"
string="Reserve"
@@ -93,6 +95,7 @@
<field name="name" />
<field name="product_id" />
<field name="move_id" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
<group expand="0" string="Group By...">
<filter string="Status"
name="groupby_state"

View File

@@ -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',

View File

@@ -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
-

View File

@@ -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)

View File

@@ -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

View File

@@ -16,6 +16,7 @@
<field name="location_id"/>
<field name="location_dest_id"/>
<field name="date_validity"/>
<field name="owner_id" groups="stock.group_tracking_owner"/>
</group>
<group name="note" string="Notes">
<field name="note" nolabel="1"/>