From 71b42c805e3f5693891fad74ac947abddb4edb60 Mon Sep 17 00:00:00 2001 From: David Beal Date: Thu, 18 Jul 2024 19:09:10 +0200 Subject: [PATCH 1/5] ADD account_stock_situation --- account_stock_situation/README.rst | 66 +++ account_stock_situation/__init__.py | 1 + account_stock_situation/__manifest__.py | 19 + account_stock_situation/models/__init__.py | 2 + account_stock_situation/models/company.py | 122 +++++ .../models/config_settings.py | 37 ++ .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 1 + account_stock_situation/readme/USAGE.rst | 1 + .../static/description/index.html | 427 ++++++++++++++++++ account_stock_situation/views/action.xml | 21 + .../views/config_settings.xml | 77 ++++ requirements.txt | 1 + .../odoo/addons/account_stock_situation | 1 + setup/account_stock_situation/setup.py | 6 + 15 files changed, 784 insertions(+) create mode 100644 account_stock_situation/README.rst create mode 100644 account_stock_situation/__init__.py create mode 100644 account_stock_situation/__manifest__.py create mode 100644 account_stock_situation/models/__init__.py create mode 100644 account_stock_situation/models/company.py create mode 100644 account_stock_situation/models/config_settings.py create mode 100644 account_stock_situation/readme/CONTRIBUTORS.rst create mode 100644 account_stock_situation/readme/DESCRIPTION.rst create mode 100644 account_stock_situation/readme/USAGE.rst create mode 100644 account_stock_situation/static/description/index.html create mode 100644 account_stock_situation/views/action.xml create mode 100644 account_stock_situation/views/config_settings.xml create mode 120000 setup/account_stock_situation/odoo/addons/account_stock_situation create mode 100644 setup/account_stock_situation/setup.py diff --git a/account_stock_situation/README.rst b/account_stock_situation/README.rst new file mode 100644 index 000000000..a97ccd388 --- /dev/null +++ b/account_stock_situation/README.rst @@ -0,0 +1,66 @@ +======================= +Account Stock Situation +======================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:17a4d0785da8b351798bf3c7d2b0463b8a22bf996209b21ecc9043ea00b9bfce + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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-akretion%2Fak--odoo--incubator-lightgray.png?logo=github + :target: https://github.com/akretion/ak-odoo-incubator/tree/16.0/account_stock_situation + :alt: akretion/ak-odoo-incubator + +|badge1| |badge2| |badge3| + +Generate Periodically a miscellaneous account move for stock valuation with an xlsx report attachement + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Consider to check your report before validate your account move and reverse the previous 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 to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Akretion + +Contributors +~~~~~~~~~~~~ + +* Akretion + * David BEAL + +Maintainers +~~~~~~~~~~~ + +This module is part of the `akretion/ak-odoo-incubator `_ project on GitHub. + +You are welcome to contribute. diff --git a/account_stock_situation/__init__.py b/account_stock_situation/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/account_stock_situation/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/account_stock_situation/__manifest__.py b/account_stock_situation/__manifest__.py new file mode 100644 index 000000000..1c058e25b --- /dev/null +++ b/account_stock_situation/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2024 David BEAL @ akretion +{ + "name": "Account Stock Situation", + "version": "16.0.1.0.0", + "author": "Akretion", + "website": "https://github.com/akretion/ak-odoo-incubator", + "license": "AGPL-3", + "category": "Accounting", + "depends": [ + "account", + "stock", + ], + "data": [ + "views/config_settings.xml", + "views/action.xml", + ], + "external_dependencies": {"python": ["polars"]}, + "installable": True, +} diff --git a/account_stock_situation/models/__init__.py b/account_stock_situation/models/__init__.py new file mode 100644 index 000000000..ff33dd7a1 --- /dev/null +++ b/account_stock_situation/models/__init__.py @@ -0,0 +1,2 @@ +from . import company +from . import config_settings diff --git a/account_stock_situation/models/company.py b/account_stock_situation/models/company.py new file mode 100644 index 000000000..30c86c2c5 --- /dev/null +++ b/account_stock_situation/models/company.py @@ -0,0 +1,122 @@ +import base64 +import io +from collections import defaultdict + +import polars as pl + +from odoo import fields, models, tools +from odoo.exceptions import UserError + + +class ResCompany(models.Model): + _inherit = "res.company" + + valued_warehouse_ids = fields.Many2many( + comodel_name="stock.warehouse", + domain=lambda self: [("company_id", "=", self.env.company.id)], + ) + stock_journal_id = fields.Many2one(comodel_name="account.journal") + cost_vs_purchase_threshold = fields.Integer(string="Seuil en %") + account_purchase_stock_id = fields.Many2one(comodel_name="account.account") + account_stock_id = fields.Many2one(comodel_name="account.account") + + def _set_account_stock_valuation(self, company_string_id): + self = self.env.ref(company_string_id) + value, attach = self._get_stock_valuation_another() + for mfield in ( + "account_stock_id", + "account_purchase_stock_id", + "stock_journal_id", + ): + if not self[mfield]: + raise UserError( + f"Le champ '{mfield}' n'est pas défini: vérifiez les " + "paramètres intitulés 'Valorisation de stock'" + ) + move = self.env["account.move"].create( + { + "journal_id": self.stock_journal_id.id, + "company_id": self.id, + "to_check": True, + "move_type": "entry", + "line_ids": [ + ( + 0, + 0, + { + "account_id": self.account_stock_id.id, + "name": "stock", + "debit": 0, + "credit": value, + }, + ), + ( + 0, + 0, + { + "account_id": self.account_purchase_stock_id.id, + "name": "stock", + "debit": value, + "credit": 0, + }, + ), + ], + } + ) + attach.res_id = move.id + + def _get_stock_valuation_another(self): + self.ensure_one() + coef = self.cost_vs_purchase_threshold + base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url") + if tools.config.get("running_env") == "dev": + base_url = "http://anothercorp.localhost/" + location_ids = [x.lot_stock_id.id for x in self.valued_warehouse_ids] + # TODO conserver un group par emplacement : donc autant de colonnes + # de nombres de produits que d'entrepots dans l'excel + product_qties = self.env["stock.quant"].read_group( + [("location_id", "child_of", location_ids)], + ["product_id", "quantity"], + ["product_id"], + ) + product_ids = [x["product_id"][0] for x in product_qties] + products = self.env["product.product"].browse(product_ids) + prices = { + x: x.variant_seller_ids and x.variant_seller_ids[0] or 0 for x in products + } + vals = defaultdict(list) + for prd_q in product_qties: + product = products.filtered(lambda s: s.id == prd_q["product_id"][0]) + vals["code"].append(product.default_code) + vals["designation"].append(product.name) + # TODO mettre une colonne qté par entrepot (x colonnes) + vals["qté"].append(round(prd_q["quantity"])) + # TODO quand la valeur est < cost_vs_purchase_threshold % de ce seuil + # mettre une colonne 'check' à la valeur 1 + vals["valeur"].append( + round( + max( + product.standard_price, + prices[product] and prices[product].price or 0 * coef / 100, + ) + * prd_q["quantity"] + ) + ) + # TODO mettre l'url en first column + vals["lien"].append( + f"{base_url}/web#id={prd_q['product_id'][0]}&cids={self.id}&action=" + f"{self.env.ref('product.product_normal_action_sell').id}&model=" + "product.product&view_type=form" + ) + df = pl.from_dict(vals) + mfile = io.BytesIO() + df.write_excel(workbook=mfile) + attach = self.env["ir.attachment"].create( + { + "name": "Valorisation_stock_jourdain", + "type": "binary", + "res_model": "account.move", + "datas": base64.b64encode(mfile.getvalue()), + } + ) + return sum(vals["valeur"]), attach diff --git a/account_stock_situation/models/config_settings.py b/account_stock_situation/models/config_settings.py new file mode 100644 index 000000000..f65779525 --- /dev/null +++ b/account_stock_situation/models/config_settings.py @@ -0,0 +1,37 @@ +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + valued_warehouse_ids = fields.Many2many( + related="company_id.valued_warehouse_ids", readonly=False + ) + cost_vs_purchase_threshold = fields.Integer( + related="company_id.cost_vs_purchase_threshold", readonly=False, default=120 + ) + stock_journal_id = fields.Many2one( + comodel_name="account.journal", + readonly=False, + related="company_id.stock_journal_id", + domain=[("type", "=", "general")], + ) + account_purchase_stock_id = fields.Many2one( + comodel_name="account.account", + readonly=False, + related="company_id.account_purchase_stock_id", + ) + account_stock_id = fields.Many2one( + comodel_name="account.account", + readonly=False, + related="company_id.account_stock_id", + ) + account_stock_help = fields.Text(compute="_compute_account_stock_help") + + def _compute_account_stock_help(self): + for rec in self: + name = "" + if "l10n_fr" in self.env.registry._init_modules: + name = "Compte de stock: '355...'" + name += "Compte de stock d'achat: '603...'" + rec.account_stock_help = name diff --git a/account_stock_situation/readme/CONTRIBUTORS.rst b/account_stock_situation/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..3237802ef --- /dev/null +++ b/account_stock_situation/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Akretion + * David BEAL diff --git a/account_stock_situation/readme/DESCRIPTION.rst b/account_stock_situation/readme/DESCRIPTION.rst new file mode 100644 index 000000000..7ddde3d3b --- /dev/null +++ b/account_stock_situation/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +Generate Periodically a miscellaneous account move for stock valuation with an xlsx report attachement diff --git a/account_stock_situation/readme/USAGE.rst b/account_stock_situation/readme/USAGE.rst new file mode 100644 index 000000000..a90351f54 --- /dev/null +++ b/account_stock_situation/readme/USAGE.rst @@ -0,0 +1 @@ +Consider to check your report before validate your account move and reverse the previous one. diff --git a/account_stock_situation/static/description/index.html b/account_stock_situation/static/description/index.html new file mode 100644 index 000000000..fb34b1c69 --- /dev/null +++ b/account_stock_situation/static/description/index.html @@ -0,0 +1,427 @@ + + + + + +Account Stock Situation + + + +
+

