Conflicts:
	stock_reserve_sale/test/sale_reserve.yml
This commit is contained in:
Miku Laitinen
2015-07-11 22:55:46 +03:00
41 changed files with 1633 additions and 79 deletions

View File

@@ -1,6 +1,11 @@
# Config file .travis.yml
sudo: required
addons:
apt:
packages:
- expect-dev # provides unbuffer utility
- python-lxml # because pip installation is slow
language: python
python:

View File

@@ -0,0 +1,35 @@
More preparation filters for inventories
========================================
Includes more options for making an inventory out of:
* Multiple products.
* Products of a category.
* Multiple lots
It also allows to make an inventory based on scanned products, adding a line
with product code and quantity
Credits
=======
Contributors
------------
* Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>
* Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>
Maintainer
----------
.. image:: http://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: http://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@@ -0,0 +1,19 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# 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 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 http://www.gnu.org/licenses/.
#
##############################################################################
from . import models

View File

@@ -0,0 +1,41 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# 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 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 http://www.gnu.org/licenses/.
#
##############################################################################
{
"name": "Extended Inventory Preparation Filters",
"version": "1.0",
"depends": [
"stock",
],
"author": "OdooMRP team,"
"AvanzOSC,"
"Serv. Tecnol. Avanzados - Pedro M. Baeza,"
"Odoo Community Association (OCA)",
"contributors": [
"Oihane Crucelaegui <oihanecrucelaegi@avanzosc.es>",
"Pedro M. Baeza <pedro.baeza@serviciosbaeza.com>",
],
"category": "Inventory, Logistic, Storage",
"website": "http://www.odoomrp.com",
"summary": "More filters for inventory adjustments",
"data": [
"views/stock_inventory_view.xml",
"security/ir.model.access.csv",
],
"installable": True,
}

View File

@@ -0,0 +1,113 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_inventory_preparation_filters
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0rc1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-07-30 08:59+0000\n"
"PO-Revision-Date: 2014-07-30 11:01+0100\n"
"Last-Translator: Oihane <oihanecruce@gmail.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0
#: field:stock.inventory,empty_line_ids:0
msgid "Capture Lines"
msgstr "Líneas capturadas"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,categ_ids:0
msgid "Categories"
msgstr "Categorias"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_uid:0
msgid "Created by"
msgstr "Creado por"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_date:0
msgid "Created on"
msgstr "Creado el"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:66
#, python-format
msgid "Empty list"
msgstr "Lista vacía"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,id:0
msgid "ID"
msgstr "ID"
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory
#: field:stock.inventory.line.empty,inventory_id:0
msgid "Inventory"
msgstr "Inventario"
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0
msgid "Inventory Details"
msgstr "Detalles del inventario"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_uid:0
msgid "Last Updated by"
msgstr "Actualizado por"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_date:0
msgid "Last Updated on"
msgstr "Actualizado el"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,lot_ids:0
msgid "Lots"
msgstr "Lotes"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_code:0
msgid "Product Code"
msgstr "Codigo de producto"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,product_ids:0
msgid "Products"
msgstr "Productos"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_qty:0
msgid "Quantity"
msgstr "Cantidad"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:61
#, python-format
msgid "Selected Categories"
msgstr "Categorias seleccionadas"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:65
#, python-format
msgid "Selected Lots"
msgstr "Lotes seleccionados"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:62
#, python-format
msgid "Selected Products"
msgstr "Productos seleccionados"
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory_line_empty
msgid "stock.inventory.line.empty"
msgstr "stock.inventory.line.empty"

View File

