diff --git a/oca_dependencies.txt b/oca_dependencies.txt new file mode 100644 index 000000000000..d8a2d4efc0cf --- /dev/null +++ b/oca_dependencies.txt @@ -0,0 +1 @@ +product-attribute diff --git a/stock_secondary_unit/README.rst b/stock_secondary_unit/README.rst new file mode 100644 index 000000000000..734b1dc78f14 --- /dev/null +++ b/stock_secondary_unit/README.rst @@ -0,0 +1,89 @@ +==================== +Stock Secondary Unit +==================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-warehouse/tree/13.0/stock_secondary_unit + :alt: OCA/stock-logistics-warehouse +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-13-0/stock-logistics-warehouse-13-0-stock_secondary_unit + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/153/13.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the functionality of stock module to allow define +other units with their conversion factor. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module you need to: + +#. Go to a *Product > General Information tab*. +#. Create any record in "Secondary unit of measure". +#. Set the conversion factor. +#. Go to *Inventory tab* and set a second unit of measure. +#. Push button 'Quantity on hand' and set quantities in stock for this product. +#. Go to product list and you can see the secondary unit value. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub 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 `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Tecnativa + +Contributors +~~~~~~~~~~~~ + +* Carlos Dauden +* Sergio Teruel +* Kitti Upariphutthiphong +* Pimolnat Suntian + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +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. + +This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_secondary_unit/__init__.py b/stock_secondary_unit/__init__.py new file mode 100644 index 000000000000..3275ac2adf3d --- /dev/null +++ b/stock_secondary_unit/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import models diff --git a/stock_secondary_unit/__manifest__.py b/stock_secondary_unit/__manifest__.py new file mode 100644 index 000000000000..b8837a32da52 --- /dev/null +++ b/stock_secondary_unit/__manifest__.py @@ -0,0 +1,21 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Stock Secondary Unit", + "summary": "Get product quantities in a secondary unit", + "version": "13.0.1.0.0", + "development_status": "Production/Stable", + "category": "stock", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["stock", "product_secondary_unit"], + "data": [ + "views/product_views.xml", + "views/stock_move_views.xml", + "views/stock_picking_views.xml", + "report/report_deliveryslip.xml", + ], +} diff --git a/stock_secondary_unit/i18n/es.po b/stock_secondary_unit/i18n/es.po new file mode 100644 index 000000000000..94b0eb80e65e --- /dev/null +++ b/stock_secondary_unit/i18n/es.po @@ -0,0 +1,114 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 11.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-09-11 06:27+0000\n" +"PO-Revision-Date: 2018-09-11 08:28+0200\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: es_ES\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 2.0.6\n" + +#. module: stock_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.report_delivery_document +msgid "Secondary Qty" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name +msgid "Display Name" +msgstr "Mostrar Nombre" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id +msgid "ID" +msgstr "ID" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update +msgid "Last Modified on" +msgstr "Última modificación en" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_template +msgid "Product Template" +msgstr "Plantilla de producto" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__secondary_unit_qty_available +msgid "Quantity On Hand (2Unit)" +msgstr "Cantidad a mano (2Ud.)" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id +#, fuzzy +msgid "Second unit" +msgstr "Unidad Secundaria" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id +msgid "Second unit for inventory" +msgstr "Segunda unidad de medida para inventario" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty +#, fuzzy +msgid "Secondary Qty" +msgstr "Unidad Secundaria" + +#. module: stock_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form +msgid "Secondary unit" +msgstr "Unidad Secundaria" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_product_secondary_unit +#, fuzzy +#| msgid "Secondary unit" +msgid "Stock Product Secondary Unit" +msgstr "Unidad Secundaria" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin +#, fuzzy +msgid "Stock Secondary Unit Mixin" +msgstr "Unidad Secundaria" + +#~ msgid "On Hand (2unit)" +#~ msgstr "A mano (2Ud.)" + +#~ msgid "Second Unit Quantity On Hand" +#~ msgstr "Segunda unidad de medida por defecto" diff --git a/stock_secondary_unit/i18n/stock_secondary_unit.pot b/stock_secondary_unit/i18n/stock_secondary_unit.pot new file mode 100644 index 000000000000..bf6fa6ff491f --- /dev/null +++ b/stock_secondary_unit/i18n/stock_secondary_unit.pot @@ -0,0 +1,100 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \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_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.report_delivery_document +msgid "Secondary Qty" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id +msgid "ID" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_product +msgid "Product" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_template +msgid "Product Template" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__secondary_unit_qty_available +msgid "Quantity On Hand (2Unit)" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id +msgid "Second unit" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id +msgid "Second unit for inventory" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty +msgid "Secondary Qty" +msgstr "" + +#. module: stock_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form +msgid "Secondary unit" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move +msgid "Stock Move" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_product_secondary_unit +msgid "Stock Product Secondary Unit" +msgstr "" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin +msgid "Stock Secondary Unit Mixin" +msgstr "" + diff --git a/stock_secondary_unit/i18n/zh_CN.po b/stock_secondary_unit/i18n/zh_CN.po new file mode 100644 index 000000000000..d326116ef04b --- /dev/null +++ b/stock_secondary_unit/i18n/zh_CN.po @@ -0,0 +1,102 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-10-21 15:32+0000\n" +"Last-Translator: Tony Gu \n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 3.8\n" + +#. module: stock_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.report_delivery_document +msgid "Secondary Qty" +msgstr " 辅助单位数量" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__display_name +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__display_name +msgid "Display Name" +msgstr "显示名称" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__id +msgid "ID" +msgstr "ID" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit____last_update +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin____last_update +msgid "Last Modified on" +msgstr "最后修改时间" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_product +msgid "Product" +msgstr "产品" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move_line +msgid "Product Moves (Stock Move Line)" +msgstr "产品移动(库存移动行)" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_product_template +msgid "Product Template" +msgstr "产品模板" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__secondary_unit_qty_available +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_product_secondary_unit__secondary_unit_qty_available +msgid "Quantity On Hand (2Unit)" +msgstr "在手数量(辅助单位)" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_id +msgid "Second unit" +msgstr "辅助单位" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_product__stock_secondary_uom_id +#: model:ir.model.fields,field_description:stock_secondary_unit.field_product_template__stock_secondary_uom_id +msgid "Second unit for inventory" +msgstr "库存辅助单位" + +#. module: stock_secondary_unit +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_move_line__secondary_uom_qty +#: model:ir.model.fields,field_description:stock_secondary_unit.field_stock_secondary_unit_mixin__secondary_uom_qty +msgid "Secondary Qty" +msgstr "辅助单位数量" + +#. module: stock_secondary_unit +#: model_terms:ir.ui.view,arch_db:stock_secondary_unit.view_template_property_form +msgid "Secondary unit" +msgstr "辅助单位" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_move +msgid "Stock Move" +msgstr "库存移动" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_product_secondary_unit +msgid "Stock Product Secondary Unit" +msgstr "库存产品辅助单位" + +#. module: stock_secondary_unit +#: model:ir.model,name:stock_secondary_unit.model_stock_secondary_unit_mixin +msgid "Stock Secondary Unit Mixin" +msgstr "库存辅助单位混合类" diff --git a/stock_secondary_unit/models/__init__.py b/stock_secondary_unit/models/__init__.py new file mode 100644 index 000000000000..960afa99e789 --- /dev/null +++ b/stock_secondary_unit/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import product +from . import stock_move diff --git a/stock_secondary_unit/models/product.py b/stock_secondary_unit/models/product.py new file mode 100644 index 000000000000..25b35cb84fc9 --- /dev/null +++ b/stock_secondary_unit/models/product.py @@ -0,0 +1,49 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models +from odoo.tools.float_utils import float_round + + +class StockProductSecondaryUnit(models.AbstractModel): + _name = "stock.product.secondary.unit" + _description = "Stock Product Secondary Unit" + + secondary_unit_qty_available = fields.Float( + string="Quantity On Hand (2Unit)", + compute="_compute_secondary_unit_qty_available", + digits="Product Unit of Measure", + ) + + def _compute_secondary_unit_qty_available(self): + for product in self: + if not product.stock_secondary_uom_id: + product.secondary_unit_qty_available = 0.0 + else: + qty = product.qty_available / ( + product.stock_secondary_uom_id.factor or 1.0 + ) + product.secondary_unit_qty_available = float_round( + qty, precision_rounding=product.uom_id.rounding + ) + + +class ProductTemplate(models.Model): + _inherit = ["product.template", "stock.product.secondary.unit"] + _name = "product.template" + + stock_secondary_uom_id = fields.Many2one( + comodel_name="product.secondary.unit", string="Second unit for inventory" + ) + + def _compute_quantities(self): + super()._compute_quantities() + self._compute_secondary_unit_qty_available() + + +class ProductProduct(models.Model): + _inherit = ["product.product", "stock.product.secondary.unit"] + _name = "product.product" + + def _compute_quantities(self): + super()._compute_quantities() + self._compute_secondary_unit_qty_available() diff --git a/stock_secondary_unit/models/stock_move.py b/stock_secondary_unit/models/stock_move.py new file mode 100644 index 000000000000..49821a399702 --- /dev/null +++ b/stock_secondary_unit/models/stock_move.py @@ -0,0 +1,47 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models +from odoo.tools.float_utils import float_round + + +class StockSecondaryUnitMixin(models.AbstractModel): + _name = "stock.secondary.unit.mixin" + _description = "Stock Secondary Unit Mixin" + + secondary_uom_id = fields.Many2one( + comodel_name="product.secondary.unit", string="Second unit" + ) + secondary_uom_qty = fields.Float( + string="Secondary Qty", digits="Product Unit of Measure" + ) + + +class StockMove(models.Model): + _inherit = ["stock.move", "stock.secondary.unit.mixin"] + _name = "stock.move" + + def _merge_moves_fields(self): + res = super()._merge_moves_fields() + res["secondary_uom_qty"] = self[-1:].secondary_uom_qty + return res + + +class StockMoveLine(models.Model): + _inherit = ["stock.move.line", "stock.secondary.unit.mixin"] + _name = "stock.move.line" + + @api.model + def create(self, vals): + move = self.env["stock.move"].browse(vals.get("move_id", False)) + if move.secondary_uom_id: + uom = self.env["uom.uom"].browse(vals["product_uom_id"]) + factor = move.secondary_uom_id.factor * uom.factor + move_line_qty = vals.get("product_uom_qty", vals.get("qty_done", 0.0)) + qty = float_round( + move_line_qty / (factor or 1.0), + precision_rounding=move.secondary_uom_id.uom_id.rounding, + ) + vals.update( + {"secondary_uom_qty": qty, "secondary_uom_id": move.secondary_uom_id.id} + ) + return super().create(vals) diff --git a/stock_secondary_unit/readme/CONTRIBUTORS.rst b/stock_secondary_unit/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..d35178a8f58f --- /dev/null +++ b/stock_secondary_unit/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* Carlos Dauden +* Sergio Teruel +* Kitti Upariphutthiphong +* Pimolnat Suntian diff --git a/stock_secondary_unit/readme/DESCRIPTION.rst b/stock_secondary_unit/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..ce69e8533cab --- /dev/null +++ b/stock_secondary_unit/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module extends the functionality of stock module to allow define +other units with their conversion factor. diff --git a/stock_secondary_unit/readme/USAGE.rst b/stock_secondary_unit/readme/USAGE.rst new file mode 100644 index 000000000000..4d189ae535ac --- /dev/null +++ b/stock_secondary_unit/readme/USAGE.rst @@ -0,0 +1,8 @@ +To use this module you need to: + +#. Go to a *Product > General Information tab*. +#. Create any record in "Secondary unit of measure". +#. Set the conversion factor. +#. Go to *Inventory tab* and set a second unit of measure. +#. Push button 'Quantity on hand' and set quantities in stock for this product. +#. Go to product list and you can see the secondary unit value. diff --git a/stock_secondary_unit/report/report_deliveryslip.xml b/stock_secondary_unit/report/report_deliveryslip.xml new file mode 100644 index 000000000000..b7c7ee700362 --- /dev/null +++ b/stock_secondary_unit/report/report_deliveryslip.xml @@ -0,0 +1,27 @@ + + + + + + + diff --git a/stock_secondary_unit/static/description/icon.png b/stock_secondary_unit/static/description/icon.png new file mode 100644 index 000000000000..3a0328b516c4 Binary files /dev/null and b/stock_secondary_unit/static/description/icon.png differ diff --git a/stock_secondary_unit/static/description/index.html b/stock_secondary_unit/static/description/index.html new file mode 100644 index 000000000000..037408bf1bc7 --- /dev/null +++ b/stock_secondary_unit/static/description/index.html @@ -0,0 +1,436 @@ + + + + + + +Stock Secondary Unit + + + +
+