Account Stock Situation

+ + +

Beta License: AGPL-3 akretion/ak-odoo-incubator

+

Generate Periodically a miscellaneous account move for stock valuation with an xlsx report attachement

+

Table of contents

+ +
+

Usage

+

Consider to check your report before validate your account move and reverse the previous 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 to smash 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 part of the akretion/ak-odoo-incubator project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/account_stock_situation/views/action.xml b/account_stock_situation/views/action.xml new file mode 100644 index 000000000..2b7494d52 --- /dev/null +++ b/account_stock_situation/views/action.xml @@ -0,0 +1,21 @@ + + + + + Stock Valorisation + + code + model._set_account_stock_valuation('base.main_company') + 1 + months + -1 + + False + + + diff --git a/account_stock_situation/views/config_settings.xml b/account_stock_situation/views/config_settings.xml new file mode 100644 index 000000000..f628bdd37 --- /dev/null +++ b/account_stock_situation/views/config_settings.xml @@ -0,0 +1,77 @@ + + + + res.config.settings + + + +

Stock Valuation

+
+
+
+ Warehouses +
+ Warehouses where stock is valued periodically +
+
+ +
+
+
+
+
+ Cost vs. purchase price % threshold +
+ Below this threshold, the cost value is substitued by purchase price. +
+
+ +
+
+
+
+
+ Journal +
+ Journal used for stock valuation. +
+
+ +
+
+
+
+
+ Aide +
+ +
+
+
+
+
+ Stock account +
+ +
+
+
+
+
+ Purchase stock account +
+ +
+
+
+
+
+
+
+ +
diff --git a/requirements.txt b/requirements.txt index 2ea583741..d98ad5c69 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ # generated from manifests external_dependencies +polars simplejson diff --git a/setup/account_stock_situation/odoo/addons/account_stock_situation b/setup/account_stock_situation/odoo/addons/account_stock_situation new file mode 120000 index 000000000..4b6c7e3f8 --- /dev/null +++ b/setup/account_stock_situation/odoo/addons/account_stock_situation @@ -0,0 +1 @@ +../../../../account_stock_situation \ No newline at end of file diff --git a/setup/account_stock_situation/setup.py b/setup/account_stock_situation/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/account_stock_situation/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 3b0ce570cc669f68023bb82486b1efae6cfe7839 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 9 Aug 2024 09:25:00 +0200 Subject: [PATCH 2/5] [IMP] _get_stock_valuation_another function to add the quantity in stock by warehouse --- .../static/description/index.html | 7 ++- account_stock_situation/models/__init__.py | 1 + account_stock_situation/models/company.py | 58 ++++++++++++++----- account_stock_situation/models/stock_quant.py | 7 +++ .../static/description/index.html | 7 ++- 5 files changed, 60 insertions(+), 20 deletions(-) create mode 100644 account_stock_situation/models/stock_quant.py diff --git a/account_move_adyen_import/static/description/index.html b/account_move_adyen_import/static/description/index.html index e1dee74c4..6f4271f1d 100644 --- a/account_move_adyen_import/static/description/index.html +++ b/account_move_adyen_import/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { diff --git a/account_stock_situation/models/__init__.py b/account_stock_situation/models/__init__.py index ff33dd7a1..6f19864b4 100644 --- a/account_stock_situation/models/__init__.py +++ b/account_stock_situation/models/__init__.py @@ -1,2 +1,3 @@ from . import company from . import config_settings +from . import stock_quant diff --git a/account_stock_situation/models/company.py b/account_stock_situation/models/company.py index 30c86c2c5..149d360f9 100644 --- a/account_stock_situation/models/company.py +++ b/account_stock_situation/models/company.py @@ -76,21 +76,57 @@ def _get_stock_valuation_another(self): # de nombres de produits que d'entrepots dans l'excel product_qties = self.env["stock.quant"].read_group( [("location_id", "child_of", location_ids)], - ["product_id", "quantity"], - ["product_id"], + ["product_id", "warehouse_id", "quantity"], + ["product_id", "warehouse_id"], + lazy=False, ) - product_ids = [x["product_id"][0] for x in product_qties] + + product_ids = list({x["product_id"][0] for x in product_qties}) + products = self.env["product.product"].browse(product_ids) prices = { x: x.variant_seller_ids and x.variant_seller_ids[0] or 0 for x in products } vals = defaultdict(list) - for prd_q in product_qties: - product = products.filtered(lambda s: s.id == prd_q["product_id"][0]) + + product_dict = {} + for product in product_qties: + if not product["product_id"][0] in product_dict: + product_dict[product["product_id"][0]] = [ + product["warehouse_id"][0], + product["quantity"], + ] + else: + product_dict[product["product_id"][0]] += [ + product["warehouse_id"][0], + product["quantity"], + ] + + for product_id, warehouse_quantities in product_dict.items(): + product = products.filtered(lambda s: s.id == product_id) + vals["lien"].append( + f"{base_url}/web#id={product_id}&cids={self.id}&action=" + f"{self.env.ref('product.product_normal_action_sell').id}&model=" + "product.product&view_type=form" + ) vals["code"].append(product.default_code) vals["designation"].append(product.name) - # TODO mettre une colonne qté par entrepot (x colonnes) - vals["qté"].append(round(prd_q["quantity"])) + for i in range(0, len(warehouse_quantities), 2): + warehouse_id = warehouse_quantities[i] + quantity = warehouse_quantities[i + 1] + warehouse_id = self.env["stock.warehouse"].browse(warehouse_id) + vals[f"qté_{warehouse_id.name}"].append(round(quantity)) + if len(warehouse_quantities) / 2 < len(self.valued_warehouse_ids): + warehouse_without_qty = self.valued_warehouse_ids.filtered( + lambda r: r.id + not in [ + warehouse_quantities[i] + for i in range(0, len(warehouse_quantities), 2) + ] + ) + for warehouse in warehouse_without_qty: + vals[f"qté_{warehouse.name}"].append(0) + # TODO quand la valeur est < cost_vs_purchase_threshold % de ce seuil # mettre une colonne 'check' à la valeur 1 vals["valeur"].append( @@ -99,15 +135,9 @@ def _get_stock_valuation_another(self): product.standard_price, prices[product] and prices[product].price or 0 * coef / 100, ) - * prd_q["quantity"] + * product["quantity"] ) ) - # TODO mettre l'url en first column - vals["lien"].append( - f"{base_url}/web#id={prd_q['product_id'][0]}&cids={self.id}&action=" - f"{self.env.ref('product.product_normal_action_sell').id}&model=" - "product.product&view_type=form" - ) df = pl.from_dict(vals) mfile = io.BytesIO() df.write_excel(workbook=mfile) diff --git a/account_stock_situation/models/stock_quant.py b/account_stock_situation/models/stock_quant.py new file mode 100644 index 000000000..b4c638bf6 --- /dev/null +++ b/account_stock_situation/models/stock_quant.py @@ -0,0 +1,7 @@ +from odoo import fields, models + + +class StockQuant(models.Model): + _inherit = "stock.quant" + + warehouse_id = fields.Many2one(store=True, index=True) diff --git a/account_stock_situation/static/description/index.html b/account_stock_situation/static/description/index.html index fb34b1c69..b5426d63f 100644 --- a/account_stock_situation/static/description/index.html +++ b/account_stock_situation/static/description/index.html @@ -8,10 +8,11 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ +:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. +Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -274,7 +275,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: grey; } /* line numbers */ +pre.code .ln { color: gray; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -300,7 +301,7 @@ span.pre { white-space: pre } -span.problematic { +span.problematic, pre.problematic { color: red } span.section-subtitle { From 66a2cfcf5aae7e989355a1a31454be2ed5f0553b Mon Sep 17 00:00:00 2001 From: Mathieu Date: Fri, 9 Aug 2024 14:31:55 +0200 Subject: [PATCH 3/5] [UPD] change following code review --- account_stock_situation/README.rst | 1 + account_stock_situation/models/__init__.py | 1 - account_stock_situation/models/company.py | 65 +++++++------------ account_stock_situation/models/stock_quant.py | 7 -- .../readme/CONTRIBUTORS.rst | 1 + .../static/description/index.html | 1 + account_stock_situation/views/action.xml | 2 +- 7 files changed, 28 insertions(+), 50 deletions(-) delete mode 100644 account_stock_situation/models/stock_quant.py diff --git a/account_stock_situation/README.rst b/account_stock_situation/README.rst index a97ccd388..8e9ad56d9 100644 --- a/account_stock_situation/README.rst +++ b/account_stock_situation/README.rst @@ -57,6 +57,7 @@ Contributors * Akretion * David BEAL + * Mathieu DELVA Maintainers ~~~~~~~~~~~ diff --git a/account_stock_situation/models/__init__.py b/account_stock_situation/models/__init__.py index 6f19864b4..ff33dd7a1 100644 --- a/account_stock_situation/models/__init__.py +++ b/account_stock_situation/models/__init__.py @@ -1,3 +1,2 @@ from . import company from . import config_settings -from . import stock_quant diff --git a/account_stock_situation/models/company.py b/account_stock_situation/models/company.py index 149d360f9..af018c3ae 100644 --- a/account_stock_situation/models/company.py +++ b/account_stock_situation/models/company.py @@ -22,7 +22,7 @@ class ResCompany(models.Model): def _set_account_stock_valuation(self, company_string_id): self = self.env.ref(company_string_id) - value, attach = self._get_stock_valuation_another() + value, attach = self._get_stock_valuation() for mfield in ( "account_stock_id", "account_purchase_stock_id", @@ -65,79 +65,62 @@ def _set_account_stock_valuation(self, company_string_id): ) attach.res_id = move.id - def _get_stock_valuation_another(self): + def _get_stock_valuation(self): self.ensure_one() - coef = self.cost_vs_purchase_threshold base_url = self.env["ir.config_parameter"].sudo().get_param("web.base.url") if tools.config.get("running_env") == "dev": base_url = "http://anothercorp.localhost/" location_ids = [x.lot_stock_id.id for x in self.valued_warehouse_ids] - # TODO conserver un group par emplacement : donc autant de colonnes - # de nombres de produits que d'entrepots dans l'excel - product_qties = self.env["stock.quant"].read_group( + + stock_quant_ids = self.env["stock.quant"].search( [("location_id", "child_of", location_ids)], - ["product_id", "warehouse_id", "quantity"], - ["product_id", "warehouse_id"], - lazy=False, ) - - product_ids = list({x["product_id"][0] for x in product_qties}) - - products = self.env["product.product"].browse(product_ids) - prices = { - x: x.variant_seller_ids and x.variant_seller_ids[0] or 0 for x in products - } + products = self.env["product.product"].browse(stock_quant_ids.product_id.ids) vals = defaultdict(list) product_dict = {} - for product in product_qties: - if not product["product_id"][0] in product_dict: - product_dict[product["product_id"][0]] = [ - product["warehouse_id"][0], - product["quantity"], + for stock_quant in stock_quant_ids: + if stock_quant.product_id.id not in product_dict: + product_dict[stock_quant.product_id.id] = [ + stock_quant.warehouse_id, + stock_quant.quantity, ] else: - product_dict[product["product_id"][0]] += [ - product["warehouse_id"][0], - product["quantity"], - ] + if stock_quant.warehouse_id in product_dict[stock_quant.product_id.id]: + product_dict[stock_quant.product_id.id][1] += stock_quant.quantity + else: + product_dict[stock_quant.product_id.id] += [ + stock_quant.warehouse_id, + stock_quant.quantity, + ] for product_id, warehouse_quantities in product_dict.items(): product = products.filtered(lambda s: s.id == product_id) - vals["lien"].append( + vals["link"].append( f"{base_url}/web#id={product_id}&cids={self.id}&action=" f"{self.env.ref('product.product_normal_action_sell').id}&model=" "product.product&view_type=form" ) vals["code"].append(product.default_code) vals["designation"].append(product.name) + for i in range(0, len(warehouse_quantities), 2): warehouse_id = warehouse_quantities[i] quantity = warehouse_quantities[i + 1] - warehouse_id = self.env["stock.warehouse"].browse(warehouse_id) - vals[f"qté_{warehouse_id.name}"].append(round(quantity)) + vals[f"qty_{warehouse_id.code}"].append(round(quantity)) if len(warehouse_quantities) / 2 < len(self.valued_warehouse_ids): warehouse_without_qty = self.valued_warehouse_ids.filtered( lambda r: r.id not in [ - warehouse_quantities[i] + warehouse_quantities[i].id for i in range(0, len(warehouse_quantities), 2) ] ) for warehouse in warehouse_without_qty: - vals[f"qté_{warehouse.name}"].append(0) + vals[f"qty_{warehouse.code}"].append(0) + + vals["value"].append(round(product.standard_price)) - # TODO quand la valeur est < cost_vs_purchase_threshold % de ce seuil - # mettre une colonne 'check' à la valeur 1 - vals["valeur"].append( - round( - max( - product.standard_price, - prices[product] and prices[product].price or 0 * coef / 100, - ) - * product["quantity"] - ) - ) df = pl.from_dict(vals) mfile = io.BytesIO() df.write_excel(workbook=mfile) diff --git a/account_stock_situation/models/stock_quant.py b/account_stock_situation/models/stock_quant.py deleted file mode 100644 index b4c638bf6..000000000 --- a/account_stock_situation/models/stock_quant.py +++ /dev/null @@ -1,7 +0,0 @@ -from odoo import fields, models - - -class StockQuant(models.Model): - _inherit = "stock.quant" - - warehouse_id = fields.Many2one(store=True, index=True) diff --git a/account_stock_situation/readme/CONTRIBUTORS.rst b/account_stock_situation/readme/CONTRIBUTORS.rst index 3237802ef..51f1ed707 100644 --- a/account_stock_situation/readme/CONTRIBUTORS.rst +++ b/account_stock_situation/readme/CONTRIBUTORS.rst @@ -1,2 +1,3 @@ * Akretion * David BEAL + * Mathieu DELVA \ No newline at end of file diff --git a/account_stock_situation/static/description/index.html b/account_stock_situation/static/description/index.html index b5426d63f..1b44c16e4 100644 --- a/account_stock_situation/static/description/index.html +++ b/account_stock_situation/static/description/index.html @@ -411,6 +411,7 @@