@@ -0,0 +1,112 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_inventory_preparation_filters
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0rc1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-07-30 08:59+0000\n"
"PO-Revision-Date: 2015-06-27 11:09+0100\n"
"Last-Translator: Antoine Morit <amorit@team-dsi.fr>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: \n"
"X-Generator: Poedit 1.5.4\n"
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0 field:stock.inventory,empty_line_ids:0
msgid "Capture Lines"
msgstr "Lignes extraites"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,categ_ids:0
msgid "Categories"
msgstr "Catégories"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_uid:0
msgid "Created by"
msgstr "Créé par"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_date:0
msgid "Created on"
msgstr "Créé le"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:66
#, python-format
msgid "Empty list"
msgstr "Liste vide"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,id:0
msgid "ID"
msgstr "ID"
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory
#: field:stock.inventory.line.empty,inventory_id:0
msgid "Inventory"
msgstr "Inventaire"
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0
msgid "Inventory Details"
msgstr "Détails de l'inventaire"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_uid:0
msgid "Last Updated by"
msgstr "Dernière màj par"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_date:0
msgid "Last Updated on"
msgstr "Dernière màj le"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,lot_ids:0
msgid "Lots"
msgstr "Lots"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_code:0
msgid "Product Code"
msgstr "Code produit"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,product_ids:0
msgid "Products"
msgstr "Produits"
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_qty:0
msgid "Quantity"
msgstr "Quantité"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:61
#, python-format
msgid "Selected Categories"
msgstr "Catégories sélectionnées"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:65
#, python-format
msgid "Selected Lots"
msgstr "Lots sélectionnés"
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:62
#, python-format
msgid "Selected Products"
msgstr "Produits sélectionnés"
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory_line_empty
msgid "stock.inventory.line.empty"
msgstr "stock.inventory.line.empty"

View File

@@ -0,0 +1,113 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_inventory_preparation_filters
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0rc1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-07-30 08:58+0000\n"
"PO-Revision-Date: 2014-07-30 08:58+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0
#: field:stock.inventory,empty_line_ids:0
msgid "Capture Lines"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,categ_ids:0
msgid "Categories"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_uid:0
msgid "Created by"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,create_date:0
msgid "Created on"
msgstr ""
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:66
#, python-format
msgid "Empty list"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,id:0
msgid "ID"
msgstr ""
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory
#: field:stock.inventory.line.empty,inventory_id:0
msgid "Inventory"
msgstr ""
#. module: stock_inventory_preparation_filters
#: view:stock.inventory:0
msgid "Inventory Details"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_uid:0
msgid "Last Updated by"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,write_date:0
msgid "Last Updated on"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,lot_ids:0
msgid "Lots"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_code:0
msgid "Product Code"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory,product_ids:0
msgid "Products"
msgstr ""
#. module: stock_inventory_preparation_filters
#: field:stock.inventory.line.empty,product_qty:0
msgid "Quantity"
msgstr ""
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:61
#, python-format
msgid "Selected Categories"
msgstr ""
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:65
#, python-format
msgid "Selected Lots"
msgstr ""
#. module: stock_inventory_preparation_filters
#: code:addons/stock_inventory_preparation_filters/models/stock_inventory.py:62
#, python-format
msgid "Selected Products"
msgstr ""
#. module: stock_inventory_preparation_filters
#: model:ir.model,name:stock_inventory_preparation_filters.model_stock_inventory_line_empty
msgid "stock.inventory.line.empty"
msgstr ""

View File

@@ -0,0 +1,19 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# 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 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 http://www.gnu.org/licenses/.
#
##############################################################################
from . import stock_inventory

View File

