diff --git a/stock_account_valuation_report/README.rst b/stock_account_valuation_report/README.rst index 016f41f..30ddbaa 100644 --- a/stock_account_valuation_report/README.rst +++ b/stock_account_valuation_report/README.rst @@ -14,13 +14,13 @@ Stock Account Valuation Report :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/12.0/stock_account_valuation_report + :target: https://github.com/OCA/stock-logistics-reporting/tree/13.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-12-0/stock-logistics-reporting-12-0-stock_account_valuation_report + :target: https://translation.odoo-community.org/projects/stock-logistics-reporting-13-0/stock-logistics-reporting-13-0-stock_account_valuation_report :alt: Translate me on Weblate .. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/151/12.0 + :target: https://runbot.odoo-community.org/runbot/151/13.0 :alt: Try me on Runbot |badge1| |badge2| |badge3| |badge4| |badge5| @@ -30,7 +30,8 @@ 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 / Inventory Valuation* +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 . @@ -45,7 +46,7 @@ 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 `_. +`feedback `_. Do not contact contributors directly about support or help with technical issues. @@ -55,12 +56,13 @@ Credits Authors ~~~~~~~ -* Eficent +* ForgeFlow S.L. Contributors ~~~~~~~~~~~~ -* Jordi Ballester Alomar +* Jordi Ballester Alomar +* Aaron Henriquez Maintainers ~~~~~~~~~~~ @@ -75,6 +77,6 @@ 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. +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/__manifest__.py b/stock_account_valuation_report/__manifest__.py index fcf0fa1..e7b287b 100644 --- a/stock_account_valuation_report/__manifest__.py +++ b/stock_account_valuation_report/__manifest__.py @@ -1,17 +1,16 @@ -# Copyright 2018 Eficent Business and IT Consulting Services, S.L. -# () -# Copyright 2018 Aleph Objects, Inc. +# 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": "12.0.1.0.0", + "version": "13.0.1.0.0", "summary": "Improves logic of the Inventory Valuation Report", - "author": "Eficent, Odoo Community Association (OCA)", + "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": ["views/product_product_views.xml"], + "data": ["views/product_product_views.xml", "wizards/stock_valuation_history.xml"], "installable": True, } diff --git a/stock_account_valuation_report/models/account_move_line.py b/stock_account_valuation_report/models/account_move_line.py index 7afc6c6..0e182df 100644 --- a/stock_account_valuation_report/models/account_move_line.py +++ b/stock_account_valuation_report/models/account_move_line.py @@ -1,4 +1,5 @@ -# Copyright 2018 Eficent Business and IT Consulting Services, S.L. +# 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 diff --git a/stock_account_valuation_report/models/product_product.py b/stock_account_valuation_report/models/product_product.py index a96db63..742d263 100644 --- a/stock_account_valuation_report/models/product_product.py +++ b/stock_account_valuation_report/models/product_product.py @@ -1,9 +1,9 @@ -# Copyright 2018 Eficent Business and IT Consulting Services, S.L. -# () -# Copyright 2018 Aleph Objects, Inc. +# 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 + +from odoo import _, api, fields, models class ProductProduct(models.Model): @@ -18,67 +18,104 @@ class ProductProduct(models.Model): stock_fifo_real_time_aml_ids = fields.Many2many( "account.move.line", compute="_compute_inventory_value" ) - stock_fifo_manual_move_ids = fields.Many2many( - "stock.move", 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): - stock_move = self.env["stock.move"] self.env["account.move.line"].check_access_rights("read") - to_date = self.env.context.get("to_date", False) - location = self.env.context.get("location", False) + to_date = self.env.context.get("at_date", False) accounting_values = {} - if not location: - query = """ - SELECT aml.product_id, aml.account_id, - sum(aml.debit) - sum(aml.credit), sum(quantity), - array_agg(aml.id) - FROM account_move_line AS aml - WHERE aml.product_id IN %%s - AND aml.company_id=%%s %s - GROUP BY aml.product_id, aml.account_id""" - params = (tuple(self._ids,), self.env.user.company_id.id) - if to_date: - # pylint: disable=sql-injection - query = query % ("AND aml.date <= %s",) - params = params + (to_date,) - else: - query = query % ("",) - 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])) - stock_move_domain = [ - ("product_id", "in", self._ids), - ("date", "<=", to_date), - ] + stock_move._get_all_base_domain() - moves = stock_move.search(stock_move_domain) - history = {} + 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 + WHERE aml.product_id IN %%s + 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: - query = """ - SELECT DISTINCT ON ("product_id") product_id, cost - FROM "product_price_history" - WHERE datetime <= %s::date - AND product_id IN %s - ORDER BY "product_id", "datetime" DESC NULLS LAST - """ - args = (to_date, tuple(self._ids)) - self.env.cr.execute(query, args) - for row in self.env.cr.dictfetchall(): - history.update({row["product_id"]: row["cost"]}) - quantities_dict = self._compute_quantities_dict( - self._context.get("lot_id"), - self._context.get("owner_id"), - self._context.get("package_id"), - self._context.get("from_date"), - self._context.get("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: - qty_available = quantities_dict[product.id]["qty_available"] # 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" and not location: + if product.valuation == "real_time": valuation_account_id = ( product.categ_id.property_stock_valuation_account_id.id ) @@ -90,31 +127,31 @@ class ProductProduct(models.Model): 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 - if product.cost_method in ["standard", "average"]: - - price_used = product.standard_price - if to_date: - price_used = history.get(product.id, 0) - product.stock_value = price_used * qty_available - product.qty_at_date = qty_available - elif product.cost_method == "fifo": - if to_date: - if product.product_tmpl_id.valuation == "manual_periodic": - product.stock_value = sum(moves.mapped("value")) - product.qty_at_date = qty_available - product.stock_fifo_manual_move_ids = stock_move.browse( - moves.ids - ) - else: - product.stock_value, moves = product._sum_remaining_values() - product.qty_at_date = qty_available - product.stock_fifo_manual_move_ids = moves + 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() - to_date = self.env.context.get("to_date") - tree_view_ref = self.env.ref("stock_account.view_stock_account_aml") + 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"), @@ -123,36 +160,23 @@ class ProductProduct(models.Model): "view_mode": "tree,form", "context": self.env.context, "res_model": "account.move.line", - "domain": [ - ( - "id", - "in", - self.with_context(to_date=to_date).stock_fifo_real_time_aml_ids.ids, - ) - ], + "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_stock_moves(self): + def action_view_valuation_layers(self): self.ensure_one() - to_date = self.env.context.get("to_date") - tree_view_ref = self.env.ref("stock_account.view_move_tree_valuation_at_date") - form_view_ref = self.env.ref("stock.view_move_form") + 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.move", - "domain": [ - ( - "id", - "in", - self.with_context(to_date=to_date).stock_fifo_manual_move_ids.ids, - ) - ], + "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 index 6860aff..27e2b53 100644 --- a/stock_account_valuation_report/readme/CONTRIBUTORS.rst +++ b/stock_account_valuation_report/readme/CONTRIBUTORS.rst @@ -1 +1,2 @@ -* Jordi Ballester Alomar +* Jordi Ballester Alomar +* Aaron Henriquez diff --git a/stock_account_valuation_report/readme/DESCRIPTION.rst b/stock_account_valuation_report/readme/DESCRIPTION.rst index 70ea676..5d935bb 100644 --- a/stock_account_valuation_report/readme/DESCRIPTION.rst +++ b/stock_account_valuation_report/readme/DESCRIPTION.rst @@ -3,6 +3,7 @@ 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 / Inventory Valuation* +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/static/description/index.html b/stock_account_valuation_report/static/description/index.html index d4566ac..19138c9 100644 --- a/stock_account_valuation_report/static/description/index.html +++ b/stock_account_valuation_report/static/description/index.html @@ -3,7 +3,7 @@ - + Stock Account Valuation Report