Contributors

Akretion
diff --git a/account_stock_situation/views/action.xml b/account_stock_situation/views/action.xml index 2b7494d52..623adcf36 100644 --- a/account_stock_situation/views/action.xml +++ b/account_stock_situation/views/action.xml @@ -2,7 +2,7 @@ - Stock Valorisation + Stock Situation code Date: Mon, 19 Aug 2024 16:12:59 +0200 Subject: [PATCH 4/5] FIX aac_stk_situation: in _get_stock_valuation() --- .../static/description/index.html | 7 +++---- account_stock_situation/models/company.py | 12 +++++------- .../static/description/index.html | 7 +++---- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/account_move_adyen_import/static/description/index.html b/account_move_adyen_import/static/description/index.html index 6f4271f1d..e1dee74c4 100644 --- a/account_move_adyen_import/static/description/index.html +++ b/account_move_adyen_import/static/description/index.html @@ -8,11 +8,10 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ +:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. -Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +274,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: gray; } /* line numbers */ +pre.code .ln { color: grey; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +300,7 @@ span.pre { white-space: pre } -span.problematic, pre.problematic { +span.problematic { color: red } span.section-subtitle { diff --git a/account_stock_situation/models/company.py b/account_stock_situation/models/company.py index af018c3ae..e19db5089 100644 --- a/account_stock_situation/models/company.py +++ b/account_stock_situation/models/company.py @@ -71,13 +71,11 @@ def _get_stock_valuation(self): if tools.config.get("running_env") == "dev": base_url = "http://anothercorp.localhost/" location_ids = [x.lot_stock_id.id for x in self.valued_warehouse_ids] - stock_quant_ids = self.env["stock.quant"].search( [("location_id", "child_of", location_ids)], ) products = self.env["product.product"].browse(stock_quant_ids.product_id.ids) vals = defaultdict(list) - product_dict = {} for stock_quant in stock_quant_ids: if stock_quant.product_id.id not in product_dict: @@ -86,14 +84,16 @@ def _get_stock_valuation(self): stock_quant.quantity, ] else: - if stock_quant.warehouse_id in product_dict[stock_quant.product_id.id]: + if ( + stock_quant.warehouse_id + in product_dict.get(stock_quant.product_id.id)[0] + ): product_dict[stock_quant.product_id.id][1] += stock_quant.quantity else: product_dict[stock_quant.product_id.id] += [ stock_quant.warehouse_id, stock_quant.quantity, ] - for product_id, warehouse_quantities in product_dict.items(): product = products.filtered(lambda s: s.id == product_id) vals["link"].append( @@ -103,7 +103,6 @@ def _get_stock_valuation(self): ) vals["code"].append(product.default_code) vals["designation"].append(product.name) - for i in range(0, len(warehouse_quantities), 2): warehouse_id = warehouse_quantities[i] quantity = warehouse_quantities[i + 1] @@ -120,7 +119,6 @@ def _get_stock_valuation(self): vals[f"qty_{warehouse.code}"].append(0) vals["value"].append(round(product.standard_price)) - df = pl.from_dict(vals) mfile = io.BytesIO() df.write_excel(workbook=mfile) @@ -132,4 +130,4 @@ def _get_stock_valuation(self): "datas": base64.b64encode(mfile.getvalue()), } ) - return sum(vals["valeur"]), attach + return sum(vals["value"]), attach diff --git a/account_stock_situation/static/description/index.html b/account_stock_situation/static/description/index.html index 1b44c16e4..2bb7a2bf5 100644 --- a/account_stock_situation/static/description/index.html +++ b/account_stock_situation/static/description/index.html @@ -8,11 +8,10 @@ /* :Author: David Goodger (goodger@python.org) -:Id: $Id: html4css1.css 9511 2024-01-13 09:50:07Z milde $ +:Id: $Id: html4css1.css 8954 2022-01-20 10:10:25Z milde $ :Copyright: This stylesheet has been placed in the public domain. Default cascading style sheet for the HTML output of Docutils. -Despite the name, some widely supported CSS2 features are used. See https://docutils.sourceforge.io/docs/howto/html-stylesheets.html for how to customize this style sheet. @@ -275,7 +274,7 @@ margin-left: 2em ; margin-right: 2em } -pre.code .ln { color: gray; } /* line numbers */ +pre.code .ln { color: grey; } /* line numbers */ pre.code, code { background-color: #eeeeee } pre.code .comment, code .comment { color: #5C6576 } pre.code .keyword, code .keyword { color: #3B0D06; font-weight: bold } @@ -301,7 +300,7 @@ span.pre { white-space: pre } -span.problematic, pre.problematic { +span.problematic { color: red } span.section-subtitle { From e8bbcea4c8f20a32e0d3df4d5431930a49172330 Mon Sep 17 00:00:00 2001 From: David Beal Date: Mon, 19 Aug 2024 17:21:16 +0200 Subject: [PATCH 5/5] wip --- account_stock_situation/models/company.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/account_stock_situation/models/company.py b/account_stock_situation/models/company.py index e19db5089..3cc134ef1 100644 --- a/account_stock_situation/models/company.py +++ b/account_stock_situation/models/company.py @@ -118,7 +118,7 @@ def _get_stock_valuation(self): for warehouse in warehouse_without_qty: vals[f"qty_{warehouse.code}"].append(0) - vals["value"].append(round(product.standard_price)) + vals["value"].append(round(product.standard_price, 2)) df = pl.from_dict(vals) mfile = io.BytesIO() df.write_excel(workbook=mfile)