@@ -0,0 +1,133 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# 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 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 http://www.gnu.org/licenses/.
#
##############################################################################
from openerp import models, fields, api, _
class StockInventoryEmptyLines(models.Model):
_name = 'stock.inventory.line.empty'
product_code = fields.Char(
string='Product Code', size=64, required=True)
product_qty = fields.Float(
string='Quantity', required=True, default=1.0)
inventory_id = fields.Many2one(
comodel_name='stock.inventory', string='Inventory',
required=True, ondelete="cascade")
class StockInventoryFake(object):
def __init__(self, inventory, product=None, lot=None):
self.id = inventory.id
self.location_id = inventory.location_id
self.product_id = product
self.lot_id = lot
self.partner_id = inventory.partner_id
self.package_id = inventory.package_id
class StockInventory(models.Model):
_inherit = 'stock.inventory'
@api.model
def _get_available_filters(self):
"""This function will return the list of filters allowed according to
the options checked in 'Settings/Warehouse'.
:return: list of tuple
"""
res_filters = super(StockInventory, self)._get_available_filters()
res_filters.append(('categories', _('Selected Categories')))
res_filters.append(('products', _('Selected Products')))
for res_filter in res_filters:
if res_filter[0] == 'lot':
res_filters.append(('lots', _('Selected Lots')))
res_filters.append(('empty', _('Empty list')))
return res_filters
filter = fields.Selection(
selection=_get_available_filters, string='Selection Filter',
required=True)
categ_ids = fields.Many2many(
comodel_name='product.category', relation='rel_inventories_categories',
column1='inventory_id', column2='category_id', string='Categories')
product_ids = fields.Many2many(
comodel_name='product.product', relation='rel_inventories_products',
column1='inventory_id', column2='product_id', string='Products')
lot_ids = fields.Many2many(
comodel_name='stock.production.lot', relation='rel_inventories_lots',
column1='inventory_id', column2='lot_id', string='Lots')
empty_line_ids = fields.One2many(
comodel_name='stock.inventory.line.empty', inverse_name='inventory_id',
string='Capture Lines')
@api.model
def _get_inventory_lines(self, inventory):
vals = []
product_tmpl_obj = self.env['product.template']
product_obj = self.env['product.product']
if inventory.filter in ('categories', 'products'):
products = product_obj
if inventory.filter == 'categories':
product_tmpls = product_tmpl_obj.search(
[('categ_id', 'in', inventory.categ_ids.ids)])
products = product_obj.search(
[('product_tmpl_id', 'in', product_tmpls.ids)])
elif inventory.filter == 'products':
products = inventory.product_ids
for product in products:
fake_inventory = StockInventoryFake(inventory, product=product)
vals += super(StockInventory, self)._get_inventory_lines(
fake_inventory)
elif inventory.filter == 'lots':
for lot in inventory.lot_ids:
fake_inventory = StockInventoryFake(inventory, lot=lot)
vals += super(StockInventory, self)._get_inventory_lines(
fake_inventory)
elif inventory.filter == 'empty':
tmp_lines = {}
empty_line_obj = self.env['stock.inventory.line.empty']
for line in inventory.empty_line_ids:
if line.product_code in tmp_lines:
tmp_lines[line.product_code] += line.product_qty
else:
tmp_lines[line.product_code] = line.product_qty
inventory.empty_line_ids.unlink()
for product_code in tmp_lines.keys():
products = product_obj.search(
[('default_code', '=', product_code)])
if products:
product = products[0]
fake_inventory = StockInventoryFake(
inventory, product=product)
values = super(StockInventory, self)._get_inventory_lines(
fake_inventory)
if values:
values[0]['product_qty'] = tmp_lines[product_code]
else:
empty_line_obj.create(
{
'product_code': product_code,
'product_qty': tmp_lines[product_code],
'inventory_id': inventory.id,
})
vals += values
else:
vals = super(StockInventory, self)._get_inventory_lines(
inventory)
return vals

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_inventory_line_empty_user,access_stock_inventory_line_empty_user,model_stock_inventory_line_empty,stock.group_stock_user,1,0,0,0
access_stock_inventory_line_empty_manager,access_stock_inventory_line_empty_manager,model_stock_inventory_line_empty,stock.group_stock_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_inventory_line_empty_user access_stock_inventory_line_empty_user model_stock_inventory_line_empty stock.group_stock_user 1 0 0 0
3 access_stock_inventory_line_empty_manager access_stock_inventory_line_empty_manager model_stock_inventory_line_empty stock.group_stock_manager 1 1 1 1

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -0,0 +1,17 @@
##############################################################################
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from . import test_stock_inventory_preparation_filter

View File