Stock Secondary Unit

+ + +

Beta License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runbot

+

This module extends the functionality of stock module to allow define +other units with their conversion factor.

+

Table of contents

+ +
+

Usage

+

To use this module you need to:

+
    +
  1. Go to a Product > General Information tab.
  2. +
  3. Create any record in “Secondary unit of measure”.
  4. +
  5. Set the conversion factor.
  6. +
  7. Go to Inventory tab and set a second unit of measure.
  8. +
  9. Push button ‘Quantity on hand’ and set quantities in stock for this product.
  10. +
  11. Go to product list and you can see the secondary unit value.
  12. +
+
+
+

Bug Tracker

+

Bugs are tracked on GitHub 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.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

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.

+

This module is part of the OCA/stock-logistics-warehouse project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/stock_secondary_unit/tests/__init__.py b/stock_secondary_unit/tests/__init__.py new file mode 100644 index 000000000000..38c91ad2e9f9 --- /dev/null +++ b/stock_secondary_unit/tests/__init__.py @@ -0,0 +1,2 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from . import test_stock_secondary_unit diff --git a/stock_secondary_unit/tests/test_stock_secondary_unit.py b/stock_secondary_unit/tests/test_stock_secondary_unit.py new file mode 100644 index 000000000000..5059a43b3123 --- /dev/null +++ b/stock_secondary_unit/tests/test_stock_secondary_unit.py @@ -0,0 +1,132 @@ +# Copyright 2018 Tecnativa - Sergio Teruel +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests import SavepointCase + + +class TestProductSecondaryUnit(SavepointCase): + at_install = False + post_install = True + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.warehouse = cls.env.ref("stock.warehouse0") + cls.product_uom_kg = cls.env.ref("uom.product_uom_kgm") + cls.product_uom_unit = cls.env.ref("uom.product_uom_unit") + ProductAttribute = cls.env["product.attribute"] + ProductAttributeValue = cls.env["product.attribute.value"] + cls.attribute_color = ProductAttribute.create({"name": "test_color"}) + cls.attribute_value_white = ProductAttributeValue.create( + {"name": "test_white", "attribute_id": cls.attribute_color.id} + ) + cls.attribute_value_black = ProductAttributeValue.create( + {"name": "test_black", "attribute_id": cls.attribute_color.id} + ) + cls.product_template = cls.env["product.template"].create( + { + "name": "test", + "uom_id": cls.product_uom_kg.id, + "uom_po_id": cls.product_uom_kg.id, + "type": "product", + "secondary_uom_ids": [ + ( + 0, + 0, + { + "code": "A", + "name": "unit-700", + "uom_id": cls.product_uom_unit.id, + "factor": 0.5, + }, + ), + ( + 0, + 0, + { + "code": "B", + "name": "unit-900", + "uom_id": cls.product_uom_unit.id, + "factor": 0.9, + }, + ), + ], + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": cls.attribute_color.id, + "value_ids": [ + (4, cls.attribute_value_white.id), + (4, cls.attribute_value_black.id), + ], + }, + ) + ], + } + ) + secondary_unit = cls.env["product.secondary.unit"].search( + [("product_tmpl_id", "=", cls.product_template.id)], limit=1 + ) + cls.product_template.write({"stock_secondary_uom_id": secondary_unit.id}) + StockQuant = cls.env["stock.quant"] + cls.quant_white = StockQuant.create( + { + "product_id": cls.product_template.product_variant_ids[0].id, + "location_id": cls.warehouse.lot_stock_id.id, + "quantity": 10.0, + } + ) + cls.quant_black = StockQuant.create( + { + "product_id": cls.product_template.product_variant_ids[1].id, + "location_id": cls.warehouse.lot_stock_id.id, + "quantity": 10.0, + } + ) + + def test_01_stock_secondary_unit_template(self): + self.assertEqual(self.product_template.secondary_unit_qty_available, 40.0) + + def test_02_stock_secondary_unit_variant(self): + for variant in self.product_template.product_variant_ids.filtered( + "product_template_attribute_value_ids" + ): + self.assertEqual(variant.secondary_unit_qty_available, 20) + + def test_03_stock_picking_secondary_unit(self): + StockPicking = self.env["stock.picking"] + product1 = self.product_template.product_variant_ids[0] + location = self.env.ref("stock.stock_location_suppliers") + location_dest = self.env.ref("stock.stock_location_stock") + picking_type = self.env.ref("stock.picking_type_in") + move_vals = { + "product_id": product1.id, + "name": product1.display_name, + "secondary_uom_id": product1.secondary_uom_ids[0].id, + "product_uom": product1.uom_id.id, + "product_uom_qty": 10.0, + "location_id": location.id, + "location_dest_id": location_dest.id, + } + do_vals = { + "location_id": location.id, + "location_dest_id": location_dest.id, + "picking_type_id": picking_type.id, + "move_ids_without_package": [ + (0, None, move_vals), + (0, None, move_vals), + ], # 2 moves + } + delivery_order = StockPicking.create(do_vals) + delivery_order.action_confirm() + # Move is merged into 1 line for both stock.move and stock.move.line + self.assertEquals(len(delivery_order.move_lines), 1) + self.assertEquals(len(delivery_order.move_line_ids), 1) + # Qty merged to 20, and secondary unit qty is 40line + uom_qty = sum(delivery_order.move_lines.mapped("product_uom_qty")) + secondary_uom_qty = sum( + delivery_order.move_line_ids.mapped("secondary_uom_qty") + ) + self.assertEquals(uom_qty, 20.0) + self.assertEquals(secondary_uom_qty, 40.0) diff --git a/stock_secondary_unit/views/product_views.xml b/stock_secondary_unit/views/product_views.xml new file mode 100644 index 000000000000..28441445a110 --- /dev/null +++ b/stock_secondary_unit/views/product_views.xml @@ -0,0 +1,86 @@ + + + + + + Product template Secondary Unit + product.template + + + + + + + + + + + + + product.template + + + + + + + + + + + product.product + + + + + + + + + + + product.template + + + + + + + + + + + + product.product + + + + + + + + + + + diff --git a/stock_secondary_unit/views/stock_move_views.xml b/stock_secondary_unit/views/stock_move_views.xml new file mode 100644 index 000000000000..d2adcf37c634 --- /dev/null +++ b/stock_secondary_unit/views/stock_move_views.xml @@ -0,0 +1,36 @@ + + + + + + Stock Move Secondary Unit + stock.move.line + + + + + + + + + + + + stock.move.line.operations.tree + stock.move.line + + + + + + + + + + + diff --git a/stock_secondary_unit/views/stock_picking_views.xml b/stock_secondary_unit/views/stock_picking_views.xml new file mode 100644 index 000000000000..08c9b926eabd --- /dev/null +++ b/stock_secondary_unit/views/stock_picking_views.xml @@ -0,0 +1,21 @@ + + + + + + Stock Picking Secondary Unit + stock.picking + + + + + + + + + + +