diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 749967bb6..6c30e9008 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,13 +12,14 @@ exclude: | (LICENSE.*|COPYING.*) default_language_version: python: python3 + node: "14.13.0" repos: - repo: https://github.com/psf/black rev: 19.10b0 hooks: - id: black - - repo: https://github.com/prettier/prettier - rev: "1.19.1" + - repo: https://github.com/prettier/pre-commit + rev: "v1.19.1" hooks: - id: prettier # TODO Avoid awebdeveloper/pre-commit-prettier if possible @@ -75,17 +76,17 @@ repos: files: /__init__\.py$ additional_dependencies: ["flake8-bugbear==19.8.0"] - repo: https://github.com/pre-commit/mirrors-pylint - rev: v2.3.1 + rev: v2.5.3 hooks: - id: pylint name: pylint with optional checks args: ["--rcfile=.pylintrc", "--exit-zero"] verbose: true - additional_dependencies: ["pylint-odoo==3.1.0"] + additional_dependencies: ["pylint-odoo==3.5.0"] - id: pylint name: pylint with mandatory checks args: ["--rcfile=.pylintrc-mandatory"] - additional_dependencies: ["pylint-odoo==3.1.0"] + additional_dependencies: ["pylint-odoo==3.5.0"] - repo: https://github.com/asottile/pyupgrade rev: v1.26.2 hooks: diff --git a/.pylintrc b/.pylintrc index f9ddbaa3f..485836baf 100644 --- a/.pylintrc +++ b/.pylintrc @@ -28,6 +28,7 @@ enable=anomalous-backslash-in-string, class-camelcase, dangerous-default-value, dangerous-view-replace-wo-priority, + development-status-allowed, duplicate-id-csv, duplicate-key, duplicate-xml-fields, diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory index 7635cbb17..55893fe8b 100644 --- a/.pylintrc-mandatory +++ b/.pylintrc-mandatory @@ -21,6 +21,7 @@ enable=anomalous-backslash-in-string, class-camelcase, dangerous-default-value, dangerous-view-replace-wo-priority, + development-status-allowed, duplicate-id-csv, duplicate-key, duplicate-xml-fields, diff --git a/account_move_line_stock_info/__manifest__.py b/account_move_line_stock_info/__manifest__.py index 7ad91d3e4..7c018957b 100644 --- a/account_move_line_stock_info/__manifest__.py +++ b/account_move_line_stock_info/__manifest__.py @@ -2,7 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). { "name": "Account Move Line Stock Info", - "version": "13.0.1.0.0", + "version": "13.0.1.1.0", "depends": ["stock_account"], "author": "ForgeFlow," "Odoo Community Association (OCA)", "website": "https://github.com/OCA/stock-logistics-warehouse", diff --git a/account_move_line_stock_info/views/stock_move_view.xml b/account_move_line_stock_info/views/stock_move_view.xml index 8cad7c929..2952f4669 100644 --- a/account_move_line_stock_info/views/stock_move_view.xml +++ b/account_move_line_stock_info/views/stock_move_view.xml @@ -18,7 +18,7 @@ diff --git a/oca_dependencies.txt b/oca_dependencies.txt index b468c811f..731715c8d 100644 --- a/oca_dependencies.txt +++ b/oca_dependencies.txt @@ -1,3 +1,5 @@ +account-analytic +connector product-attribute server-env server-ux diff --git a/procurement_auto_create_group/i18n/cs_CZ.po b/procurement_auto_create_group/i18n/cs_CZ.po index 202174464..9ea00c03b 100644 --- a/procurement_auto_create_group/i18n/cs_CZ.po +++ b/procurement_auto_create_group/i18n/cs_CZ.po @@ -27,14 +27,12 @@ msgstr "Automatické vytvoření skupiny nákupu" #. module: procurement_auto_create_group #: code:addons/procurement_auto_create_group/models/procurement_group.py:0 #, fuzzy, python-format -#| msgid "No sequence defined for procurement group" msgid "No sequence defined for procurement group." msgstr "Nebyla definována žádná sekvence pro skupinu zakázek" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Pravidlo zadávání zakázek" diff --git a/procurement_auto_create_group/i18n/de.po b/procurement_auto_create_group/i18n/de.po index 68f170d0a..5e0a04e27 100644 --- a/procurement_auto_create_group/i18n/de.po +++ b/procurement_auto_create_group/i18n/de.po @@ -27,14 +27,12 @@ msgstr "Auto-Anlage Beschaffungsgruppe" #. module: procurement_auto_create_group #: code:addons/procurement_auto_create_group/models/procurement_group.py:0 #, fuzzy, python-format -#| msgid "No sequence defined for procurement group" msgid "No sequence defined for procurement group." msgstr "Keine Reihenfolge in Beschaffungsgruppe festgelegt" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Beschaffungsregel" diff --git a/procurement_auto_create_group/i18n/es.po b/procurement_auto_create_group/i18n/es.po index 32ceedfae..0f4d8ac3e 100644 --- a/procurement_auto_create_group/i18n/es.po +++ b/procurement_auto_create_group/i18n/es.po @@ -27,14 +27,12 @@ msgstr "Crear grupo de abastecimiento automáticamene" #. module: procurement_auto_create_group #: code:addons/procurement_auto_create_group/models/procurement_group.py:0 #, fuzzy, python-format -#| msgid "No sequence defined for procurement group" msgid "No sequence defined for procurement group." msgstr "No se ha definido una secuencia para el grupo de abastecimiento" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Regla de abastecimiento" diff --git a/procurement_auto_create_group/i18n/hr.po b/procurement_auto_create_group/i18n/hr.po index 7f6d05a59..57ee85147 100644 --- a/procurement_auto_create_group/i18n/hr.po +++ b/procurement_auto_create_group/i18n/hr.po @@ -28,14 +28,12 @@ msgstr "Automatski kreiraj grupu nabave" #. module: procurement_auto_create_group #: code:addons/procurement_auto_create_group/models/procurement_group.py:0 #, fuzzy, python-format -#| msgid "No sequence defined for procurement group" msgid "No sequence defined for procurement group." msgstr "Nema definiranog brojevnog kruga za grupe nabave" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Pavilo nabave" diff --git a/procurement_auto_create_group/i18n/it.po b/procurement_auto_create_group/i18n/it.po index 46bce8b45..6df84fca6 100644 --- a/procurement_auto_create_group/i18n/it.po +++ b/procurement_auto_create_group/i18n/it.po @@ -33,7 +33,6 @@ msgstr "" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Regola d'Approvvigionamento" diff --git a/procurement_auto_create_group/i18n/sl.po b/procurement_auto_create_group/i18n/sl.po index 44153d385..fca10bb6b 100644 --- a/procurement_auto_create_group/i18n/sl.po +++ b/procurement_auto_create_group/i18n/sl.po @@ -34,7 +34,6 @@ msgstr "" #. module: procurement_auto_create_group #: model:ir.model,name:procurement_auto_create_group.model_procurement_group #, fuzzy -#| msgid "Procurement Rule" msgid "Procurement Group" msgstr "Oskrbovalno pravilo" diff --git a/sale_stock_available_info_popup/README.rst b/sale_stock_available_info_popup/README.rst new file mode 100644 index 000000000..eade50bc5 --- /dev/null +++ b/sale_stock_available_info_popup/README.rst @@ -0,0 +1,98 @@ +=============================== +Sale Stock Available Info Popup +=============================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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/sale_stock_available_info_popup + :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-sale_stock_available_info_popup + :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 'Sale Stock' module +to add the 'Available to promise' quantity of the corresponding product +to the pop-up that show stock information at sales order line level. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +#. Go to *Sales > Orders > quotations* and create a new one. +#. Add a sale order line with a storable product +#. Click on the icon |fa_info_circle| in the line and you will + see in the popover the 'Available to promise' quantity of the + corresponding product. + +Note: Now the color of the icon depends on the 'Available to promise' +quantity of the corresponding product instead of 'Forecast Quantity'. +If that quantity is less than the quantity to deliver, the color of +the icon will be red, indicating an alert; otherwise it will be blue. + +.. |fa_info_circle| image:: https://raw.githubusercontent.com/OCA/stock-logistics-warehouse/13.0/sale_stock_available_info_popup/static/src/img/info-circle-solid.png + :width: 10px + +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 +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Ernesto Tejeda + * Pedro M. Baeza + * Víctor Martínez + +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/sale_stock_available_info_popup/__init__.py b/sale_stock_available_info_popup/__init__.py new file mode 100644 index 000000000..4b76c7b2d --- /dev/null +++ b/sale_stock_available_info_popup/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/sale_stock_available_info_popup/__manifest__.py b/sale_stock_available_info_popup/__manifest__.py new file mode 100644 index 000000000..942a5aec6 --- /dev/null +++ b/sale_stock_available_info_popup/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). +{ + "name": "Sale Stock Available Info Popup", + "summary": "Adds an 'Available to promise' quantity to the popover shown " + "in sale order line that display stock info of the product", + "author": "Tecnativa, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse Management", + "version": "13.0.1.0.0", + "license": "AGPL-3", + "depends": ["sale_stock", "stock_available"], + "data": ["views/sale_order_views.xml"], + "qweb": ["static/src/xml/qty_at_date.xml"], + "installable": True, +} diff --git a/sale_stock_available_info_popup/i18n/es.po b/sale_stock_available_info_popup/i18n/es.po new file mode 100644 index 000000000..25b0ad26f --- /dev/null +++ b/sale_stock_available_info_popup/i18n/es.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_stock_available_info_popup +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-24 19:48+0000\n" +"PO-Revision-Date: 2020-04-24 15:53-0400\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: es\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 2.0.6\n" + +#. module: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "Available to promise" +msgstr "Disponible para Prometer" + +#. module: sale_stock_available_info_popup +#: model:ir.model.fields,field_description:sale_stock_available_info_popup.field_sale_order_line__immediately_usable_qty_today +msgid "Immediately Usable Qty Today" +msgstr "" + +#. module: sale_stock_available_info_popup +#: model:ir.model,name:sale_stock_available_info_popup.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de pedido de venta" + +#. module: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "" +"widget.data.immediately_usable_qty_today < widget.data.qty_to_deliver and !" +"widget.data.is_mto" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" diff --git a/sale_stock_available_info_popup/i18n/sale_stock_available_info_popup.pot b/sale_stock_available_info_popup/i18n/sale_stock_available_info_popup.pot new file mode 100644 index 000000000..8154fda13 --- /dev/null +++ b/sale_stock_available_info_popup/i18n/sale_stock_available_info_popup.pot @@ -0,0 +1,40 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_stock_available_info_popup +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "Available to promise" +msgstr "" + +#. module: sale_stock_available_info_popup +#: model:ir.model.fields,field_description:sale_stock_available_info_popup.field_sale_order_line__immediately_usable_qty_today +msgid "Immediately Usable Qty Today" +msgstr "" + +#. module: sale_stock_available_info_popup +#: model:ir.model,name:sale_stock_available_info_popup.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "" +"widget.data.immediately_usable_qty_today < widget.data.qty_to_deliver and " +"!widget.data.is_mto" +msgstr "" diff --git a/sale_stock_available_info_popup/i18n/sl.po b/sale_stock_available_info_popup/i18n/sl.po new file mode 100644 index 000000000..877b19c8b --- /dev/null +++ b/sale_stock_available_info_popup/i18n/sl.po @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_stock_available_info_popup +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-08-11 10:59+0000\n" +"Last-Translator: Matjaz Mozetic \n" +"Language-Team: none\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3;\n" +"X-Generator: Weblate 3.10\n" + +#. module: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "Available to promise" +msgstr "Lahko obljubimo" + +#. module: sale_stock_available_info_popup +#: model:ir.model.fields,field_description:sale_stock_available_info_popup.field_sale_order_line__immediately_usable_qty_today +msgid "Immediately Usable Qty Today" +msgstr "Takoj razpoložljiva današnja kol" + +#. module: sale_stock_available_info_popup +#: model:ir.model,name:sale_stock_available_info_popup.model_sale_order_line +msgid "Sales Order Line" +msgstr "Prodajna postavka" + +#. module: sale_stock_available_info_popup +#. openerp-web +#: code:addons/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml:0 +#, python-format +msgid "" +"widget.data.immediately_usable_qty_today < widget.data.qty_to_deliver and !" +"widget.data.is_mto" +msgstr "" +"widget.data.immediately_usable_qty_today < widget.data.qty_to_deliver and !" +"widget.data.is_mto" diff --git a/sale_stock_available_info_popup/models/__init__.py b/sale_stock_available_info_popup/models/__init__.py new file mode 100644 index 000000000..b1ad204bd --- /dev/null +++ b/sale_stock_available_info_popup/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import sale_order diff --git a/sale_stock_available_info_popup/models/sale_order.py b/sale_stock_available_info_popup/models/sale_order.py new file mode 100644 index 000000000..53c6eff34 --- /dev/null +++ b/sale_stock_available_info_popup/models/sale_order.py @@ -0,0 +1,30 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from collections import defaultdict + +from odoo import api, fields, models + + +class SaleOrderLine(models.Model): + _inherit = "sale.order.line" + + immediately_usable_qty_today = fields.Float( + compute="_compute_immediately_usable_qty_today" + ) + + @api.depends("product_id", "product_uom_qty") + def _compute_immediately_usable_qty_today(self): + qty_processed_per_product = defaultdict(lambda: 0) + remaining = self.env["sale.order.line"] + for line in self.sorted(key=lambda r: r.sequence): + if not line.display_qty_widget: + remaining |= line + continue + product = line.product_id + qty_processed = qty_processed_per_product[product.id] + line.immediately_usable_qty_today = ( + product.immediately_usable_qty - qty_processed + ) + qty_processed_per_product[product.id] += line.product_uom_qty + remaining.write({"immediately_usable_qty_today": False}) diff --git a/sale_stock_available_info_popup/readme/CONTRIBUTORS.rst b/sale_stock_available_info_popup/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..bef4cdf82 --- /dev/null +++ b/sale_stock_available_info_popup/readme/CONTRIBUTORS.rst @@ -0,0 +1,5 @@ +* `Tecnativa `_: + + * Ernesto Tejeda + * Pedro M. Baeza + * Víctor Martínez diff --git a/sale_stock_available_info_popup/readme/DESCRIPTION.rst b/sale_stock_available_info_popup/readme/DESCRIPTION.rst new file mode 100644 index 000000000..e690dfbcd --- /dev/null +++ b/sale_stock_available_info_popup/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module extends the functionality of 'Sale Stock' module +to add the 'Available to promise' quantity of the corresponding product +to the pop-up that show stock information at sales order line level. diff --git a/sale_stock_available_info_popup/readme/USAGE.rst b/sale_stock_available_info_popup/readme/USAGE.rst new file mode 100644 index 000000000..a9e540334 --- /dev/null +++ b/sale_stock_available_info_popup/readme/USAGE.rst @@ -0,0 +1,15 @@ +To use this module, you need to: + +#. Go to *Sales > Orders > quotations* and create a new one. +#. Add a sale order line with a storable product +#. Click on the icon |fa_info_circle| in the line and you will + see in the popover the 'Available to promise' quantity of the + corresponding product. + +Note: Now the color of the icon depends on the 'Available to promise' +quantity of the corresponding product instead of 'Forecast Quantity'. +If that quantity is less than the quantity to deliver, the color of +the icon will be red, indicating an alert; otherwise it will be blue. + +.. |fa_info_circle| image:: ../static/src/img/info-circle-solid.png + :width: 10px diff --git a/sale_stock_available_info_popup/static/description/icon.png b/sale_stock_available_info_popup/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/sale_stock_available_info_popup/static/description/icon.png differ diff --git a/sale_stock_available_info_popup/static/description/index.html b/sale_stock_available_info_popup/static/description/index.html new file mode 100644 index 000000000..aa6b6939e --- /dev/null +++ b/sale_stock_available_info_popup/static/description/index.html @@ -0,0 +1,442 @@ + + + + + + +Sale Stock Available Info Popup + + + +
+

Sale Stock Available Info Popup

+ + +

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

+

This module extends the functionality of ‘Sale Stock’ module +to add the ‘Available to promise’ quantity of the corresponding product +to the pop-up that show stock information at sales order line level.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to Sales > Orders > quotations and create a new one.
  2. +
  3. Add a sale order line with a storable product
  4. +
  5. Click on the icon fa_info_circle in the line and you will +see in the popover the ‘Available to promise’ quantity of the +corresponding product.
  6. +
+

Note: Now the color of the icon depends on the ‘Available to promise’ +quantity of the corresponding product instead of ‘Forecast Quantity’. +If that quantity is less than the quantity to deliver, the color of +the icon will be red, indicating an alert; otherwise it will be blue.

+
+
+

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

+
    +
  • Tecnativa:
      +
    • Ernesto Tejeda
    • +
    • Pedro M. Baeza
    • +
    • Víctor Martínez
    • +
    +
  • +