@@ -0,0 +1,147 @@
##############################################################################
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
import openerp.tests.common as common
class TestStockInventoryPreparationFilterCategories(common.TransactionCase):
def setUp(self):
super(TestStockInventoryPreparationFilterCategories, self).setUp()
self.inventory_model = self.env['stock.inventory']
# Create a category
self.category = self.env['product.category'].create(
{
'name': 'Category for inventory',
'type': 'normal',
})
# Create some products in the category
self.product1 = self.env['product.product'].create(
{
'name': 'Product for inventory 1',
'type': 'product',
'categ_id': self.category.id,
'default_code': 'PROD1',
}
)
self.product2 = self.env['product.product'].create(
{
'name': 'Product for inventory 2',
'type': 'product',
'categ_id': self.category.id,
'default_code': 'PROD2',
}
)
# And have some stock in a location
self.location = self.env['stock.location'].create(
{
'name': 'Inventory tests',
'usage': 'internal',
}
)
inventory = self.inventory_model.create(
{
'name': 'Product1 inventory',
'filter': 'product',
'line_ids': [
(0, 0, {
'product_id': self.product1.id,
'product_uom_id': self.env.ref(
"product.product_uom_unit").id,
'product_qty': 2.0,
'location_id': self.location.id,
}),
(0, 0, {
'product_id': self.product2.id,
'product_uom_id': self.env.ref(
"product.product_uom_unit").id,
'product_qty': 4.0,
'location_id': self.location.id,
}),
],
})
inventory.action_done()
def test_inventory_category_filter(self):
inventory = self.inventory_model.create(
{
'name': 'Category inventory',
'filter': 'categories',
'location_id': self.location.id,
'categ_ids': [(6, 0, [self.category.id])],
}
)
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 2)
line1 = inventory.line_ids[0]
self.assertEqual(line1.product_id, self.product1)
self.assertEqual(line1.theoretical_qty, 2.0)
self.assertEqual(line1.location_id, self.location)
line2 = inventory.line_ids[1]
self.assertEqual(line2.product_id, self.product2)
self.assertEqual(line2.theoretical_qty, 4.0)
self.assertEqual(line2.location_id, self.location)
def test_inventory_products_filter(self):
inventory = self.inventory_model.create(
{
'name': 'Products inventory',
'filter': 'products',
'location_id': self.location.id,
'product_ids': [(6, 0, [self.product1.id, self.product2.id])],
}
)
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 2)
line1 = inventory.line_ids[0]
self.assertEqual(line1.product_id, self.product1)
self.assertEqual(line1.theoretical_qty, 2.0)
self.assertEqual(line1.location_id, self.location)
line2 = inventory.line_ids[1]
self.assertEqual(line2.product_id, self.product2)
self.assertEqual(line2.theoretical_qty, 4.0)
self.assertEqual(line2.location_id, self.location)
def test_inventory_empty_filter(self):
inventory = self.inventory_model.create(
{
'name': 'Products inventory',
'filter': 'empty',
'location_id': self.location.id,
'empty_line_ids': [
(0, 0, {
'product_code': 'PROD1',
'product_qty': 3.0,
}),
(0, 0, {
'product_code': 'PROD2',
'product_qty': 7.0,
}),
],
}
)
inventory.prepare_inventory()
self.assertEqual(len(inventory.line_ids), 2)
line1 = inventory.line_ids[0]
self.assertEqual(line1.product_id, self.product1)
self.assertEqual(line1.theoretical_qty, 2.0)
self.assertEqual(line1.product_qty, 3.0)
self.assertEqual(line1.location_id, self.location)
line2 = inventory.line_ids[1]
self.assertEqual(line2.product_id, self.product2)
self.assertEqual(line2.theoretical_qty, 4.0)
self.assertEqual(line2.product_qty, 7.0)
self.assertEqual(line2.location_id, self.location)

View File

