diff --git a/setup/stock_account_valuation_report/odoo/addons/stock_account_valuation_report b/setup/stock_account_valuation_report/odoo/addons/stock_account_valuation_report new file mode 120000 index 000000000..e68a76ebb --- /dev/null +++ b/setup/stock_account_valuation_report/odoo/addons/stock_account_valuation_report @@ -0,0 +1 @@ +../../../../stock_account_valuation_report \ No newline at end of file diff --git a/setup/stock_account_valuation_report/setup.py b/setup/stock_account_valuation_report/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_account_valuation_report/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_account_valuation_report/README.rst b/stock_account_valuation_report/README.rst new file mode 100644 index 000000000..a3866cbf5 --- /dev/null +++ b/stock_account_valuation_report/README.rst @@ -0,0 +1,85 @@ +============================== +Stock Account Valuation Report +============================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:8eba82c0ba0bf8977a42d5cb00400a6870c2a15d84924e34006179c1947be659 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--reporting-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-reporting/tree/15.0/stock_account_valuation_report + :alt: OCA/stock-logistics-reporting +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-reporting-15-0/stock-logistics-reporting-15-0-stock_account_valuation_report + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/stock-logistics-reporting&target_branch=15.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +When you trigger a report of inventory valuation, and you use +perpetual inventory, you should be able to reconcile the valuation +from an inventory perspective with the valuation +from an accounting perspective. + +This module changes the report in *Inventory / Reporting / +Dual Inventory Valuation* +to display separately the Quantity and Value of each product for the +Inventory and the Accounting systems . + +**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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* ForgeFlow S.L. + +Contributors +~~~~~~~~~~~~ + +* Jordi Ballester Alomar +* Aaron Henriquez + +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-reporting `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_account_valuation_report/__init__.py b/stock_account_valuation_report/__init__.py new file mode 100644 index 000000000..aee8895e7 --- /dev/null +++ b/stock_account_valuation_report/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizards diff --git a/stock_account_valuation_report/__manifest__.py b/stock_account_valuation_report/__manifest__.py new file mode 100644 index 000000000..e16e69605 --- /dev/null +++ b/stock_account_valuation_report/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2020 ForgeFlow S.L. +# Copyright 2019 Aleph Objects, Inc. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +{ + "name": "Stock Account Valuation Report", + "version": "16.0.1.0.0", + "summary": "Improves logic of the Inventory Valuation Report", + "author": "ForgeFlow S.L., Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-reporting", + "category": "Warehouse Management", + "depends": ["stock_account"], + "license": "AGPL-3", + "data": [ + "security/ir.model.access.csv", + "views/product_product_views.xml", + "wizards/stock_valuation_history.xml", + ], + "installable": True, +} diff --git a/stock_account_valuation_report/i18n/de.po b/stock_account_valuation_report/i18n/de.po new file mode 100644 index 000000000..d7154d430 --- /dev/null +++ b/stock_account_valuation_report/i18n/de.po @@ -0,0 +1,195 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-05-30 01:05+0000\n" +"Last-Translator: Iryna Vyshnevska \n" +"Language-Team: none\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" +"X-Generator: Weblate 4.3.2\n" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "Buchhaltungsmenge" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "Buchhaltungsmenge" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:0 +#, python-format +msgid "Accounting Valuation at date" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Cancel" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,help:stock_account_valuation_report.field_stock_valuation_history__inventory_datetime +msgid "Choose a date to get the valuation at that date" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Choose your date" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Confirm" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.actions.act_window,help:stock_account_valuation_report.product_valuation_action +msgid "Create a product to see its name and valuation." +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__create_date +msgid "Created on" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.actions.act_window,name:stock_account_valuation_report.history_valuation_action +#: model:ir.actions.act_window,name:stock_account_valuation_report.product_valuation_action +#: model:ir.ui.menu,name:stock_account_valuation_report.menu_dual_valuation +msgid "Dual Inventory Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__inventory_datetime +msgid "Dual Valuation at Date" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__id +msgid "ID" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:0 +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__valuation +#, python-format +msgid "Inventory Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +msgid "Manual" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,help:stock_account_valuation_report.field_product_product__valuation +msgid "" +"Manual: The accounting entries to value the inventory are not posted automatically.\n" +" Automated: An accounting entry is automatically created to value the inventory when a product enters or leaves the company.\n" +" " +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_discrepancy +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Qty Discrepancy" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +msgid "Real time" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Stock Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_valuation_history +msgid "Stock Valuation History" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_valuation_layer_ids +msgid "Stock Valuation Layer" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__valuation_discrepancy +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Valuation Discrepancy" +msgstr "" diff --git a/stock_account_valuation_report/i18n/es.po b/stock_account_valuation_report/i18n/es.po new file mode 100644 index 000000000..8f734cbad --- /dev/null +++ b/stock_account_valuation_report/i18n/es.po @@ -0,0 +1,83 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: Automatically generated\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" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:115 +#, python-format +msgid "Accounting Valuation at date" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:131 +#, python-format +msgid "Inventory Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_manual_move_ids +msgid "Stock Fifo Manual Move" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_quantity_history +msgid "Stock Quantity History" +msgstr "" diff --git a/stock_account_valuation_report/i18n/es_MX.po b/stock_account_valuation_report/i18n/es_MX.po new file mode 100644 index 000000000..8600805e2 --- /dev/null +++ b/stock_account_valuation_report/i18n/es_MX.po @@ -0,0 +1,85 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2020-02-26 15:13+0000\n" +"Last-Translator: Jesús Alan Ramos Rodríguez \n" +"Language-Team: none\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" +"X-Generator: Weblate 3.10\n" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "Cant Contable" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "Cantidad Contable" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "Valoración Contable" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:115 +#, python-format +msgid "Accounting Valuation at date" +msgstr "Valoración contable a la fecha" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "Valor Contable" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "Cantidad en Inventario" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:131 +#, python-format +msgid "Inventory Valuation" +msgstr "Valoración de Inventario" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "Valor de Inventario" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "Elemento de Diario" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "Producto" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_manual_move_ids +msgid "Stock Fifo Manual Move" +msgstr "Movimiento manual de stock PEPS" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "Movimientos contables PEPS en Tiempo Real" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_quantity_history +msgid "Stock Quantity History" +msgstr "Historial de cantidad de inventario" diff --git a/stock_account_valuation_report/i18n/fr.po b/stock_account_valuation_report/i18n/fr.po new file mode 100644 index 000000000..4fa80e72c --- /dev/null +++ b/stock_account_valuation_report/i18n/fr.po @@ -0,0 +1,85 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-01-22 15:46+0000\n" +"Last-Translator: Yann Papouin \n" +"Language-Team: none\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 4.3.2\n" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "Qté comptable" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "Quantité comptable" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "Valorisation comptable" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:115 +#, python-format +msgid "Accounting Valuation at date" +msgstr "Valorisation comptable à ce jour" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "Valeur comptable" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "Quantité d'inventaire" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:131 +#, python-format +msgid "Inventory Valuation" +msgstr "Valorisation de l'inventaire" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "Valeur d'inventaire" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "Écriture comptable" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "Article" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_manual_move_ids +msgid "Stock Fifo Manual Move" +msgstr "Mouvement manuel de stock FIFO" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "Stock FIFO en temps réel" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_quantity_history +msgid "Stock Quantity History" +msgstr "Historique des quantités en stock" diff --git a/stock_account_valuation_report/i18n/sl.po b/stock_account_valuation_report/i18n/sl.po new file mode 100644 index 000000000..0f93d0365 --- /dev/null +++ b/stock_account_valuation_report/i18n/sl.po @@ -0,0 +1,86 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-04-11 10:25+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 4.14.1\n" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "Knjigovodska kol" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "Knjigovodska količina" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "Knjig. vrednotenje" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:115 +#, python-format +msgid "Accounting Valuation at date" +msgstr "Knjigovodsko vrednotenje na datum" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "Knjigovodska vrednost" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "Količina inventarja" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:131 +#, python-format +msgid "Inventory Valuation" +msgstr "Vrednotenje inventarja" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "Vrednost inventarja" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "Dnevniška postavka" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "Proizvod" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_manual_move_ids +msgid "Stock Fifo Manual Move" +msgstr "FIFO ročni premik zalog" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "FIFO premik v realnem času" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_quantity_history +msgid "Stock Quantity History" +msgstr "Zgodovina količin zalog" diff --git a/stock_account_valuation_report/i18n/stock_account_valuation_report.pot b/stock_account_valuation_report/i18n/stock_account_valuation_report.pot new file mode 100644 index 000000000..1daa9f08f --- /dev/null +++ b/stock_account_valuation_report/i18n/stock_account_valuation_report.pot @@ -0,0 +1,192 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_account_valuation_report +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.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_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Qty" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_qty_at_date +msgid "Accounting Quantity" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Accounting Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:0 +#, python-format +msgid "Accounting Valuation at date" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__account_value +msgid "Accounting Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Cancel" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,help:stock_account_valuation_report.field_stock_valuation_history__inventory_datetime +msgid "Choose a date to get the valuation at that date" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Choose your date" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_valuation_history +msgid "Confirm" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.actions.act_window,help:stock_account_valuation_report.product_valuation_action +msgid "Create a product to see its name and valuation." +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__create_date +msgid "Created on" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.actions.act_window,name:stock_account_valuation_report.history_valuation_action +#: model:ir.actions.act_window,name:stock_account_valuation_report.product_valuation_action +#: model:ir.ui.menu,name:stock_account_valuation_report.menu_dual_valuation +msgid "Dual Inventory Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__inventory_datetime +msgid "Dual Valuation at Date" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__id +msgid "ID" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_at_date +msgid "Inventory Quantity" +msgstr "" + +#. module: stock_account_valuation_report +#: code:addons/stock_account_valuation_report/models/product_product.py:0 +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__valuation +#, python-format +msgid "Inventory Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_value +msgid "Inventory Value" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_account_move_line +msgid "Journal Item" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_stock_valuation_history__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +msgid "Manual" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,help:stock_account_valuation_report.field_product_product__valuation +msgid "" +"Manual: The accounting entries to value the inventory are not posted automatically.\n" +" Automated: An accounting entry is automatically created to value the inventory when a product enters or leaves the company.\n" +" " +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_product_product +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_account_move_line__product_id +msgid "Product" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__qty_discrepancy +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Qty Discrepancy" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +msgid "Real time" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_fifo_real_time_aml_ids +msgid "Stock Fifo Real Time Aml" +msgstr "" + +#. module: stock_account_valuation_report +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Stock Valuation" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model,name:stock_account_valuation_report.model_stock_valuation_history +msgid "Stock Valuation History" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__stock_valuation_layer_ids +msgid "Stock Valuation Layer" +msgstr "" + +#. module: stock_account_valuation_report +#: model:ir.model.fields,field_description:stock_account_valuation_report.field_product_product__valuation_discrepancy +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.product_search_form_view +#: model_terms:ir.ui.view,arch_db:stock_account_valuation_report.view_stock_product_tree2 +msgid "Valuation Discrepancy" +msgstr "" diff --git a/stock_account_valuation_report/models/__init__.py b/stock_account_valuation_report/models/__init__.py new file mode 100644 index 000000000..4f7160950 --- /dev/null +++ b/stock_account_valuation_report/models/__init__.py @@ -0,0 +1,2 @@ +from . import product_product +from . import account_move_line diff --git a/stock_account_valuation_report/models/account_move_line.py b/stock_account_valuation_report/models/account_move_line.py new file mode 100644 index 000000000..0e182df14 --- /dev/null +++ b/stock_account_valuation_report/models/account_move_line.py @@ -0,0 +1,11 @@ +# Copyright 2020 ForgeFlow S.L. +# Copyright 2019 Aleph Objects, Inc. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class AccountMoveLine(models.Model): + _inherit = "account.move.line" + + product_id = fields.Many2one(index=True) diff --git a/stock_account_valuation_report/models/product_product.py b/stock_account_valuation_report/models/product_product.py new file mode 100644 index 000000000..ab80125be --- /dev/null +++ b/stock_account_valuation_report/models/product_product.py @@ -0,0 +1,208 @@ +# Copyright 2020 ForgeFlow S.L. +# Copyright 2019 Aleph Objects, Inc. +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + + +from odoo import _, api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + stock_value = fields.Float("Inventory Value", compute="_compute_inventory_value") + account_value = fields.Float("Accounting Value", compute="_compute_inventory_value") + qty_at_date = fields.Float("Inventory Quantity", compute="_compute_inventory_value") + account_qty_at_date = fields.Float( + "Accounting Quantity", compute="_compute_inventory_value" + ) + stock_fifo_real_time_aml_ids = fields.Many2many( + "account.move.line", compute="_compute_inventory_value" + ) + stock_valuation_layer_ids = fields.Many2many( + "stock.valuation.layer", compute="_compute_inventory_value" + ) + valuation_discrepancy = fields.Float( + compute="_compute_inventory_value", + search="_search_valuation_discrepancy", + ) + qty_discrepancy = fields.Float( + compute="_compute_inventory_value", + search="_search_qty_discrepancy", + ) + valuation = fields.Selection( + related="product_tmpl_id.valuation", search="_search_valuation" + ) + + @api.model + def _search_valuation(self, operator, value): + domain = [ + "|", + ("categ_id.property_valuation", operator, value), + ("property_valuation", operator, value), + ] + products = self.env["product.product"].search(domain) + if value: + return [("id", "in", products.ids)] + else: + return [("id", "not in", products.ids)] + + @api.model + def _search_qty_discrepancy(self, operator, value): + products = self.env["product.product"].search([("type", "=", "product")]) + pp_list = [] + for pp in products: + if pp.qty_at_date != pp.account_qty_at_date: + pp_list.append(pp.id) + return [("id", "in", pp_list)] + + @api.model + def _search_valuation_discrepancy(self, operator, value): + products = self.env["product.product"].search([("type", "=", "product")]) + pp_list = [] + for pp in products: + if pp.stock_value != pp.account_value: + pp_list.append(pp.id) + return [("id", "in", pp_list)] + + def _compute_inventory_value(self): + self.env["account.move.line"].check_access_rights("read") + to_date = self.env.context.get("at_date", False) + accounting_values = {} + layer_values = {} + # pylint: disable=E8103 + query = """ + SELECT aml.product_id, aml.account_id, + sum(aml.balance), sum(quantity), + array_agg(aml.id) + FROM account_move_line AS aml + INNER JOIN account_move AS am ON am.id = aml.move_id + WHERE aml.product_id IN %%s + AND am.state = 'posted' + AND aml.company_id=%%s %s + GROUP BY aml.product_id, aml.account_id""" + params = ( + tuple( + self._ids, + ), + self.env.company.id, + ) + if to_date: + # pylint: disable=sql-injection + query = query % ("AND aml.date <= %s",) + params = params + (to_date,) + else: + query = query % ("",) + # pylint: disable=E8103 + self.env.cr.execute(query, params=params) + res = self.env.cr.fetchall() + for row in res: + accounting_values[(row[0], row[1])] = (row[2], row[3], list(row[4])) + # pylint: disable=E8103 + query = """ + SELECT DISTINCT ON ("product_id") product_id, sum(quantity), + sum(value), array_agg(svl.id) + FROM "stock_valuation_layer" AS svl + WHERE svl.product_id IN %%s + AND svl.company_id=%%s %s + GROUP BY product_id + ORDER BY "product_id" DESC NULLS LAST + """ + params = ( + tuple( + self._ids, + ), + self.env.company.id, + ) + if to_date: + # pylint: disable=sql-injection + query = query % ("AND svl.create_date <= %s",) + params = params + (to_date,) + else: + query = query % ("",) + # pylint: disable=E8103 + self.env.cr.execute(query, params=params) + res = self.env.cr.fetchall() + aml_ids = self.env["account.move.line"] + for row in res: + layer_values[row[0]] = (row[1], row[2], list(row[3])) + for product in self: + # Retrieve the values from accounting + # We cannot provide location-specific accounting valuation, + # so better, leave the data empty in that case: + if product.valuation == "real_time": + valuation_account_id = ( + product.categ_id.property_stock_valuation_account_id.id + ) + value, quantity, aml_ids = accounting_values.get( + (product.id, valuation_account_id) + ) or (0, 0, []) + product.account_value = value + product.account_qty_at_date = quantity + product.stock_fifo_real_time_aml_ids = self.env[ + "account.move.line" + ].browse(aml_ids) + else: + product.account_value = 0.0 + product.account_qty_at_date = 0.0 + product.stock_fifo_real_time_aml_ids = [] + # Retrieve the values from inventory + quantity, value, svl_ids = layer_values.get(product.id) or (0, 0, []) + product.stock_value = value + product.qty_at_date = quantity + product.stock_valuation_layer_ids = self.env[ + "stock.valuation.layer" + ].browse(svl_ids) + if product.valuation == "real_time": + product.valuation_discrepancy = ( + product.stock_value - product.account_value + ) + product.qty_discrepancy = ( + product.qty_at_date - product.account_qty_at_date + ) + else: + product.valuation_discrepancy = 0.0 + product.qty_discrepancy = 0.0 + + def action_view_amls(self): + self.ensure_one() + tree_view_ref = self.env.ref("account.view_move_line_tree") + form_view_ref = self.env.ref("account.view_move_line_form") + action = { + "name": _("Accounting Valuation at date"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "tree,form", + "context": self.env.context, + "res_model": "account.move.line", + "domain": [ + ( + "id", + "in", + self.stock_fifo_real_time_aml_ids.ids, + ) + ], + "views": [(tree_view_ref.id, "tree"), (form_view_ref.id, "form")], + } + return action + + def action_view_valuation_layers(self): + self.ensure_one() + tree_view_ref = self.env.ref("stock_account.stock_valuation_layer_tree") + form_view_ref = self.env.ref("stock_account.stock_valuation_layer_form") + action = { + "name": _("Inventory Valuation"), + "type": "ir.actions.act_window", + "view_type": "form", + "view_mode": "tree,form", + "context": self.env.context, + "res_model": "stock.valuation.layer", + "domain": [ + ( + "id", + "in", + self.stock_valuation_layer_ids.ids, + ) + ], + "views": [(tree_view_ref.id, "tree"), (form_view_ref.id, "form")], + } + return action diff --git a/stock_account_valuation_report/readme/CONTRIBUTORS.rst b/stock_account_valuation_report/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..27e2b531a --- /dev/null +++ b/stock_account_valuation_report/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Jordi Ballester Alomar +* Aaron Henriquez diff --git a/stock_account_valuation_report/readme/DESCRIPTION.rst b/stock_account_valuation_report/readme/DESCRIPTION.rst new file mode 100644 index 000000000..5d935bbc8 --- /dev/null +++ b/stock_account_valuation_report/readme/DESCRIPTION.rst @@ -0,0 +1,9 @@ +When you trigger a report of inventory valuation, and you use +perpetual inventory, you should be able to reconcile the valuation +from an inventory perspective with the valuation +from an accounting perspective. + +This module changes the report in *Inventory / Reporting / +Dual Inventory Valuation* +to display separately the Quantity and Value of each product for the +Inventory and the Accounting systems . diff --git a/stock_account_valuation_report/security/ir.model.access.csv b/stock_account_valuation_report/security/ir.model.access.csv new file mode 100644 index 000000000..31dca360d --- /dev/null +++ b/stock_account_valuation_report/security/ir.model.access.csv @@ -0,0 +1,2 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_stock_valuation_history,access.stock.valuation.history,model_stock_valuation_history,stock.group_stock_user,1,1,1,1 diff --git a/stock_account_valuation_report/static/description/icon.png b/stock_account_valuation_report/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_account_valuation_report/static/description/icon.png differ diff --git a/stock_account_valuation_report/static/description/index.html b/stock_account_valuation_report/static/description/index.html new file mode 100644 index 000000000..50c836a82 --- /dev/null +++ b/stock_account_valuation_report/static/description/index.html @@ -0,0 +1,429 @@ + + + + + + +Stock Account Valuation Report + + + +
+

Stock Account Valuation Report

+ + +

Beta License: AGPL-3 OCA/stock-logistics-reporting Translate me on Weblate Try me on Runboat

+

When you trigger a report of inventory valuation, and you use +perpetual inventory, you should be able to reconcile the valuation +from an inventory perspective with the valuation +from an accounting perspective.

+

This module changes the report in Inventory / Reporting / +Dual Inventory Valuation +to display separately the Quantity and Value of each product for the +Inventory and the Accounting systems .

+

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 to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • ForgeFlow S.L.
  • +
+
+
+

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-reporting project on GitHub.

+

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

+
+
+
+ + diff --git a/stock_account_valuation_report/tests/__init__.py b/stock_account_valuation_report/tests/__init__.py new file mode 100644 index 000000000..f16fdd869 --- /dev/null +++ b/stock_account_valuation_report/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_account_valuation_report diff --git a/stock_account_valuation_report/tests/test_stock_account_valuation_report.py b/stock_account_valuation_report/tests/test_stock_account_valuation_report.py new file mode 100644 index 000000000..fab1cbe15 --- /dev/null +++ b/stock_account_valuation_report/tests/test_stock_account_valuation_report.py @@ -0,0 +1,368 @@ +# 2020 Copyright ForgeFlow, S.L. (https://www.forgeflow.com) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html). + +from dateutil.relativedelta import relativedelta + +from odoo import fields +from odoo.tests.common import TransactionCase + + +class TestStockAccountValuationReport(TransactionCase): + def setUp(self): + super(TestStockAccountValuationReport, self).setUp() + # Get required Model + self.product_model = self.env["product.product"] + self.template_model = self.env["product.template"] + self.product_ctg_model = self.env["product.category"] + self.account_model = self.env["account.account"] + self.quant_model = self.env["stock.quant"] + self.layer_model = self.env["stock.valuation.layer"] + self.stock_location_model = self.env["stock.location"] + self.res_users_model = self.env["res.users"] + self.account_move_model = self.env["account.move"] + self.aml_model = self.env["account.move.line"] + self.journal_model = self.env["account.journal"] + # Get required Model data + self.product_uom = self.env.ref("uom.product_uom_unit") + self.company = self.env.ref("base.main_company") + self.stock_picking_type_out = self.env.ref("stock.picking_type_out") + self.stock_picking_type_in = self.env.ref("stock.picking_type_in") + self.stock_location_id = self.ref("stock.stock_location_stock") + self.stock_location_customer_id = self.ref("stock.stock_location_customers") + self.stock_location_supplier_id = self.ref("stock.stock_location_suppliers") + # Account types + expense_type = "expense" + equity_type = "equity" + asset_type = "asset_current" + # Create account for Goods Received Not Invoiced + name = "Goods Received Not Invoiced" + code = "grni" + account_type = equity_type + self.account_grni = self._create_account(account_type, name, code, self.company) + # Create account for Cost of Goods Sold + name = "Cost of Goods Sold" + code = "cogs" + account_type = expense_type + self.account_cogs = self._create_account(account_type, name, code, self.company) + # Create account for Goods Delivered Not Invoiced + name = "Goods Delivered Not Invoiced" + code = "gdni" + account_type = expense_type + self.account_gdni = self._create_account(account_type, name, code, self.company) + # Create account for Inventory + name = "Inventory" + code = "inventory" + account_type = asset_type + self.account_inventory = self._create_account( + account_type, name, code, self.company + ) + + self.stock_journal = self.env["account.journal"].create( + {"name": "Stock journal", "type": "general", "code": "STK00"} + ) + # Create product category + self.product_ctg = self._create_product_category() + + # Create partners + self.supplier = self.env["res.partner"].create({"name": "Test supplier"}) + self.customer = self.env["res.partner"].create({"name": "Test customer"}) + + # Create a Product with real cost + standard_price = 10.0 + list_price = 20.0 + self.product = self._create_product(standard_price, False, list_price) + + # Create a vendor + self.vendor_partner = self.env["res.partner"].create( + {"name": "dropship vendor"} + ) + + def _create_user(self, login, groups, company): + """Create a user.""" + group_ids = [group.id for group in groups] + user = self.res_users_model.with_context(no_reset_password=True).create( + { + "name": "Test User", + "login": login, + "password": "demo", + "email": "test@yourcompany.com", + "company_id": company.id, + "company_ids": [(4, company.id)], + "groups_id": [(6, 0, group_ids)], + } + ) + return user + + def _create_account(self, account_type, name, code, company): + """Create an account.""" + account = self.account_model.create( + { + "name": name, + "code": code, + "account_type": account_type, + "company_id": company.id, + } + ) + return account + + def _create_product_category(self): + product_ctg = self.product_ctg_model.create( + { + "name": "test_product_ctg", + "property_stock_valuation_account_id": self.account_inventory.id, + "property_stock_account_input_categ_id": self.account_grni.id, + "property_account_expense_categ_id": self.account_cogs.id, + "property_stock_account_output_categ_id": self.account_gdni.id, + "property_valuation": "real_time", + "property_cost_method": "fifo", + "property_stock_journal": self.stock_journal.id, + } + ) + return product_ctg + + def _create_product(self, standard_price, template, list_price): + """Create a Product variant.""" + if not template: + template = self.template_model.create( + { + "name": "test_product", + "categ_id": self.product_ctg.id, + "type": "product", + "standard_price": standard_price, + "valuation": "real_time", + } + ) + return template.product_variant_ids[0] + product = self.product_model.create( + {"product_tmpl_id": template.id, "list_price": list_price} + ) + return product + + def _create_delivery(self, product, qty, price_unit=10.0): + return self.env["stock.picking"].create( + { + "name": self.stock_picking_type_out.sequence_id._next(), + "partner_id": self.customer.id, + "picking_type_id": self.stock_picking_type_out.id, + "location_id": self.stock_location_id, + "location_dest_id": self.stock_location_customer_id, + "move_ids": [ + ( + 0, + 0, + { + "name": product.name, + "product_id": product.id, + "product_uom": product.uom_id.id, + "product_uom_qty": qty, + "price_unit": price_unit, + "location_id": self.stock_location_id, + "location_dest_id": self.stock_location_customer_id, + "procure_method": "make_to_stock", + }, + ) + ], + } + ) + + def _create_drophip_picking(self, product, qty, price_unit=10.0): + return self.env["stock.picking"].create( + { + "name": self.stock_picking_type_out.sequence_id._next(), + "partner_id": self.customer.id, + "picking_type_id": self.stock_picking_type_out.id, + "location_id": self.stock_location_supplier_id, + "location_dest_id": self.stock_location_customer_id, + "move_ids": [ + ( + 0, + 0, + { + "name": product.name, + "product_id": product.id, + "product_uom": product.uom_id.id, + "product_uom_qty": qty, + "price_unit": price_unit, + "location_id": self.stock_location_supplier_id, + "location_dest_id": self.stock_location_customer_id, + }, + ) + ], + } + ) + + def _create_receipt(self, product, qty, move_dest_id=False, price_unit=10.0): + move_dest_id = [(4, move_dest_id)] if move_dest_id else False + return self.env["stock.picking"].create( + { + "name": self.stock_picking_type_in.sequence_id._next(), + "partner_id": self.vendor_partner.id, + "picking_type_id": self.stock_picking_type_in.id, + "location_id": self.stock_location_supplier_id, + "location_dest_id": self.stock_location_id, + "move_ids": [ + ( + 0, + 0, + { + "name": product.name, + "product_id": product.id, + "product_uom": product.uom_id.id, + "product_uom_qty": qty, + "price_unit": price_unit, + "move_dest_ids": move_dest_id, + "location_id": self.stock_location_supplier_id, + "location_dest_id": self.stock_location_id, + "procure_method": "make_to_stock", + }, + ) + ], + } + ) + + def _do_picking(self, picking, date, qty): + """Do picking with only one move on the given date.""" + picking.write({"date": date}) + picking.move_ids.write({"date": date}) + picking.action_confirm() + picking.action_assign() + picking.move_ids.quantity_done = qty + picking.button_validate() + # hacking the create_date of the layer in order to test + self.env.cr.execute( + """UPDATE stock_valuation_layer SET create_date = %s WHERE id in %s""", + (date, tuple(picking.move_ids.stock_valuation_layer_ids.ids)), + ) + return True + + def test_01_stock_receipt(self): + """Receive into stock and ship to the customer""" + # Create receipt + in_picking = self._create_receipt(self.product, 1.0) + # Receive one unit. + self._do_picking(in_picking, fields.Datetime.now(), 1.0) + # This will create an entry: + # dr cr + # GRNI 10 + # Inventory 10 + + # Inventory is 10 + aml = self.aml_model.search([("product_id", "=", self.product.id)]) + inv_aml = aml.filtered(lambda l: l.account_id == self.account_inventory) + balance_inv = sum(inv_aml.mapped("balance")) + self.assertEqual(balance_inv, 10.0) + move = in_picking.move_ids + layer = self.layer_model.search([("stock_move_id", "=", move.id)]) + self.assertEqual(layer.remaining_value, 10.0) + # The accounting value and the stock value match + self.assertEqual(self.product.stock_value, 10.0) + self.assertEqual(self.product.account_value, 10.0) + # The qty also match + self.assertEqual(self.product.qty_at_date, 1.0) + self.assertEqual(self.product.account_qty_at_date, 1.0) + # Create an out picking + out_picking = self._create_delivery(self.product, 1) + self._do_picking(out_picking, fields.Datetime.now(), 1.0) + # The original layer must have been reduced. + self.assertEqual(layer.remaining_qty, 0.0) + self.assertEqual(layer.remaining_value, 0.0) + # The layer out took that out + move = out_picking.move_ids + layer = self.layer_model.search([("stock_move_id", "=", move.id)]) + self.assertEqual(layer.value, -10.0) + # The report shows the material is gone + self.product._compute_inventory_value() + self.assertEqual(self.product.stock_value, 0.0) + self.assertEqual(self.product.account_value, 0.0) + self.assertEqual(self.product.qty_at_date, 0.0) + self.assertEqual(self.product.account_qty_at_date, 0.0) + + def test_02_drop_ship(self): + """Drop shipment from vendor to customer""" + # Create drop_shipment + dropship_picking = self._create_drophip_picking(self.product, 1.0) + # Receive one unit. + self._do_picking(dropship_picking, fields.Datetime.now(), 1.0) + # This will create the following entries + # dr cr + # GRNI 10 + # Inventory 10 + # dr cr + # Inventory 10 + # GDNI 10 + aml = self.aml_model.search([("product_id", "=", self.product.id)]) + # Inventory is 0 + inv_aml = aml.filtered(lambda l: l.account_id == self.account_inventory) + balance_inv = sum(inv_aml.mapped("balance")) + self.assertEqual(balance_inv, 0.0) + # There are two a stock valuation layers associated to this product + move = dropship_picking.move_ids + layers = self.layer_model.search([("stock_move_id", "=", move.id)]) + self.assertEqual(len(layers), 2) + in_layer = layers.filtered(lambda l: l.quantity > 0) + # Check that the layer created for the outgoing move + self.assertEqual(in_layer.remaining_qty, 0.0) + self.assertEqual(in_layer.remaining_value, 0.0) + # The report shows the material is gone + self.assertEqual(self.product.stock_value, 0.0) + self.assertEqual(self.product.account_value, 0.0) + self.assertEqual(self.product.qty_at_date, 0.0) + self.assertEqual(self.product.account_qty_at_date, 0.0) + + def test_03_stock_receipt_several_costs_several_dates(self): + """Receive into stock at different cost""" + # Create receipt + in_picking = self._create_receipt(self.product, 1.0) + # Receive one unit. + self._do_picking(in_picking, fields.Datetime.now(), 1.0) + # This will create an entry: + # dr cr + # GRNI 10 + # Inventory 10 + + # Inventory is 10 + aml = self.aml_model.search([("product_id", "=", self.product.id)]) + inv_aml = aml.filtered(lambda l: l.account_id == self.account_inventory) + balance_inv = sum(inv_aml.mapped("balance")) + self.assertEqual(balance_inv, 10.0) + move = in_picking.move_ids + layer = self.layer_model.search([("stock_move_id", "=", move.id)]) + self.assertEqual(layer.remaining_value, 10.0) + # Receive more + in_picking2 = self._create_receipt(self.product, 2.0, False, 20.0) + # Receive two unitsat double cost. + self._do_picking( + in_picking2, fields.Datetime.now() + relativedelta(days=3), 2.0 + ) + # This will create an entry: + # dr cr + # GRNI 40 + # Inventory 40 + + # Inventory is 50 + aml = self.aml_model.search([("product_id", "=", self.product.id)]) + inv_aml = aml.filtered(lambda l: l.account_id == self.account_inventory) + balance_inv = sum(inv_aml.mapped("balance")) + self.assertEqual(balance_inv, 50.0) + move2 = in_picking2.move_ids + layer = self.layer_model.search([("stock_move_id", "=", move2.id)]) + self.assertEqual(layer.remaining_value, 40.0) + # Now we check the report reflects the same + self.assertEqual(self.product.stock_value, 50.0) + self.assertEqual(self.product.account_value, 50.0) + self.assertEqual(self.product.qty_at_date, 3.0) + self.assertEqual(self.product.account_qty_at_date, 3.0) + # That is the value tomorrow, today it is less + # We hack the date in the account move, not a topic for this module + aml_layer = layer.account_move_id.line_ids + self.env.cr.execute( + """UPDATE account_move_line SET date = %s WHERE id in %s""", + (fields.Datetime.now() + relativedelta(days=3), tuple(aml_layer.ids)), + ) + self.product.with_context( + at_date=fields.Datetime.now() + relativedelta(days=1) + )._compute_inventory_value() + self.assertEqual(self.product.stock_value, 10.0) + self.assertEqual(self.product.account_value, 10.0) + self.assertEqual(self.product.qty_at_date, 1.0) + self.assertEqual(self.product.account_qty_at_date, 1.0) diff --git a/stock_account_valuation_report/views/product_product_views.xml b/stock_account_valuation_report/views/product_product_views.xml new file mode 100644 index 000000000..bd733b455 --- /dev/null +++ b/stock_account_valuation_report/views/product_product_views.xml @@ -0,0 +1,101 @@ + + + + product.stock.tree.2 + product.product + + + + + + + + + +