+
+
+

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/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml b/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml new file mode 100644 index 000000000..dea9486b9 --- /dev/null +++ b/sale_stock_available_info_popup/static/src/xml/qty_at_date.xml @@ -0,0 +1,28 @@ + + + +
+ + widget.data.immediately_usable_qty_today < widget.data.qty_to_deliver and !widget.data.is_mto + +
+
+ + + + Available to promise + + + + + + + +
+
diff --git a/sale_stock_available_info_popup/tests/__init__.py b/sale_stock_available_info_popup/tests/__init__.py new file mode 100644 index 000000000..47d980912 --- /dev/null +++ b/sale_stock_available_info_popup/tests/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from . import test_sale_stock_available_info_popup diff --git a/sale_stock_available_info_popup/tests/test_sale_stock_available_info_popup.py b/sale_stock_available_info_popup/tests/test_sale_stock_available_info_popup.py new file mode 100644 index 000000000..ef95d663e --- /dev/null +++ b/sale_stock_available_info_popup/tests/test_sale_stock_available_info_popup.py @@ -0,0 +1,152 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import SavepointCase + + +class SaleStockAvailableInfoPopup(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + user_group_stock_user = cls.env.ref("stock.group_stock_user") + cls.user_stock_user = cls.env["res.users"].create( + { + "name": "Pauline Poivraisselle", + "login": "pauline", + "email": "p.p@example.com", + "notification_type": "inbox", + "groups_id": [(6, 0, [user_group_stock_user.id])], + } + ) + cls.product = cls.env["product.product"].create( + {"name": "Storable product", "type": "product"} + ) + cls.stock_location = cls.env.ref("stock.stock_location_stock") + cls.customers_location = cls.env.ref("stock.stock_location_customers") + cls.suppliers_location = cls.env.ref("stock.stock_location_suppliers") + cls.env["stock.quant"].create( + { + "product_id": cls.product.id, + "location_id": cls.stock_location.id, + "quantity": 40.0, + } + ) + cls.picking_out = cls.env["stock.picking"].create( + { + "picking_type_id": cls.env.ref("stock.picking_type_out").id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + } + ) + cls.env["stock.move"].create( + { + "name": "a move", + "product_id": cls.product.id, + "product_uom_qty": 3.0, + "product_uom": cls.product.uom_id.id, + "picking_id": cls.picking_out.id, + "location_id": cls.stock_location.id, + "location_dest_id": cls.customers_location.id, + } + ) + cls.picking_in = cls.env["stock.picking"].create( + { + "picking_type_id": cls.env.ref("stock.picking_type_in").id, + "location_id": cls.suppliers_location.id, + "location_dest_id": cls.stock_location.id, + } + ) + cls.env["stock.move"].create( + { + "restrict_partner_id": cls.user_stock_user.partner_id.id, + "name": "another move", + "product_id": cls.product.id, + "product_uom_qty": 5.0, + "product_uom": cls.product.uom_id.id, + "picking_id": cls.picking_in.id, + "location_id": cls.suppliers_location.id, + "location_dest_id": cls.stock_location.id, + } + ) + + def test_immediately_usable_qty_today(self): + self.picking_out.action_confirm() + self.picking_in.action_assign() + so = self.env["sale.order"].create( + { + "partner_id": self.env.ref("base.res_partner_1").id, + "order_line": [ + ( + 0, + 0, + { + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 1, + "product_uom": self.product.uom_id.id, + "price_unit": self.product.list_price, + }, + ), + ], + } + ) + line = so.order_line + self.assertEqual( + line.immediately_usable_qty_today, self.product.immediately_usable_qty, + ) + + def test_immediately_usable_qty_today_similar_solines(self): + """Create a sale order containing three times the same product. The + quantity available should be different for the 3 lines. + """ + so = self.env["sale.order"].create( + { + "partner_id": self.env.ref("base.res_partner_1").id, + "order_line": [ + ( + 0, + 0, + { + "sequence": 1, + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 5, + "product_uom": self.product.uom_id.id, + "price_unit": self.product.list_price, + }, + ), + ( + 0, + 0, + { + "sequence": 2, + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 5, + "product_uom": self.product.uom_id.id, + "price_unit": self.product.list_price, + }, + ), + ( + 0, + 0, + { + "sequence": 3, + "name": self.product.name, + "product_id": self.product.id, + "product_uom_qty": 5, + "product_uom": self.product.uom_id.id, + "price_unit": self.product.list_price, + }, + ), + ], + } + ) + self.assertEqual( + so.order_line.mapped("immediately_usable_qty_today"), + [ + self.product.immediately_usable_qty, + self.product.immediately_usable_qty - 5, + self.product.immediately_usable_qty - 10, + ], + ) diff --git a/sale_stock_available_info_popup/views/sale_order_views.xml b/sale_stock_available_info_popup/views/sale_order_views.xml new file mode 100644 index 000000000..52d82ba84 --- /dev/null +++ b/sale_stock_available_info_popup/views/sale_order_views.xml @@ -0,0 +1,18 @@ + + + + + sale.order.line.tree.inherit + sale.order + + + + + + + + diff --git a/scrap_reason_code/__manifest__.py b/scrap_reason_code/__manifest__.py index 19d944d1a..7c487f505 100644 --- a/scrap_reason_code/__manifest__.py +++ b/scrap_reason_code/__manifest__.py @@ -2,7 +2,7 @@ { "name": "Scrap Reason Code", - "version": "13.0.1.1.0", + "version": "13.0.1.1.1", "license": "AGPL-3", "summary": "Reason code for scrapping", "author": "Open Source Integrators, Odoo Community Association (OCA)", diff --git a/scrap_reason_code/models/stock_scrap.py b/scrap_reason_code/models/stock_scrap.py index afa1dd2c8..9b3f90277 100644 --- a/scrap_reason_code/models/stock_scrap.py +++ b/scrap_reason_code/models/stock_scrap.py @@ -25,21 +25,23 @@ class StockScrap(models.Model): def write(self, vals): if "reason_code_id" in vals: - vals.update( - { - "scrap_location_id": self.env["scrap.reason.code"] - .browse(vals.get("reason_code_id")) - .location_id - } + location_id = ( + self.env["scrap.reason.code"] + .browse(vals.get("reason_code_id")) + .location_id ) + if location_id: + vals.update({"scrap_location_id": location_id}) return super(StockScrap, self).write(vals) @api.model def create(self, vals): if "reason_code_id" in vals: - vals["scrap_location_id"] = ( + location_id = ( self.env["scrap.reason.code"] .browse(vals.get("reason_code_id")) - .location_id.id + .location_id ) + if location_id: + vals["scrap_location_id"] = location_id.id return super(StockScrap, self).create(vals) diff --git a/setup/_metapackage/VERSION.txt b/setup/_metapackage/VERSION.txt index 1da6cef0e..97c0d9589 100644 --- a/setup/_metapackage/VERSION.txt +++ b/setup/_metapackage/VERSION.txt @@ -1 +1 @@ -13.0.20200929.0 \ No newline at end of file +13.0.20210611.0 \ No newline at end of file diff --git a/setup/_metapackage/setup.py b/setup/_metapackage/setup.py index 5dc42ee74..84a1d7a89 100644 --- a/setup/_metapackage/setup.py +++ b/setup/_metapackage/setup.py @@ -12,49 +12,76 @@ setuptools.setup( 'odoo13-addon-account_move_line_stock_info', 'odoo13-addon-procurement_auto_create_group', 'odoo13-addon-product_quantity_update_force_inventory', + 'odoo13-addon-sale_stock_available_info_popup', 'odoo13-addon-scrap_reason_code', 'odoo13-addon-stock_account_change_qty_reason', + 'odoo13-addon-stock_archive_constraint', 'odoo13-addon-stock_available', + 'odoo13-addon-stock_available_immediately', + 'odoo13-addon-stock_available_mrp', 'odoo13-addon-stock_available_unreserved', 'odoo13-addon-stock_change_qty_reason', 'odoo13-addon-stock_cubiscan', 'odoo13-addon-stock_cycle_count', 'odoo13-addon-stock_demand_estimate', 'odoo13-addon-stock_demand_estimate_matrix', + 'odoo13-addon-stock_helper', 'odoo13-addon-stock_inventory_chatter', 'odoo13-addon-stock_inventory_cost_info', 'odoo13-addon-stock_inventory_discrepancy', 'odoo13-addon-stock_inventory_exclude_sublocation', 'odoo13-addon-stock_inventory_include_exhausted', + 'odoo13-addon-stock_inventory_justification', + 'odoo13-addon-stock_inventory_line_open', 'odoo13-addon-stock_inventory_lockdown', 'odoo13-addon-stock_inventory_preparation_filter', 'odoo13-addon-stock_location_bin_name', + 'odoo13-addon-stock_location_children', + 'odoo13-addon-stock_location_last_inventory_date', + 'odoo13-addon-stock_location_lockdown', 'odoo13-addon-stock_location_position', 'odoo13-addon-stock_location_tray', 'odoo13-addon-stock_location_zone', + 'odoo13-addon-stock_lot_filter_available', + 'odoo13-addon-stock_measuring_device', + 'odoo13-addon-stock_measuring_device_zippcube', 'odoo13-addon-stock_move_auto_assign', 'odoo13-addon-stock_move_common_dest', 'odoo13-addon-stock_move_location', + 'odoo13-addon-stock_mts_mto_rule', + 'odoo13-addon-stock_orderpoint_generator', 'odoo13-addon-stock_orderpoint_manual_procurement', + 'odoo13-addon-stock_orderpoint_manual_procurement_uom', 'odoo13-addon-stock_orderpoint_move_link', 'odoo13-addon-stock_orderpoint_purchase_link', 'odoo13-addon-stock_orderpoint_route', 'odoo13-addon-stock_orderpoint_uom', 'odoo13-addon-stock_packaging_calculator', + 'odoo13-addon-stock_packaging_calculator_packaging_type', 'odoo13-addon-stock_picking_completion_info', 'odoo13-addon-stock_picking_consolidation_priority', + 'odoo13-addon-stock_picking_procure_method', + 'odoo13-addon-stock_product_qty_by_packaging', + 'odoo13-addon-stock_pull_list', + 'odoo13-addon-stock_putaway_product_template', 'odoo13-addon-stock_quant_manual_assign', 'odoo13-addon-stock_removal_location_by_priority', 'odoo13-addon-stock_request', + 'odoo13-addon-stock_request_analytic', + 'odoo13-addon-stock_request_direction', 'odoo13-addon-stock_request_kanban', 'odoo13-addon-stock_request_mrp', + 'odoo13-addon-stock_request_picking_type', 'odoo13-addon-stock_request_purchase', + 'odoo13-addon-stock_request_submit', 'odoo13-addon-stock_request_tier_validation', 'odoo13-addon-stock_reserve_rule', 'odoo13-addon-stock_secondary_unit', 'odoo13-addon-stock_vertical_lift', + 'odoo13-addon-stock_vertical_lift_empty_tray_check', 'odoo13-addon-stock_vertical_lift_kardex', 'odoo13-addon-stock_vertical_lift_packaging_type', + 'odoo13-addon-stock_vertical_lift_qty_by_packaging', 'odoo13-addon-stock_vertical_lift_server_env', 'odoo13-addon-stock_vertical_lift_storage_type', 'odoo13-addon-stock_warehouse_calendar', diff --git a/setup/sale_stock_available_info_popup/odoo/addons/sale_stock_available_info_popup b/setup/sale_stock_available_info_popup/odoo/addons/sale_stock_available_info_popup new file mode 120000 index 000000000..7ddb79ef2 --- /dev/null +++ b/setup/sale_stock_available_info_popup/odoo/addons/sale_stock_available_info_popup @@ -0,0 +1 @@ +../../../../sale_stock_available_info_popup \ No newline at end of file diff --git a/setup/sale_stock_available_info_popup/setup.py b/setup/sale_stock_available_info_popup/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/sale_stock_available_info_popup/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_archive_constraint/odoo/addons/stock_archive_constraint b/setup/stock_archive_constraint/odoo/addons/stock_archive_constraint new file mode 120000 index 000000000..06320188a --- /dev/null +++ b/setup/stock_archive_constraint/odoo/addons/stock_archive_constraint @@ -0,0 +1 @@ +../../../../stock_archive_constraint \ No newline at end of file diff --git a/setup/stock_archive_constraint/setup.py b/setup/stock_archive_constraint/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_archive_constraint/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_available_immediately/odoo/addons/stock_available_immediately b/setup/stock_available_immediately/odoo/addons/stock_available_immediately new file mode 120000 index 000000000..8ab3a1f19 --- /dev/null +++ b/setup/stock_available_immediately/odoo/addons/stock_available_immediately @@ -0,0 +1 @@ +../../../../stock_available_immediately \ No newline at end of file diff --git a/setup/stock_available_immediately/setup.py b/setup/stock_available_immediately/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_available_immediately/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_available_mrp/odoo/addons/stock_available_mrp b/setup/stock_available_mrp/odoo/addons/stock_available_mrp new file mode 120000 index 000000000..cd15a8cae --- /dev/null +++ b/setup/stock_available_mrp/odoo/addons/stock_available_mrp @@ -0,0 +1 @@ +../../../../stock_available_mrp \ No newline at end of file diff --git a/setup/stock_available_mrp/setup.py b/setup/stock_available_mrp/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_available_mrp/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_helper/odoo/addons/stock_helper b/setup/stock_helper/odoo/addons/stock_helper new file mode 120000 index 000000000..0284ed59e --- /dev/null +++ b/setup/stock_helper/odoo/addons/stock_helper @@ -0,0 +1 @@ +../../../../stock_helper \ No newline at end of file diff --git a/setup/stock_helper/setup.py b/setup/stock_helper/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_helper/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_inventory_justification/.eggs/README.txt b/setup/stock_inventory_justification/.eggs/README.txt new file mode 100644 index 000000000..5d0166882 --- /dev/null +++ b/setup/stock_inventory_justification/.eggs/README.txt @@ -0,0 +1,6 @@ +This directory contains eggs that were downloaded by setuptools to build, test, and run plug-ins. + +This directory caches those eggs to prevent repeated downloads. + +However, it is safe to delete this directory. + diff --git a/setup/stock_inventory_justification/odoo/addons/stock_inventory_justification b/setup/stock_inventory_justification/odoo/addons/stock_inventory_justification new file mode 120000 index 000000000..86563f133 --- /dev/null +++ b/setup/stock_inventory_justification/odoo/addons/stock_inventory_justification @@ -0,0 +1 @@ +../../../../stock_inventory_justification \ No newline at end of file diff --git a/setup/stock_inventory_justification/setup.py b/setup/stock_inventory_justification/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_inventory_justification/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_inventory_line_open/odoo/addons/stock_inventory_line_open b/setup/stock_inventory_line_open/odoo/addons/stock_inventory_line_open new file mode 120000 index 000000000..cbdc529ca --- /dev/null +++ b/setup/stock_inventory_line_open/odoo/addons/stock_inventory_line_open @@ -0,0 +1 @@ +../../../../stock_inventory_line_open \ No newline at end of file diff --git a/setup/stock_inventory_line_open/setup.py b/setup/stock_inventory_line_open/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_inventory_line_open/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_location_children/odoo/addons/stock_location_children b/setup/stock_location_children/odoo/addons/stock_location_children new file mode 120000 index 000000000..094bfef70 --- /dev/null +++ b/setup/stock_location_children/odoo/addons/stock_location_children @@ -0,0 +1 @@ +../../../../stock_location_children \ No newline at end of file diff --git a/setup/stock_location_children/setup.py b/setup/stock_location_children/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_location_children/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_location_last_inventory_date/odoo/addons/stock_location_last_inventory_date b/setup/stock_location_last_inventory_date/odoo/addons/stock_location_last_inventory_date new file mode 120000 index 000000000..f6b3dd1eb --- /dev/null +++ b/setup/stock_location_last_inventory_date/odoo/addons/stock_location_last_inventory_date @@ -0,0 +1 @@ +../../../../stock_location_last_inventory_date \ No newline at end of file diff --git a/setup/stock_location_last_inventory_date/setup.py b/setup/stock_location_last_inventory_date/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_location_last_inventory_date/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_location_lockdown/odoo/addons/stock_location_lockdown b/setup/stock_location_lockdown/odoo/addons/stock_location_lockdown new file mode 120000 index 000000000..d42a395d7 --- /dev/null +++ b/setup/stock_location_lockdown/odoo/addons/stock_location_lockdown @@ -0,0 +1 @@ +../../../../stock_location_lockdown \ No newline at end of file diff --git a/setup/stock_location_lockdown/setup.py b/setup/stock_location_lockdown/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_location_lockdown/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_lot_filter_available/odoo/addons/stock_lot_filter_available b/setup/stock_lot_filter_available/odoo/addons/stock_lot_filter_available new file mode 120000 index 000000000..bff6f8e24 --- /dev/null +++ b/setup/stock_lot_filter_available/odoo/addons/stock_lot_filter_available @@ -0,0 +1 @@ +../../../../stock_lot_filter_available \ No newline at end of file diff --git a/setup/stock_lot_filter_available/setup.py b/setup/stock_lot_filter_available/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_lot_filter_available/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_measuring_device/odoo/addons/stock_measuring_device b/setup/stock_measuring_device/odoo/addons/stock_measuring_device new file mode 120000 index 000000000..03db46a1b --- /dev/null +++ b/setup/stock_measuring_device/odoo/addons/stock_measuring_device @@ -0,0 +1 @@ +../../../../stock_measuring_device \ No newline at end of file diff --git a/setup/stock_measuring_device/setup.py b/setup/stock_measuring_device/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_measuring_device/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_measuring_device_zippcube/odoo/addons/stock_measuring_device_zippcube b/setup/stock_measuring_device_zippcube/odoo/addons/stock_measuring_device_zippcube new file mode 120000 index 000000000..fa10ebc8a --- /dev/null +++ b/setup/stock_measuring_device_zippcube/odoo/addons/stock_measuring_device_zippcube @@ -0,0 +1 @@ +../../../../stock_measuring_device_zippcube \ No newline at end of file diff --git a/setup/stock_measuring_device_zippcube/setup.py b/setup/stock_measuring_device_zippcube/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_measuring_device_zippcube/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_mts_mto_rule/odoo/addons/stock_mts_mto_rule b/setup/stock_mts_mto_rule/odoo/addons/stock_mts_mto_rule new file mode 120000 index 000000000..de51d31cf --- /dev/null +++ b/setup/stock_mts_mto_rule/odoo/addons/stock_mts_mto_rule @@ -0,0 +1 @@ +../../../../stock_mts_mto_rule \ No newline at end of file diff --git a/setup/stock_mts_mto_rule/setup.py b/setup/stock_mts_mto_rule/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_mts_mto_rule/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_orderpoint_generator/odoo/addons/stock_orderpoint_generator b/setup/stock_orderpoint_generator/odoo/addons/stock_orderpoint_generator new file mode 120000 index 000000000..280f25ec6 --- /dev/null +++ b/setup/stock_orderpoint_generator/odoo/addons/stock_orderpoint_generator @@ -0,0 +1 @@ +../../../../stock_orderpoint_generator \ No newline at end of file diff --git a/setup/stock_orderpoint_generator/setup.py b/setup/stock_orderpoint_generator/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_orderpoint_generator/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_orderpoint_manual_procurement_uom/odoo/addons/stock_orderpoint_manual_procurement_uom b/setup/stock_orderpoint_manual_procurement_uom/odoo/addons/stock_orderpoint_manual_procurement_uom new file mode 120000 index 000000000..be5ae9eaa --- /dev/null +++ b/setup/stock_orderpoint_manual_procurement_uom/odoo/addons/stock_orderpoint_manual_procurement_uom @@ -0,0 +1 @@ +../../../../stock_orderpoint_manual_procurement_uom \ No newline at end of file diff --git a/setup/stock_orderpoint_manual_procurement_uom/setup.py b/setup/stock_orderpoint_manual_procurement_uom/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_orderpoint_manual_procurement_uom/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_packaging_calculator_packaging_type/odoo/addons/stock_packaging_calculator_packaging_type b/setup/stock_packaging_calculator_packaging_type/odoo/addons/stock_packaging_calculator_packaging_type new file mode 120000 index 000000000..f1de9f895 --- /dev/null +++ b/setup/stock_packaging_calculator_packaging_type/odoo/addons/stock_packaging_calculator_packaging_type @@ -0,0 +1 @@ +../../../../stock_packaging_calculator_packaging_type \ No newline at end of file diff --git a/setup/stock_packaging_calculator_packaging_type/setup.py b/setup/stock_packaging_calculator_packaging_type/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_packaging_calculator_packaging_type/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_picking_procure_method/odoo/addons/stock_picking_procure_method b/setup/stock_picking_procure_method/odoo/addons/stock_picking_procure_method new file mode 120000 index 000000000..1c33a9a7c --- /dev/null +++ b/setup/stock_picking_procure_method/odoo/addons/stock_picking_procure_method @@ -0,0 +1 @@ +../../../../stock_picking_procure_method \ No newline at end of file diff --git a/setup/stock_picking_procure_method/setup.py b/setup/stock_picking_procure_method/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_picking_procure_method/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_product_qty_by_packaging/odoo/addons/stock_product_qty_by_packaging b/setup/stock_product_qty_by_packaging/odoo/addons/stock_product_qty_by_packaging new file mode 120000 index 000000000..702cf61a4 --- /dev/null +++ b/setup/stock_product_qty_by_packaging/odoo/addons/stock_product_qty_by_packaging @@ -0,0 +1 @@ +../../../../stock_product_qty_by_packaging \ No newline at end of file diff --git a/setup/stock_product_qty_by_packaging/setup.py b/setup/stock_product_qty_by_packaging/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_product_qty_by_packaging/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_pull_list/odoo/addons/stock_pull_list b/setup/stock_pull_list/odoo/addons/stock_pull_list new file mode 120000 index 000000000..a6ea144b4 --- /dev/null +++ b/setup/stock_pull_list/odoo/addons/stock_pull_list @@ -0,0 +1 @@ +../../../../stock_pull_list \ No newline at end of file diff --git a/setup/stock_pull_list/setup.py b/setup/stock_pull_list/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_pull_list/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_putaway_product_template/odoo/addons/stock_putaway_product_template b/setup/stock_putaway_product_template/odoo/addons/stock_putaway_product_template new file mode 120000 index 000000000..2b9ca4b93 --- /dev/null +++ b/setup/stock_putaway_product_template/odoo/addons/stock_putaway_product_template @@ -0,0 +1 @@ +../../../../stock_putaway_product_template \ No newline at end of file diff --git a/setup/stock_putaway_product_template/setup.py b/setup/stock_putaway_product_template/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_putaway_product_template/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_request_analytic/odoo/addons/stock_request_analytic b/setup/stock_request_analytic/odoo/addons/stock_request_analytic new file mode 120000 index 000000000..f4f495d18 --- /dev/null +++ b/setup/stock_request_analytic/odoo/addons/stock_request_analytic @@ -0,0 +1 @@ +../../../../stock_request_analytic \ No newline at end of file diff --git a/setup/stock_request_analytic/setup.py b/setup/stock_request_analytic/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_request_analytic/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_request_direction/odoo/addons/stock_request_direction b/setup/stock_request_direction/odoo/addons/stock_request_direction new file mode 120000 index 000000000..0e365a6c0 --- /dev/null +++ b/setup/stock_request_direction/odoo/addons/stock_request_direction @@ -0,0 +1 @@ +../../../../stock_request_direction \ No newline at end of file diff --git a/setup/stock_request_direction/setup.py b/setup/stock_request_direction/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_request_direction/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_request_picking_type/odoo/addons/stock_request_picking_type b/setup/stock_request_picking_type/odoo/addons/stock_request_picking_type new file mode 120000 index 000000000..8155692d1 --- /dev/null +++ b/setup/stock_request_picking_type/odoo/addons/stock_request_picking_type @@ -0,0 +1 @@ +../../../../stock_request_picking_type \ No newline at end of file diff --git a/setup/stock_request_picking_type/setup.py b/setup/stock_request_picking_type/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_request_picking_type/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_request_submit/odoo/addons/stock_request_submit b/setup/stock_request_submit/odoo/addons/stock_request_submit new file mode 120000 index 000000000..a183bdbeb --- /dev/null +++ b/setup/stock_request_submit/odoo/addons/stock_request_submit @@ -0,0 +1 @@ +../../../../stock_request_submit \ No newline at end of file diff --git a/setup/stock_request_submit/setup.py b/setup/stock_request_submit/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_request_submit/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_vertical_lift_empty_tray_check/odoo/addons/stock_vertical_lift_empty_tray_check b/setup/stock_vertical_lift_empty_tray_check/odoo/addons/stock_vertical_lift_empty_tray_check new file mode 120000 index 000000000..405a5f896 --- /dev/null +++ b/setup/stock_vertical_lift_empty_tray_check/odoo/addons/stock_vertical_lift_empty_tray_check @@ -0,0 +1 @@ +../../../../stock_vertical_lift_empty_tray_check \ No newline at end of file diff --git a/setup/stock_vertical_lift_empty_tray_check/setup.py b/setup/stock_vertical_lift_empty_tray_check/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_vertical_lift_empty_tray_check/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/setup/stock_vertical_lift_qty_by_packaging/odoo/addons/stock_vertical_lift_qty_by_packaging b/setup/stock_vertical_lift_qty_by_packaging/odoo/addons/stock_vertical_lift_qty_by_packaging new file mode 120000 index 000000000..9493f2eac --- /dev/null +++ b/setup/stock_vertical_lift_qty_by_packaging/odoo/addons/stock_vertical_lift_qty_by_packaging @@ -0,0 +1 @@ +../../../../stock_vertical_lift_qty_by_packaging \ No newline at end of file diff --git a/setup/stock_vertical_lift_qty_by_packaging/setup.py b/setup/stock_vertical_lift_qty_by_packaging/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_vertical_lift_qty_by_packaging/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_archive_constraint/README.rst b/stock_archive_constraint/README.rst new file mode 100644 index 000000000..eddc13a84 --- /dev/null +++ b/stock_archive_constraint/README.rst @@ -0,0 +1,91 @@ +======================== +Stock archive constraint +======================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |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_archive_constraint + :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_archive_constraint + :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| + +Allows to block archiving products with associated stock.quant or stock.move. +Allows to block archiving locations with associated stock.quant or stock.move. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +#. Go to Settings > Users > Edit a user and check the "Manage Multiple Stock Locations" permission +#. Go to Inventory > Settings > Locations and disable one + +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 +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Carlos Daudén + * Víctor Martínez + +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. + +.. |maintainer-victoralmau| image:: https://github.com/victoralmau.png?size=40px + :target: https://github.com/victoralmau + :alt: victoralmau + +Current `maintainer `__: + +|maintainer-victoralmau| + +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_archive_constraint/__init__.py b/stock_archive_constraint/__init__.py new file mode 100644 index 000000000..83e553ac4 --- /dev/null +++ b/stock_archive_constraint/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/stock_archive_constraint/__manifest__.py b/stock_archive_constraint/__manifest__.py new file mode 100644 index 000000000..3b9806b86 --- /dev/null +++ b/stock_archive_constraint/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Stock archive constraint", + "version": "13.0.1.0.0", + "license": "AGPL-3", + "website": "https://github.com/stock-logistics-warehouse", + "author": "Tecnativa, Odoo Community Association (OCA)", + "development_status": "Production/Stable", + "category": "Warehouse", + "depends": ["stock"], + "installable": True, + "maintainers": ["victoralmau"], +} diff --git a/stock_archive_constraint/i18n/es.po b/stock_archive_constraint/i18n/es.po new file mode 100644 index 000000000..7a95b8cc2 --- /dev/null +++ b/stock_archive_constraint/i18n/es.po @@ -0,0 +1,88 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_archive_constraint +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-01-08 09:03+0000\n" +"PO-Revision-Date: 2021-01-08 10:06+0100\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: es\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 2.3\n" + +#. module: stock_archive_constraint +#: model:ir.model,name:stock_archive_constraint.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicaciones de inventario" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:41 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated picking " +"lines." +msgstr "" +"No es posible archivar la ubicación '%s' que tiene líneas de albaranes " +"asociadas." + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:24 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated stock " +"quantities." +msgstr "" +"No es posible archivar la ubicación '%s' que tiene asociadas cantidades " +"de stock." + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:58 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated stock " +"reservations." +msgstr "" +"No es posible archivar la ubicación '%s' que tiene reservas de stock " +"asociadas." + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:36 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated picking " +"lines." +msgstr "" +"No es posible archivar el producto '%s' que tiene líneas de albaranes " +"asociadas." + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:22 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated stock " +"quantities." +msgstr "" +"No es posible archivar el producto '%s' que tiene asociadas cantidades " +"de stock." + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:50 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated stock " +"reservations." +msgstr "" +"No es posible archivar el producto '%s' que tiene reservas de stock " +"asociadas." + +#. module: stock_archive_constraint +#: model:ir.model,name:stock_archive_constraint.model_product_product +msgid "Product" +msgstr "Producto" diff --git a/stock_archive_constraint/i18n/stock_archive_constraint.pot b/stock_archive_constraint/i18n/stock_archive_constraint.pot new file mode 100644 index 000000000..c3f58e531 --- /dev/null +++ b/stock_archive_constraint/i18n/stock_archive_constraint.pot @@ -0,0 +1,72 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_archive_constraint +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_archive_constraint +#: model:ir.model,name:stock_archive_constraint.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:0 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated picking " +"lines." +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:0 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated stock " +"quantities." +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/stock_location.py:0 +#, python-format +msgid "" +"It is not possible to archive location '%s' which has associated stock " +"reservations." +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:0 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated picking " +"lines." +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:0 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated stock " +"quantities." +msgstr "" + +#. module: stock_archive_constraint +#: code:addons/stock_archive_constraint/models/product_product.py:0 +#, python-format +msgid "" +"It is not possible to archive product '%s' which has associated stock " +"reservations." +msgstr "" + +#. module: stock_archive_constraint +#: model:ir.model,name:stock_archive_constraint.model_product_product +msgid "Product" +msgstr "" diff --git a/stock_archive_constraint/models/__init__.py b/stock_archive_constraint/models/__init__.py new file mode 100644 index 000000000..1b6574480 --- /dev/null +++ b/stock_archive_constraint/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_product +from . import stock_location diff --git a/stock_archive_constraint/models/product_product.py b/stock_archive_constraint/models/product_product.py new file mode 100644 index 000000000..d639e8c5e --- /dev/null +++ b/stock_archive_constraint/models/product_product.py @@ -0,0 +1,61 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class ProductProduct(models.Model): + _inherit = "product.product" + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_quant(self): + res = self.env["stock.quant"].search( + [ + ("location_id.usage", "in", ("internal", "transit")), + ("product_id", "in", self.filtered(lambda x: not x.active).ids), + ("quantity", "!=", 0.0), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive product '%s' which has " + "associated stock quantities." % res[0].product_id.display_name + ) + ) + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_move(self): + res = self.env["stock.move"].search( + [ + ("product_id", "in", self.filtered(lambda x: not x.active).ids), + ("state", "not in", ("done", "cancel")), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive product '%s' which has " + "associated picking lines." % res[0].product_id.display_name + ) + ) + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_move_line(self): + res = self.env["stock.move.line"].search( + [ + ("product_id", "in", self.filtered(lambda x: not x.active).ids), + ("state", "not in", ("done", "cancel")), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive product '%s' which has " + "associated stock reservations." % res[0].product_id.display_name + ) + ) diff --git a/stock_archive_constraint/models/product_template.py b/stock_archive_constraint/models/product_template.py new file mode 100644 index 000000000..d6813c9f4 --- /dev/null +++ b/stock_archive_constraint/models/product_template.py @@ -0,0 +1,12 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + @api.constrains("active") + def _check_active_stock_archive_constraint(self): + self.product_variant_ids._check_active_stock_archive_constraint() diff --git a/stock_archive_constraint/models/stock_location.py b/stock_archive_constraint/models/stock_location.py new file mode 100644 index 000000000..3152db12f --- /dev/null +++ b/stock_archive_constraint/models/stock_location.py @@ -0,0 +1,69 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class StockLocation(models.Model): + _inherit = "stock.location" + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_quant(self): + res = self.env["stock.quant"].search( + [ + "&", + ("location_id.usage", "in", ("internal", "transit")), + "|", + ("location_id", "in", self.filtered(lambda x: not x.active).ids), + ("location_id", "child_of", self.filtered(lambda x: not x.active).ids), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive location '%s' which has " + "associated stock quantities." % res[0].display_name + ) + ) + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_move(self): + res = self.env["stock.move"].search( + [ + "&", + ("state", "not in", ("done", "cancel")), + "|", + ("location_id", "in", self.filtered(lambda x: not x.active).ids), + ("location_id", "child_of", self.filtered(lambda x: not x.active).ids), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive location '%s' which has " + "associated picking lines." % res[0].display_name + ) + ) + + @api.constrains("active") + def _check_active_stock_archive_constraint_stock_move_line(self): + res = self.env["stock.move.line"].search( + [ + "&", + ("state", "not in", ("done", "cancel")), + "|", + ("location_id", "in", self.filtered(lambda x: not x.active).ids), + ("location_id", "child_of", self.filtered(lambda x: not x.active).ids), + ], + limit=1, + ) + if res: + raise ValidationError( + _( + "It is not possible to archive location '%s' which has " + "associated stock reservations." % res[0].display_name + ) + ) diff --git a/stock_archive_constraint/readme/CONTRIBUTORS.rst b/stock_archive_constraint/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..48848770a --- /dev/null +++ b/stock_archive_constraint/readme/CONTRIBUTORS.rst @@ -0,0 +1,4 @@ +* `Tecnativa `_: + + * Carlos Daudén + * Víctor Martínez diff --git a/stock_archive_constraint/readme/DESCRIPTION.rst b/stock_archive_constraint/readme/DESCRIPTION.rst new file mode 100644 index 000000000..ccdf56f17 --- /dev/null +++ b/stock_archive_constraint/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +Allows to block archiving products with associated stock.quant or stock.move. +Allows to block archiving locations with associated stock.quant or stock.move. diff --git a/stock_archive_constraint/readme/USAGE.rst b/stock_archive_constraint/readme/USAGE.rst new file mode 100644 index 000000000..65f800d9d --- /dev/null +++ b/stock_archive_constraint/readme/USAGE.rst @@ -0,0 +1,2 @@ +#. Go to Settings > Users > Edit a user and check the "Manage Multiple Stock Locations" permission +#. Go to Inventory > Settings > Locations and disable one diff --git a/stock_archive_constraint/static/description/icon.png b/stock_archive_constraint/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_archive_constraint/static/description/icon.png differ diff --git a/stock_archive_constraint/static/description/index.html b/stock_archive_constraint/static/description/index.html new file mode 100644 index 000000000..ba4b0f795 --- /dev/null +++ b/stock_archive_constraint/static/description/index.html @@ -0,0 +1,437 @@ + + + + + + +Stock archive constraint + + + +
+

Stock archive constraint

+ + +

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

+

Allows to block archiving products with associated stock.quant or stock.move. +Allows to block archiving locations with associated stock.quant or stock.move.

+

Table of contents

+ +
+

Usage

+
    +
  1. Go to Settings > Users > Edit a user and check the “Manage Multiple Stock Locations” permission
  2. +
  3. Go to Inventory > Settings > Locations and disable one
  4. +
+
+
+

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

+
    +
  • Tecnativa:

    +
    +
      +
    • Carlos Daudén
    • +
    • Víctor Martínez
    • +
    +
    +
  • +
+
+
+

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.

+

Current maintainer:

+

victoralmau

+

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_archive_constraint/tests/__init__.py b/stock_archive_constraint/tests/__init__.py new file mode 100644 index 000000000..6712ad66e --- /dev/null +++ b/stock_archive_constraint/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2020 Tecnativa - Víctor Martínez +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from . import test_location_archive_constraint diff --git a/stock_archive_constraint/tests/test_location_archive_constraint.py b/stock_archive_constraint/tests/test_location_archive_constraint.py new file mode 100644 index 000000000..9b1f25dbb --- /dev/null +++ b/stock_archive_constraint/tests/test_location_archive_constraint.py @@ -0,0 +1,189 @@ +# Copyright 2021 Tecnativa - Víctor Martínez +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html). + +from odoo.exceptions import ValidationError +from odoo.tests.common import Form, SavepointCase + + +class TestLocationArchiveConstraint(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.company = cls.env.ref("base.main_company") + cls.product_1 = cls._create_product(cls, "Product 1") + cls.product_2 = cls._create_product(cls, "Product 2") + stock_location_stock = cls.env.ref("stock.stock_location_stock") + cls.stock_location = cls._create_stock_location( + cls, "%s (Copy)" % (stock_location_stock.name) + ) + cls.stock_location_child = cls._create_stock_location( + cls, "%s (Child)" % (cls.stock_location.name) + ) + cls.stock_location_child.location_id = cls.stock_location + + def _create_product(self, name): + product_form = Form(self.env["product.product"]) + product_form.name = name + product_form.type = "product" + return product_form.save() + + def _create_stock_location(self, name): + stock_location_form = Form(self.env["stock.location"]) + stock_location_form.name = name + stock_location_form.usage = self.env.ref("stock.stock_location_stock").usage + return stock_location_form.save() + + def _create_stock_quant(self, location_id, product_id, qty): + self.env["stock.quant"].create( + { + "company_id": self.company.id, + "location_id": location_id.id, + "product_id": product_id.id, + "quantity": qty, + } + ) + + def _create_stock_move(self, location_id, location_dest_id, product_id, qty): + stock_move_form = Form(self.env["stock.move"]) + stock_move_form.name = product_id.display_name + stock_move_form.location_id = location_id + stock_move_form.location_dest_id = location_dest_id + stock_move_form.product_id = product_id + stock_move_form.product_uom_qty = qty + stock_move = stock_move_form.save() + stock_move._action_done() + + def _create_stock_move_line(self, location_id, location_dest_id, product_id, qty): + self.env["stock.move.line"].create( + { + "company_id": self.company.id, + "location_id": location_id.id, + "location_dest_id": location_dest_id.id, + "product_id": product_id.id, + "product_uom_qty": qty, + "product_uom_id": product_id.uom_id.id, + "qty_done": qty, + "state": "done", + } + ) + + def _create_stock_picking(self, location_id, location_dest_id, product_id, qty): + stock_picking_form = Form(self.env["stock.picking"]) + stock_picking_form.picking_type_id = self.env.ref("stock.picking_type_in") + with stock_picking_form.move_ids_without_package.new() as line: + line.product_id = product_id + line.product_uom_qty = qty + stock_picking = stock_picking_form.save() + stock_picking.write( + {"location_id": location_id.id, "location_dest_id": location_dest_id.id} + ) + stock_picking.action_confirm() + for line in stock_picking.move_ids_without_package: + line.quantity_done = line.product_uom_qty + stock_picking.button_validate() + + def test_archive_product_ok(self): + self.product_1.active = False + self.assertFalse(self.product_1.active) + self.product_2.active = False + self.assertFalse(self.product_2.active) + + def test_archive_unarchive_product(self): + self.product_1.active = False + self.assertFalse(self.product_1.active) + self.product_1.active = True + self.assertTrue(self.product_1.active) + + def test_archive_product_with_stock_move_in(self): + self._create_stock_move( + self.env.ref("stock.stock_location_suppliers"), + self.stock_location, + self.product_2, + 20.00, + ) + self.product_1.active = False + self.assertFalse(self.product_1.active) + with self.assertRaises(ValidationError): + self.product_2.active = False + + def test_archive_product_with_stock_move_line_in(self): + self._create_stock_move_line( + self.env.ref("stock.stock_location_suppliers"), + self.stock_location, + self.product_2, + 20.00, + ) + self.product_1.active = False + self.assertFalse(self.product_1.active) + with self.assertRaises(ValidationError): + self.product_2.active = False + + def test_archive_product_with_stock_picking_in(self): + self._create_stock_picking( + self.env.ref("stock.stock_location_suppliers"), + self.stock_location, + self.product_2, + 20.00, + ) + self.product_1.active = False + self.assertFalse(self.product_1.active) + with self.assertRaises(ValidationError): + self.product_2.active = False + + def test_archive_product_with_stock_picking_in_out(self): + self._create_stock_picking( + self.env.ref("stock.stock_location_suppliers"), + self.stock_location, + self.product_2, + 20.00, + ) + self._create_stock_picking( + self.stock_location, + self.env.ref("stock.stock_location_customers"), + self.product_2, + 20.00, + ) + self.product_1.active = False + self.assertFalse(self.product_1.active) + self.product_2.active = False + self.assertFalse(self.product_2.active) + + def test_archive_product_stock_location(self): + self._create_stock_quant(self.stock_location, self.product_2, 20.00) + self.product_1.active = False + self.assertFalse(self.product_1.active) + with self.assertRaises(ValidationError): + self.product_2.active = False + + def test_archive_product_stock_location_child(self): + self._create_stock_quant(self.stock_location_child, self.product_2, 20.00) + self.product_1.active = False + self.assertFalse(self.product_1.active) + with self.assertRaises(ValidationError): + self.product_2.active = False + + def test_archive_unarchive_stock_location(self): + self.stock_location.active = False + self.assertFalse(self.stock_location.active) + self.stock_location.active = True + self.assertTrue(self.stock_location.active) + + def test_archive_stock_location_ok(self): + self.stock_location.active = False + self.assertFalse(self.stock_location.active) + + def test_archive_stock_location(self): + self._create_stock_quant(self.stock_location, self.product_2, 20.00) + with self.assertRaises(ValidationError): + self.stock_location.with_context(do_not_check_quant=True).active = False + + def test_archive_unarchive_stock_location_child(self): + self.stock_location_child.active = False + self.assertFalse(self.stock_location_child.active) + self.stock_location_child.active = True + self.assertTrue(self.stock_location_child.active) + + def test_archive_stock_location_child(self): + self._create_stock_quant(self.stock_location_child, self.product_2, 20.00) + with self.assertRaises(ValidationError): + self.stock_location.with_context(do_not_check_quant=True).active = False diff --git a/stock_available/i18n/ar.po b/stock_available/i18n/ar.po index bf1e26772..4375bb857 100644 --- a/stock_available/i18n/ar.po +++ b/stock_available/i18n/ar.po @@ -51,7 +51,6 @@ msgstr "" #. module: stock_available #: model:ir.model,name:stock_available.model_res_config_settings #, fuzzy -#| msgid "res.config.settings" msgid "Config Settings" msgstr "الإعدادات" diff --git a/stock_available/tests/test_stock_available.py b/stock_available/tests/test_stock_available.py index 5ffa91c0d..637d2828e 100644 --- a/stock_available/tests/test_stock_available.py +++ b/stock_available/tests/test_stock_available.py @@ -21,38 +21,41 @@ class TestStockLogisticsWarehouse(TransactionCase): """checking that immediately_usable_qty actually reflects \ the variations in stock, both on product and template""" moveObj = self.env["stock.move"] - productObj = self.env["product.product"] templateObj = self.env["product.template"] supplier_location = self.env.ref("stock.stock_location_suppliers") stock_location = self.env.ref("stock.stock_location_stock") customer_location = self.env.ref("stock.stock_location_customers") uom_unit = self.env.ref("uom.product_uom_unit") - # Create product template - templateAB = templateObj.create({"name": "templAB", "uom_id": uom_unit.id}) - - # Create product A and B - productA = productObj.create( - { - "name": "product A", - "standard_price": 1, - "type": "product", - "uom_id": uom_unit.id, - "default_code": "A", - "product_tmpl_id": templateAB.id, - } + size_attr = self.env["product.attribute"].create({"name": "Size"}) + size_attr_value_s = self.env["product.attribute.value"].create( + {"name": "S", "attribute_id": size_attr.id} + ) + size_attr_value_m = self.env["product.attribute.value"].create( + {"name": "M", "attribute_id": size_attr.id} ) - productB = productObj.create( + # Create products + templateAB = templateObj.create( { - "name": "product B", - "standard_price": 1, - "type": "product", + "name": "templAB", "uom_id": uom_unit.id, - "default_code": "B", - "product_tmpl_id": templateAB.id, + "type": "product", + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": size_attr.id, + "value_ids": [ + (6, 0, [size_attr_value_s.id, size_attr_value_m.id]) + ], + }, + ) + ], } ) + productA, productB = templateAB.product_variant_ids # Create a stock move from INCOMING to STOCK stockMoveInA = moveObj.create( diff --git a/stock_available_immediately/README.rst b/stock_available_immediately/README.rst new file mode 100644 index 000000000..39c06acdf --- /dev/null +++ b/stock_available_immediately/README.rst @@ -0,0 +1,87 @@ +========================================================== +Ignore planned receptions in quantity available to promise +========================================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_available_immediately + :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_available_immediately + :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| + +Normally the quantity available to promise is based on the virtual stock, +which includes both planned outgoing and incoming goods. +This module will subtract the planned receptions from the quantity available to +promise. + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Camptocamp +* Sodexis +* Sergio Díaz + +Contributors +~~~~~~~~~~~~ + +* Author: Guewen Baconnier (Camptocamp SA) +* Sébastien BEAU (Akretion) +* Lionel Sausin (Numérigraphe) +* Sodexis +* Cédric Pigeon +* Sergio Díaz +* `Tecnativa `_: + + * Pedro M. Baeza + * Víctor Martínez + +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_available_immediately/__init__.py b/stock_available_immediately/__init__.py new file mode 100644 index 000000000..83e553ac4 --- /dev/null +++ b/stock_available_immediately/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/stock_available_immediately/__manifest__.py b/stock_available_immediately/__manifest__.py new file mode 100644 index 000000000..fb758c052 --- /dev/null +++ b/stock_available_immediately/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2014 Camptocamp, Akretion, Numérigraphe +# Copyright 2016 Sodexis +# Copyright 2019 Sergio Díaz +# Copyright 2020 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Ignore planned receptions in quantity available to promise", + "version": "13.0.1.0.0", + "depends": ["stock_available"], + "website": "https://github.com/stock-logistics-warehouse", + "author": "Camptocamp,Sodexis,Odoo Community Association (OCA),Sergio Díaz", + "license": "AGPL-3", + "category": "Hidden", + "installable": True, +} diff --git a/stock_available_immediately/i18n/ca.po b/stock_available_immediately/i18n/ca.po new file mode 100644 index 000000000..11cbdd34a --- /dev/null +++ b/stock_available_immediately/i18n/ca.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Producte" diff --git a/stock_available_immediately/i18n/cs_CZ.po b/stock_available_immediately/i18n/cs_CZ.po new file mode 100644 index 000000000..2150a116f --- /dev/null +++ b/stock_available_immediately/i18n/cs_CZ.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# Lukáš Spurný , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-02-27 11:37+0000\n" +"PO-Revision-Date: 2018-02-27 11:37+0000\n" +"Last-Translator: Lukáš Spurný , 2018\n" +"Language-Team: Czech (Czech Republic) (https://www.transifex.com/oca/" +"teams/23907/cs_CZ/)\n" +"Language: cs_CZ\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produkt" diff --git a/stock_available_immediately/i18n/de.po b/stock_available_immediately/i18n/de.po new file mode 100644 index 000000000..1b9f9e29c --- /dev/null +++ b/stock_available_immediately/i18n/de.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produkt" diff --git a/stock_available_immediately/i18n/el_GR.po b/stock_available_immediately/i18n/el_GR.po new file mode 100644 index 000000000..fba06d96c --- /dev/null +++ b/stock_available_immediately/i18n/el_GR.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Greek (Greece) (https://www.transifex.com/oca/teams/23907/" +"el_GR/)\n" +"Language: el_GR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Προϊόν" diff --git a/stock_available_immediately/i18n/es.po b/stock_available_immediately/i18n/es.po new file mode 100644 index 000000000..92c181447 --- /dev/null +++ b/stock_available_immediately/i18n/es.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Producto" diff --git a/stock_available_immediately/i18n/es_ES.po b/stock_available_immediately/i18n/es_ES.po new file mode 100644 index 000000000..4595b90f5 --- /dev/null +++ b/stock_available_immediately/i18n/es_ES.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Spanish (Spain) (https://www.transifex.com/oca/teams/23907/" +"es_ES/)\n" +"Language: es_ES\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Producto" diff --git a/stock_available_immediately/i18n/es_MX.po b/stock_available_immediately/i18n/es_MX.po new file mode 100644 index 000000000..e2c5f9ff8 --- /dev/null +++ b/stock_available_immediately/i18n/es_MX.po @@ -0,0 +1,28 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Spanish (Mexico) (https://www.transifex.com/oca/teams/23907/" +"es_MX/)\n" +"Language: es_MX\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Plantilla del producto" diff --git a/stock_available_immediately/i18n/eu.po b/stock_available_immediately/i18n/eu.po new file mode 100644 index 000000000..1e696cd1d --- /dev/null +++ b/stock_available_immediately/i18n/eu.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Basque (https://www.transifex.com/oca/teams/23907/eu/)\n" +"Language: eu\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produktua" diff --git a/stock_available_immediately/i18n/fi.po b/stock_available_immediately/i18n/fi.po new file mode 100644 index 000000000..6c5f4e970 --- /dev/null +++ b/stock_available_immediately/i18n/fi.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Finnish (https://www.transifex.com/oca/teams/23907/fi/)\n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Tuote" diff --git a/stock_available_immediately/i18n/fr.po b/stock_available_immediately/i18n/fr.po new file mode 100644 index 000000000..346d567f3 --- /dev/null +++ b/stock_available_immediately/i18n/fr.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Article" diff --git a/stock_available_immediately/i18n/fr_CH.po b/stock_available_immediately/i18n/fr_CH.po new file mode 100644 index 000000000..5b3ea4eb5 --- /dev/null +++ b/stock_available_immediately/i18n/fr_CH.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: French (Switzerland) (https://www.transifex.com/oca/" +"teams/23907/fr_CH/)\n" +"Language: fr_CH\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produit" diff --git a/stock_available_immediately/i18n/fr_FR.po b/stock_available_immediately/i18n/fr_FR.po new file mode 100644 index 000000000..b45424fdb --- /dev/null +++ b/stock_available_immediately/i18n/fr_FR.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: French (France) (https://www.transifex.com/oca/teams/23907/" +"fr_FR/)\n" +"Language: fr_FR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produit" diff --git a/stock_available_immediately/i18n/gl.po b/stock_available_immediately/i18n/gl.po new file mode 100644 index 000000000..748a5aa9e --- /dev/null +++ b/stock_available_immediately/i18n/gl.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Galician (https://www.transifex.com/oca/teams/23907/gl/)\n" +"Language: gl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produto" diff --git a/stock_available_immediately/i18n/hr.po b/stock_available_immediately/i18n/hr.po new file mode 100644 index 000000000..48707b334 --- /dev/null +++ b/stock_available_immediately/i18n/hr.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Proizvod" diff --git a/stock_available_immediately/i18n/hr_HR.po b/stock_available_immediately/i18n/hr_HR.po new file mode 100644 index 000000000..761931224 --- /dev/null +++ b/stock_available_immediately/i18n/hr_HR.po @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Croatian (Croatia) (https://www.transifex.com/oca/teams/23907/" +"hr_HR/)\n" +"Language: hr_HR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Proizvod" diff --git a/stock_available_immediately/i18n/it.po b/stock_available_immediately/i18n/it.po new file mode 100644 index 000000000..7d371ca6d --- /dev/null +++ b/stock_available_immediately/i18n/it.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Italian (https://www.transifex.com/oca/teams/23907/it/)\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Prodotto" diff --git a/stock_available_immediately/i18n/nl.po b/stock_available_immediately/i18n/nl.po new file mode 100644 index 000000000..7069a746d --- /dev/null +++ b/stock_available_immediately/i18n/nl.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Dutch (https://www.transifex.com/oca/teams/23907/nl/)\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Product" diff --git a/stock_available_immediately/i18n/nl_NL.po b/stock_available_immediately/i18n/nl_NL.po new file mode 100644 index 000000000..1b6deae0f --- /dev/null +++ b/stock_available_immediately/i18n/nl_NL.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Dutch (Netherlands) (https://www.transifex.com/oca/" +"teams/23907/nl_NL/)\n" +"Language: nl_NL\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Product" diff --git a/stock_available_immediately/i18n/pt.po b/stock_available_immediately/i18n/pt.po new file mode 100644 index 000000000..84a55d679 --- /dev/null +++ b/stock_available_immediately/i18n/pt.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-06-03 01:23+0000\n" +"PO-Revision-Date: 2017-06-03 01:23+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Portuguese (https://www.transifex.com/oca/teams/23907/pt/)\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produto" diff --git a/stock_available_immediately/i18n/pt_BR.po b/stock_available_immediately/i18n/pt_BR.po new file mode 100644 index 000000000..0a83f9145 --- /dev/null +++ b/stock_available_immediately/i18n/pt_BR.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Portuguese (Brazil) (https://www.transifex.com/oca/" +"teams/23907/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produto" diff --git a/stock_available_immediately/i18n/ro.po b/stock_available_immediately/i18n/ro.po new file mode 100644 index 000000000..d51379315 --- /dev/null +++ b/stock_available_immediately/i18n/ro.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Romanian (https://www.transifex.com/oca/teams/23907/ro/)\n" +"Language: ro\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?" +"2:1));\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Produs" diff --git a/stock_available_immediately/i18n/ru.po b/stock_available_immediately/i18n/ru.po new file mode 100644 index 000000000..b684c031d --- /dev/null +++ b/stock_available_immediately/i18n/ru.po @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2018 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2018\n" +"Language-Team: Russian (https://www.transifex.com/oca/teams/23907/ru/)\n" +"Language: ru\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n" +"%100>=11 && n%100<=14)? 2 : 3);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Товар/Услуга" diff --git a/stock_available_immediately/i18n/sl.po b/stock_available_immediately/i18n/sl.po new file mode 100644 index 000000000..e4404449d --- /dev/null +++ b/stock_available_immediately/i18n/sl.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Slovenian (https://www.transifex.com/oca/teams/23907/sl/)\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Proizvod" diff --git a/stock_available_immediately/i18n/stock_available_immediately.pot b/stock_available_immediately/i18n/stock_available_immediately.pot new file mode 100644 index 000000000..a140f59f7 --- /dev/null +++ b/stock_available_immediately/i18n/stock_available_immediately.pot @@ -0,0 +1,19 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "" diff --git a/stock_available_immediately/i18n/tr.po b/stock_available_immediately/i18n/tr.po new file mode 100644 index 000000000..61375ee76 --- /dev/null +++ b/stock_available_immediately/i18n/tr.po @@ -0,0 +1,24 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/tr/)\n" +"Language: tr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Ürün" diff --git a/stock_available_immediately/i18n/tr_TR.po b/stock_available_immediately/i18n/tr_TR.po new file mode 100644 index 000000000..6beabb80f --- /dev/null +++ b/stock_available_immediately/i18n/tr_TR.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Turkish (Turkey) (https://www.transifex.com/oca/teams/23907/" +"tr_TR/)\n" +"Language: tr_TR\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" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Ürün" diff --git a/stock_available_immediately/i18n/vi_VN.po b/stock_available_immediately/i18n/vi_VN.po new file mode 100644 index 000000000..a9217cd97 --- /dev/null +++ b/stock_available_immediately/i18n/vi_VN.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Vietnamese (Viet Nam) (https://www.transifex.com/oca/" +"teams/23907/vi_VN/)\n" +"Language: vi_VN\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" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "Sản phẩm" diff --git a/stock_available_immediately/i18n/zh_CN.po b/stock_available_immediately/i18n/zh_CN.po new file mode 100644 index 000000000..15df1d1e9 --- /dev/null +++ b/stock_available_immediately/i18n/zh_CN.po @@ -0,0 +1,25 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_immediately +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-01-16 14:35+0000\n" +"PO-Revision-Date: 2018-01-16 14:35+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Chinese (China) (https://www.transifex.com/oca/teams/23907/" +"zh_CN/)\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" + +#. module: stock_available_immediately +#: model:ir.model,name:stock_available_immediately.model_product_product +msgid "Product" +msgstr "产品" diff --git a/stock_available_immediately/models/__init__.py b/stock_available_immediately/models/__init__.py new file mode 100644 index 000000000..586a7eff4 --- /dev/null +++ b/stock_available_immediately/models/__init__.py @@ -0,0 +1,3 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_product diff --git a/stock_available_immediately/models/product_product.py b/stock_available_immediately/models/product_product.py new file mode 100644 index 000000000..90a0d4bb6 --- /dev/null +++ b/stock_available_immediately/models/product_product.py @@ -0,0 +1,22 @@ +# Copyright 2014 Camptocamp, Akretion, Numérigraphe +# Copyright 2016 Sodexis +# Copyright 2019 Sergio Díaz +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import api, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + def _compute_available_quantities_dict(self): + res, stock_dict = super()._compute_available_quantities_dict() + for product in self: + res[product.id]["immediately_usable_qty"] -= stock_dict[product.id][ + "incoming_qty" + ] + return res, stock_dict + + @api.depends("virtual_available", "incoming_qty") + def _compute_available_quantities(self): + return super()._compute_available_quantities() diff --git a/stock_available_immediately/readme/CONTRIBUTORS.rst b/stock_available_immediately/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..f7743fe84 --- /dev/null +++ b/stock_available_immediately/readme/CONTRIBUTORS.rst @@ -0,0 +1,10 @@ +* Author: Guewen Baconnier (Camptocamp SA) +* Sébastien BEAU (Akretion) +* Lionel Sausin (Numérigraphe) +* Sodexis +* Cédric Pigeon +* Sergio Díaz +* `Tecnativa `_: + + * Pedro M. Baeza + * Víctor Martínez diff --git a/stock_available_immediately/readme/DESCRIPTION.rst b/stock_available_immediately/readme/DESCRIPTION.rst new file mode 100644 index 000000000..920e88bb4 --- /dev/null +++ b/stock_available_immediately/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +Normally the quantity available to promise is based on the virtual stock, +which includes both planned outgoing and incoming goods. +This module will subtract the planned receptions from the quantity available to +promise. diff --git a/stock_available_immediately/static/description/icon.png b/stock_available_immediately/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_available_immediately/static/description/icon.png differ diff --git a/stock_available_immediately/static/description/index.html b/stock_available_immediately/static/description/index.html new file mode 100644 index 000000000..719d5d675 --- /dev/null +++ b/stock_available_immediately/static/description/index.html @@ -0,0 +1,434 @@ + + + + + + +Ignore planned receptions in quantity available to promise + + + +
+

Ignore planned receptions in quantity available to promise

+ + +

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

+

Normally the quantity available to promise is based on the virtual stock, +which includes both planned outgoing and incoming goods. +This module will subtract the planned receptions from the quantity available to +promise.

+

Table of contents

+ +
+

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

+
    +
  • Camptocamp
  • +
  • Sodexis
  • +
  • Sergio Díaz
  • +
+
+
+

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_available_immediately/tests/__init__.py b/stock_available_immediately/tests/__init__.py new file mode 100644 index 000000000..84148ecde --- /dev/null +++ b/stock_available_immediately/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_available_immediately diff --git a/stock_available_immediately/tests/test_stock_available_immediately.py b/stock_available_immediately/tests/test_stock_available_immediately.py new file mode 100644 index 000000000..2f4957902 --- /dev/null +++ b/stock_available_immediately/tests/test_stock_available_immediately.py @@ -0,0 +1,125 @@ +# Copyright 2014 Camptocamp, Akretion, Numérigraphe +# Copyright 2016 Sodexis +# Copyright 2019 Sergio Díaz +# Copyright 2020 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import TransactionCase + + +class TestStockLogisticsWarehouse(TransactionCase): + def test01_stock_levels(self): + """ + Checking that immediately_usable_qty actually reflects the variations + in stock, both on product and template. + """ + moveObj = self.env["stock.move"] + templateObj = self.env["product.template"] + supplier_location = self.env.ref("stock.stock_location_suppliers") + stock_location = self.env.ref("stock.stock_location_stock") + customer_location = self.env.ref("stock.stock_location_customers") + uom_unit = self.env.ref("uom.product_uom_unit") + + # Create product template with 2 variant + templateAB = templateObj.create( + {"name": "templAB", "uom_id": uom_unit.id, "type": "product"} + ) + + self.env["product.template.attribute.line"].create( + { + "product_tmpl_id": templateAB.id, + "attribute_id": self.env.ref("product.product_attribute_2").id, + "value_ids": [ + ( + 6, + 0, + [ + self.env.ref("product.product_attribute_value_3").id, + self.env.ref("product.product_attribute_value_4").id, + ], + ) + ], + } + ) + + # Create product A and B + productA = templateAB.product_variant_ids[0] + productB = templateAB.product_variant_ids[1] + + # Create a stock move from INCOMING to STOCK + stockMoveInA = moveObj.create( + { + "location_id": supplier_location.id, + "location_dest_id": stock_location.id, + "name": "MOVE INCOMING -> STOCK ", + "product_id": productA.id, + "product_uom": productA.uom_id.id, + "product_uom_qty": 2, + } + ) + + stockMoveInB = moveObj.create( + { + "location_id": supplier_location.id, + "location_dest_id": stock_location.id, + "name": "MOVE INCOMING -> STOCK ", + "product_id": productB.id, + "product_uom": productB.uom_id.id, + "product_uom_qty": 3, + } + ) + + def compare_product_usable_qty(product, value): + # Refresh, because the function field is not recalculated between + # transactions + product.refresh() + self.assertEqual(product.immediately_usable_qty, value) + + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA._action_confirm() + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA._action_assign() + compare_product_usable_qty(productA, 0) + compare_product_usable_qty(templateAB, 0) + + stockMoveInA.move_line_ids.write({"qty_done": 2.0}) + stockMoveInA._action_done() + compare_product_usable_qty(productA, 2) + compare_product_usable_qty(templateAB, 2) + + # will directly trigger action_done on productB + stockMoveInB._action_confirm() + stockMoveInB._action_assign() + stockMoveInB.move_line_ids.write({"qty_done": 3.0}) + stockMoveInB._action_done() + compare_product_usable_qty(productA, 2) + compare_product_usable_qty(productB, 3) + compare_product_usable_qty(templateAB, 5) + + # Create a stock move from STOCK to CUSTOMER + stockMoveOutA = moveObj.create( + { + "location_id": stock_location.id, + "location_dest_id": customer_location.id, + "name": " STOCK --> CUSTOMER ", + "product_id": productA.id, + "product_uom": productA.uom_id.id, + "product_uom_qty": 1, + "state": "confirmed", + } + ) + + stockMoveOutA._action_confirm() + stockMoveOutA._action_assign() + stockMoveOutA.move_line_ids.write({"qty_done": 1.0}) + stockMoveOutA._action_done() + compare_product_usable_qty(productA, 1) + compare_product_usable_qty(templateAB, 4) + + # Potential Qty is set as 0.0 by default + self.assertEquals(templateAB.potential_qty, 0.0) + self.assertEquals(productA.potential_qty, 0.0) diff --git a/stock_available_mrp/README.rst b/stock_available_mrp/README.rst new file mode 100644 index 000000000..f6b7538ea --- /dev/null +++ b/stock_available_mrp/README.rst @@ -0,0 +1,132 @@ +========================================================= +Consider the production potential is available to promise +========================================================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_available_mrp + :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_available_mrp + :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 takes the potential quantities available for Products into account in +the quantity available to promise, where the "Potential quantity" is the +quantity that can be manufactured with the components immediately at hand. +By configuration, the "Potential quantity" can be computed based on other product field. +For example, "Potential quantity" can be the quantity that can be manufactured +with the components available to promise. + +**Table of contents** + +.. contents:: + :local: + +Known issues / Roadmap +====================== + +Known issues +~~~~~~~~~~~~ +The manufacturing delays are not taken into account : this module assumes that +if you have components in stock goods, you can manufacture finished goods +quickly enough. + +As a consequence, and to avoid overestimating, **only the first level** of Bill +of Materials is considered. + +However Sets (a.k.a "phantom" BoMs) are taken into account: if a component must +be replaced with a set, it's the stock of the set's product which will decide +the potential. + +If a product has several variants, only the variant with the biggest potential +will be taken into account when reporting the production potential. For +example, even if you actually have enough components to make 10 iPads 16Go AND +42 iPads 32Go, we'll consider that you can promise only 42 iPads. + +Removed features +~~~~~~~~~~~~~~~~ +Previous versions of this module used to let programmers demand to get the +potential quantity in an arbitrary Unit of Measure using the `context`. This +feature was present in the standard computations too until v8.0, but it has +been dropped from the standard from v8.0 on. + +For the sake of consistency the potential quantity is now always reported in +the product's main Unit of Measure too. + +Roadmap +~~~~~~~ +Possible improvements for future versions: + +* Take manufacturing delays into account: we should not promise goods to + customers if they want them delivered earlier that we can make them +* Compute the quantity of finished product that can be made directly on each + Bill of Material: this would be useful for production managers, and may make + the computations faster by avoiding to compute the same BoM several times + when several variants share the same BoM. +* Add an option (probably as a sub-module) to consider all raw materials as + available if they can be bought from the suppliers in time for the + manufacturing. + +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 +~~~~~~~ + +* Numérigraphe + +Contributors +~~~~~~~~~~~~ + +* Loïc Bellier (Numérigraphe) +* Lionel Sausin (Numérigraphe) +* many thanks to Graeme Gellatly for his advice and code review +* Laurent Mignon +* Cédric Pigeon +* Florian da Costa + +* `Tecnativa `_: + + * Víctor Martínez + +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_available_mrp/__init__.py b/stock_available_mrp/__init__.py new file mode 100644 index 000000000..2f72d6f91 --- /dev/null +++ b/stock_available_mrp/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2014 Numérigraphe SARL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import models diff --git a/stock_available_mrp/__manifest__.py b/stock_available_mrp/__manifest__.py new file mode 100644 index 000000000..114ddfa8e --- /dev/null +++ b/stock_available_mrp/__manifest__.py @@ -0,0 +1,13 @@ +# Copyright 2014 Numérigraphe SARL, Camptocamp +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +{ + "name": "Consider the production potential is available to promise", + "version": "13.0.1.0.0", + "author": "Numérigraphe," "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Hidden", + "depends": ["stock_available", "mrp"], + "demo": ["demo/mrp_data.xml"], + "license": "AGPL-3", + "installable": True, +} diff --git a/stock_available_mrp/demo/mrp_data.xml b/stock_available_mrp/demo/mrp_data.xml new file mode 100644 index 000000000..4e7b818ed --- /dev/null +++ b/stock_available_mrp/demo/mrp_data.xml @@ -0,0 +1,47 @@ + + + + PCSC234-WHITE + + + + + + + + + + + Bolt + + 1.0 + 5.0 + product + + + BOLT-WHITE + + + + 4 + + 5 + + + + diff --git a/stock_available_mrp/i18n/de.po b/stock_available_mrp/i18n/de.po new file mode 100644 index 000000000..8c659cbd0 --- /dev/null +++ b/stock_available_mrp/i18n/de.po @@ -0,0 +1,62 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +# Rudolf Schnapka , 2016 +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-14 01:38+0000\n" +"PO-Revision-Date: 2016-01-14 09:35+0000\n" +"Last-Translator: Rudolf Schnapka \n" +"Language-Team: German (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-8-0/language/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Produkt" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Produktvorlage" + +#~ msgid "Thousand" +#~ msgstr "Tausend" diff --git a/stock_available_mrp/i18n/es.po b/stock_available_mrp/i18n/es.po new file mode 100644 index 000000000..e1dd723b4 --- /dev/null +++ b/stock_available_mrp/i18n/es.po @@ -0,0 +1,58 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-14 01:38+0000\n" +"PO-Revision-Date: 2016-01-13 16:35+0000\n" +"Last-Translator: <>\n" +"Language-Team: Spanish (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-8-0/language/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Producto" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" diff --git a/stock_available_mrp/i18n/fi.po b/stock_available_mrp/i18n/fi.po new file mode 100644 index 000000000..43a9ceff6 --- /dev/null +++ b/stock_available_mrp/i18n/fi.po @@ -0,0 +1,58 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-14 01:38+0000\n" +"PO-Revision-Date: 2016-01-13 16:35+0000\n" +"Last-Translator: <>\n" +"Language-Team: Finnish (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-8-0/language/fi/)\n" +"Language: fi\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Tuote" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Tuotteen malli" diff --git a/stock_available_mrp/i18n/fr.po b/stock_available_mrp/i18n/fr.po new file mode 100644 index 000000000..5b140808a --- /dev/null +++ b/stock_available_mrp/i18n/fr.po @@ -0,0 +1,65 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-14 01:38+0000\n" +"PO-Revision-Date: 2020-11-12 12:44+0000\n" +"Last-Translator: Yann Papouin \n" +"Language-Team: French (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-8-0/language/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "Nomenclature" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "Boulon" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Article" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "Table en kit" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "Table en kit" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Unit(s)" +#~ msgstr "Unité(s)" + +#~ msgid "kg" +#~ msgstr "kg" + +#~ msgid "Product Template" +#~ msgstr "Modèle de produit" diff --git a/stock_available_mrp/i18n/hr_HR.po b/stock_available_mrp/i18n/hr_HR.po new file mode 100644 index 000000000..770026d47 --- /dev/null +++ b/stock_available_mrp/i18n/hr_HR.po @@ -0,0 +1,89 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +# Bole , 2016 +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (9.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-06-12 19:59+0000\n" +"PO-Revision-Date: 2016-06-14 10:45+0000\n" +"Last-Translator: Bole \n" +"Language-Team: Croatian (Croatia) (http://www.transifex.com/oca/OCA-stock-" +"logistics-warehouse-9-0/language/hr_HR/)\n" +"Language: hr_HR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" +"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Proizvod" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Predložak proizvoda" + +#~ msgid "Potential" +#~ msgstr "Potencijal" + +#~ msgid "Component ids" +#~ msgstr "ID-ovi komponenata" + +#~ msgid "Potential" +#~ msgstr "Potencijal" + +#~ msgid "" +#~ "Quantity of this Product that could be produced using the materials " +#~ "already at hand." +#~ msgstr "" +#~ "Količina ovog proizvoda nije mogla biti proizvedena korištenjem trenutno " +#~ "raspoloživih materijala." + +#~ msgid "" +#~ "Quantity of this Product that could be produced using the materials " +#~ "already at hand. If the product has several variants, this will be the " +#~ "biggest quantity that can be made for a any single variant." +#~ msgstr "" +#~ "Količina ovog proizvoda koja može biti proizvodedna raspoloživim " +#~ "količinama sirovina. Ako proizvod ima nekoliko varijanti, ovo će biti " +#~ "najveća moguća količina koja se može proizvesti za svaku pojedinu " +#~ "varijantu." + +#~ msgid "Thousand" +#~ msgstr "Tisuću" diff --git a/stock_available_mrp/i18n/it.po b/stock_available_mrp/i18n/it.po new file mode 100644 index 000000000..0d59f0339 --- /dev/null +++ b/stock_available_mrp/i18n/it.po @@ -0,0 +1,55 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (9.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-09-04 10:11+0000\n" +"PO-Revision-Date: 2016-04-27 11:10+0000\n" +"Last-Translator: <>\n" +"Language-Team: Italian (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-9-0/language/it/)\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Prodotto" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" diff --git a/stock_available_mrp/i18n/pt_BR.po b/stock_available_mrp/i18n/pt_BR.po new file mode 100644 index 000000000..38e147055 --- /dev/null +++ b/stock_available_mrp/i18n/pt_BR.po @@ -0,0 +1,87 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +# Claudio Araujo Santos , 2016 +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (9.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-07-03 20:56+0000\n" +"PO-Revision-Date: 2016-07-07 19:41+0000\n" +"Last-Translator: Claudio Araujo Santos \n" +"Language-Team: Portuguese (Brazil) (http://www.transifex.com/oca/OCA-stock-" +"logistics-warehouse-9-0/language/pt_BR/)\n" +"Language: pt_BR\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Produto" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Modelo Produto" + +#~ msgid "Potential" +#~ msgstr "Potencial" + +#~ msgid "Component ids" +#~ msgstr "IDs de componentes" + +#~ msgid "Potential" +#~ msgstr "Potencial" + +#~ msgid "" +#~ "Quantity of this Product that could be produced using the materials " +#~ "already at hand." +#~ msgstr "" +#~ "Quantidade deste produto que poderia ser produzido usando os materiais já " +#~ "na mão." + +#~ msgid "" +#~ "Quantity of this Product that could be produced using the materials " +#~ "already at hand. If the product has several variants, this will be the " +#~ "biggest quantity that can be made for a any single variant." +#~ msgstr "" +#~ "Quantidade deste produto que poderia ser produzido usando os materiais já " +#~ "na mão. Se o produto tiver várias variantes, esta será a maior quantidade " +#~ "que pode ser feito por qualquer uma única variante." + +#~ msgid "Thousand" +#~ msgstr "Mil" diff --git a/stock_available_mrp/i18n/sl.po b/stock_available_mrp/i18n/sl.po new file mode 100644 index 000000000..01b1ecdfa --- /dev/null +++ b/stock_available_mrp/i18n/sl.po @@ -0,0 +1,63 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +# Matjaž Mozetič , 2016 +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (8.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-01-14 01:38+0000\n" +"PO-Revision-Date: 2016-01-14 05:18+0000\n" +"Last-Translator: Matjaž Mozetič \n" +"Language-Team: Slovenian (http://www.transifex.com/oca/OCA-stock-logistics-" +"warehouse-8-0/language/sl/)\n" +"Language: sl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n" +"%100==4 ? 2 : 3);\n" + +#. module: stock_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "Proizvod" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" + +#~ msgid "Product Template" +#~ msgstr "Predloga proizvoda" + +#~ msgid "Thousand" +#~ msgstr "Tisoč" diff --git a/stock_available_mrp/i18n/stock_available_mrp.pot b/stock_available_mrp/i18n/stock_available_mrp.pot new file mode 100644 index 000000000..b7c0f998f --- /dev/null +++ b/stock_available_mrp/i18n/stock_available_mrp.pot @@ -0,0 +1,50 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Units" +msgstr "" diff --git a/stock_available_mrp/i18n/zh_CN.po b/stock_available_mrp/i18n/zh_CN.po new file mode 100644 index 000000000..07f53d170 --- /dev/null +++ b/stock_available_mrp/i18n/zh_CN.po @@ -0,0 +1,77 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_available_mrp +# +# Translators: +# Jeffery Chenn , 2016 +msgid "" +msgstr "" +"Project-Id-Version: stock-logistics-warehouse (9.0)\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2016-08-28 10:00+0000\n" +"PO-Revision-Date: 2019-09-26 15:05+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\n" +"Language-Team: Chinese (China) (http://www.transifex.com/oca/" +"OCA-stock-logistics-warehouse-9-0/language/zh_CN/)\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_available_mrp +#: model:ir.model.fields,field_description:stock_available_mrp.field_product_product__bom_id +msgid "BOM" +msgstr "BOM" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.template,name:stock_available_mrp.product_computer_desk_bolt_white_product_template +msgid "Bolt" +msgstr "螺栓" + +#. module: stock_available_mrp +#: model:ir.model,name:stock_available_mrp.model_product_product +msgid "Product" +msgstr "产品" + +#. module: stock_available_mrp +#: model:product.product,name:stock_available_mrp.product_kit_1a +#: model:product.template,name:stock_available_mrp.product_kit_1a_product_template +msgid "Table Kit" +msgstr "桌台套件" + +#. module: stock_available_mrp +#: model:product.product,description:stock_available_mrp.product_kit_1a +#: model:product.template,description:stock_available_mrp.product_kit_1a_product_template +msgid "Table kit" +msgstr "桌台套件" + +#. module: stock_available_mrp +#: model:product.product,uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "Unit(s)" +msgstr "件" + +#. module: stock_available_mrp +#: model:product.product,weight_uom_name:stock_available_mrp.product_computer_desk_bolt_white +#: model:product.product,weight_uom_name:stock_available_mrp.product_kit_1a +#: model:product.template,weight_uom_name:stock_available_mrp.product_computer_desk_bolt_white_product_template +#: model:product.template,weight_uom_name:stock_available_mrp.product_kit_1a_product_template +msgid "kg" +msgstr "公斤" + +#~ msgid "Product Template" +#~ msgstr "产品模板" + +#~ msgid "Potential" +#~ msgstr "潜在" + +#~ msgid "Potential" +#~ msgstr "潜在" + +#~ msgid "Thousand" +#~ msgstr "千" diff --git a/stock_available_mrp/models/__init__.py b/stock_available_mrp/models/__init__.py new file mode 100644 index 000000000..bf91af2eb --- /dev/null +++ b/stock_available_mrp/models/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2014 Numérigraphe SARL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import product_product diff --git a/stock_available_mrp/models/product_product.py b/stock_available_mrp/models/product_product.py new file mode 100644 index 000000000..fcd8af5c6 --- /dev/null +++ b/stock_available_mrp/models/product_product.py @@ -0,0 +1,139 @@ +# Copyright 2014 Numérigraphe SARL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from collections import Counter + +from odoo import api, fields, models +from odoo.fields import first + + +class ProductProduct(models.Model): + _inherit = "product.product" + + bom_id = fields.Many2one( + comodel_name="mrp.bom", compute="_compute_bom_id", string="BOM" + ) + + @api.depends("virtual_available", "bom_id", "bom_id.product_qty") + def _compute_available_quantities(self): + super()._compute_available_quantities() + + def _get_bom_id_domain(self): + """ + Real multi domain + :return: + """ + return [ + "|", + ("product_id", "in", self.ids), + "&", + ("product_id", "=", False), + ("product_tmpl_id", "in", self.mapped("product_tmpl_id.id")), + ] + + @api.depends("product_tmpl_id") + def _compute_bom_id(self): + bom_obj = self.env["mrp.bom"] + boms = bom_obj.search(self._get_bom_id_domain(), order="sequence, product_id") + for product in self: + product.bom_id = product.bom_id + product_boms = boms.filtered( + lambda b: b.product_id == product + or (not b.product_id and b.product_tmpl_id == product.product_tmpl_id) + ) + if product_boms: + product.bom_id = first(product_boms) + + def _compute_available_quantities_dict(self): + res, stock_dict = super()._compute_available_quantities_dict() + # compute qty for product with bom + product_with_bom = self.filtered("bom_id") + + if not product_with_bom: + return res, stock_dict + icp = self.env["ir.config_parameter"] + stock_available_mrp_based_on = icp.sudo().get_param( + "stock_available_mrp_based_on", "qty_available" + ) + + # explode all boms at once + exploded_boms = product_with_bom._explode_boms() + + # extract the list of product used as bom component + component_products = self.env["product.product"].browse() + for exploded_components in exploded_boms.values(): + for bom_component in exploded_components: + component_products |= first(bom_component).product_id + + # Compute stock for product components. + # {'productid': {field_name: qty}} + if res and stock_available_mrp_based_on in list(res.values())[0]: + # If the qty is computed by the same method use it to avoid + # stressing the cache + component_qties, _ = component_products._compute_available_quantities_dict() + else: + # The qty is a field computed by an other method than the + # current one. Take the value on the record. + component_qties = { + p.id: {stock_available_mrp_based_on: p[stock_available_mrp_based_on]} + for p in component_products + } + + for product in product_with_bom: + # Need by product (same product can be in many BOM lines/levels) + exploded_components = exploded_boms[product.id] + component_needs = product._get_components_needs(exploded_components) + if not component_needs: + # The BoM has no line we can use + potential_qty = immediately_usable_qty = 0.0 + else: + # Find the lowest quantity we can make with the stock at hand + components_potential_qty = min( + [ + component_qties[component.id][stock_available_mrp_based_on] + / need + for component, need in component_needs.items() + ] + ) + + bom_id = product.bom_id + potential_qty = bom_id.product_qty * components_potential_qty + potential_qty = potential_qty > 0.0 and potential_qty or 0.0 + + # We want to respect the rounding factor of the potential_qty + # Rounding down as we want to be pesimistic. + potential_qty = bom_id.product_uom_id._compute_quantity( + potential_qty, + product.bom_id.product_tmpl_id.uom_id, + rounding_method="DOWN", + ) + + res[product.id]["potential_qty"] = potential_qty + immediately_usable_qty = potential_qty if bom_id.type != "phantom" else 0 + res[product.id]["immediately_usable_qty"] += immediately_usable_qty + + return res, stock_dict + + def _explode_boms(self): + """ + return a dict by product_id of exploded bom lines + :return: + """ + exploded_boms = {} + for rec in self: + exploded_boms[rec.id] = rec.bom_id.explode(rec, 1.0)[1] + return exploded_boms + + @api.model + def _get_components_needs(self, exploded_components): + """ Return the needed qty of each compoments in the exploded_components + + :type exploded_components + :rtype: collections.Counter + """ + needs = Counter() + for bom_component in exploded_components: + component = bom_component[0].product_id + needs += Counter({component: bom_component[1]["qty"]}) + + return needs diff --git a/stock_available_mrp/readme/CONTRIBUTORS.rst b/stock_available_mrp/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..1089a647b --- /dev/null +++ b/stock_available_mrp/readme/CONTRIBUTORS.rst @@ -0,0 +1,10 @@ +* Loïc Bellier (Numérigraphe) +* Lionel Sausin (Numérigraphe) +* many thanks to Graeme Gellatly for his advice and code review +* Laurent Mignon +* Cédric Pigeon +* Florian da Costa + +* `Tecnativa `_: + + * Víctor Martínez diff --git a/stock_available_mrp/readme/DESCRIPTION.rst b/stock_available_mrp/readme/DESCRIPTION.rst new file mode 100644 index 000000000..83df836a5 --- /dev/null +++ b/stock_available_mrp/readme/DESCRIPTION.rst @@ -0,0 +1,6 @@ +This module takes the potential quantities available for Products into account in +the quantity available to promise, where the "Potential quantity" is the +quantity that can be manufactured with the components immediately at hand. +By configuration, the "Potential quantity" can be computed based on other product field. +For example, "Potential quantity" can be the quantity that can be manufactured +with the components available to promise. diff --git a/stock_available_mrp/readme/ROADMAP.rst b/stock_available_mrp/readme/ROADMAP.rst new file mode 100644 index 000000000..88ebb1f2e --- /dev/null +++ b/stock_available_mrp/readme/ROADMAP.rst @@ -0,0 +1,41 @@ +Known issues +~~~~~~~~~~~~ +The manufacturing delays are not taken into account : this module assumes that +if you have components in stock goods, you can manufacture finished goods +quickly enough. + +As a consequence, and to avoid overestimating, **only the first level** of Bill +of Materials is considered. + +However Sets (a.k.a "phantom" BoMs) are taken into account: if a component must +be replaced with a set, it's the stock of the set's product which will decide +the potential. + +If a product has several variants, only the variant with the biggest potential +will be taken into account when reporting the production potential. For +example, even if you actually have enough components to make 10 iPads 16Go AND +42 iPads 32Go, we'll consider that you can promise only 42 iPads. + +Removed features +~~~~~~~~~~~~~~~~ +Previous versions of this module used to let programmers demand to get the +potential quantity in an arbitrary Unit of Measure using the `context`. This +feature was present in the standard computations too until v8.0, but it has +been dropped from the standard from v8.0 on. + +For the sake of consistency the potential quantity is now always reported in +the product's main Unit of Measure too. + +Roadmap +~~~~~~~ +Possible improvements for future versions: + +* Take manufacturing delays into account: we should not promise goods to + customers if they want them delivered earlier that we can make them +* Compute the quantity of finished product that can be made directly on each + Bill of Material: this would be useful for production managers, and may make + the computations faster by avoiding to compute the same BoM several times + when several variants share the same BoM. +* Add an option (probably as a sub-module) to consider all raw materials as + available if they can be bought from the suppliers in time for the + manufacturing. diff --git a/stock_available_mrp/static/description/icon.png b/stock_available_mrp/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_available_mrp/static/description/icon.png differ diff --git a/stock_available_mrp/static/description/index.html b/stock_available_mrp/static/description/index.html new file mode 100644 index 000000000..df95846e2 --- /dev/null +++ b/stock_available_mrp/static/description/index.html @@ -0,0 +1,481 @@ + + + + + + +Consider the production potential is available to promise + + + +
+

Consider the production potential is available to promise

+ + +

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

+

This module takes the potential quantities available for Products into account in +the quantity available to promise, where the “Potential quantity” is the +quantity that can be manufactured with the components immediately at hand. +By configuration, the “Potential quantity” can be computed based on other product field. +For example, “Potential quantity” can be the quantity that can be manufactured +with the components available to promise.

+

Table of contents

+ +
+

Known issues / Roadmap

+
+

Known issues

+

The manufacturing delays are not taken into account : this module assumes that +if you have components in stock goods, you can manufacture finished goods +quickly enough.

+

As a consequence, and to avoid overestimating, only the first level of Bill +of Materials is considered.

+

However Sets (a.k.a “phantom” BoMs) are taken into account: if a component must +be replaced with a set, it’s the stock of the set’s product which will decide +the potential.

+

If a product has several variants, only the variant with the biggest potential +will be taken into account when reporting the production potential. For +example, even if you actually have enough components to make 10 iPads 16Go AND +42 iPads 32Go, we’ll consider that you can promise only 42 iPads.

+
+
+

Removed features

+

Previous versions of this module used to let programmers demand to get the +potential quantity in an arbitrary Unit of Measure using the context. This +feature was present in the standard computations too until v8.0, but it has +been dropped from the standard from v8.0 on.

+

For the sake of consistency the potential quantity is now always reported in +the product’s main Unit of Measure too.

+
+
+

Roadmap

+

Possible improvements for future versions:

+
    +
  • Take manufacturing delays into account: we should not promise goods to +customers if they want them delivered earlier that we can make them
  • +
  • Compute the quantity of finished product that can be made directly on each +Bill of Material: this would be useful for production managers, and may make +the computations faster by avoiding to compute the same BoM several times +when several variants share the same BoM.
  • +
  • Add an option (probably as a sub-module) to consider all raw materials as +available if they can be bought from the suppliers in time for the +manufacturing.
  • +
+
+
+
+

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

+
    +
  • Numérigraphe
  • +
+
+
+

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_available_mrp/tests/__init__.py b/stock_available_mrp/tests/__init__.py new file mode 100644 index 000000000..4382bb886 --- /dev/null +++ b/stock_available_mrp/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2014 Numérigraphe SARL +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from . import test_potential_qty diff --git a/stock_available_mrp/tests/test_potential_qty.py b/stock_available_mrp/tests/test_potential_qty.py new file mode 100644 index 000000000..022e0f58c --- /dev/null +++ b/stock_available_mrp/tests/test_potential_qty.py @@ -0,0 +1,394 @@ +# Copyright 2014 Numérigraphe SARL +# Copyright 2021 Tecnativa - Víctor Martínez +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.osv.expression import TRUE_LEAF +from odoo.tests.common import TransactionCase + + +class TestPotentialQty(TransactionCase): + """Test the potential quantity on a product with a multi-line BoM""" + + def setUp(self): + super().setUp() + + self.product_model = self.env["product.product"] + self.bom_model = self.env["mrp.bom"] + self.bom_line_model = self.env["mrp.bom.line"] + self.stock_quant_model = self.env["stock.quant"] + self.config = self.env["ir.config_parameter"] + self.location = self.env["stock.location"] + self.main_company = self.browse_ref("base.main_company") + # Get the warehouses + self.wh_main = self.browse_ref("stock.warehouse0") + self.wh_ch = self.browse_ref("stock.stock_warehouse_shop0") + #  An interesting product (multi-line BoM, variants) + self.tmpl = self.browse_ref("mrp.product_product_table_kit_product_template") + #  First variant + self.var1 = self.browse_ref("mrp.product_product_table_kit") + #  Second variant + self.var2 = self.browse_ref("stock_available_mrp.product_kit_1a") + # Make bolt a stockable product to be able to change its stock + # we need to unreserve the existing move before being able to do it. + bolt = self.env.ref("mrp.product_product_computer_desk_bolt") + bolt.stock_move_ids._do_unreserve() + bolt.type = "product" + # Components that can be used to make the product + components = [ + # Bolt + bolt, + # Wood Panel + self.browse_ref("mrp.product_product_wood_panel"), + ] + + # Zero-out the inventory of all variants and components + for component in components + [v for v in self.tmpl.product_variant_ids]: + component.stock_quant_ids.unlink() + + #  A product without a BoM + self.product_wo_bom = self.browse_ref("product.product_product_11") + + # Record the initial quantity available for sale + self.initial_usable_qties = { + i.id: i.immediately_usable_qty + for i in [self.tmpl, self.var1, self.var2, self.product_wo_bom] + } + + def _create_inventory(self, location_id, company_id): + inventory = self.env["stock.inventory"].create( + { + "name": "Test inventory", + "company_id": company_id, + "location_ids": [(4, location_id)], + "start_empty": True, + } + ) + inventory.action_start() + return inventory + + def _create_inventory_line(self, inventory_id, product_id, location_id, qty): + self.env["stock.inventory.line"].create( + { + "inventory_id": inventory_id, + "product_id": product_id, + "location_id": location_id, + "product_qty": qty, + } + ) + + def create_inventory(self, product_id, qty, location_id=None, company_id=None): + if location_id is None: + location_id = self.wh_main.lot_stock_id.id + + if company_id is None: + company_id = self.main_company.id + + inventory = self._create_inventory(location_id, company_id) + self._create_inventory_line(inventory.id, product_id, location_id, qty) + inventory._action_done() + + def create_simple_bom( + self, product, sub_product, product_qty=1, sub_product_qty=1, routing_id=False + ): + bom = self.bom_model.create( + { + "product_tmpl_id": product.product_tmpl_id.id, + "product_id": product.id, + "product_qty": product_qty, + "routing_id": routing_id, + } + ) + self.bom_line_model.create( + { + "bom_id": bom.id, + "product_id": sub_product.id, + "product_qty": sub_product_qty, + } + ) + + return bom + + def assertPotentialQty(self, record, qty, msg): + record.refresh() + # Check the potential + self.assertEqual(record.potential_qty, qty, msg) + # Check the variation of quantity available for sale + self.assertEqual( + (record.immediately_usable_qty - self.initial_usable_qties[record.id]), + qty, + msg, + ) + + def test_potential_qty_no_bom(self): + #  Check the potential when there's no BoM + self.assertPotentialQty( + self.product_wo_bom, 0.0, "The potential without a BoM should be 0" + ) + + def test_potential_qty_no_bom_for_company(self): + chicago_id = self.ref("stock.res_company_1") + # Receive 1000x Wood Panel owned by Chicago + self.create_inventory( + product_id=self.env.ref("mrp.product_product_wood_panel").id, + qty=1000.0, + location_id=self.wh_ch.lot_stock_id.id, + company_id=chicago_id, + ) + # Put Bolt owned by Chicago for 1000x the 1st variant in main WH + self.create_inventory( + product_id=self.env.ref("mrp.product_product_computer_desk_bolt").id, + qty=1000.0, + location_id=self.wh_ch.lot_stock_id.id, + company_id=chicago_id, + ) + self.assertPotentialQty( + self.tmpl, 250.0, "Wrong template potential after receiving components" + ) + + test_user = self.env["res.users"].create( + { + "name": "test_demo", + "login": "test_demo", + "company_id": self.main_company.id, + "company_ids": [(4, self.main_company.id), (4, chicago_id)], + "groups_id": [ + (4, self.ref("stock.group_stock_user")), + (4, self.ref("mrp.group_mrp_user")), + ], + } + ) + + bom = self.env["mrp.bom"].search([("product_tmpl_id", "=", self.tmpl.id)]) + + test_user_tmpl = self.tmpl.with_user(test_user) + self.assertPotentialQty( + test_user_tmpl, 250.0, "Simple user can access to the potential_qty" + ) + + # Set the bom on the main company (visible to members of main company) + # and all products without company (visible to all) + # and the demo user on Chicago (child of main company) + self.env["product.product"].search([TRUE_LEAF]).write({"company_id": False}) + test_user.write({"company_ids": [(6, 0, self.main_company.ids)]}) + bom.company_id = self.main_company + self.assertPotentialQty( + test_user_tmpl, + 0, + "The bom should not be visible to non members of the bom's " + "company or company child of the bom's company", + ) + bom.company_id = chicago_id + test_user.write({"company_ids": [(4, chicago_id)]}) + self.assertPotentialQty(test_user_tmpl, 250.0, "") + + def test_potential_qty(self): + for i in [self.tmpl, self.var1, self.var2]: + self.assertPotentialQty(i, 0.0, "The potential quantity should start at 0") + + # Receive 1000x Wood Panel + self.create_inventory( + product_id=self.env.ref("mrp.product_product_wood_panel").id, + qty=1000.0, + location_id=self.wh_main.lot_stock_id.id, + ) + for i in [self.tmpl, self.var1, self.var2]: + self.assertPotentialQty( + i, + 0.0, + "Receiving a single component should not change the " + "potential of %s" % i, + ) + + # Receive enough bolt to make 1000x the 1st variant in main WH + self.create_inventory( + product_id=self.env.ref("mrp.product_product_computer_desk_bolt").id, + qty=1000.0, + location_id=self.wh_main.lot_stock_id.id, + ) + self.assertPotentialQty( + self.tmpl, 250.0, "Wrong template potential after receiving components" + ) + self.assertPotentialQty( + self.var1, 250.0, "Wrong variant 1 potential after receiving components" + ) + self.assertPotentialQty( + self.var2, + 0.0, + "Receiving variant 1's component should not change " + "variant 2's potential", + ) + + # Receive enough components to make 213 the 2nd variant at Chicago + inventory = self._create_inventory( + self.wh_ch.lot_stock_id.id, self.ref("stock.res_company_1") + ) + self._create_inventory_line( + inventory.id, + self.ref("mrp.product_product_wood_panel"), + self.wh_ch.lot_stock_id.id, + 1000.0, + ) + self._create_inventory_line( + inventory.id, + self.ref("stock_available_mrp.product_computer_desk_bolt_white"), + self.wh_ch.lot_stock_id.id, + 852.0, + ) + inventory._action_done() + self.assertPotentialQty( + self.tmpl.with_context(test=True), + 250.0, + "Wrong template potential after receiving components", + ) + self.assertPotentialQty( + self.var1, + 250.0, + "Receiving variant 2's component should not change " + "variant 1's potential", + ) + self.assertPotentialQty( + self.var2, 213.0, "Wrong variant 2 potential after receiving components" + ) + # Check by warehouse + self.assertPotentialQty( + self.tmpl.with_context(warehouse=self.wh_main.id), + 250.0, + "Wrong potential quantity in main WH", + ) + self.assertPotentialQty( + self.tmpl.with_context(warehouse=self.wh_ch.id), + 213.0, + "Wrong potential quantity in Chicago WH", + ) + # Check by location + self.assertPotentialQty( + self.tmpl.with_context(location=self.wh_main.lot_stock_id.id), + 250.0, + "Wrong potential quantity in main WH location", + ) + self.assertPotentialQty( + self.tmpl.with_context(location=self.wh_ch.lot_stock_id.id), + 213.0, + "Wrong potential quantity in Chicago WH location", + ) + + def test_multi_unit_recursive_bom(self): + # Test multi-level and multi-units BOM + uom_unit = self.env.ref("uom.product_uom_unit") + uom_unit.rounding = 1.0 + p1 = self.product_model.create( + { + "name": "Test product with BOM", + "type": "product", + "uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + p2 = self.product_model.create( + { + "name": "Test sub product with BOM", + "type": "consu", + "uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + p3 = self.product_model.create( + { + "name": "Test component", + "type": "product", + "uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + bom_p1 = self.bom_model.create( + {"product_tmpl_id": p1.product_tmpl_id.id, "product_id": p1.id} + ) + + self.bom_line_model.create( + { + "bom_id": bom_p1.id, + "product_id": p3.id, + "product_qty": 1, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + # Two p2 which have a bom + self.bom_line_model.create( + { + "bom_id": bom_p1.id, + "product_id": p2.id, + "product_qty": 2, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + bom_p2 = self.bom_model.create( + { + "product_tmpl_id": p2.product_tmpl_id.id, + "product_id": p2.id, + "type": "phantom", + } + ) + + # p2 need 2 unit of component + self.bom_line_model.create( + { + "bom_id": bom_p2.id, + "product_id": p3.id, + "product_qty": 2, + "product_uom_id": self.env.ref("uom.product_uom_unit").id, + } + ) + + p1.refresh() + + # Need a least 5 units for one P1 + self.assertEqual(0, p1.potential_qty) + + self.create_inventory(p3.id, 1) + p1.refresh() + self.assertEqual(0, p1.potential_qty) + + self.create_inventory(p3.id, 3) + p1.refresh() + self.assertEqual(0, p1.potential_qty) + + self.create_inventory(p3.id, 5) + p1.refresh() + self.assertEqual(1.0, p1.potential_qty) + + self.create_inventory(p3.id, 6) + p1.refresh() + self.assertEqual(1.0, p1.potential_qty) + + self.create_inventory(p3.id, 10) + p1.refresh() + self.assertEqual(2.0, p1.potential_qty) + + def test_potential_qty_list(self): + # Try to highlight a bug when _get_potential_qty is called on + # a recordset with multiple products + # Recursive compute is not working + + p1 = self.product_model.create({"name": "Test P1"}) + p2 = self.product_model.create({"name": "Test P2"}) + p3 = self.product_model.create({"name": "Test P3", "type": "product"}) + + self.config.set_param("stock_available_mrp_based_on", "immediately_usable_qty") + + # P1 need one P2 + self.create_simple_bom(p1, p2) + # P2 need one P3 + self.create_simple_bom(p2, p3) + + self.create_inventory(p3.id, 3) + + self.product_model.invalidate_cache() + + products = self.product_model.search([("id", "in", [p1.id, p2.id, p3.id])]) + + self.assertEqual( + {p1.id: 3.0, p2.id: 3.0, p3.id: 0.0}, + {p.id: p.potential_qty for p in products}, + ) diff --git a/stock_cubiscan/__manifest__.py b/stock_cubiscan/__manifest__.py index 8c2d05859..0168df969 100644 --- a/stock_cubiscan/__manifest__.py +++ b/stock_cubiscan/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Stock Cubiscan", "summary": "Implement inteface with Cubiscan devices for packaging", - "version": "13.0.1.1.0", + "version": "13.0.1.1.1", "category": "Warehouse", "author": "Camptocamp, Odoo Community Association (OCA)", "license": "AGPL-3", diff --git a/stock_cubiscan/wizard/cubiscan_wizard.py b/stock_cubiscan/wizard/cubiscan_wizard.py index 042307a62..6dd8d4a65 100644 --- a/stock_cubiscan/wizard/cubiscan_wizard.py +++ b/stock_cubiscan/wizard/cubiscan_wizard.py @@ -83,7 +83,7 @@ class CubiscanWizard(models.TransientModel): "wizard_id": self.id, "sequence": seq + 1, "name": pack_type.name, - "qty": 0, + "qty": 1.0, "max_weight": 0, "lngth": 0, "width": 0, diff --git a/stock_cycle_count/__manifest__.py b/stock_cycle_count/__manifest__.py index 7dc945377..13849f813 100644 --- a/stock_cycle_count/__manifest__.py +++ b/stock_cycle_count/__manifest__.py @@ -5,7 +5,7 @@ "name": "Stock Cycle Count", "summary": "Adds the capability to schedule cycle counts in a " "warehouse through different rules defined by the user.", - "version": "13.0.1.0.1", + "version": "13.0.1.1.0", "development_status": "Mature", "maintainers": ["LoisRForgeFlow"], "author": "ForgeFlow, Odoo Community Association (OCA)", diff --git a/stock_cycle_count/models/stock_inventory.py b/stock_cycle_count/models/stock_inventory.py index bbbae6ed6..210c02dec 100644 --- a/stock_cycle_count/models/stock_inventory.py +++ b/stock_cycle_count/models/stock_inventory.py @@ -43,6 +43,34 @@ class StockInventory(models.Model): inv.cycle_count_id.state = "done" return True + def _domain_cycle_count_candidate(self): + return [ + ("state", "=", "draft"), + ("location_id", "in", self.location_ids.ids), + ] + + def _link_to_planned_cycle_count(self): + self.ensure_one() + domain = self._domain_cycle_count_candidate() + candidate = self.env["stock.cycle.count"].search( + domain, limit=1, order="date_deadline asc" + ) + # Also find inventories that do not exclude subloations but that are + # for a bin location (no childs). This makes the attachment logic more + # flexible and user friendly (no need to remember to tick the + # non-standard `exclude_sublocation` field). + if ( + candidate + and not self.product_ids + and ( + self.exclude_sublocation + or (len(self.location_ids) == 1 and not self.location_ids[0].child_ids) + ) + ): + candidate.state = "open" + self.write({"cycle_count_id": candidate.id, "exclude_sublocation": True}) + return True + def action_validate(self): res = super(StockInventory, self).action_validate() self._update_cycle_state() @@ -53,6 +81,13 @@ class StockInventory(models.Model): self._update_cycle_state() return res + @api.model + def create(self, vals): + res = super().create(vals) + if not res.cycle_count_id: + res._link_to_planned_cycle_count() + return res + def write(self, vals): for inventory in self: if ( diff --git a/stock_cycle_count/reports/report_stock_location_accuracy.py b/stock_cycle_count/reports/report_stock_location_accuracy.py index e207c10da..880efb661 100644 --- a/stock_cycle_count/reports/report_stock_location_accuracy.py +++ b/stock_cycle_count/reports/report_stock_location_accuracy.py @@ -14,6 +14,7 @@ class LocationAccuracyReport(models.AbstractModel): return [ ("location_id", "=", loc_id), ("exclude_sublocation", "=", exclude_sublocation), + ("filter", "=", "none"), ("state", "=", "done"), ] diff --git a/stock_cycle_count/tests/test_stock_cycle_count.py b/stock_cycle_count/tests/test_stock_cycle_count.py index 6bd6b9a17..914fd0ecf 100644 --- a/stock_cycle_count/tests/test_stock_cycle_count.py +++ b/stock_cycle_count/tests/test_stock_cycle_count.py @@ -293,3 +293,26 @@ class TestStockCycleCount(common.TransactionCase): zero2.warehouse_ids = [(4, self.big_wh.id)] with self.assertRaises(ValidationError): self.zero_rule.warehouse_ids = [(4, self.small_wh.id)] + + def test_auto_link_inventory_to_cycle_count_1(self): + """Create an inventory that could fit a planned cycle count should + auto-link it to that cycle count.""" + self.assertEqual(self.cycle_count_1.state, "draft") + inventory = self.inventory_model.create( + { + "name": "new inventory", + "location_ids": [(4, self.count_loc.id)], + "exclude_sublocation": True, + } + ) + self.assertEqual(inventory.cycle_count_id, self.cycle_count_1) + self.assertEqual(self.cycle_count_1.state, "open") + + def test_auto_link_inventory_to_cycle_count_2(self): + """Test auto-link when exclude sublocation is no set.""" + self.assertEqual(self.cycle_count_1.state, "draft") + inventory = self.inventory_model.create( + {"name": "new inventory", "location_ids": [(4, self.count_loc.id)]} + ) + self.assertEqual(inventory.cycle_count_id, self.cycle_count_1) + self.assertEqual(self.cycle_count_1.state, "open") diff --git a/stock_helper/README.rst b/stock_helper/README.rst new file mode 100644 index 000000000..c7354737a --- /dev/null +++ b/stock_helper/README.rst @@ -0,0 +1,73 @@ +============= +Stock Helpers +============= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-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_helper + :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_helper + :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| + +Add methods to be used by other modules. This is not a functional module. + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Guewen Baconnier + +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_helper/__init__.py b/stock_helper/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_helper/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_helper/__manifest__.py b/stock_helper/__manifest__.py new file mode 100644 index 000000000..64f890f1d --- /dev/null +++ b/stock_helper/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2020-2021 Camptocamp SA +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +{ + "name": "Stock Helpers", + "summary": "Add methods shared between various stock modules", + "version": "13.0.1.1.0", + "author": "Camptocamp, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Hidden", + "depends": ["stock"], + "data": [], + "installable": True, + "license": "LGPL-3", +} diff --git a/stock_helper/i18n/stock_helper.pot b/stock_helper/i18n/stock_helper.pot new file mode 100644 index 000000000..ed5ca5af8 --- /dev/null +++ b/stock_helper/i18n/stock_helper.pot @@ -0,0 +1,19 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_helper +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_helper +#: model:ir.model,name:stock_helper.model_stock_location +msgid "Inventory Locations" +msgstr "" diff --git a/stock_helper/models/__init__.py b/stock_helper/models/__init__.py new file mode 100644 index 000000000..88493e35d --- /dev/null +++ b/stock_helper/models/__init__.py @@ -0,0 +1 @@ +from . import stock_location diff --git a/stock_helper/models/stock_location.py b/stock_helper/models/stock_location.py new file mode 100644 index 000000000..cad6d288c --- /dev/null +++ b/stock_helper/models/stock_location.py @@ -0,0 +1,20 @@ +# Copyright 2020-2021 Camptocamp SA (http://www.camptocamp.com) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo import models + + +class StockLocation(models.Model): + _inherit = "stock.location" + + def is_sublocation_of(self, others, func=any): + """Return True if self is a sublocation of others (or equal) + + By default, it return True if any other is a parent or equal. + ``all`` can be passed to ``func`` to require all the other locations + to be parent or equal to be True. + """ + self.ensure_one() + # Efficient way to verify that the current location is + # below one of the other location without using SQL. + return func(self.parent_path.startswith(other.parent_path) for other in others) diff --git a/stock_helper/readme/CONTRIBUTORS.rst b/stock_helper/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..48286263c --- /dev/null +++ b/stock_helper/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Guewen Baconnier diff --git a/stock_helper/readme/DESCRIPTION.rst b/stock_helper/readme/DESCRIPTION.rst new file mode 100644 index 000000000..198d259e3 --- /dev/null +++ b/stock_helper/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Add methods to be used by other modules. This is not a functional module. diff --git a/stock_helper/static/description/icon.png b/stock_helper/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_helper/static/description/icon.png differ diff --git a/stock_helper/static/description/index.html b/stock_helper/static/description/index.html new file mode 100644 index 000000000..4ae81b83f --- /dev/null +++ b/stock_helper/static/description/index.html @@ -0,0 +1,419 @@ + + + + + + +Stock Helpers + + + +
+

Stock Helpers

+ + +

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

+

Add methods to be used by other modules. This is not a functional module.

+

Table of contents

+ +
+

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

+
    +
  • Camptocamp
  • +
+
+
+

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_helper/tests/__init__.py b/stock_helper/tests/__init__.py new file mode 100644 index 000000000..e67580e62 --- /dev/null +++ b/stock_helper/tests/__init__.py @@ -0,0 +1 @@ +from . import test_location_is_sublocation_of diff --git a/stock_helper/tests/common.py b/stock_helper/tests/common.py new file mode 100644 index 000000000..871a216ad --- /dev/null +++ b/stock_helper/tests/common.py @@ -0,0 +1,19 @@ +# Copyright 2020-2021 Camptocamp SA +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + +from odoo.tests import SavepointCase + + +class StockHelperCommonCase(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + + cls.wh = cls.env.ref("stock.warehouse0") + + cls.customer_loc = cls.env.ref("stock.stock_location_customers") + cls.supplier_loc = cls.env.ref("stock.stock_location_suppliers") + cls.stock_loc = cls.wh.lot_stock_id + cls.shelf1_loc = cls.env.ref("stock.stock_location_components") + cls.shelf2_loc = cls.env.ref("stock.stock_location_14") diff --git a/stock_helper/tests/test_location_is_sublocation_of.py b/stock_helper/tests/test_location_is_sublocation_of.py new file mode 100644 index 000000000..f88047727 --- /dev/null +++ b/stock_helper/tests/test_location_is_sublocation_of.py @@ -0,0 +1,48 @@ +# Copyright 2020-2021 Camptocamp SA +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl.html). + + +from .common import StockHelperCommonCase + + +class TestStockLocationIsSublocationOf(StockHelperCommonCase): + def test_is_sublocation_of_equal(self): + self.assertTrue(self.shelf1_loc.is_sublocation_of(self.shelf1_loc)) + + def test_is_sublocation_of_equal_child_ko(self): + bin_loc = self.env["stock.location"].create( + {"name": "bin", "location_id": self.shelf1_loc.id} + ) + self.assertFalse(self.shelf1_loc.is_sublocation_of(bin_loc)) + + def test_is_sublocation_of_equal_child_sibling(self): + self.assertFalse(self.shelf1_loc.is_sublocation_of(self.shelf2_loc)) + + def test_is_sublocation_of_any_ok(self): + self.assertTrue( + self.shelf1_loc.is_sublocation_of(self.stock_loc | self.customer_loc) + ) + + def test_is_sublocation_of_any_ko(self): + self.assertFalse( + self.shelf1_loc.is_sublocation_of(self.supplier_loc | self.customer_loc) + ) + + def test_is_sublocation_of_all_ok(self): + self.assertTrue( + self.shelf1_loc.is_sublocation_of( + self.stock_loc | self.stock_loc.location_id, func=all + ) + ) + + def test_is_sublocation_of_all_ko(self): + self.assertFalse( + self.shelf1_loc.is_sublocation_of( + self.stock_loc | self.customer_loc, func=all + ) + ) + self.assertFalse( + self.shelf1_loc.is_sublocation_of( + self.supplier_loc | self.customer_loc, func=all + ) + ) diff --git a/stock_inventory_discrepancy/__manifest__.py b/stock_inventory_discrepancy/__manifest__.py index 951c3df47..f3d42f03f 100644 --- a/stock_inventory_discrepancy/__manifest__.py +++ b/stock_inventory_discrepancy/__manifest__.py @@ -5,7 +5,7 @@ "summary": "Adds the capability to show the discrepancy of every line in " "an inventory and to block the inventory validation when the " "discrepancy is over a user defined threshold.", - "version": "13.0.1.0.0", + "version": "13.0.1.1.0", "author": "ForgeFlow, Odoo Community Association (OCA)", "website": "https://github.com/OCA/stock-logistics-warehouse", "category": "Warehouse", diff --git a/stock_inventory_discrepancy/i18n/cs_CZ.po b/stock_inventory_discrepancy/i18n/cs_CZ.po index 37218a71f..f1eec2289 100644 --- a/stock_inventory_discrepancy/i18n/cs_CZ.po +++ b/stock_inventory_discrepancy/i18n/cs_CZ.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/de.po b/stock_inventory_discrepancy/i18n/de.po index 683d86ba3..a6dfb8f77 100644 --- a/stock_inventory_discrepancy/i18n/de.po +++ b/stock_inventory_discrepancy/i18n/de.po @@ -33,6 +33,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/es.po b/stock_inventory_discrepancy/i18n/es.po index 1ab5076d9..3f3e2d562 100644 --- a/stock_inventory_discrepancy/i18n/es.po +++ b/stock_inventory_discrepancy/i18n/es.po @@ -33,6 +33,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/es_ES.po b/stock_inventory_discrepancy/i18n/es_ES.po index 977d8e610..8da3b5de6 100644 --- a/stock_inventory_discrepancy/i18n/es_ES.po +++ b/stock_inventory_discrepancy/i18n/es_ES.po @@ -35,6 +35,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/fr.po b/stock_inventory_discrepancy/i18n/fr.po index 90696e80f..15f22b614 100644 --- a/stock_inventory_discrepancy/i18n/fr.po +++ b/stock_inventory_discrepancy/i18n/fr.po @@ -33,6 +33,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/fr_FR.po b/stock_inventory_discrepancy/i18n/fr_FR.po index 30cdfd2fb..68a329cca 100644 --- a/stock_inventory_discrepancy/i18n/fr_FR.po +++ b/stock_inventory_discrepancy/i18n/fr_FR.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/hr.po b/stock_inventory_discrepancy/i18n/hr.po index 662b43c7f..563f84fa7 100644 --- a/stock_inventory_discrepancy/i18n/hr.po +++ b/stock_inventory_discrepancy/i18n/hr.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/it.po b/stock_inventory_discrepancy/i18n/it.po index 51a2a084f..4a91ffe56 100644 --- a/stock_inventory_discrepancy/i18n/it.po +++ b/stock_inventory_discrepancy/i18n/it.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/nl.po b/stock_inventory_discrepancy/i18n/nl.po index 7c66e25b2..289ed07e7 100644 --- a/stock_inventory_discrepancy/i18n/nl.po +++ b/stock_inventory_discrepancy/i18n/nl.po @@ -33,6 +33,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/nl_NL.po b/stock_inventory_discrepancy/i18n/nl_NL.po index a97cbf1ec..de0aea447 100644 --- a/stock_inventory_discrepancy/i18n/nl_NL.po +++ b/stock_inventory_discrepancy/i18n/nl_NL.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/pt_BR.po b/stock_inventory_discrepancy/i18n/pt_BR.po index 343ca9843..1d9241a44 100644 --- a/stock_inventory_discrepancy/i18n/pt_BR.po +++ b/stock_inventory_discrepancy/i18n/pt_BR.po @@ -35,6 +35,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/sl.po b/stock_inventory_discrepancy/i18n/sl.po index 374dd3f1c..5a1f1e046 100644 --- a/stock_inventory_discrepancy/i18n/sl.po +++ b/stock_inventory_discrepancy/i18n/sl.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/stock_inventory_discrepancy.pot b/stock_inventory_discrepancy/i18n/stock_inventory_discrepancy.pot index bd17bbe61..461a9ca8c 100644 --- a/stock_inventory_discrepancy/i18n/stock_inventory_discrepancy.pot +++ b/stock_inventory_discrepancy/i18n/stock_inventory_discrepancy.pot @@ -28,6 +28,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/tr_TR.po b/stock_inventory_discrepancy/i18n/tr_TR.po index 233fc226e..891625053 100644 --- a/stock_inventory_discrepancy/i18n/tr_TR.po +++ b/stock_inventory_discrepancy/i18n/tr_TR.po @@ -34,6 +34,11 @@ msgstr "" msgid "Force Validation" msgstr "" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/i18n/zh_CN.po b/stock_inventory_discrepancy/i18n/zh_CN.po index f78d3ce56..0fdf0113e 100644 --- a/stock_inventory_discrepancy/i18n/zh_CN.po +++ b/stock_inventory_discrepancy/i18n/zh_CN.po @@ -31,6 +31,11 @@ msgstr "差异百分比(%)" msgid "Force Validation" msgstr "强制验证" +#. module: stock_inventory_discrepancy +#: model:ir.model.fields,field_description:stock_inventory_discrepancy.field_stock_inventory_line__has_over_discrepancy +msgid "Has Over Discrepancy" +msgstr "" + #. module: stock_inventory_discrepancy #: model:ir.model,name:stock_inventory_discrepancy.model_stock_inventory msgid "Inventory" diff --git a/stock_inventory_discrepancy/models/stock_inventory.py b/stock_inventory_discrepancy/models/stock_inventory.py index fe44f56f7..6ae5bec86 100644 --- a/stock_inventory_discrepancy/models/stock_inventory.py +++ b/stock_inventory_discrepancy/models/stock_inventory.py @@ -1,5 +1,4 @@ -# Copyright 2017-2020 ForgeFlow S.L. -# (http://www.forgeflow.com) +# Copyright 2017-21 ForgeFlow S.L. (https://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import _, api, fields, models @@ -33,7 +32,7 @@ class StockInventory(models.Model): def _compute_over_discrepancy_line_count(self): for inventory in self: lines = inventory.line_ids.filtered( - lambda line: line.discrepancy_percent > line.discrepancy_threshold + lambda line: line._has_over_discrepancy() ) inventory.over_discrepancy_line_count = len(lines) @@ -57,9 +56,7 @@ class StockInventory(models.Model): def _action_done(self): for inventory in self: - if inventory.over_discrepancy_line_count and inventory.line_ids.filtered( - lambda t: t.discrepancy_threshold > 0.0 - ): + if inventory.over_discrepancy_line_count > 0.0: if self.user_has_groups( "stock_inventory_discrepancy.group_stock_inventory_validation" ) and not self.user_has_groups( diff --git a/stock_inventory_discrepancy/models/stock_inventory_line.py b/stock_inventory_discrepancy/models/stock_inventory_line.py index a1a0fceda..546931bef 100644 --- a/stock_inventory_discrepancy/models/stock_inventory_line.py +++ b/stock_inventory_discrepancy/models/stock_inventory_line.py @@ -1,5 +1,4 @@ -# Copyright 2017-2020 ForgeFlow S.L. -# (http://www.forgeflow.com) +# Copyright 2017-21 ForgeFlow S.L. (https://www.forgeflow.com) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). from odoo import api, fields, models @@ -29,6 +28,7 @@ class StockInventoryLine(models.Model): help="Maximum Discrepancy Rate Threshold", compute="_compute_discrepancy_threshold", ) + has_over_discrepancy = fields.Boolean(compute="_compute_has_over_discrepancy",) @api.depends("theoretical_qty", "product_qty") def _compute_discrepancy(self): @@ -52,3 +52,10 @@ class StockInventoryLine(models.Model): line.discrepancy_threshold = whs.discrepancy_threshold else: line.discrepancy_threshold = False + + def _compute_has_over_discrepancy(self): + for rec in self: + rec.has_over_discrepancy = rec._has_over_discrepancy() + + def _has_over_discrepancy(self): + return self.discrepancy_percent > self.discrepancy_threshold > 0 diff --git a/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py b/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py index 07b894086..3c97c309c 100644 --- a/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py +++ b/stock_inventory_discrepancy/tests/test_inventory_discrepancy.py @@ -173,6 +173,7 @@ class TestInventoryDiscrepancy(TransactionCase): ) inventory.with_user(self.user).action_start() inventory.with_user(self.user).action_validate() + self.assertTrue(inventory.line_ids.has_over_discrepancy) self.assertEqual( inventory.over_discrepancy_line_count, 1, diff --git a/stock_inventory_discrepancy/views/stock_inventory_view.xml b/stock_inventory_discrepancy/views/stock_inventory_view.xml index 26927dd88..69fb87db4 100644 --- a/stock_inventory_discrepancy/views/stock_inventory_view.xml +++ b/stock_inventory_discrepancy/views/stock_inventory_view.xml @@ -59,11 +59,12 @@ + theoretical_qty < 0 or discrepancy_percent > discrepancy_threshold or "product_qty != theoretical_qty" + >theoretical_qty < 0 or has_over_discrepancy diff --git a/stock_inventory_justification/README.rst b/stock_inventory_justification/README.rst new file mode 100644 index 000000000..c09f23945 --- /dev/null +++ b/stock_inventory_justification/README.rst @@ -0,0 +1,88 @@ +============================= +Stock Inventory Justification +============================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_inventory_justification + :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_inventory_justification + :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 allows to set justification on inventories + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +* Create a Stock Adjustement +* Fill in justification + +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 +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Thomas Binsfeld +* Denis Roussel + +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. + +.. |maintainer-rousseldenis| image:: https://github.com/rousseldenis.png?size=40px + :target: https://github.com/rousseldenis + :alt: rousseldenis + +Current `maintainer `__: + +|maintainer-rousseldenis| + +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_inventory_justification/__init__.py b/stock_inventory_justification/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_inventory_justification/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory_justification/__manifest__.py b/stock_inventory_justification/__manifest__.py new file mode 100644 index 000000000..267dba230 --- /dev/null +++ b/stock_inventory_justification/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2020 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Inventory Justification", + "summary": """ + This module allows to set justification on inventories""", + "version": "13.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "maintainers": ["rousseldenis"], + "depends": ["stock"], + "data": [ + "security/security.xml", + "views/stock_inventory.xml", + "views/stock_inventory_justification.xml", + ], +} diff --git a/stock_inventory_justification/i18n/stock_inventory_justification.pot b/stock_inventory_justification/i18n/stock_inventory_justification.pot new file mode 100644 index 000000000..1bb9be2b7 --- /dev/null +++ b/stock_inventory_justification/i18n/stock_inventory_justification.pot @@ -0,0 +1,85 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_inventory_justification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__active +msgid "Active" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__create_date +msgid "Created on" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__id +msgid "ID" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model,name:stock_inventory_justification.model_stock_inventory +msgid "Inventory" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model,name:stock_inventory_justification.model_stock_inventory_justification +msgid "Inventory justification" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.actions.act_window,name:stock_inventory_justification.stock_inventory_justification_act_window +#: model:ir.ui.menu,name:stock_inventory_justification.silog_stock_inventory_justification_menu +msgid "Inventory justifications" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory__justification_ids +msgid "Justifications" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.fields,field_description:stock_inventory_justification.field_stock_inventory_justification__name +msgid "Name" +msgstr "" + +#. module: stock_inventory_justification +#: model:ir.model.constraint,message:stock_inventory_justification.constraint_stock_inventory_justification_unique_name +msgid "This stock inventory justification already exists." +msgstr "" diff --git a/stock_inventory_justification/models/__init__.py b/stock_inventory_justification/models/__init__.py new file mode 100644 index 000000000..48b6b849c --- /dev/null +++ b/stock_inventory_justification/models/__init__.py @@ -0,0 +1,2 @@ +from . import stock_inventory_justification +from . import stock_inventory diff --git a/stock_inventory_justification/models/stock_inventory.py b/stock_inventory_justification/models/stock_inventory.py new file mode 100644 index 000000000..c96c776a7 --- /dev/null +++ b/stock_inventory_justification/models/stock_inventory.py @@ -0,0 +1,12 @@ +# Copyright 2019 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockInventory(models.Model): + _inherit = "stock.inventory" + + justification_ids = fields.Many2many( + string="Justifications", comodel_name="stock.inventory.justification", + ) diff --git a/stock_inventory_justification/models/stock_inventory_justification.py b/stock_inventory_justification/models/stock_inventory_justification.py new file mode 100644 index 000000000..70db5ac01 --- /dev/null +++ b/stock_inventory_justification/models/stock_inventory_justification.py @@ -0,0 +1,20 @@ +# Copyright 2019 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class StockInventoryJustification(models.Model): + _name = "stock.inventory.justification" + _description = "Inventory justification" + + _sql_constraints = [ + ( + "unique_name", + "EXCLUDE (name WITH =) WHERE (active = True)", + "This stock inventory justification already exists.", + ), + ] + + name = fields.Char(required=True) + active = fields.Boolean(default=True) diff --git a/stock_inventory_justification/readme/CONTRIBUTORS.rst b/stock_inventory_justification/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..d02b48998 --- /dev/null +++ b/stock_inventory_justification/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Thomas Binsfeld +* Denis Roussel diff --git a/stock_inventory_justification/readme/DESCRIPTION.rst b/stock_inventory_justification/readme/DESCRIPTION.rst new file mode 100644 index 000000000..c772633c5 --- /dev/null +++ b/stock_inventory_justification/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to set justification on inventories diff --git a/stock_inventory_justification/readme/USAGE.rst b/stock_inventory_justification/readme/USAGE.rst new file mode 100644 index 000000000..684b65824 --- /dev/null +++ b/stock_inventory_justification/readme/USAGE.rst @@ -0,0 +1,2 @@ +* Create a Stock Adjustement +* Fill in justification diff --git a/stock_inventory_justification/security/security.xml b/stock_inventory_justification/security/security.xml new file mode 100644 index 000000000..479e49310 --- /dev/null +++ b/stock_inventory_justification/security/security.xml @@ -0,0 +1,28 @@ + + + + + + stock.inventory.justification reader access + + + + + + + + + + stock.inventory.justification manager access + + + + + + + + diff --git a/stock_inventory_justification/static/description/icon.png b/stock_inventory_justification/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_inventory_justification/static/description/icon.png differ diff --git a/stock_inventory_justification/static/description/index.html b/stock_inventory_justification/static/description/index.html new file mode 100644 index 000000000..6d063d99c --- /dev/null +++ b/stock_inventory_justification/static/description/index.html @@ -0,0 +1,430 @@ + + + + + + +Stock Inventory Justification + + + +
+

Stock Inventory Justification

+ + +

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

+

This module allows to set justification on inventories

+

Table of contents

+ +
+

Usage

+
    +
  • Create a Stock Adjustement
  • +
  • Fill in justification
  • +
+
+
+

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

+
    +
  • ACSONE SA/NV
  • +
+
+
+

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.

+

Current maintainer:

+

rousseldenis

+

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_inventory_justification/views/stock_inventory.xml b/stock_inventory_justification/views/stock_inventory.xml new file mode 100644 index 000000000..efde97588 --- /dev/null +++ b/stock_inventory_justification/views/stock_inventory.xml @@ -0,0 +1,31 @@ + + + + + + stock.inventory.form (in stock_inventory_justification) + stock.inventory + + + + + + + + + + stock.inventory.search (in stock_inventory_justification) + stock.inventory + + + + + + + + diff --git a/stock_inventory_justification/views/stock_inventory_justification.xml b/stock_inventory_justification/views/stock_inventory_justification.xml new file mode 100644 index 000000000..f290883db --- /dev/null +++ b/stock_inventory_justification/views/stock_inventory_justification.xml @@ -0,0 +1,65 @@ + + + + + + stock.inventory.justification.form (in stock_inventory_justification) + stock.inventory.justification + +
+
+ + + + + +
+ + + + + + stock.inventory.justification.tree (in stock_inventory_justification) + stock.inventory.justification + + + + + + + + + stock.inventory.justification.search (in stock_inventory_justification) + stock.inventory.justification + + + + + + + + + Inventory justifications + stock.inventory.justification + tree,form + [] + {} + + + + Inventory justifications + + + + + diff --git a/stock_inventory_line_open/README.rst b/stock_inventory_line_open/README.rst new file mode 100644 index 000000000..93a51727a --- /dev/null +++ b/stock_inventory_line_open/README.rst @@ -0,0 +1,74 @@ +========================= +Stock Inventory Line Open +========================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_inventory_line_open + :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_inventory_line_open + :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 adds the capability to navigate to inventory lines on validated +inventory adjustments. + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* ForgeFlow + +Contributors +~~~~~~~~~~~~ + +* Lois Rilo + +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_inventory_line_open/__init__.py b/stock_inventory_line_open/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_inventory_line_open/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_inventory_line_open/__manifest__.py b/stock_inventory_line_open/__manifest__.py new file mode 100644 index 000000000..624741310 --- /dev/null +++ b/stock_inventory_line_open/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Stock Inventory Line Open", + "version": "13.0.1.0.0", + "author": "ForgeFlow," "Odoo Community Association (OCA)", + "development_status": "Beta", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse", + "summary": "Open inventory lines on validated inventory adjustments", + "depends": ["stock"], + "data": ["views/stock_inventory_view.xml"], + "license": "AGPL-3", + "installable": True, + "application": False, +} diff --git a/stock_inventory_line_open/i18n/stock_inventory_line_open.pot b/stock_inventory_line_open/i18n/stock_inventory_line_open.pot new file mode 100644 index 000000000..70b872c6b --- /dev/null +++ b/stock_inventory_line_open/i18n/stock_inventory_line_open.pot @@ -0,0 +1,26 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_inventory_line_open +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_inventory_line_open +#: model:ir.model,name:stock_inventory_line_open.model_stock_inventory +msgid "Inventory" +msgstr "" + +#. module: stock_inventory_line_open +#: code:addons/stock_inventory_line_open/models/stock_inventory.py:0 +#: model_terms:ir.ui.view,arch_db:stock_inventory_line_open.view_inventory_form +#, python-format +msgid "Inventory Lines" +msgstr "" diff --git a/stock_inventory_line_open/models/__init__.py b/stock_inventory_line_open/models/__init__.py new file mode 100644 index 000000000..35536816e --- /dev/null +++ b/stock_inventory_line_open/models/__init__.py @@ -0,0 +1 @@ +from . import stock_inventory diff --git a/stock_inventory_line_open/models/stock_inventory.py b/stock_inventory_line_open/models/stock_inventory.py new file mode 100644 index 000000000..8babc3cba --- /dev/null +++ b/stock_inventory_line_open/models/stock_inventory.py @@ -0,0 +1,31 @@ +# Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import _, models + + +class StockInventory(models.Model): + _inherit = "stock.inventory" + + def action_validated_inventory_lines(self): + self.ensure_one() + action = { + "type": "ir.actions.act_window", + "views": [ + ( + self.env.ref( + "stock_inventory_line_open.stock_inventory_line_tree_readonly" + ).id, + "tree", + ) + ], + "view_mode": "tree", + "name": _("Inventory Lines"), + "res_model": "stock.inventory.line", + } + domain = [ + ("inventory_id", "=", self.id), + ("location_id.usage", "in", ["internal", "transit"]), + ] + action["domain"] = domain + return action diff --git a/stock_inventory_line_open/readme/CONTRIBUTORS.rst b/stock_inventory_line_open/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..77dfbe89e --- /dev/null +++ b/stock_inventory_line_open/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Lois Rilo diff --git a/stock_inventory_line_open/readme/DESCRIPTION.rst b/stock_inventory_line_open/readme/DESCRIPTION.rst new file mode 100644 index 000000000..9b277a672 --- /dev/null +++ b/stock_inventory_line_open/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +This module adds the capability to navigate to inventory lines on validated +inventory adjustments. diff --git a/stock_inventory_line_open/static/description/icon.png b/stock_inventory_line_open/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_inventory_line_open/static/description/icon.png differ diff --git a/stock_inventory_line_open/static/description/index.html b/stock_inventory_line_open/static/description/index.html new file mode 100644 index 000000000..5cd24be6a --- /dev/null +++ b/stock_inventory_line_open/static/description/index.html @@ -0,0 +1,420 @@ + + + + + + +Stock Inventory Line Open + + + +
+

Stock Inventory Line Open

+ + +

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

+

This module adds the capability to navigate to inventory lines on validated +inventory adjustments.

+

Table of contents

+ +
+

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

+
    +
  • ForgeFlow
  • +
+
+ +
+

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_inventory_line_open/views/stock_inventory_view.xml b/stock_inventory_line_open/views/stock_inventory_view.xml new file mode 100644 index 000000000..eb4770797 --- /dev/null +++ b/stock_inventory_line_open/views/stock_inventory_view.xml @@ -0,0 +1,35 @@ + + + + + stock.inventory.form - stock_inventory_line_open + stock.inventory + + +
+
+
+
+ + stock.inventory.line.tree.readonly + stock.inventory.line + + primary + + + 0 + + + + + +
diff --git a/stock_inventory_lockdown/__manifest__.py b/stock_inventory_lockdown/__manifest__.py index 4b4681bd2..2e25ad6bf 100644 --- a/stock_inventory_lockdown/__manifest__.py +++ b/stock_inventory_lockdown/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Inventory Lock Down", "summary": "Lock down stock locations during inventories.", - "version": "13.0.1.0.1", + "version": "13.0.1.0.2", "development_status": "Mature", "depends": ["stock"], "author": "Numérigraphe, ForgeFlow, Odoo Community Association (OCA)", diff --git a/stock_inventory_lockdown/i18n/cs_CZ.po b/stock_inventory_lockdown/i18n/cs_CZ.po index dd9df2c9e..867c59752 100644 --- a/stock_inventory_lockdown/i18n/cs_CZ.po +++ b/stock_inventory_lockdown/i18n/cs_CZ.po @@ -22,9 +22,6 @@ msgstr "" #. module: stock_inventory_lockdown #: code:addons/stock_inventory_lockdown/models/stock_move.py:0 #, fuzzy, python-format -#| msgid "" -#| "An inventory is being conducted at the following location(s):\n" -#| "%s" msgid "" "An inventory is being conducted at the following location(s):\n" " - %s" diff --git a/stock_inventory_lockdown/i18n/pt_BR.po b/stock_inventory_lockdown/i18n/pt_BR.po index ad2eb05ec..3c66caa69 100644 --- a/stock_inventory_lockdown/i18n/pt_BR.po +++ b/stock_inventory_lockdown/i18n/pt_BR.po @@ -23,9 +23,6 @@ msgstr "" #. module: stock_inventory_lockdown #: code:addons/stock_inventory_lockdown/models/stock_move.py:0 #, fuzzy, python-format -#| msgid "" -#| "An inventory is being conducted at the following location(s):\n" -#| "%s" msgid "" "An inventory is being conducted at the following location(s):\n" " - %s" diff --git a/stock_inventory_lockdown/i18n/zh_CN.po b/stock_inventory_lockdown/i18n/zh_CN.po index 68e521642..20ce5fd94 100644 --- a/stock_inventory_lockdown/i18n/zh_CN.po +++ b/stock_inventory_lockdown/i18n/zh_CN.po @@ -23,9 +23,6 @@ msgstr "" #. module: stock_inventory_lockdown #: code:addons/stock_inventory_lockdown/models/stock_move.py:0 #, fuzzy, python-format -#| msgid "" -#| "An inventory is being conducted at the following location(s):\n" -#| "%s" msgid "" "An inventory is being conducted at the following location(s):\n" " - %s" diff --git a/stock_inventory_lockdown/models/stock_location.py b/stock_inventory_lockdown/models/stock_location.py index cdb7b2c1d..39d3479d5 100644 --- a/stock_inventory_lockdown/models/stock_location.py +++ b/stock_inventory_lockdown/models/stock_location.py @@ -9,7 +9,6 @@ class StockLocation(models.Model): """Refuse changes during exhaustive Inventories""" _inherit = "stock.location" - _order = "name" @api.constrains("location_id") def _check_inventory_location_id(self): diff --git a/stock_inventory_preparation_filter/migrations/13.0.1.0.0/post-migration.py b/stock_inventory_preparation_filter/migrations/13.0.1.0.0/post-migration.py new file mode 100644 index 000000000..8530b9169 --- /dev/null +++ b/stock_inventory_preparation_filter/migrations/13.0.1.0.0/post-migration.py @@ -0,0 +1,26 @@ +# Copyright 2020 Tecnativa - Sergio Teruel +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from openupgradelib import openupgrade + + +def convert_m2o_to_x2m_fields(env): + categ_column = openupgrade.get_legacy_name("category_id") + if openupgrade.column_exists(env.cr, "stock_inventory", categ_column): + openupgrade.m2o_to_x2m( + env.cr, + env["stock.inventory"], + "stock_inventory", + "categ_ids", + categ_column, + ) + lot_column = openupgrade.get_legacy_name("lot_id") + if openupgrade.column_exists(env.cr, "stock_inventory", lot_column): + openupgrade.m2o_to_x2m( + env.cr, env["stock.inventory"], "stock_inventory", "lot_ids", lot_column, + ) + + +@openupgrade.migrate() +def migrate(env, version): + convert_m2o_to_x2m_fields(env) diff --git a/stock_location_children/README.rst b/stock_location_children/README.rst new file mode 100644 index 000000000..70f2b6b79 --- /dev/null +++ b/stock_location_children/README.rst @@ -0,0 +1,80 @@ +======================= +Stock location children +======================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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_location_children + :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_location_children + :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 adds a `children_ids` field on `stock.location` in order to compute +and store all the children for a `stock.location` and not only its first level +children as is the case for `child_ids`. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Akim Juillerat + +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_location_children/__init__.py b/stock_location_children/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_location_children/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_location_children/__manifest__.py b/stock_location_children/__manifest__.py new file mode 100644 index 000000000..4305ce452 --- /dev/null +++ b/stock_location_children/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +{ + "name": "Stock location children", + "summary": "Add relation between stock location and all its children", + "version": "13.0.1.0.1", + "development_status": "Alpha", + "category": "Warehouse Management", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["stock"], +} diff --git a/stock_location_children/i18n/stock_location_children.pot b/stock_location_children/i18n/stock_location_children.pot new file mode 100644 index 000000000..edb90caff --- /dev/null +++ b/stock_location_children/i18n/stock_location_children.pot @@ -0,0 +1,29 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_children +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_location_children +#: model:ir.model.fields,help:stock_location_children.field_stock_location__children_ids +msgid "All the children (multi-level) stock location of this location" +msgstr "" + +#. module: stock_location_children +#: model:ir.model.fields,field_description:stock_location_children.field_stock_location__children_ids +msgid "Children" +msgstr "" + +#. module: stock_location_children +#: model:ir.model,name:stock_location_children.model_stock_location +msgid "Inventory Locations" +msgstr "" diff --git a/stock_location_children/models/__init__.py b/stock_location_children/models/__init__.py new file mode 100644 index 000000000..88493e35d --- /dev/null +++ b/stock_location_children/models/__init__.py @@ -0,0 +1 @@ +from . import stock_location diff --git a/stock_location_children/models/stock_location.py b/stock_location_children/models/stock_location.py new file mode 100644 index 000000000..efe3d14b1 --- /dev/null +++ b/stock_location_children/models/stock_location.py @@ -0,0 +1,45 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo import api, fields, models + + +class StockLocation(models.Model): + + _inherit = "stock.location" + + children_ids = fields.Many2many( + "stock.location", + "stock_location_children_ids", + "parent_id", + "children_id", + compute="_compute_children_ids", + store=True, + help="All the children (multi-level) stock location of this location", + ) + + @api.depends("child_ids", "children_ids.child_ids") + def _compute_children_ids(self): + query = """SELECT sub.id, ARRAY_AGG(sl2.id) AS children + FROM stock_location sl2, + ( + SELECT id, parent_path + FROM stock_location sl + ) sub + WHERE sl2.parent_path LIKE sub.parent_path || '%%' + AND sl2.id != sub.id + AND sub.id IN %s + GROUP BY sub.id; + """ + self.flush(["location_id", "child_ids"]) + self.env.cr.execute(query, (tuple(self.ids),)) + rows = self.env.cr.dictfetchall() + for loc in self: + all_ids = [] + for row in rows: + if row.get("id") == loc.id: + all_ids = row.get("children") + break + if all_ids: + loc.children_ids = [(6, 0, all_ids)] + else: + loc.children_ids = [(5, 0, 0)] diff --git a/stock_location_children/readme/CONTRIBUTORS.rst b/stock_location_children/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..e31e2f0c4 --- /dev/null +++ b/stock_location_children/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Akim Juillerat diff --git a/stock_location_children/readme/DESCRIPTION.rst b/stock_location_children/readme/DESCRIPTION.rst new file mode 100644 index 000000000..6dd2b549b --- /dev/null +++ b/stock_location_children/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +This module adds a `children_ids` field on `stock.location` in order to compute +and store all the children for a `stock.location` and not only its first level +children as is the case for `child_ids`. diff --git a/stock_location_children/static/description/icon.png b/stock_location_children/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_location_children/static/description/icon.png differ diff --git a/stock_location_children/static/description/index.html b/stock_location_children/static/description/index.html new file mode 100644 index 000000000..a1059dab0 --- /dev/null +++ b/stock_location_children/static/description/index.html @@ -0,0 +1,427 @@ + + + + + + +Stock location children + + + +
+

Stock location children

+ + +

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

+

This module adds a children_ids field on stock.location in order to compute +and store all the children for a stock.location and not only its first level +children as is the case for child_ids.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

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

+
    +
  • Camptocamp
  • +
+
+ +
+

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_location_children/tests/__init__.py b/stock_location_children/tests/__init__.py new file mode 100644 index 000000000..0bd71126f --- /dev/null +++ b/stock_location_children/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_location_children diff --git a/stock_location_children/tests/test_stock_location_children.py b/stock_location_children/tests/test_stock_location_children.py new file mode 100644 index 000000000..773f64b8b --- /dev/null +++ b/stock_location_children/tests/test_stock_location_children.py @@ -0,0 +1,70 @@ +# Copyright 2020 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo.tests import SavepointCase + + +class TestStockLocationChildren(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + ref = cls.env.ref + cls.stock_input = ref("stock.stock_location_company") + cls.stock_location = ref("stock.stock_location_stock") + cls.test_location = cls.env["stock.location"].create( + {"name": "Test Location", "location_id": cls.stock_location.id} + ) + cls.stock_shelf_1 = cls.env["stock.location"].create( + {"name": "Test Shelf 1", "location_id": cls.test_location.id} + ) + cls.stock_shelf_2 = cls.env["stock.location"].create( + {"name": "Test Shelf 2", "location_id": cls.test_location.id} + ) + cls.stock_shelf_2_refrigerator = cls.env["stock.location"].create( + {"name": "Test Shelf Refrigerator", "location_id": cls.stock_shelf_2.id} + ) + + def test_location_children(self): + self.assertFalse(self.stock_shelf_2_refrigerator.child_ids) + self.assertEqual(self.stock_shelf_2.child_ids, self.stock_shelf_2_refrigerator) + self.assertEqual(self.stock_shelf_2.child_ids, self.stock_shelf_2.children_ids) + self.assertFalse(self.stock_shelf_1.child_ids) + self.assertFalse(self.stock_shelf_1.children_ids) + self.assertEqual( + self.test_location.child_ids, self.stock_shelf_1 | self.stock_shelf_2 + ) + self.assertEqual( + self.test_location.children_ids, + self.stock_shelf_1 | self.stock_shelf_2 | self.stock_shelf_2_refrigerator, + ) + + def test_create_write_location(self): + refrigerator_drawer = self.env["stock.location"].create( + { + "name": "Refrigerator drawer", + "location_id": self.stock_shelf_2_refrigerator.id, + } + ) + self.assertEqual(self.stock_shelf_2_refrigerator.child_ids, refrigerator_drawer) + self.assertEqual( + self.stock_shelf_2_refrigerator.children_ids, refrigerator_drawer + ) + self.assertEqual( + self.stock_shelf_2.children_ids, + self.stock_shelf_2_refrigerator | refrigerator_drawer, + ) + self.assertEqual( + self.test_location.children_ids, + self.stock_shelf_1 + | self.stock_shelf_2 + | self.stock_shelf_2_refrigerator + | refrigerator_drawer, + ) + refrigerator_drawer.location_id = self.stock_input + self.assertFalse(self.stock_shelf_2_refrigerator.child_ids) + self.assertEqual(self.stock_shelf_2.child_ids, self.stock_shelf_2_refrigerator) + self.assertEqual(self.stock_shelf_2.child_ids, self.stock_shelf_2.children_ids) + self.assertEqual( + self.test_location.children_ids, + self.stock_shelf_1 | self.stock_shelf_2 | self.stock_shelf_2_refrigerator, + ) diff --git a/stock_location_last_inventory_date/README.rst b/stock_location_last_inventory_date/README.rst new file mode 100644 index 000000000..6a0044428 --- /dev/null +++ b/stock_location_last_inventory_date/README.rst @@ -0,0 +1,80 @@ +================================== +Stock Location Last Inventory Date +================================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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_location_last_inventory_date + :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_location_last_inventory_date + :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| + +Add a stored computed field on locations that states the last inventory date +of the location (only for validated inventories). This is only computed +for leaf locations, not parent ones. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +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 +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Carlos Serra-Toro + +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_location_last_inventory_date/__init__.py b/stock_location_last_inventory_date/__init__.py new file mode 100644 index 000000000..67e28b5c3 --- /dev/null +++ b/stock_location_last_inventory_date/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import models diff --git a/stock_location_last_inventory_date/__manifest__.py b/stock_location_last_inventory_date/__manifest__.py new file mode 100644 index 000000000..9422a8e19 --- /dev/null +++ b/stock_location_last_inventory_date/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +{ + "name": "Stock Location Last Inventory Date", + "summary": "Show the last inventory date for a leaf location", + "version": "13.0.1.0.0", + "development_status": "Alpha", + "category": "Warehouse", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["product", "stock"], +} diff --git a/stock_location_last_inventory_date/i18n/stock_location_last_inventory_date.pot b/stock_location_last_inventory_date/i18n/stock_location_last_inventory_date.pot new file mode 100644 index 000000000..ca61e2a30 --- /dev/null +++ b/stock_location_last_inventory_date/i18n/stock_location_last_inventory_date.pot @@ -0,0 +1,41 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_last_inventory_date +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_location_last_inventory_date +#: model:ir.model.fields,help:stock_location_last_inventory_date.field_stock_location__last_inventory_date +msgid "" +"Indicates the last inventory date for the location (only for validated " +"inventories). It is only computed for leaf locations." +msgstr "" + +#. module: stock_location_last_inventory_date +#: model:ir.model,name:stock_location_last_inventory_date.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_location_last_inventory_date +#: model:ir.model.fields,field_description:stock_location_last_inventory_date.field_stock_location__last_inventory_date +msgid "Last Inventory Date" +msgstr "" + +#. module: stock_location_last_inventory_date +#: model:ir.model.fields,field_description:stock_location_last_inventory_date.field_stock_location__validated_inventory_ids +msgid "Stock Inventories" +msgstr "" + +#. module: stock_location_last_inventory_date +#: model:ir.model.fields,help:stock_location_last_inventory_date.field_stock_location__validated_inventory_ids +msgid "Stock inventories in state validated for this location." +msgstr "" diff --git a/stock_location_last_inventory_date/models/__init__.py b/stock_location_last_inventory_date/models/__init__.py new file mode 100644 index 000000000..e06d283bf --- /dev/null +++ b/stock_location_last_inventory_date/models/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import stock_location diff --git a/stock_location_last_inventory_date/models/stock_location.py b/stock_location_last_inventory_date/models/stock_location.py new file mode 100644 index 000000000..a086b8612 --- /dev/null +++ b/stock_location_last_inventory_date/models/stock_location.py @@ -0,0 +1,52 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo import api, fields, models + + +class StockLocation(models.Model): + _inherit = "stock.location" + + last_inventory_date = fields.Datetime( + "Last Inventory Date", + compute="_compute_last_inventory_date", + store=True, + help="Indicates the last inventory date for the location (only for " + "validated inventories). It is only computed for leaf locations.", + ) + + # This field reuses the Many2many already defined in the model + # stock.inventory, so this definition adds little overhead, and + # allows to create the list of depends needed by the field for the + # Last Inventory Date. + validated_inventory_ids = fields.Many2many( + "stock.inventory", + relation="stock_inventory_stock_location_rel", + column1="stock_location_id", + column2="stock_inventory_id", + string="Stock Inventories", + help="Stock inventories in state validated for this location.", + domain="[('location_ids', 'in', id), ('state', '=', 'done')]", + ) + + @api.depends( + "usage", + "child_ids", + "validated_inventory_ids", + "validated_inventory_ids.date", + "validated_inventory_ids.state", + "validated_inventory_ids.location_ids.usage", + "validated_inventory_ids.location_ids.child_ids", + ) + def _compute_last_inventory_date(self): + """Store date of the last inventory for each leaf location""" + for loc in self: + if ( + loc.usage != "view" + and not loc.child_ids + and loc.validated_inventory_ids + ): + loc.last_inventory_date = loc.validated_inventory_ids.sorted( + lambda inventory: inventory.date + )[-1].date + else: + loc.last_inventory_date = False diff --git a/stock_location_last_inventory_date/readme/CONTRIBUTORS.rst b/stock_location_last_inventory_date/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..1d2f3d485 --- /dev/null +++ b/stock_location_last_inventory_date/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Carlos Serra-Toro diff --git a/stock_location_last_inventory_date/readme/DESCRIPTION.rst b/stock_location_last_inventory_date/readme/DESCRIPTION.rst new file mode 100644 index 000000000..8335d5376 --- /dev/null +++ b/stock_location_last_inventory_date/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Add a stored computed field on locations that states the last inventory date +of the location (only for validated inventories). This is only computed +for leaf locations, not parent ones. diff --git a/stock_location_last_inventory_date/static/description/icon.png b/stock_location_last_inventory_date/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_location_last_inventory_date/static/description/icon.png differ diff --git a/stock_location_last_inventory_date/static/description/index.html b/stock_location_last_inventory_date/static/description/index.html new file mode 100644 index 000000000..839fe9026 --- /dev/null +++ b/stock_location_last_inventory_date/static/description/index.html @@ -0,0 +1,427 @@ + + + + + + +Stock Location Last Inventory Date + + + +
+

Stock Location Last Inventory Date

+ + +

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

+

Add a stored computed field on locations that states the last inventory date +of the location (only for validated inventories). This is only computed +for leaf locations, not parent ones.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

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

+
    +
  • Camptocamp
  • +
+
+
+

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_location_last_inventory_date/tests/__init__.py b/stock_location_last_inventory_date/tests/__init__.py new file mode 100644 index 000000000..8f8e66e4f --- /dev/null +++ b/stock_location_last_inventory_date/tests/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from . import test_stock_location diff --git a/stock_location_last_inventory_date/tests/test_stock_location.py b/stock_location_last_inventory_date/tests/test_stock_location.py new file mode 100644 index 000000000..11ecdbbff --- /dev/null +++ b/stock_location_last_inventory_date/tests/test_stock_location.py @@ -0,0 +1,91 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl) +from odoo import fields +from odoo.exceptions import AccessError +from odoo.tests import SavepointCase + + +class TestStockLocation(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product = cls.env.ref("product.product_product_7") + cls.leaf_location = cls.env.ref("stock.location_refrigerator_small") + cls.top_location = cls.leaf_location.location_id + + def _create_user(self, name, groups): + return ( + self.env["res.users"] + .with_context({"no_reset_password": True}) + .create( + { + "name": name.capitalize(), + "password": "password", + "login": name, + "email": "{}@test.com".format(name.lower()), + "groups_id": [(6, 0, groups.ids)], + "company_ids": [(6, 0, self.env["res.company"].search([]).ids)], + } + ) + ) + + def test_leaf_location_non_privileged_user(self): + stock_user = self._create_user( + "Stock Normal", self.env.ref("stock.group_stock_user") + ) + stock_manager = self._create_user( + "Stock Admin", self.env.ref("stock.group_stock_manager") + ) + inventory = self.env["stock.inventory"].create( + { + "name": "Inventory Adjustment", + "product_ids": [(4, self.product.id)], + "location_ids": [(4, self.leaf_location.id)], + } + ) + inventory.with_user(stock_user).action_start() + inventory.with_user(stock_manager).action_validate() + self.assertEqual( + self.leaf_location.with_user(stock_user).validated_inventory_ids.ids, + [inventory.id], + ) + self.assertEqual( + self.leaf_location.with_user(stock_user).last_inventory_date, inventory.date + ) + try: + # Triggers the computation indirectly, `date` is in the depends. + inventory.with_user(stock_user).date = fields.Datetime.now() + except AccessError: + self.fail("A non-privileged user could not trigger the recomputation.") + + def test_leaf_location(self): + self.assertFalse(self.leaf_location.child_ids) + self.assertFalse(self.leaf_location.validated_inventory_ids) + self.assertFalse(self.leaf_location.last_inventory_date) + inventory = self.env["stock.inventory"].create( + { + "name": "Inventory Adjustment", + "product_ids": [(4, self.product.id)], + "location_ids": [(4, self.leaf_location.id)], + } + ) + inventory.action_start() + inventory.action_validate() + self.assertEqual(self.leaf_location.validated_inventory_ids.ids, [inventory.id]) + self.assertEqual(self.leaf_location.last_inventory_date, inventory.date) + + def test_top_location(self): + self.assertTrue(self.top_location.child_ids) + self.assertFalse(self.top_location.validated_inventory_ids) + self.assertFalse(self.top_location.last_inventory_date) + inventory = self.env["stock.inventory"].create( + { + "name": "Inventory Adjustment", + "product_ids": [(4, self.product.id)], + "location_ids": [(4, self.top_location.id)], + } + ) + inventory.action_start() + inventory.action_validate() + self.assertEqual(self.top_location.validated_inventory_ids.ids, [inventory.id]) + self.assertFalse(self.top_location.last_inventory_date) diff --git a/stock_location_lockdown/README.rst b/stock_location_lockdown/README.rst new file mode 100644 index 000000000..cbd127e6b --- /dev/null +++ b/stock_location_lockdown/README.rst @@ -0,0 +1,82 @@ +======================= +Stock Location Lockdown +======================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_location_lockdown + :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_location_lockdown + :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| + +The aim of this module is to mark internal locations where no product should transit. +Indeed, in complex warehouse setups, we may have a complicated tree of internal locations with parent locations only used to create the hierarchy of the internal locations. +We may want to avoid to put stock on these parent internal locations since they are not physical locations, they just represent a zone of the warehouse. +Theses locations must have *Location Type* set to *Internal Location* because they belong to a warehouse (they can't be configured with *Location Type* set to *View*, cf `Odoo bug #26679 `_). With this module, you will be able to enable a new option *Block stock entrance* for these locations. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +* Once the module is installed, select any internal location for which you want to prevent stock entrance and check the box *Block Stock Entrance*. Then, you won't be allow to add stock on these locations. + +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 +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Florian da Costa +* Manuel Regidor + +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_location_lockdown/__init__.py b/stock_location_lockdown/__init__.py new file mode 100644 index 000000000..79e06e260 --- /dev/null +++ b/stock_location_lockdown/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2018 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import models diff --git a/stock_location_lockdown/__manifest__.py b/stock_location_lockdown/__manifest__.py new file mode 100644 index 000000000..dafd59f42 --- /dev/null +++ b/stock_location_lockdown/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2018 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Location Lockdown", + "summary": "Prevent to add stock on locked locations", + "author": "Akretion, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-warehouse", + "category": "Warehouse", + "version": "13.0.1.0.1", + "license": "AGPL-3", + "application": False, + "installable": True, + "depends": ["stock"], + "data": ["views/stock_location.xml"], +} diff --git a/stock_location_lockdown/i18n/es.po b/stock_location_lockdown/i18n/es.po new file mode 100644 index 000000000..3fb2be677 --- /dev/null +++ b/stock_location_lockdown/i18n/es.po @@ -0,0 +1,60 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-11-02 19:08+0000\n" +"Last-Translator: Harald Panten \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 3.10\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "Bloquear entrada de stock" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "Ubicaciones de inventario" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving" +" products as it already contains some." +msgstr "" +"No es posible limitar la recepción de mercancías en esta " +"ubicación debido a que actualmente ya contiene stock." + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "Quants" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %s is blocked and can not be used for moving the product %s" +msgstr "" +"La ubicación %s está bloqueada y no puede ser utilizada para mover el " +"producto %s" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"si esta casilla está marcada, no se permitirá almacenar existencias en esta " +"ubicación. Normalmente se utiliza para una ubicación virtual que tenga hijos." diff --git a/stock_location_lockdown/i18n/fr.po b/stock_location_lockdown/i18n/fr.po new file mode 100644 index 000000000..08dd77e7b --- /dev/null +++ b/stock_location_lockdown/i18n/fr.po @@ -0,0 +1,66 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2018-09-06 13:10+0000\n" +"PO-Revision-Date: 2018-09-06 13:10+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "Block Stock Entrance" +msgstr "Bloquer les entrées de stock" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %s is blocked and can not be used for moving the product %s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"Si cette case est cochée, il ne sera pas possible d'ajouter du stock dans " +"cette emplacement. Habituellement utilisée pour les emplacements virtuels " +"ayant des enfants." + +#, fuzzy +#~ msgid "The location '%s' is not configured to receive stock." +#~ msgstr "L'emplacement %s n'est pas configuré pour recevoir du stock." + +#~ msgid "Location" +#~ msgstr "Emplacement" diff --git a/stock_location_lockdown/i18n/pt.po b/stock_location_lockdown/i18n/pt.po new file mode 100644 index 000000000..97499cb55 --- /dev/null +++ b/stock_location_lockdown/i18n/pt.po @@ -0,0 +1,61 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2018-12-28 01:41+0000\n" +"Last-Translator: Pedro Castro Silva \n" +"Language-Team: none\n" +"Language: pt\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 3.3\n" + +#. module: stock_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +#, fuzzy +msgid "Block Stock Entrance" +msgstr "Bloquear entradas de stock" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "Localizações de Inventário" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %s is blocked and can not be used for moving the product %s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" +"Se esta caixa estiver selecionada, não será permitido colocar stock nesta " +"localização. É geralmente utilizada em localizações virtuais com " +"descendentes." + +#~ msgid "The location '%s' is not configured to receive stock." +#~ msgstr "A localização '%s' não está configurada para receber stock." diff --git a/stock_location_lockdown/i18n/stock_location_lockdown.pot b/stock_location_lockdown/i18n/stock_location_lockdown.pot new file mode 100644 index 000000000..fc046a5be --- /dev/null +++ b/stock_location_lockdown/i18n/stock_location_lockdown.pot @@ -0,0 +1,51 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving" +" products as it already contains some." +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %s is blocked and can not be used for moving the product %s" +msgstr "" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "" diff --git a/stock_location_lockdown/i18n/zh_CN.po b/stock_location_lockdown/i18n/zh_CN.po new file mode 100644 index 000000000..375cc41cd --- /dev/null +++ b/stock_location_lockdown/i18n/zh_CN.po @@ -0,0 +1,54 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_location_lockdown +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2019-10-16 16:05+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\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_location_lockdown +#: model:ir.model.fields,field_description:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "Block Stock Entrance" +msgstr "阻止入库" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_location +msgid "Inventory Locations" +msgstr "库存位置" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_location.py:0 +#, python-format +msgid "" +"It is impossible to prohibit this location from receiving " +"products as it already contains some." +msgstr "因为已经包含一些产品,所以无法禁止此位置接收产品。" + +#. module: stock_location_lockdown +#: model:ir.model,name:stock_location_lockdown.model_stock_quant +msgid "Quants" +msgstr "数量分析" + +#. module: stock_location_lockdown +#: code:addons/stock_location_lockdown/models/stock_quant.py:0 +#, python-format +msgid "" +"The location %s is blocked and can not be used for moving the product %s" +msgstr "位置%s被阻止,无法用于移动产品%s" + +#. module: stock_location_lockdown +#: model:ir.model.fields,help:stock_location_lockdown.field_stock_location__block_stock_entrance +msgid "" +"if this box is checked, putting stock on this location won't be allowed. " +"Usually used for a virtual location that has childrens." +msgstr "如果选中此框,则不允许在此位置放货。通常用于有子位置的虚拟位置。" diff --git a/stock_location_lockdown/models/__init__.py b/stock_location_lockdown/models/__init__.py new file mode 100644 index 000000000..d081518d5 --- /dev/null +++ b/stock_location_lockdown/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import stock_location +from . import stock_quant diff --git a/stock_location_lockdown/models/stock_location.py b/stock_location_lockdown/models/stock_location.py new file mode 100644 index 000000000..8b69b922f --- /dev/null +++ b/stock_location_lockdown/models/stock_location.py @@ -0,0 +1,33 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class StockLocation(models.Model): + _inherit = "stock.location" + + block_stock_entrance = fields.Boolean( + help="if this box is checked, putting stock on this location won't be " + "allowed. Usually used for a virtual location that has " + "childrens." + ) + + # Raise error if the location that you're trying to block + # has already got quants + def write(self, values): + res = super().write(values) + + if "block_stock_entrance" in values and values["block_stock_entrance"]: + # Unlink zero quants before checking + # if there are quants on the location + self.env["stock.quant"]._unlink_zero_quants() + if self.mapped("quant_ids"): + raise UserError( + _( + "It is impossible to prohibit this location from\ + receiving products as it already contains some." + ) + ) + return res diff --git a/stock_location_lockdown/models/stock_quant.py b/stock_location_lockdown/models/stock_quant.py new file mode 100644 index 000000000..8f63b9e01 --- /dev/null +++ b/stock_location_lockdown/models/stock_quant.py @@ -0,0 +1,24 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + # Raise an error when trying to change a quant + # which corresponding stock location is blocked + @api.constrains("location_id") + def check_location_blocked(self): + for record in self: + if record.location_id.block_stock_entrance: + raise ValidationError( + _( + "The location %s is blocked and can " + "not be used for moving the product %s" + ) + % (record.location_id.name, record.product_id.name) + ) + return True diff --git a/stock_location_lockdown/readme/CONTRIBUTORS.rst b/stock_location_lockdown/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..0113e2351 --- /dev/null +++ b/stock_location_lockdown/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Florian da Costa +* Manuel Regidor diff --git a/stock_location_lockdown/readme/DESCRIPTION.rst b/stock_location_lockdown/readme/DESCRIPTION.rst new file mode 100644 index 000000000..4fc3faa49 --- /dev/null +++ b/stock_location_lockdown/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +The aim of this module is to mark internal locations where no product should transit. +Indeed, in complex warehouse setups, we may have a complicated tree of internal locations with parent locations only used to create the hierarchy of the internal locations. +We may want to avoid to put stock on these parent internal locations since they are not physical locations, they just represent a zone of the warehouse. +Theses locations must have *Location Type* set to *Internal Location* because they belong to a warehouse (they can't be configured with *Location Type* set to *View*, cf `Odoo bug #26679 `_). With this module, you will be able to enable a new option *Block stock entrance* for these locations. diff --git a/stock_location_lockdown/readme/USAGE.rst b/stock_location_lockdown/readme/USAGE.rst new file mode 100644 index 000000000..a8727fb3b --- /dev/null +++ b/stock_location_lockdown/readme/USAGE.rst @@ -0,0 +1 @@ +* Once the module is installed, select any internal location for which you want to prevent stock entrance and check the box *Block Stock Entrance*. Then, you won't be allow to add stock on these locations. diff --git a/stock_location_lockdown/static/description/icon.png b/stock_location_lockdown/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_location_lockdown/static/description/icon.png differ diff --git a/stock_location_lockdown/static/description/index.html b/stock_location_lockdown/static/description/index.html new file mode 100644 index 000000000..1c004d840 --- /dev/null +++ b/stock_location_lockdown/static/description/index.html @@ -0,0 +1,430 @@ + + + + + + +Stock Location Lockdown + + + +
+

Stock Location Lockdown

+ + +

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

+

The aim of this module is to mark internal locations where no product should transit. +Indeed, in complex warehouse setups, we may have a complicated tree of internal locations with parent locations only used to create the hierarchy of the internal locations. +We may want to avoid to put stock on these parent internal locations since they are not physical locations, they just represent a zone of the warehouse. +Theses locations must have Location Type set to Internal Location because they belong to a warehouse (they can’t be configured with Location Type set to View, cf Odoo bug #26679). With this module, you will be able to enable a new option Block stock entrance for these locations.

+

Table of contents

+ +
+

Usage

+
    +
  • Once the module is installed, select any internal location for which you want to prevent stock entrance and check the box Block Stock Entrance. Then, you won’t be allow to add stock on these locations.
  • +
+
+
+

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

+
    +
  • Akretion
  • +
+
+
+

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_location_lockdown/tests/__init__.py b/stock_location_lockdown/tests/__init__.py new file mode 100644 index 000000000..2f0a9ad06 --- /dev/null +++ b/stock_location_lockdown/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright 2019 Akretion +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from . import test_block_stock_location_entrance diff --git a/stock_location_lockdown/tests/test_block_stock_location_entrance.py b/stock_location_lockdown/tests/test_block_stock_location_entrance.py new file mode 100644 index 000000000..15d307d90 --- /dev/null +++ b/stock_location_lockdown/tests/test_block_stock_location_entrance.py @@ -0,0 +1,97 @@ +# Copyright 2019 Akretion France +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.exceptions import UserError, ValidationError +from odoo.tests.common import TransactionCase + + +class TestStockLocationLockdown(TransactionCase): + def setUp(self, *args, **kwargs): + super(TestStockLocationLockdown, self).setUp(*args, **kwargs) + + # Create a new stock location with no quants and blocked stock entrance + new_loc = {"name": "location_test", "usage": "internal"} + self.new_stock_location = self.env["stock.location"].create(new_loc) + self.new_stock_location.block_stock_entrance = True + + self.supplier_location = self.env.ref("stock.stock_location_suppliers") + self.customer_location = self.env.ref("stock.stock_location_customers") + + # Call an existing product and force no Lot/Serial Number tracking + self.product = self.env.ref("product.product_product_27") + self.product.tracking = "none" + + # Catch the first quant's stock location + self.stock_location = self.env["stock.quant"].search([])[0].location_id + + def test_transfer_stock_in_locked_location(self): + """ + Test to move stock within a location that should not accept + stock entrance. + """ + move_vals = { + "location_id": self.supplier_location.id, + "location_dest_id": self.new_stock_location.id, + "product_id": self.product.id, + "product_uom_qty": self.product.qty_available + 1, + "product_uom": 1, + "name": "test", + "move_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "product_uom_qty": 0, + "product_uom_id": 1, + "qty_done": self.product.qty_available + 1, + "location_id": self.supplier_location.id, + "location_dest_id": self.new_stock_location.id, + }, + ) + ], + } + stock_move = self.env["stock.move"].create(move_vals) + + with self.assertRaises(ValidationError): + stock_move._action_done() + + def test_transfer_stock_out_locked_location(self): + """ + Test to move stock out from a location that should not accept + stock removal. + """ + move_vals = { + "location_id": self.new_stock_location.id, + "location_dest_id": self.customer_location.id, + "product_id": self.product.id, + "product_uom_qty": self.product.qty_available + 1, + "product_uom": 1, + "name": "test", + "move_line_ids": [ + ( + 0, + 0, + { + "product_id": self.product.id, + "product_uom_qty": 0, + "product_uom_id": 1, + "qty_done": self.product.qty_available + 1, + "location_id": self.supplier_location.id, + "location_dest_id": self.new_stock_location.id, + }, + ) + ], + } + stock_move = self.env["stock.move"].create(move_vals) + + with self.assertRaises(ValidationError): + stock_move._action_done() + + def test_block_location_with_quants(self): + """ + Test to click on block_stock_entrance checkbox in a location + that should not be blocked because it has already got quants + """ + with self.assertRaises(UserError): + self.stock_location.write({"block_stock_entrance": True}) diff --git a/stock_location_lockdown/views/stock_location.xml b/stock_location_lockdown/views/stock_location.xml new file mode 100644 index 000000000..2315c7377 --- /dev/null +++ b/stock_location_lockdown/views/stock_location.xml @@ -0,0 +1,17 @@ + + + + + stock.location + + + + + + + + diff --git a/stock_location_tray/__manifest__.py b/stock_location_tray/__manifest__.py index 15b26fee0..b2e714b97 100644 --- a/stock_location_tray/__manifest__.py +++ b/stock_location_tray/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Location Trays", "summary": "Organize a location as a matrix of cells", - "version": "13.0.1.0.1", + "version": "13.0.1.0.2", "category": "Stock", "author": "Camptocamp, Odoo Community Association (OCA)", "license": "AGPL-3", diff --git a/stock_location_tray/tests/test_location.py b/stock_location_tray/tests/test_location.py index d25fde098..bc087f243 100644 --- a/stock_location_tray/tests/test_location.py +++ b/stock_location_tray/tests/test_location.py @@ -135,9 +135,9 @@ class TestLocation(LocationTrayTypeCase): # we cannot archive an empty cell or any parent location = cell - message = "cannot be archived" + message = "You still have some product in locations" while location: - with self.assertRaisesRegex(exceptions.ValidationError, message): + with self.assertRaisesRegex(exceptions.UserError, message): location.active = False # restore state for the next test loop @@ -159,7 +159,7 @@ class TestLocation(LocationTrayTypeCase): self._cell_for(self.tray_location, x=1, y=1), self.product, 1 ) tray_type = self.tray_type_small_32x - message = "cannot be modified when they contain products" + message = "You still have some product in locations" with self.assertRaisesRegex(exceptions.UserError, message): self.tray_location.tray_type_id = tray_type diff --git a/stock_lot_filter_available/README.rst b/stock_lot_filter_available/README.rst new file mode 100644 index 000000000..2868ab080 --- /dev/null +++ b/stock_lot_filter_available/README.rst @@ -0,0 +1,93 @@ +========================== +Stock Lot Filter Available +========================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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_lot_filter_available + :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_lot_filter_available + :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 allows us to filter lots by available on our stock. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module: + + #. Go to Inventory > Master Data > Lots/Serial Numbers. + #. Press Filters > On hand. + +Now you will see just the lots with stock. + +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 +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * Carlos Roca + +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. + +.. |maintainer-CarlosRoca13| image:: https://github.com/CarlosRoca13.png?size=40px + :target: https://github.com/CarlosRoca13 + :alt: CarlosRoca13 + +Current `maintainer `__: + +|maintainer-CarlosRoca13| + +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_lot_filter_available/__init__.py b/stock_lot_filter_available/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/stock_lot_filter_available/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_lot_filter_available/__manifest__.py b/stock_lot_filter_available/__manifest__.py new file mode 100644 index 000000000..163aed969 --- /dev/null +++ b/stock_lot_filter_available/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2021 Tecnativa - Carlos Roca +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +{ + "name": "Stock Lot Filter Available", + "summary": "Allow to filter lots by available on stock", + "version": "13.0.1.0.0", + "category": "Warehouse", + "author": "Tecnativa, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["stock"], + "data": ["views/stock_production_lot_views.xml"], + "website": "https://github.com/OCA/stock-logistics-warehouse", + "installable": True, + "maintainers": ["CarlosRoca13"], +} diff --git a/stock_lot_filter_available/i18n/es.po b/stock_lot_filter_available/i18n/es.po new file mode 100644 index 000000000..6718e32d9 --- /dev/null +++ b/stock_lot_filter_available/i18n/es.po @@ -0,0 +1,39 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_lot_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-05-07 06:58+0000\n" +"PO-Revision-Date: 2021-05-07 09:00+0200\n" +"Last-Translator: Carlos \n" +"Language-Team: \n" +"Language: 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_lot_filter_available +#: model:ir.model,name:stock_lot_filter_available.model_stock_production_lot +msgid "Lot/Serial" +msgstr "Lote/Número de serie" + +#. module: stock_lot_filter_available +#: model_terms:ir.ui.view,arch_db:stock_lot_filter_available.search_product_lot_filter +msgid "On hand" +msgstr "A mano" + +#. module: stock_lot_filter_available +#: model:ir.model.fields,field_description:stock_lot_filter_available.field_stock_production_lot__product_qty +msgid "Quantity" +msgstr "Cantidad" + +#. module: stock_lot_filter_available +#: code:addons/stock_lot_filter_available/models/stock_production_lot.py:0 +#, python-format +msgid "Unsupported search" +msgstr "Búsqueda no soportada" diff --git a/stock_lot_filter_available/i18n/stock_lot_filter_available.pot b/stock_lot_filter_available/i18n/stock_lot_filter_available.pot new file mode 100644 index 000000000..e517a7f99 --- /dev/null +++ b/stock_lot_filter_available/i18n/stock_lot_filter_available.pot @@ -0,0 +1,35 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_lot_filter_available +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_lot_filter_available +#: model:ir.model,name:stock_lot_filter_available.model_stock_production_lot +msgid "Lot/Serial" +msgstr "" + +#. module: stock_lot_filter_available +#: model_terms:ir.ui.view,arch_db:stock_lot_filter_available.search_product_lot_filter +msgid "On hand" +msgstr "" + +#. module: stock_lot_filter_available +#: model:ir.model.fields,field_description:stock_lot_filter_available.field_stock_production_lot__product_qty +msgid "Quantity" +msgstr "" + +#. module: stock_lot_filter_available +#: code:addons/stock_lot_filter_available/models/stock_production_lot.py:0 +#, python-format +msgid "Unsupported search" +msgstr "" diff --git a/stock_lot_filter_available/models/__init__.py b/stock_lot_filter_available/models/__init__.py new file mode 100644 index 000000000..dd885b7be --- /dev/null +++ b/stock_lot_filter_available/models/__init__.py @@ -0,0 +1 @@ +from . import stock_production_lot diff --git a/stock_lot_filter_available/models/stock_production_lot.py b/stock_lot_filter_available/models/stock_production_lot.py new file mode 100644 index 000000000..a5a7d28a1 --- /dev/null +++ b/stock_lot_filter_available/models/stock_production_lot.py @@ -0,0 +1,29 @@ +# Copyright 2021 Tecnativa - Carlos Roca +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import _, api, fields, models + + +class StockProductionLot(models.Model): + _inherit = "stock.production.lot" + + product_qty = fields.Float(search="_search_product_qty") + + @api.model + def _is_unsupported_search_operator(self, operator): + return operator != ">" + + def _search_product_qty(self, operator, value): + if self._is_unsupported_search_operator(operator) or value: + raise ValueError(_("Unsupported search")) + ids = [] + domain = [ + ("location_id.usage", "in", ["internal", "transit"]), + ("lot_id", "!=", False), + ] + groups = self.env["stock.quant"].read_group( + domain, ["lot_id", "quantity"], ["lot_id"] + ) + for group in groups: + if group["quantity"] > value: + ids.append(group["lot_id"][0]) + return [("id", "in", ids)] diff --git a/stock_lot_filter_available/readme/CONTRIBUTORS.rst b/stock_lot_filter_available/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..3b98bebb6 --- /dev/null +++ b/stock_lot_filter_available/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* `Tecnativa `_: + + * Carlos Roca diff --git a/stock_lot_filter_available/readme/DESCRIPTION.rst b/stock_lot_filter_available/readme/DESCRIPTION.rst new file mode 100644 index 000000000..3411dac66 --- /dev/null +++ b/stock_lot_filter_available/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows us to filter lots by available on our stock. diff --git a/stock_lot_filter_available/readme/USAGE.rst b/stock_lot_filter_available/readme/USAGE.rst new file mode 100644 index 000000000..97219b428 --- /dev/null +++ b/stock_lot_filter_available/readme/USAGE.rst @@ -0,0 +1,6 @@ +To use this module: + + #. Go to Inventory > Master Data > Lots/Serial Numbers. + #. Press Filters > On hand. + +Now you will see just the lots with stock. diff --git a/stock_lot_filter_available/static/description/icon.png b/stock_lot_filter_available/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_lot_filter_available/static/description/icon.png differ diff --git a/stock_lot_filter_available/static/description/index.html b/stock_lot_filter_available/static/description/index.html new file mode 100644 index 000000000..1519c277d --- /dev/null +++ b/stock_lot_filter_available/static/description/index.html @@ -0,0 +1,436 @@ + + + + + + +Stock Lot Filter Available + + + +
+

Stock Lot Filter Available

+ + +

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

+

This module allows us to filter lots by available on our stock.

+

Table of contents

+ +
+

Usage

+

To use this module:

+
+
    +
  1. Go to Inventory > Master Data > Lots/Serial Numbers.
  2. +
  3. Press Filters > On hand.
  4. +
+
+

Now you will see just the lots with stock.

+
+
+

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.

+

Current maintainer:

+

CarlosRoca13

+

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_lot_filter_available/tests/__init__.py b/stock_lot_filter_available/tests/__init__.py new file mode 100644 index 000000000..a1988e073 --- /dev/null +++ b/stock_lot_filter_available/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_lot_filter_available diff --git a/stock_lot_filter_available/tests/test_stock_lot_filter_available.py b/stock_lot_filter_available/tests/test_stock_lot_filter_available.py new file mode 100644 index 000000000..4f0634a1f --- /dev/null +++ b/stock_lot_filter_available/tests/test_stock_lot_filter_available.py @@ -0,0 +1,36 @@ +# Copyright 2021 Tecnativa - Carlos Roca +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import SavepointCase + + +class TestStockLotFilterAvailable(SavepointCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.StockProductionLot = cls.env["stock.production.lot"] + cls.company = cls.env.ref("base.main_company") + cls.loc = cls.env.ref("stock.stock_location_stock") + cls.product = cls.env["product.product"].create( + {"name": "Test product", "type": "product", "tracking": "lot"} + ) + cls.lot = cls.StockProductionLot.create( + { + "name": "TT-LOT", + "product_id": cls.product.id, + "company_id": cls.company.id, + } + ) + cls.env["stock.quant"]._update_available_quantity( + cls.product, cls.loc, 100, lot_id=cls.lot + ) + + def test_bad_operator(self): + with self.assertRaises(ValueError): + self.StockProductionLot._search_product_qty("in", [10, 15]) + with self.assertRaises(ValueError): + self.StockProductionLot._search_product_qty(">", 2) + + def test_good_operator(self): + domain = self.StockProductionLot._search_product_qty(">", 0) + self.assertTrue(self.lot.id in domain[0][2]) diff --git a/stock_lot_filter_available/views/stock_production_lot_views.xml b/stock_lot_filter_available/views/stock_production_lot_views.xml new file mode 100644 index 000000000..bd0adbaf7 --- /dev/null +++ b/stock_lot_filter_available/views/stock_production_lot_views.xml @@ -0,0 +1,19 @@ + + + + + Production Lots Filter + stock.production.lot + + + + + + + + diff --git a/stock_measuring_device/README.rst b/stock_measuring_device/README.rst new file mode 100644 index 000000000..ec4cf1133 --- /dev/null +++ b/stock_measuring_device/README.rst @@ -0,0 +1,119 @@ +====================== +Stock Measuring Device +====================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |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_measuring_device + :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_measuring_device + :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| + +Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +This module by itself does not do anything. + +You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device. + +Configuration +============= + +The first step is to configure the Packaging Types (Pallet, Box, ...) in Inventory > Configuration > Product Packaging Types. + +Configure the measuring device in Inventory > Configuration > Measuring +Devices, don't forget to set the device type, and any other additional +parameters. + +Usage +===== + +Use the "Wizard" button on a Measuring Device to open the screen and take +measurements. + +Known issues / Roadmap +====================== + +* The UI could get some improvements +* Being able to open the measurement screen from a product would be nice + +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 +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Patrick Tombez +* Alexandre Fayolle +* Carlos Serra Toro + +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. + +.. |maintainer-gurneyalex| image:: https://github.com/gurneyalex.png?size=40px + :target: https://github.com/gurneyalex + :alt: gurneyalex + +Current `maintainer `__: + +|maintainer-gurneyalex| + +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_measuring_device/__init__.py b/stock_measuring_device/__init__.py new file mode 100644 index 000000000..0b1d65aed --- /dev/null +++ b/stock_measuring_device/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import components +from . import models +from . import wizard diff --git a/stock_measuring_device/__manifest__.py b/stock_measuring_device/__manifest__.py new file mode 100644 index 000000000..e000dc103 --- /dev/null +++ b/stock_measuring_device/__manifest__.py @@ -0,0 +1,34 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +{ + "name": "Stock Measuring Device", + "summary": "Implement a common interface for measuring and weighing devices", + "version": "13.0.1.1.0", + "category": "Warehouse", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": [ + "component", + "barcodes", + "stock", + "web_tree_dynamic_colored_field", + "product_packaging_dimension", + "product_packaging_type_required", + "product_dimension", + # To refresh wizard screen or pop-up message on the wizard + "web_notify", + "web_ir_actions_act_view_reload", + ], + "data": [ + "security/ir.model.access.csv", + "data/uom.xml", + "views/assets.xml", + "views/measuring_device_view.xml", + "wizard/measuring_wizard.xml", + "views/menu.xml", + ], + "website": "https://github.com/OCA/stock-logistics-warehouse", + "installable": True, + "development_status": "Alpha", + "maintainers": ["gurneyalex"], +} diff --git a/stock_measuring_device/components/__init__.py b/stock_measuring_device/components/__init__.py new file mode 100644 index 000000000..f1c2b4985 --- /dev/null +++ b/stock_measuring_device/components/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import measuring_device_component diff --git a/stock_measuring_device/components/measuring_device_component.py b/stock_measuring_device/components/measuring_device_component.py new file mode 100644 index 000000000..fa8af855b --- /dev/null +++ b/stock_measuring_device/components/measuring_device_component.py @@ -0,0 +1,46 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +import logging + +from odoo.addons.component.core import AbstractComponent + +_logger = logging.getLogger(__name__) + + +class MeasuringDevice(AbstractComponent): + _name = "measuring.device.base" + _collection = "measuring.device" + + def test_device(self): + """Test that the device is properly configured. + + Override to e.g. test the connection parameter or send a test command. + + :return: True on success, False otherwise""" + return True + + def preprocess_measures(self, measures): + """perform required parsing, key mapping and possible unit conversion + + :param measures: a dictionary passed to _update_packaging_measures + :return: a dictionary containing values that will be written on the + wizard line + """ + return measures + + def post_update_packaging_measures(self, measures, packaging, wizard_line): + """hook called after the update of the packaging or wizard line update. + + This method can be called to send notifications for instance. + + :return: None""" + pass + + def get_measure(self): + """Get a measure from the device + + the implementation must communicate with the device to trigger a + measure. If this can be done synchronously, call + _update_packaging_measures() to get the update""" + raise NotImplementedError() diff --git a/stock_measuring_device/data/uom.xml b/stock_measuring_device/data/uom.xml new file mode 100644 index 000000000..543ab39ea --- /dev/null +++ b/stock_measuring_device/data/uom.xml @@ -0,0 +1,9 @@ + + + + + mm + + smaller + + diff --git a/stock_measuring_device/i18n/stock_measuring_device.pot b/stock_measuring_device/i18n/stock_measuring_device.pot new file mode 100644 index 000000000..66ad12100 --- /dev/null +++ b/stock_measuring_device/i18n/stock_measuring_device.pot @@ -0,0 +1,315 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_measuring_device +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.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_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard___barcode_scanned +msgid "Barcode Scanned" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Cancel Scan" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Close" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__create_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__create_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__create_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__create_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__create_date +msgid "Created on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__device_id +msgid "Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__device_type +msgid "Device Type" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__display_name +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__display_name +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Fullscreen" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__barcode +msgid "GTIN" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__height +msgid "Height (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__id +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__id +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__id +msgid "ID" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__is_measured +msgid "Is Measured" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__is_unit_line +msgid "Is Unit Line" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device____last_update +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard____last_update +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__write_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__write_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__write_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__write_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__lngth +msgid "Length (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__line_ids +msgid "Line" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/models/measuring_device.py:0 +#, python-format +msgid "Measurement Wizard" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/wizard/measuring_wizard_line.py:0 +#, python-format +msgid "Measurement machine already in use." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.actions.act_window,name:stock_measuring_device.action_measuring_device_form +#: model:ir.model.fields,field_description:stock_measuring_device.field_stock_warehouse__measuring_device_ids +#: model:ir.ui.menu,name:stock_measuring_device.menu_measuring_device +msgid "Measuring Devices" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_device +msgid "Measuring and Weighing Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_product_packaging__measuring_device_id +msgid "Measuring device which will scan the package" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__name +msgid "Name" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields.selection,name:stock_measuring_device.selection__measuring_device__state__not_ready +msgid "Not Ready" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__name +msgid "Packaging" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__packaging_id +msgid "Packaging (rel)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__packaging_type_id +msgid "Packaging Type" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__product_id +msgid "Product" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_product_packaging +msgid "Product Packaging" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__qty +msgid "Quantity" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields.selection,name:stock_measuring_device.selection__measuring_device__state__ready +msgid "Ready" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Refresh" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__required +msgid "Required" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Retrieve Product" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Save" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Scan" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__scan_requested +msgid "Scan Requested" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__sequence +msgid "Sequence" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/models/product_packaging.py:0 +#, python-format +msgid "" +"Several packagings ({}) found to update by device {}. Will update the first:" +" {}" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__state +msgid "State" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_product_packaging__measuring_device_id +msgid "" +"Technical field set when an operator uses the device to scan this package" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_device_form +msgid "Test Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.constraint,message:stock_measuring_device.constraint_measuring_device_name_uniq +msgid "The name of the measuring/weighing device must be unique." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_measuring_device__device_type +msgid "" +"The type of device (e.g. zippcube, cubiscan...) depending on which module " +"are installed." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_measuring_wizard___barcode_scanned +msgid "Value of the last barcode scanned." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__volume +msgid "Volume (m³)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_stock_warehouse +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__warehouse_id +msgid "Warehouse" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__max_weight +msgid "Weight (kg)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__width +msgid "Width (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__wizard_id +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_device_form +msgid "Wizard" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_wizard +msgid "measuring Wizard" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_wizard_line +msgid "measuring Wizard Line" +msgstr "" + +#. module: stock_measuring_device +#: model:uom.uom,name:stock_measuring_device.product_uom_mm +msgid "mm" +msgstr "" diff --git a/stock_measuring_device/models/__init__.py b/stock_measuring_device/models/__init__.py new file mode 100644 index 000000000..5bdb916aa --- /dev/null +++ b/stock_measuring_device/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import measuring_device +from . import product_packaging +from . import stock_warehouse diff --git a/stock_measuring_device/models/measuring_device.py b/stock_measuring_device/models/measuring_device.py new file mode 100644 index 000000000..f23875954 --- /dev/null +++ b/stock_measuring_device/models/measuring_device.py @@ -0,0 +1,110 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +import logging + +from odoo import _, fields, models + +_logger = logging.getLogger(__name__) + + +class MeasuringDevice(models.Model): + _name = "measuring.device" + _inherit = "collection.base" + _description = "Measuring and Weighing Device" + _order = "warehouse_id, name" + + name = fields.Char("Name", required=True) + warehouse_id = fields.Many2one("stock.warehouse", "Warehouse", required=True) + device_type = fields.Selection( + selection=[], + help="The type of device (e.g. zippcube, cubiscan...) " + "depending on which module are installed.", + ) + state = fields.Selection( + [("not_ready", "Not Ready"), ("ready", "Ready")], + default="not_ready", + readonly=True, + copy=False, + ) + + _sql_constraints = [ + ( + "name_uniq", + "unique (name)", + "The name of the measuring/weighing device must be unique.", + ), + ] + + def _get_measuring_device(self): + with self.work_on(self._name) as work_ctx: + return work_ctx.component(usage=self.device_type) + + def open_wizard(self): + res = { + "name": _("Measurement Wizard"), + "res_model": "measuring.wizard", + "type": "ir.actions.act_window", + "view_id": False, + "view_mode": "form", + "context": {"default_device_id": self.id}, + "target": "fullscreen", + "flags": { + "withControlPanel": False, + "form_view_initial_mode": "edit", + "no_breadcrumbs": True, + }, + } + if self._is_being_used(): + pack = self.env["product.packaging"].search( + [("measuring_device_id", "=", self.id)], limit=1 + ) + res["context"]["default_product_id"] = pack.product_id.id + return res + + def _is_being_used(self): + self.ensure_one() + return bool( + self.env["product.packaging"].search_count( + [("measuring_device_id", "=", self.id)] + ) + ) + + def _update_packaging_measures(self, measures): + self.ensure_one() + measures = self._get_measuring_device().preprocess_measures(measures) + line_domain = [ + ("wizard_id.device_id", "=", self.id), + ("scan_requested", "=", True), + ] + + packaging = self.env["product.packaging"]._measuring_device_find_assigned(self) + if packaging: + line_domain += [("packaging_id", "=", packaging.id)] + else: + line_domain += [ + ("packaging_id", "=", False), + ("is_unit_line", "=", True), + ] + + wizard_line = self.env["measuring.wizard.line"].search( + line_domain, order="write_date DESC", limit=1, + ) + if not wizard_line: + _logger.warning("No wizard line found for this measure.") + packaging.write(measures) + else: + measures.update({"scan_requested": False, "is_measured": True}) + wizard_line.write(measures) + + self._get_measuring_device().post_update_packaging_measures( + measures, packaging, wizard_line + ) + return packaging + + def test_device(self): + for rec in self: + success = rec._get_measuring_device().test_device() + if success and rec.state == "not_ready": + rec.state = "ready" + elif not success and rec.state == "ready": + rec.state = "not_ready" diff --git a/stock_measuring_device/models/product_packaging.py b/stock_measuring_device/models/product_packaging.py new file mode 100644 index 000000000..753a029e2 --- /dev/null +++ b/stock_measuring_device/models/product_packaging.py @@ -0,0 +1,50 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +import logging + +from odoo import _, fields, models + +_logger = logging.getLogger(__name__) + + +class ProductPackaging(models.Model): + _inherit = "product.packaging" + + measuring_device_id = fields.Many2one( + "measuring.device", + copy=False, + string="Measuring device which will scan the package", + help="Technical field set when an operator uses the device " + "to scan this package", + index=True, + ) + + def _measuring_device_assign(self, device): + """Assign the measuring device to the current product packaging""" + # self can be an empty recordset, for the unit line which updates the + # product info + if self: + self.measuring_device_id = device + + def _measuring_device_release(self): + """Free the measuring device from the current product packaging""" + # self can be an empty recordset, for the unit line which updates the + # product info + if self: + self.measuring_device_id = False + + def _measuring_device_find_assigned(self, device): + """search packaging being assigned to the specified device""" + packaging = self.search( + [("measuring_device_id", "=", device.id)], order="write_date DESC", limit=2 + ) + if len(packaging) > 1: + warning_msg = _( + "Several packagings ({}) found to update by " + "device {}. Will update the first: {}".format( + packaging, self.name, packaging[0] + ) + ) + _logger.warning(warning_msg) + packaging = packaging[0] + return packaging diff --git a/stock_measuring_device/models/stock_warehouse.py b/stock_measuring_device/models/stock_warehouse.py new file mode 100644 index 000000000..83328dc42 --- /dev/null +++ b/stock_measuring_device/models/stock_warehouse.py @@ -0,0 +1,12 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from odoo import fields, models + + +class StockWarehouse(models.Model): + _inherit = "stock.warehouse" + + measuring_device_ids = fields.One2many( + "measuring.device", "warehouse_id", string="Measuring Devices" + ) diff --git a/stock_measuring_device/readme/CONFIGURE.rst b/stock_measuring_device/readme/CONFIGURE.rst new file mode 100644 index 000000000..e270c3f15 --- /dev/null +++ b/stock_measuring_device/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +The first step is to configure the Packaging Types (Pallet, Box, ...) in Inventory > Configuration > Product Packaging Types. + +Configure the measuring device in Inventory > Configuration > Measuring +Devices, don't forget to set the device type, and any other additional +parameters. diff --git a/stock_measuring_device/readme/CONTRIBUTORS.rst b/stock_measuring_device/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..61b56b03d --- /dev/null +++ b/stock_measuring_device/readme/CONTRIBUTORS.rst @@ -0,0 +1,3 @@ +* Patrick Tombez +* Alexandre Fayolle +* Carlos Serra Toro diff --git a/stock_measuring_device/readme/DESCRIPTION.rst b/stock_measuring_device/readme/DESCRIPTION.rst new file mode 100644 index 000000000..66bb0cf1c --- /dev/null +++ b/stock_measuring_device/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo. diff --git a/stock_measuring_device/readme/INSTALL.rst b/stock_measuring_device/readme/INSTALL.rst new file mode 100644 index 000000000..c3448c214 --- /dev/null +++ b/stock_measuring_device/readme/INSTALL.rst @@ -0,0 +1,4 @@ +This module by itself does not do anything. + +You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device. diff --git a/stock_measuring_device/readme/ROADMAP.rst b/stock_measuring_device/readme/ROADMAP.rst new file mode 100644 index 000000000..3d608500b --- /dev/null +++ b/stock_measuring_device/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* The UI could get some improvements +* Being able to open the measurement screen from a product would be nice diff --git a/stock_measuring_device/readme/USAGE.rst b/stock_measuring_device/readme/USAGE.rst new file mode 100644 index 000000000..a346d91b2 --- /dev/null +++ b/stock_measuring_device/readme/USAGE.rst @@ -0,0 +1,2 @@ +Use the "Wizard" button on a Measuring Device to open the screen and take +measurements. diff --git a/stock_measuring_device/security/ir.model.access.csv b/stock_measuring_device/security/ir.model.access.csv new file mode 100644 index 000000000..290cbbdba --- /dev/null +++ b/stock_measuring_device/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_measuring_device_inventory_manager,measuring.device.inventory.manager,stock_measuring_device.model_measuring_device,stock.group_stock_manager,1,1,1,1 +access_measuring_device_inventory_user,measuring.device.inventory.user,stock_measuring_device.model_measuring_device,stock.group_stock_user,1,0,0,0 diff --git a/stock_measuring_device/static/description/icon.png b/stock_measuring_device/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_measuring_device/static/description/icon.png differ diff --git a/stock_measuring_device/static/description/index.html b/stock_measuring_device/static/description/index.html new file mode 100644 index 000000000..5e08cf23e --- /dev/null +++ b/stock_measuring_device/static/description/index.html @@ -0,0 +1,460 @@ + + + + + + +Stock Measuring Device + + + +
+

Stock Measuring Device

+ + +

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

+

Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Installation

+

This module by itself does not do anything.

+

You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device.

+
+
+

Configuration

+

The first step is to configure the Packaging Types (Pallet, Box, …) in Inventory > Configuration > Product Packaging Types.

+

Configure the measuring device in Inventory > Configuration > Measuring +Devices, don’t forget to set the device type, and any other additional +parameters.

+
+
+

Usage

+

Use the “Wizard” button on a Measuring Device to open the screen and take +measurements.

+
+
+

Known issues / Roadmap

+
    +
  • The UI could get some improvements
  • +
  • Being able to open the measurement screen from a product would be nice
  • +
+
+
+

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

+
    +
  • Camptocamp
  • +
+
+
+

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.

+

Current maintainer:

+

gurneyalex

+

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_measuring_device/static/src/js/measuring_wizard.js b/stock_measuring_device/static/src/js/measuring_wizard.js new file mode 100644 index 000000000..bd9fc40c4 --- /dev/null +++ b/stock_measuring_device/static/src/js/measuring_wizard.js @@ -0,0 +1,60 @@ +odoo.define("stock_measuring_device.measuring_wizard", function(require) { + "use strict"; + + var FormController = require("web.FormController"); + + FormController.include({ + init: function() { + this._super.apply(this, arguments); + if (this.modelName === "measuring.wizard") { + this.call( + "bus_service", + "addChannel", + "notify_measuring_wizard_screen" + ); + this.call( + "bus_service", + "on", + "notification", + this, + this.measuring_wizard_bus_notification + ); + this.call("bus_service", "startPolling"); + } + }, + measuring_wizard_bus_notification: function(notifications) { + var self = this; + _.each(notifications, function(notification) { + var channel = notification[0]; + var message = notification[1]; + if (channel === "notify_measuring_wizard_screen") { + if (message.action === "refresh") { + self.measuring_wizard_bus_action_refresh(message.params); + } + } + }); + }, + measuring_wizard_bus_action_refresh: function(params) { + var selectedIds = this.getSelectedIds(); + if (!selectedIds.length || params.model !== this.modelName) { + return; + } + var currentId = selectedIds[0]; + if (params.id === currentId) { + this.reload(); + } + }, + destroy: function() { + if (this.modelName === "measuring.wizard") { + this.call( + "bus_service", + "deleteChannel", + "notify_measuring_wizard_screen" + ); + } + this._super.apply(this, arguments); + }, + }); + + return {}; +}); diff --git a/stock_measuring_device/static/src/scss/measuring_wizard.scss b/stock_measuring_device/static/src/scss/measuring_wizard.scss new file mode 100644 index 000000000..507cfc3bd --- /dev/null +++ b/stock_measuring_device/static/src/scss/measuring_wizard.scss @@ -0,0 +1,33 @@ +.o_web_client.o_fullscreen { + .o_form_view.measuring_wizard { + font-size: 16px; + + @include media-breakpoint-up(x1) { + font-size: 18px; + } + + .btn { + font-size: 1em; + padding: 1em; + margin: 0 5px; + } + + .o_data_cell:not(.o_list_button) { + padding: 0.75em; + font-size: 1.5em; + margin: 0 5px; + } + + .table-responsive { + overflow: hidden; + } + + .o_field_many2one input.o_input { + font-size: 1.5em; + } + + .o_form_statusbar { + display: none; + } + } +} diff --git a/stock_measuring_device/views/assets.xml b/stock_measuring_device/views/assets.xml new file mode 100644 index 000000000..8be276756 --- /dev/null +++ b/stock_measuring_device/views/assets.xml @@ -0,0 +1,20 @@ + + +