@@ -0,0 +1,45 @@
<?xml version="1.0" encoding="UTF-8"?>
<openerp>
<data>
<record model="ir.ui.view" id="stock_inventory_form">
<field name="name">stock.inventory.form</field>
<field name="model">stock.inventory</field>
<field name="inherit_id" ref="stock.view_inventory_form" />
<field name="arch" type="xml">
<data>
<notebook position="attributes">
<attribute name="attrs" />
</notebook>
<page string="Inventory Details" position="attributes">
<attribute name="attrs">{'invisible':[('state','=','draft')]}</attribute>
</page>
<notebook position="before">
<group>
<field name="categ_ids"
nolabel="1"
attrs="{'invisible':[('filter','!=','categories')]}" />
<field name="product_ids"
nolabel="1"
attrs="{'invisible':[('filter','!=','products')]}" />
<field name="lot_ids"
nolabel="1"
attrs="{'invisible':[('filter','!=','lots')]}" />
</group>
</notebook>
<notebook position="inside">
<page string="Capture Lines"
attrs="{'invisible':[('filter','!=','empty')]}">
<field name="empty_line_ids" nolabel="1">
<tree editable="bottom">
<field name="product_code"/>
<field name="product_qty"/>
</tree>
</field>
</page>
</notebook>
</data>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,47 @@
Features
========
This module was written to add surface units of measure
Screenshots
===========
... next step (after development)
Installation
============
To install this module, you just need to select the module and insure yourself dependencies are available
Configuration
=============
No particular configuration to use this module
Usage
=====
* n/a
Known issues / Roadmap
======================
* n/a
Contributors
============
* Adriana Ierfino <adriana.ierfino@savoirfairelinux.com>
* Bruno Joliveau <bruno.joliveau@savoirfairelinux.com>
* Agathe Mollé <agathe.molle@savoirfairelinux.com>
Credits
=======
* Module developed and tested with Odoo version 8.0
* For questions, please contact our support services <support@savoirfairelinux.com>
Maintainer
==========
This module is maintained by Savoir-Faire Linux.

View File

@@ -0,0 +1 @@
# -*- coding: utf-8 -*-

View File

@@ -0,0 +1,39 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Odoo, Open Source Management Solution
# This module copyright (C) 2015 Savoir-faire Linux
# (<http://www.savoirfairelinux.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Stock Location Area Data',
'version': '0.1',
'author': 'Savoir-faire Linux',
'maintainer': 'Savoir-faire Linux',
'website': 'http://www.savoirfairelinux.com',
'license': 'AGPL-3',
'category': 'Warehouse',
'summary': "Add surface units of measure",
'depends': [
'product',
],
'data': [
'data/stock_location_area_data.xml',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="product_uom_categ_surface" model="product.uom.categ">
<field name="name">Surface</field>
</record>
<record id="product_uom_m2" model="product.uom">
<field name="name"></field>
<field name="category_id" eval="product_uom_categ_surface"/>
<field name="uom_type">reference</field>
</record>
<record id="product_uom_feet2" model="product.uom">
<field name="name">feet²</field>
<field name="category_id" eval="product_uom_categ_surface"/>
<field name="uom_type">smaller</field>
<field name="factor">10.76391042</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,34 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_location_area_data
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 20:06+0000\n"
"PO-Revision-Date: 2015-04-21 16:08-0500\n"
"Last-Translator: Agathe Mollé <agathe.molle@savoirfairelinux.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 1.5.4\n"
"Language: fr\n"
"X-Poedit-SourceCharset: UTF-8\n"
#. module: stock_location_area_data
#: model:product.uom.categ,name:stock_location_area_data.product_uom_categ_surface
msgid "Surface"
msgstr "Surface"
#. module: stock_location_area_data
#: model:product.uom,name:stock_location_area_data.product_uom_feet2
msgid "feet²"
msgstr "pied²"
#. module: stock_location_area_data
#: model:product.uom,name:stock_location_area_data.product_uom_m2
msgid "m²"
msgstr "m²"

View File

@@ -0,0 +1,31 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_location_area_data
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 20:06+0000\n"
"PO-Revision-Date: 2015-04-21 20:06+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: stock_location_area_data
#: model:product.uom.categ,name:stock_location_area_data.product_uom_categ_surface
msgid "Surface"
msgstr ""
#. module: stock_location_area_data
#: model:product.uom,name:stock_location_area_data.product_uom_feet2
msgid "feet²"
msgstr ""
#. module: stock_location_area_data
#: model:product.uom,name:stock_location_area_data.product_uom_m2
msgid "m²"
msgstr ""

View File

@@ -0,0 +1,50 @@
Features
========
This module was written to enter a location's area based on different units of measure
The information is dependant on the different locations entered
Screenshots
===========
... next step (after development)
Installation
============
To install this module, you just need to select the module and insure yourself dependencies are available
Configuration
=============
No particular configuration to use this module
Usage
=====
To use this module, you need to :
- create a location and enter its area dimensions
Known issues / Roadmap
======================
* n/a
Contributors
============
* Adriana Ierfino <adriana.ierfino@savoirfairelinux.com>
* Bruno Joliveau <bruno.joliveau@savoirfairelinux.com>
* Agathe Mollé <agathe.molle@savoirfairelinux.com>
Credits
=======
* Module developed and tested with Odoo version 8.0
* For questions, please contact our support services <support@savoirfairelinux.com>
Maintainer
==========
This module is maintained by Savoir-Faire Linux.

View File

@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import (
models,
)

View File

@@ -0,0 +1,41 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Odoo, Open Source Management Solution
# This module copyright (C) 2015 Savoir-faire Linux
# (<http://www.savoirfairelinux.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
{
'name': 'Stock Location Area Management',
'version': '0.1',
'author': 'Savoir-faire Linux',
'maintainer': 'Savoir-faire Linux',
'website': 'http://www.savoirfairelinux.com',
'license': 'AGPL-3',
'category': 'Warehouse',
'summary': "Enter a location's area based on different units of measure",
'depends': [
'stock',
'stock_location_area_data'
],
'data': [
'views/res_company.xml',
'views/stock_location.xml',
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,81 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_location_area_management
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 20:09+0000\n"
"PO-Revision-Date: 2015-04-21 16:19-0500\n"
"Last-Translator: Agathe Mollé <agathe.molle@savoirfairelinux.com>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Generator: Poedit 1.5.4\n"
"Language: fr\n"
"X-Poedit-SourceCharset: UTF-8\n"
#. module: stock_location_area_management
#: model:ir.model,name:stock_location_area_management.model_res_company
msgid "Companies"
msgstr "Sociétés"
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
#: field:stock.location,area_dimension:0
msgid "Dimension"
msgstr "Dimension"
#. module: stock_location_area_management
#: field:stock.location,active_dimension:0
msgid "Area Dimension"
msgstr "Dimension de la surface"
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Group By"
msgstr "Grouper par"
#. module: stock_location_area_management
#: model:ir.model,name:stock_location_area_management.model_stock_location
msgid "Inventory Locations"
msgstr "Emplacements d'inventaire"
#. module: stock_location_area_management
#: view:res.company:stock_location_area_management.stock_location_area_management_res_company_form_view
msgid "Locations"
msgstr "Emplacements"
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Owner"
msgstr "Propriétaire"
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Partner"
msgstr "Partenaire"
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_form_view
msgid "Surface"
msgstr "Surface"
#. module: stock_location_area_management
#: help:stock.location,location_uom:0
msgid "This field corresponds to the unit of measure of the location"
msgstr "Ce champ correspond à l'unité de mesure de l'emplacement"
#. module: stock_location_area_management
#: help:res.company,locations_uom:0
msgid ""
"This field corresponds to the unit of measure of the warehouse locations"
msgstr "Ce champ correspond à l'unité de mesure des emplacements de l'entrepôt"
#. module: stock_location_area_management
#: field:res.company,locations_uom:0 field:stock.location,location_uom:0
msgid "Unit of Measure"
msgstr "Unité de mesure"

View File

@@ -0,0 +1,78 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * stock_location_area_management
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 8.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-04-21 20:09+0000\n"
"PO-Revision-Date: 2015-04-21 20:09+0000\n"
"Last-Translator: <>\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: stock_location_area_management
#: model:ir.model,name:stock_location_area_management.model_res_company
msgid "Companies"
msgstr ""
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
#: field:stock.location,area_dimension:0
msgid "Dimension"
msgstr ""
#. module: stock_location_area_management
#: field:stock.location,active_dimension:0
msgid "Area Dimension"
msgstr ""
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Group By"
msgstr ""
#. module: stock_location_area_management
#: model:ir.model,name:stock_location_area_management.model_stock_location
msgid "Inventory Locations"
msgstr ""
#. module: stock_location_area_management
#: view:res.company:stock_location_area_management.stock_location_area_management_res_company_form_view
msgid "Locations"
msgstr ""
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Owner"
msgstr ""
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_search
msgid "Partner"
msgstr ""
#. module: stock_location_area_management
#: view:stock.location:stock_location_area_management.stock_location_area_management_stock_location_form_view
msgid "Surface"
msgstr ""
#. module: stock_location_area_management
#: help:stock.location,location_uom:0
msgid "This field corresponds to the unit of measure of the location"
msgstr ""
#. module: stock_location_area_management
#: help:res.company,locations_uom:0
msgid "This field corresponds to the unit of measure of the warehouse locations"
msgstr ""
#. module: stock_location_area_management
#: field:res.company,locations_uom:0
#: field:stock.location,location_uom:0
msgid "Unit of Measure"
msgstr ""

View File

@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
from . import (
res_company,
stock_location,
)

View File

@@ -0,0 +1,47 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Odoo, Open Source Management Solution
# This module copyright (C) 2015 Savoir-faire Linux
# (<http://www.savoirfairelinux.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields
class ResCompany(models.Model):
"""
Add the unit of measure of the warehouse locations.
Set by default to m².
"""
_inherit = 'res.company'
def _get_default_locations_uom(self):
"""
Get the unit of measure m² (default)
:return: Unit of measure m²
"""
return self.env.ref('stock_location_area_data.product_uom_m2')
locations_uom = fields.Many2one(
string='Unit of Measure',
comodel_name='product.uom',
help='This field corresponds to the unit of measure of the warehouse '
'locations',
domain="[('category_id.name','=','Surface')]",
default=lambda self: self._get_default_locations_uom(),
)

View File

@@ -0,0 +1,52 @@
# -*- encoding: utf-8 -*-
##############################################################################
#
# Odoo, Open Source Management Solution
# This module copyright (C) 2015 Savoir-faire Linux
# (<http://www.savoirfairelinux.com>).
#
# 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 <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import models, fields
class StockLocation(models.Model):
"""
Add the area dimension and the unit of measure of the warehouse locations.
By default, the unit of measure is the one of the user's company.
Add a boolean for the form view in order to display or not area
dimensions fields.
"""
_inherit = 'stock.location'
area_dimension = fields.Integer('Dimension')
active_dimension = fields.Boolean('Area Dimension')
def _get_company_locations_uom(self):
"""
Get the unit of measure of the user's company locations
:return: Unit of measure of the user's company
"""
return self.env['res.users'].browse(self._uid).company_id.locations_uom
location_uom = fields.Many2one(
string='Unit of Measure',
comodel_name='product.uom',
help='This field corresponds to the unit of measure of the location',
domain="[('category_id.name','=','Surface')]",
default=lambda self: self._get_company_locations_uom(),
)

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="stock_location_area_management_res_company_form_view"
model="ir.ui.view">
<field name="name">stock.location.area.management.res.company.form</field>
<field name="inherit_id" ref="base.view_company_form"/>
<field name="model">res.company</field>
<field name="arch" type="xml">
<xpath expr="//group[@name='account_grp']" position="after">
<group name="locations_grp" string="Locations">
<field name="locations_uom"/>
</group>
</xpath>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data>
<record id="stock_location_area_management_stock_location_form_view"
model="ir.ui.view">
<field name="name">stock.location.area.management.stock.location.form</field>
<field name="inherit_id" ref="stock.view_location_form"/>
<field name="model">stock.location</field>
<field name="arch" type="xml">
<xpath expr="//group[@name='localization']" position="after">
<group name="surface_grp" string="Surface" col="4">
<field name="active_dimension"/>
<field name="area_dimension"
nolabel="1"
attrs="{'invisible': [('active_dimension', '=', False)]}"/>
<field name="location_uom"
nolabel="1"
attrs="{'invisible': [('active_dimension', '=', False)]}"/>
</group>
</xpath>
</field>
</record>
<record id="stock_location_area_management_stock_location_list_view"
model="ir.ui.view">
<field name="name">stock.location.area.management.stock.location.list</field>
<field name="inherit_id" ref="stock.view_location_tree2"/>
<field name="model">stock.location</field>
<field name="arch" type="xml">
<field name="usage" position="after">
<field name="area_dimension"/>
<field name="location_uom"/>
</field>
</field>
</record>
<record id="stock_location_area_management_stock_location_search"
model="ir.ui.view">
<field name="name">stock.location.area.management.stock.location.search</field>
<field name="model">stock.location</field>
<field name="inherit_id" ref="stock.view_location_search"/>
<field name="arch" type="xml">
<field name="location_id" position="after">
<field name="area_dimension" string="Dimension"/>
<field name="partner_id" string="Owner"/>
<group expand="0" string="Group By">
<filter string="Partner"
domain="[]"
context="{'group_by' : 'partner_id'}"/>
</group>
</field>
</field>
</record>
</data>
</openerp>

View File

@@ -0,0 +1,45 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Stock Location Ownership
========================
Adds an ownership on the stock locations
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_location_ownership%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Leonardo Pistone <leonardo.pistone@camptocamp.com>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Nicolas Bessi <nicolas.bessi@camptocamp.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Joel Grand-Guillaume <joel.grandguillaume@camptocamp.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@@ -27,12 +27,6 @@
'complexity': 'normal',
'images': [],
'website': "http://www.camptocamp.com",
'description': """
Stock Location Ownership
========================
Adds an ownership on the stock locations
""",
'depends': ['stock',
],
'demo': [],

56
stock_reserve/README.rst Normal file
View File

@@ -0,0 +1,56 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Stock Reservation
=================
Allows to create stock reservations on products.
Each reservation can have a validity date, once passed, the reservation
is automatically lifted.
The reserved products are substracted from the virtual stock. It means
that if you reserved a quantity of products which bring the virtual
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.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_reserve%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Leonardo Pistone <leonardo.pistone@camptocamp.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

View File

@@ -28,28 +28,6 @@
'complexity': 'normal',
'images': [],
'website': "http://www.camptocamp.com",
'description': """
Stock Reservation
=================
Allows to create stock reservations on products.
Each reservation can have a validity date, once passed, the reservation
is automatically lifted.
The reserved products are substracted from the virtual stock. It means
that if you reserved a quantity of products which bring the virtual
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.
Contributors
------------
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
""",
'depends': ['stock',
],
'demo': [],

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

@@ -0,0 +1,66 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Stock Reserve Sale
==================
Allows to create stock reservations for quotation lines before the
confirmation of the quotation. The reservations might have a validity
date and in any case they are lifted when the quotation is canceled or
confirmed.
Reservations can be done only on "make to stock" and stockable products.
The reserved products are subtracted from the virtual stock. It means
that if you reserved a quantity of products which bring the virtual
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 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.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues <https://github.com/OCA/stock-logistics-warehouse/issues>`_.
In case of trouble, please check there if your issue has already been reported.
If you spotted it first, help us smashing it by providing a detailed and welcomed feedback
`here <https://github.com/OCA/stock-logistics-warehouse/issues/new?body=module:%20stock_reserve_sale%0Aversion:%208.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.
Credits
=======
Contributors
------------
* Leonardo Pistone <leonardo.pistone@camptocamp.com>
* Alexandre Fayolle <alexandre.fayolle@camptocamp.com>
* Yannick Vaucher <yannick.vaucher@camptocamp.com>
* Guewen Baconnier <guewen.baconnier@camptocamp.com>
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit http://odoo-community.org.

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,35 +20,13 @@
##############################################################################
{'name': 'Stock Reserve Sales',
'version': '0.1',
'version': '1.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'category': 'Warehouse',
'license': 'AGPL-3',
'complexity': 'normal',
'images': [],
'website': "http://www.camptocamp.com",
'description': """
Stock Reserve Sales
===================
Allows to create stock reservations for quotation lines before the
confirmation of the quotation. The reservations might have a validity
date and in any case they are lifted when the quotation is canceled or
confirmed.
Reservations can be done only on "make to stock" and stockable products.
The reserved products are substracted from the virtual stock. It means
that if you reserved a quantity of products which bring the virtual
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 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.
""",
'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

@@ -37,22 +37,20 @@
product_uom_qty: 1
-
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 == 5, "Stock is not updated after reservation."
!python {model: product.product, id: product_gelato}: |
from nose.tools import *
assert_almost_equal(self.virtual_available, 5.0)
-
I release the sales order's reservations
-
@@ -61,6 +59,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 after releasing reservations."
!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"/>