From d491ea013a2f9b52471ac6ce6d996443f90e3b0f Mon Sep 17 00:00:00 2001 From: nobuQuartile Date: Tue, 11 Mar 2025 02:53:31 +0000 Subject: [PATCH 1/4] [4947][ADD] purchase_stock_price_variance --- purchase_stock_price_variance/README.rst | 132 +++++ purchase_stock_price_variance/__init__.py | 1 + purchase_stock_price_variance/__manifest__.py | 19 + purchase_stock_price_variance/i18n/ja.po | 159 ++++++ .../models/__init__.py | 5 + .../models/product_category.py | 31 ++ .../models/product_template.py | 52 ++ .../models/res_company.py | 32 ++ .../models/res_config_settings.py | 27 + .../models/stock_picking.py | 83 +++ .../readme/CONFIGURE.md | 17 + .../readme/CONTRIBUTORS.md | 4 + .../readme/DESCRIPTION.md | 2 + purchase_stock_price_variance/readme/USAGE.md | 9 + ...purchase_stock_price_variance_security.xml | 8 + .../static/description/index.html | 477 ++++++++++++++++++ .../tests/__init__.py | 1 + .../test_purchase_stock_price_variance.py | 130 +++++ .../views/product_category_views.xml | 12 + .../views/product_template_views.xml | 20 + .../views/res_config_setting_views.xml | 60 +++ .../views/stock_picking_views.xml | 16 + .../odoo/addons/purchase_stock_price_variance | 1 + setup/purchase_stock_price_variance/setup.py | 6 + 24 files changed, 1304 insertions(+) create mode 100644 purchase_stock_price_variance/README.rst create mode 100644 purchase_stock_price_variance/__init__.py create mode 100644 purchase_stock_price_variance/__manifest__.py create mode 100644 purchase_stock_price_variance/i18n/ja.po create mode 100644 purchase_stock_price_variance/models/__init__.py create mode 100644 purchase_stock_price_variance/models/product_category.py create mode 100644 purchase_stock_price_variance/models/product_template.py create mode 100644 purchase_stock_price_variance/models/res_company.py create mode 100644 purchase_stock_price_variance/models/res_config_settings.py create mode 100644 purchase_stock_price_variance/models/stock_picking.py create mode 100644 purchase_stock_price_variance/readme/CONFIGURE.md create mode 100644 purchase_stock_price_variance/readme/CONTRIBUTORS.md create mode 100644 purchase_stock_price_variance/readme/DESCRIPTION.md create mode 100644 purchase_stock_price_variance/readme/USAGE.md create mode 100644 purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml create mode 100644 purchase_stock_price_variance/static/description/index.html create mode 100644 purchase_stock_price_variance/tests/__init__.py create mode 100644 purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py create mode 100644 purchase_stock_price_variance/views/product_category_views.xml create mode 100644 purchase_stock_price_variance/views/product_template_views.xml create mode 100644 purchase_stock_price_variance/views/res_config_setting_views.xml create mode 100644 purchase_stock_price_variance/views/stock_picking_views.xml create mode 120000 setup/purchase_stock_price_variance/odoo/addons/purchase_stock_price_variance create mode 100644 setup/purchase_stock_price_variance/setup.py diff --git a/purchase_stock_price_variance/README.rst b/purchase_stock_price_variance/README.rst new file mode 100644 index 00000000..7e59fe4c --- /dev/null +++ b/purchase_stock_price_variance/README.rst @@ -0,0 +1,132 @@ +============================= +Purchase Stock Price Variance +============================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:72cb1add4c5ee6b19905a1be828b07390a01f239384becae1d2de35e95adf800 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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--workflow-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-workflow/tree/16.0/purchase_stock_price_variance + :alt: OCA/stock-logistics-workflow +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-workflow-16-0/stock-logistics-workflow-16-0-purchase_stock_price_variance + :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-workflow&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module checks the variance between the purchase price and the +product's standard price at the time of receipt picking validation. If +the variance exceeds a given threshold, the notification can be left in +the chatter. Additionally, an error can be triggered before receiving +the stock if needed. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +1. Navigate to Inventory > Configuration > Settings. +2. Find and enable the 'Enable Price Variance Error' option to activate + this feature. An error will occur if the price difference exceeds the + threshold when receiving the product. +3. Set the following global values to apply if no specific value is set + at the product level. If the threshold value is set to 0, this + threshold will not be checked. + + - **Price Variance Threshold Percent**: Default percentage variance + for all products. + - **Price Variance Threshold Amount**: Default maximum variance for + all products. + +4. Go to Inventory > Configuration > Product Categories. +5. Enable **Bypass Price Variance Check** to skip the error check for + the products under this category. +6. Go to Inventory > Products and open the product. +7. Click on the Inventory tab and configure the following fields. If the + threshold value is set to 0, the threshold will refer to the global + value. + + - **Bypass Price Variance Check**: Enable this to skip the error + check for this specific product. + - **Price Variance Threshold Percent**: Set the allowable percentage + variance. + - **Price Variance Threshold Amount**: Define the maximum allowable + price variance. + +8. Assign the internal user to the "Manage Price Variance Check" group. + This will make the "Bypass Price Variance Check" checkbox updatable + in the receipt form. + +Usage +===== + +This module logs a notification in the chatter when the variance between +the purchase price and the standard price exceeds a given threshold +during the receipt process. + +You can configure the price variance threshold at the product level. + +If needed, an error message can also be triggered. The 'Bypass Price +Variance Check' option can be set both at the product level and in each +Stock Picking to skip the error + +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 +------- + +* Quartile + +Contributors +------------ + +- `Quartile `__: + + - Aung Ko Ko Lin + - Yoshi Tashiro + - Toshikimi Shigenobu + +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-workflow `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/purchase_stock_price_variance/__init__.py b/purchase_stock_price_variance/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/purchase_stock_price_variance/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/purchase_stock_price_variance/__manifest__.py b/purchase_stock_price_variance/__manifest__.py new file mode 100644 index 00000000..9969baf8 --- /dev/null +++ b/purchase_stock_price_variance/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Purchase Stock Price Variance", + "version": "16.0.1.0.0", + "category": "Stock", + "author": "Quartile, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/stock-logistics-workflow", + "depends": ["purchase_stock"], + "license": "AGPL-3", + "data": [ + "security/purchase_stock_price_variance_security.xml", + "views/product_category_views.xml", + "views/product_template_views.xml", + "views/res_config_setting_views.xml", + "views/stock_picking_views.xml", + ], + "installable": True, +} diff --git a/purchase_stock_price_variance/i18n/ja.po b/purchase_stock_price_variance/i18n/ja.po new file mode 100644 index 00000000..f8b815bf --- /dev/null +++ b/purchase_stock_price_variance/i18n/ja.po @@ -0,0 +1,159 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_stock_price_variance +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2025-02-25 03:06+0000\n" +"PO-Revision-Date: 2025-02-25 03:06+0000\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: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +msgid " %" +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__bypass_price_variance_check +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_template__bypass_price_variance_check +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_stock_picking__bypass_price_variance_check +#: model:res.groups,name:purchase_stock_price_variance.group_bypass_price_variance_check +msgid "Bypass Price Variance Check" +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model,name:purchase_stock_price_variance.model_res_company +msgid "Companies" +msgstr "会社" + +#. module: purchase_stock_price_variance +#: model:ir.model,name:purchase_stock_price_variance.model_res_config_settings +msgid "Config Settings" +msgstr "コンフィグ設定" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold +msgid "Enable price variance threshold check" +msgstr "" + +#. module: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +msgid "" +"Enable the feature to check the price variance between the purchase price " +"unit and the product's standard price." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_stock_picking__bypass_price_variance_check +msgid "" +"If enabled, no error is raised for price variance between the product's " +"standard price and purchase receipt unit price." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__bypass_price_variance_check +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__bypass_price_variance_check +msgid "" +"If enabled, this product will not be checked for price variance between the " +"product's standard price and purchase receipt unit price.Setting this to " +"zero means the threshold will refer to the global setting." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_amount +msgid "" +"Maximum allowable variance (in monetary amount, based on company currency) " +"between the product's standard price and the purchase receipt unit price." +msgstr "" + +#. module: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +msgid "" +"Maximum allowable variance (in monetary amount, based on company currency) between the product's standard price and the purchase receipt unit price.\n" +" Keeping it at zero means that this threshold will not be checked." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__price_variance_threshold_amount +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__price_variance_threshold_amount +msgid "" +"Maximum allowable variance (in monetary amount, based on company currency) " +"between the product's standard price and the purchase receipt unit " +"price.Setting this to zero means the threshold will refer to the global " +"setting." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__price_variance_threshold_percent +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__price_variance_threshold_percent +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_percent +msgid "" +"Maximum variance (in percent) allowable between the product's standard price" +" and purchase receipt unit price." +msgstr "" + +#. module: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +msgid "" +"Maximum variance (in percent) allowable between the product's standard price and purchase receipt unit price.\n" +" Keeping it at zero means that this threshold will not be checked." +msgstr "" + +#. module: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.product_normal_form_view_inherit +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_product_template_form_inherit +msgid "Price Discrepancy Settings" +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__price_variance_threshold_amount +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_template__price_variance_threshold_amount +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_amount +msgid "Price Variance Threshold Amount" +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__price_variance_threshold_percent +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_template__price_variance_threshold_percent +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_percent +msgid "Price Variance Threshold Percent" +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model,name:purchase_stock_price_variance.model_product_template +msgid "Product" +msgstr "プロダクト" + +#. module: purchase_stock_price_variance +#. odoo-python +#: code:addons/purchase_stock_price_variance/models/res_company.py:0 +#, python-format +msgid "The threshold values cannot be negative." +msgstr "" + +#. module: purchase_stock_price_variance +#: model:ir.model,name:purchase_stock_price_variance.model_stock_picking +msgid "Transfer" +msgstr "運送" + +#. module: purchase_stock_price_variance +#. odoo-python +#: code:addons/purchase_stock_price_variance/models/stock_picking.py:0 +#, python-format +msgid "" +"You do not have permission to modify the 'Bypass Price Variance Check' " +"field. Please contact an administrator or a user with the appropriate " +"permissions." +msgstr "" diff --git a/purchase_stock_price_variance/models/__init__.py b/purchase_stock_price_variance/models/__init__.py new file mode 100644 index 00000000..60c83992 --- /dev/null +++ b/purchase_stock_price_variance/models/__init__.py @@ -0,0 +1,5 @@ +from . import product_category +from . import product_template +from . import res_company +from . import res_config_settings +from . import stock_picking diff --git a/purchase_stock_price_variance/models/product_category.py b/purchase_stock_price_variance/models/product_category.py new file mode 100644 index 00000000..c365f25d --- /dev/null +++ b/purchase_stock_price_variance/models/product_category.py @@ -0,0 +1,31 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class ProductCategory(models.Model): + _inherit = "product.category" + + bypass_price_variance_check = fields.Boolean( + copy=False, + tracking=True, + help="If enabled, the products under this category will not raise an error for price" + " variance between the product's standard price and the purchase receipt unit price.", + ) + + def write(self, vals): + if "bypass_price_variance_check" in vals: + if not self.env.user.has_group( + "purchase_stock_price_variance.group_manage_price_variance_check" + ): + raise UserError( + _( + "You do not have permission to modify the " + "'Bypass Price Variance Check' field. " + "Please contact an administrator or a user " + "with the appropriate permissions." + ) + ) + return super().write(vals) diff --git a/purchase_stock_price_variance/models/product_template.py b/purchase_stock_price_variance/models/product_template.py new file mode 100644 index 00000000..a7fa53d4 --- /dev/null +++ b/purchase_stock_price_variance/models/product_template.py @@ -0,0 +1,52 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import UserError, ValidationError + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + price_variance_threshold_percent = fields.Float( + help="Maximum variance (in percent) allowable between the product's standard price" + " and purchase receipt unit price. " + "Setting this to zero means the threshold will refer to the global setting." + ) + price_variance_threshold_amount = fields.Monetary( + help="Maximum allowable variance (in monetary amount, based on company currency)" + " between the product's standard price and the purchase receipt unit price. " + "Setting this to zero means the threshold will refer to the global setting." + ) + bypass_price_variance_check = fields.Boolean( + copy=False, + tracking=True, + help="If enabled, this product will not raise an error for price variance between " + "the product's standard price and the purchase receipt unit price.", + ) + + @api.constrains( + "price_variance_threshold_percent", "price_variance_threshold_amount" + ) + def _check_price_variance_threshold(self): + for rec in self: + if ( + rec.price_variance_threshold_percent < 0 + or rec.price_variance_threshold_amount < 0 + ): + raise ValidationError(_("The threshold values cannot be negative.")) + + def write(self, vals): + if "bypass_price_variance_check" in vals: + if not self.env.user.has_group( + "purchase_stock_price_variance.group_manage_price_variance_check" + ): + raise UserError( + _( + "You do not have permission to modify the " + "'Bypass Price Variance Check' field. " + "Please contact an administrator or a user " + "with the appropriate permissions." + ) + ) + return super().write(vals) diff --git a/purchase_stock_price_variance/models/res_company.py b/purchase_stock_price_variance/models/res_company.py new file mode 100644 index 00000000..f8557230 --- /dev/null +++ b/purchase_stock_price_variance/models/res_company.py @@ -0,0 +1,32 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from odoo.exceptions import ValidationError + + +class ResCompany(models.Model): + _inherit = "res.company" + + enable_price_variance_error = fields.Boolean() + price_variance_threshold_percent = fields.Float( + help="Maximum variance (in percent) allowable between the product's standard price" + " and purchase receipt unit price." + "Setting this to zero means this threshold will not be checked." + ) + price_variance_threshold_amount = fields.Monetary( + help="Maximum allowable variance (in monetary amount, based on company currency)" + " between the product's standard price and the purchase receipt unit price." + "Setting this to zero means this threshold will not be checked." + ) + + @api.constrains( + "price_variance_threshold_percent", "price_variance_threshold_amount" + ) + def _check_price_variance_threshold(self): + for rec in self: + if ( + rec.price_variance_threshold_percent < 0 + or rec.price_variance_threshold_amount < 0 + ): + raise ValidationError(_("The threshold values cannot be negative.")) diff --git a/purchase_stock_price_variance/models/res_config_settings.py b/purchase_stock_price_variance/models/res_config_settings.py new file mode 100644 index 00000000..68e8a778 --- /dev/null +++ b/purchase_stock_price_variance/models/res_config_settings.py @@ -0,0 +1,27 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + enable_price_variance_error = fields.Boolean( + related="company_id.enable_price_variance_error", + readonly=False, + ) + price_variance_threshold_percent = fields.Float( + related="company_id.price_variance_threshold_percent", + readonly=False, + help="Maximum variance (in percent) allowable between the product's standard price" + " and purchase receipt unit price. " + "Setting this to zero means this threshold will not be checked.", + ) + price_variance_threshold_amount = fields.Monetary( + related="company_id.price_variance_threshold_amount", + readonly=False, + help="Maximum allowable variance (in monetary amount, based on company currency)" + " between the product's standard price and the purchase receipt unit price. " + "Setting this to zero means this threshold will not be checked.", + ) diff --git a/purchase_stock_price_variance/models/stock_picking.py b/purchase_stock_price_variance/models/stock_picking.py new file mode 100644 index 00000000..a6012567 --- /dev/null +++ b/purchase_stock_price_variance/models/stock_picking.py @@ -0,0 +1,83 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class Stockpick(models.Model): + _inherit = "stock.picking" + + bypass_price_variance_check = fields.Boolean( + copy=False, + tracking=True, + help="If enabled, no error is raised for price variance between " + "the product's standard price and purchase receipt unit price.", + ) + + def write(self, vals): + if "bypass_price_variance_check" in vals: + if not self.env.user.has_group( + "purchase_stock_price_variance.group_manage_price_variance_check" + ): + raise UserError( + _( + "You do not have permission to modify the " + "'Bypass Price Variance Check' field. " + "Please contact an administrator or a user " + "with the appropriate permissions." + ) + ) + return super().write(vals) + + def _action_done(self): + company = self.env.company + global_threshold_percent = company.price_variance_threshold_percent + global_threshold_amount = company.price_variance_threshold_amount + for pick in self: + error_messages = [] + messages = [] + for move in pick.move_ids: + if not (move._is_in() or move._is_dropshipped()): + continue + product = move.product_id + threshold_percent = ( + product.price_variance_threshold_percent or global_threshold_percent + ) + threshold_amount = ( + product.price_variance_threshold_amount or global_threshold_amount + ) + if not threshold_percent and not threshold_amount: + continue + received_price = move._get_price_unit() + standard_price = product.standard_price + amount_difference = abs(received_price - standard_price) + percentage_difference = ( + (amount_difference / standard_price) * 100 if standard_price else 0 + ) + if ( + threshold_percent and percentage_difference > threshold_percent + ) or (threshold_amount and amount_difference > threshold_amount): + message = ( + f"{product.name}: Received Price = {received_price}, " + f"Product Price = {standard_price}." + ) + if ( + not product.categ_id.bypass_price_variance_check + and not product.bypass_price_variance_check + and not pick.bypass_price_variance_check + ): + error_messages.append(message) + messages.append(message) + + def get_message(products, delimiter): + message = _( + "Price variance exceeding a threshold detected for the following products:" + ) + return message + delimiter + delimiter.join(products) + + if pick.company_id.enable_price_variance_error and error_messages: + raise UserError(get_message(error_messages, "\n")) + if messages: + pick.message_post(body=get_message(messages, "
")) + return super()._action_done() diff --git a/purchase_stock_price_variance/readme/CONFIGURE.md b/purchase_stock_price_variance/readme/CONFIGURE.md new file mode 100644 index 00000000..f2c68947 --- /dev/null +++ b/purchase_stock_price_variance/readme/CONFIGURE.md @@ -0,0 +1,17 @@ +1. Navigate to Inventory > Configuration > Settings. +2. Find and enable the 'Enable Price Variance Error' option to activate this feature. + An error will occur if the price difference exceeds the threshold when receiving the product. +3. Set the following global values to apply if no specific value is set at the product level. + If the threshold value is set to 0, this threshold will not be checked. + * **Price Variance Threshold Percent**: Default percentage variance for all products. + * **Price Variance Threshold Amount**: Default maximum variance for all products. +4. Go to Inventory > Configuration > Product Categories. +5. Enable **Bypass Price Variance Check** to skip the error check for the products under this category. +6. Go to Inventory > Products and open the product. +7. Click on the Inventory tab and configure the following fields. + If the threshold value is set to 0, the threshold will refer to the global value. + * **Bypass Price Variance Check**: Enable this to skip the error check for this specific product. + * **Price Variance Threshold Percent**: Set the allowable percentage variance. + * **Price Variance Threshold Amount**: Define the maximum allowable price variance. +8. Assign the internal user to the "Manage Price Variance Check" group. + This will make the "Bypass Price Variance Check" checkbox updatable in the receipt form. diff --git a/purchase_stock_price_variance/readme/CONTRIBUTORS.md b/purchase_stock_price_variance/readme/CONTRIBUTORS.md new file mode 100644 index 00000000..9fc009d1 --- /dev/null +++ b/purchase_stock_price_variance/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [Quartile](https://www.quartile.co): + - Aung Ko Ko Lin + - Yoshi Tashiro + - Toshikimi Shigenobu diff --git a/purchase_stock_price_variance/readme/DESCRIPTION.md b/purchase_stock_price_variance/readme/DESCRIPTION.md new file mode 100644 index 00000000..7c8f4d78 --- /dev/null +++ b/purchase_stock_price_variance/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module checks the variance between the purchase price and the product's standard price at the time of receipt picking validation. +If the variance exceeds a given threshold, the notification can be left in the chatter. Additionally, an error can be triggered before receiving the stock if needed. \ No newline at end of file diff --git a/purchase_stock_price_variance/readme/USAGE.md b/purchase_stock_price_variance/readme/USAGE.md new file mode 100644 index 00000000..e5fbf5b2 --- /dev/null +++ b/purchase_stock_price_variance/readme/USAGE.md @@ -0,0 +1,9 @@ +This module logs a notification in the chatter when the variance between +the purchase price and the standard price exceeds a given threshold during +the receipt process. + +You can configure the price variance threshold at the product level. + +If needed, an error message can also be triggered. +The 'Bypass Price Variance Check' option can be set both at the product +level and in each Stock Picking to skip the error diff --git a/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml b/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml new file mode 100644 index 00000000..eca7bb12 --- /dev/null +++ b/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml @@ -0,0 +1,8 @@ + + + + Manage Price Variance Check + + + + diff --git a/purchase_stock_price_variance/static/description/index.html b/purchase_stock_price_variance/static/description/index.html new file mode 100644 index 00000000..cf498a55 --- /dev/null +++ b/purchase_stock_price_variance/static/description/index.html @@ -0,0 +1,477 @@ + + + + + +Purchase Stock Price Variance + + + +
+

Purchase Stock Price Variance

+ + +

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

+

This module checks the variance between the purchase price and the +product’s standard price at the time of receipt picking validation. If +the variance exceeds a given threshold, the notification can be left in +the chatter. Additionally, an error can be triggered before receiving +the stock if needed.

+

Table of contents

+ +
+

Configuration

+
    +
  1. Navigate to Inventory > Configuration > Settings.
  2. +
  3. Find and enable the ‘Enable Price Variance Error’ option to activate +this feature. An error will occur if the price difference exceeds the +threshold when receiving the product.
  4. +
  5. Set the following global values to apply if no specific value is set +at the product level. If the threshold value is set to 0, this +threshold will not be checked.
      +
    • Price Variance Threshold Percent: Default percentage variance +for all products.
    • +
    • Price Variance Threshold Amount: Default maximum variance for +all products.
    • +
    +
  6. +
  7. Go to Inventory > Configuration > Product Categories.
  8. +
  9. Enable Bypass Price Variance Check to skip the error check for +the products under this category.
  10. +
  11. Go to Inventory > Products and open the product.
  12. +
  13. Click on the Inventory tab and configure the following fields. If the +threshold value is set to 0, the threshold will refer to the global +value.
      +
    • Bypass Price Variance Check: Enable this to skip the error +check for this specific product.
    • +
    • Price Variance Threshold Percent: Set the allowable percentage +variance.
    • +
    • Price Variance Threshold Amount: Define the maximum allowable +price variance.
    • +
    +
  14. +
  15. Assign the internal user to the “Manage Price Variance Check” group. +This will make the “Bypass Price Variance Check” checkbox updatable +in the receipt form.
  16. +
+
+
+

Usage

+

This module logs a notification in the chatter when the variance between +the purchase price and the standard price exceeds a given threshold +during the receipt process.

+

You can configure the price variance threshold at the product level.

+

If needed, an error message can also be triggered. The ‘Bypass Price +Variance Check’ option can be set both at the product level and in each +Stock Picking to skip the error

+
+
+

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

+
    +
  • Quartile
  • +
+
+
+

Contributors

+
    +
  • Quartile:
      +
    • Aung Ko Ko Lin
    • +
    • Yoshi Tashiro
    • +
    • Toshikimi Shigenobu
    • +
    +
  • +
+
+
+

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

+

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

+
+
+
+ + diff --git a/purchase_stock_price_variance/tests/__init__.py b/purchase_stock_price_variance/tests/__init__.py new file mode 100644 index 00000000..7ec77b31 --- /dev/null +++ b/purchase_stock_price_variance/tests/__init__.py @@ -0,0 +1 @@ +from . import test_purchase_stock_price_variance diff --git a/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py b/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py new file mode 100644 index 00000000..a21de6a4 --- /dev/null +++ b/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py @@ -0,0 +1,130 @@ +# Copyright 2025 Quartile (https://www.quartile.co) +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.exceptions import UserError +from odoo.tests.common import TransactionCase + + +class TestPurchaseStockPriceVariance(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.company = cls.env.user.company_id + cls.product_category = cls.env["product.category"].create( + {"name": "Test Category"} + ) + cls.product = cls.env["product.template"].create( + { + "name": "Test Product", + "standard_price": 100, + "categ_id": cls.product_category.id, + } + ) + cls.supplier = cls.env["res.partner"].create({"name": "Test Supplier"}) + cls.group_manage_price_variance_check = cls.env.ref( + "purchase_stock_price_variance.group_manage_price_variance_check" + ) + cls.company.enable_price_variance_error = True + + def create_purchase_order(self, price_unit=100): + return self.env["purchase.order"].create( + { + "partner_id": self.supplier.id, + "order_line": [ + ( + 0, + 0, + { + "product_id": self.product.product_variant_id.id, + "product_qty": 1, + "price_unit": price_unit, + }, + ) + ], + } + ) + + def validate_picking(self, picking, expect_error=False): + picking.move_ids.write({"quantity_done": 1}) + if expect_error: + with self.assertRaises(UserError): + picking.button_validate() + else: + picking.button_validate() + self.assertEqual(picking.state, "done") + + def check_chatter_message(self, picking, should_contain): + messages = picking.message_ids.mapped("body") + found = any( + "Price variance exceeding a threshold detected" in message + for message in messages + ) + self.assertEqual(found, should_contain) + + def test_01_normal_workflow_no_error(self): + po = self.create_purchase_order() + po.button_confirm() + picking = po.picking_ids + self.assertTrue(picking) + self.validate_picking(picking) + self.check_chatter_message(picking, False) + + def test_02_price_variance_check_category(self): + with self.assertRaises(UserError): + self.product_category.bypass_price_variance_check = True + self.product.price_variance_threshold_percent = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking, expect_error=True) + self.env.user.groups_id |= self.group_manage_price_variance_check + self.product_category.bypass_price_variance_check = True + self.validate_picking(picking) + self.check_chatter_message(picking, True) + + def test_03_price_variance_check_product(self): + with self.assertRaises(UserError): + self.product.bypass_price_variance_check = True + self.product.price_variance_threshold_percent = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking, expect_error=True) + self.env.user.groups_id |= self.group_manage_price_variance_check + self.product.bypass_price_variance_check = True + self.validate_picking(picking) + self.check_chatter_message(picking, True) + + def test_04_price_variance_check_threshold_amount(self): + self.product.price_variance_threshold_amount = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking, expect_error=True) + self.env.user.groups_id |= self.group_manage_price_variance_check + self.product.bypass_price_variance_check = True + self.validate_picking(picking) + self.check_chatter_message(picking, True) + + def test_05_price_variance_check_global_threshold_amount(self): + self.company.price_variance_threshold_amount = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking, expect_error=True) + + def test_06_price_variance_check_global_threshold_percent(self): + self.company.price_variance_threshold_percent = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking, expect_error=True) + + def test_07_global_price_variance_check_disable(self): + self.company.enable_price_variance_error = False + self.company.price_variance_threshold_percent = 5 + po = self.create_purchase_order(price_unit=110) + po.button_confirm() + picking = po.picking_ids + self.validate_picking(picking) + self.check_chatter_message(picking, True) diff --git a/purchase_stock_price_variance/views/product_category_views.xml b/purchase_stock_price_variance/views/product_category_views.xml new file mode 100644 index 00000000..b831a0b7 --- /dev/null +++ b/purchase_stock_price_variance/views/product_category_views.xml @@ -0,0 +1,12 @@ + + + + product.category + + + + + + + + diff --git a/purchase_stock_price_variance/views/product_template_views.xml b/purchase_stock_price_variance/views/product_template_views.xml new file mode 100644 index 00000000..e482253c --- /dev/null +++ b/purchase_stock_price_variance/views/product_template_views.xml @@ -0,0 +1,20 @@ + + + + product.template.stock.property.form.inherit + product.template + + + + + + + + + + + + diff --git a/purchase_stock_price_variance/views/res_config_setting_views.xml b/purchase_stock_price_variance/views/res_config_setting_views.xml new file mode 100644 index 00000000..69f42487 --- /dev/null +++ b/purchase_stock_price_variance/views/res_config_setting_views.xml @@ -0,0 +1,60 @@ + + + + res.config.settings + res.config.settings + + + +
+
+ +
+
+
+
+
+
+
+
+
+
+
+
diff --git a/purchase_stock_price_variance/views/stock_picking_views.xml b/purchase_stock_price_variance/views/stock_picking_views.xml new file mode 100644 index 00000000..2746e8bc --- /dev/null +++ b/purchase_stock_price_variance/views/stock_picking_views.xml @@ -0,0 +1,16 @@ + + + + stock.picking.form + stock.picking + + + + + + + + diff --git a/setup/purchase_stock_price_variance/odoo/addons/purchase_stock_price_variance b/setup/purchase_stock_price_variance/odoo/addons/purchase_stock_price_variance new file mode 120000 index 00000000..c19226ab --- /dev/null +++ b/setup/purchase_stock_price_variance/odoo/addons/purchase_stock_price_variance @@ -0,0 +1 @@ +../../../../purchase_stock_price_variance \ No newline at end of file diff --git a/setup/purchase_stock_price_variance/setup.py b/setup/purchase_stock_price_variance/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/purchase_stock_price_variance/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) From 2842fd5b7f19d04e33707410bbed18bf4173e835 Mon Sep 17 00:00:00 2001 From: nobuQuartile Date: Tue, 11 Mar 2025 07:07:30 +0000 Subject: [PATCH 2/4] upd translation --- purchase_stock_price_variance/i18n/ja.po | 141 ++++++++++++------ .../models/res_company.py | 6 +- 2 files changed, 98 insertions(+), 49 deletions(-) diff --git a/purchase_stock_price_variance/i18n/ja.po b/purchase_stock_price_variance/i18n/ja.po index f8b815bf..a8e1999b 100644 --- a/purchase_stock_price_variance/i18n/ja.po +++ b/purchase_stock_price_variance/i18n/ja.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2025-02-25 03:06+0000\n" -"PO-Revision-Date: 2025-02-25 03:06+0000\n" +"POT-Creation-Date: 2025-03-11 06:28+0000\n" +"PO-Revision-Date: 2025-03-11 06:28+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -16,17 +16,12 @@ msgstr "" "Plural-Forms: \n" #. module: purchase_stock_price_variance -#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings -msgid " %" -msgstr "" - -#. module: purchase_stock_price_variance +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_category__bypass_price_variance_check #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__bypass_price_variance_check #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_template__bypass_price_variance_check #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_stock_picking__bypass_price_variance_check -#: model:res.groups,name:purchase_stock_price_variance.group_bypass_price_variance_check msgid "Bypass Price Variance Check" -msgstr "" +msgstr "価格差チェックをバイパス" #. module: purchase_stock_price_variance #: model:ir.model,name:purchase_stock_price_variance.model_res_company @@ -39,81 +34,105 @@ msgid "Config Settings" msgstr "コンフィグ設定" #. module: purchase_stock_price_variance -#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold -#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold -msgid "Enable price variance threshold check" -msgstr "" +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__enable_price_variance_error +#: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__enable_price_variance_error +msgid "Enable Price Variance Error" +msgstr "価格差エラーを有効化" #. module: purchase_stock_price_variance #: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings msgid "" -"Enable the feature to check the price variance between the purchase price " -"unit and the product's standard price." -msgstr "" +"Enable the feature that triggers an error when receiving a product if\n" +" the price difference exceeds the threshold." +msgstr "受領時に価格差がしきい値を超えた場合にエラーを発生させる機能を有効化します。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_stock_picking__bypass_price_variance_check msgid "" "If enabled, no error is raised for price variance between the product's " "standard price and purchase receipt unit price." -msgstr "" +msgstr "有効にすると、商品の標準価格と購買受領単価の間の価格差によるエラーは発生しません。" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_product_category__bypass_price_variance_check +msgid "" +"If enabled, the products under this category will not raise an error for " +"price variance between the product's standard price and the purchase receipt" +" unit price." +msgstr "有効にすると、このカテゴリ内の製品は、標準価格と購買受領単価の価格差によるエラーを発生させません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__bypass_price_variance_check #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__bypass_price_variance_check msgid "" -"If enabled, this product will not be checked for price variance between the " -"product's standard price and purchase receipt unit price.Setting this to " -"zero means the threshold will refer to the global setting." -msgstr "" +"If enabled, this product will not raise an error for price variance between " +"the product's standard price and the purchase receipt unit price." +msgstr "有効にすると、この製品は、標準価格と購買受領単価の価格差によるエラーを発生させません。" #. module: purchase_stock_price_variance -#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount -#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_amount -msgid "" -"Maximum allowable variance (in monetary amount, based on company currency) " -"between the product's standard price and the purchase receipt unit price." -msgstr "" +#: model:res.groups,name:purchase_stock_price_variance.group_manage_price_variance_check +msgid "Manage Price Variance Check" +msgstr "価格差チェックの管理" #. module: purchase_stock_price_variance #: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings msgid "" -"Maximum allowable variance (in monetary amount, based on company currency) between the product's standard price and the purchase receipt unit price.\n" +"Maximum allowable variance (in monetary amount, based on company\n" +" currency) between the product's standard price and the purchase receipt\n" +" unit price.\n" " Keeping it at zero means that this threshold will not be checked." msgstr "" +"製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。\n" +" 0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__price_variance_threshold_amount #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__price_variance_threshold_amount msgid "" "Maximum allowable variance (in monetary amount, based on company currency) " -"between the product's standard price and the purchase receipt unit " -"price.Setting this to zero means the threshold will refer to the global " -"setting." -msgstr "" +"between the product's standard price and the purchase receipt unit price. " +"Setting this to zero means the threshold will refer to the global setting." +msgstr "製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このグローバル設定が利用されます。" + +#. module: purchase_stock_price_variance +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_amount +msgid "" +"Maximum allowable variance (in monetary amount, based on company currency) " +"between the product's standard price and the purchase receipt unit price. " +"Setting this to zero means this threshold will not be checked." +msgstr "製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このしきい値はチェックされません。" + +#. module: purchase_stock_price_variance +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +msgid "" +"Maximum variance (in percent) allowable between the product's standard\n" +" price and purchase receipt unit price.\n" +" Keeping it at zero means that this threshold will not be checked." +msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__price_variance_threshold_percent #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_template__price_variance_threshold_percent -#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent -#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_percent msgid "" "Maximum variance (in percent) allowable between the product's standard price" -" and purchase receipt unit price." -msgstr "" +" and purchase receipt unit price. Setting this to zero means the threshold " +"will refer to the global setting." +msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0 に設定すると、このグローバル設定が利用されます。" #. module: purchase_stock_price_variance -#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent +#: model:ir.model.fields,help:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_percent msgid "" -"Maximum variance (in percent) allowable between the product's standard price and purchase receipt unit price.\n" -" Keeping it at zero means that this threshold will not be checked." -msgstr "" +"Maximum variance (in percent) allowable between the product's standard price" +" and purchase receipt unit price.Setting this to zero means this threshold " +"will not be checked." +msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance -#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.product_normal_form_view_inherit -#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_product_template_form_inherit +#: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_template_property_form msgid "Price Discrepancy Settings" -msgstr "" +msgstr "価格差異設定" #. module: purchase_stock_price_variance #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__price_variance_threshold_amount @@ -121,7 +140,7 @@ msgstr "" #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_amount msgid "Price Variance Threshold Amount" -msgstr "" +msgstr "価格差しきい値(金額)" #. module: purchase_stock_price_variance #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_product_product__price_variance_threshold_percent @@ -129,19 +148,46 @@ msgstr "" #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent #: model:ir.model.fields,field_description:purchase_stock_price_variance.field_res_config_settings__price_variance_threshold_percent msgid "Price Variance Threshold Percent" +msgstr "価格差しきい値(パーセント)" + +#. module: purchase_stock_price_variance +#. odoo-python +#: code:addons/purchase_stock_price_variance/models/stock_picking.py:0 +#, python-format +msgid "" +"Price variance exceeding a threshold detected for the following products:" +msgstr "以下の製品でしきい値を超える価格差が検出されました:" + +#. module: purchase_stock_price_variance +#. odoo-python +#: code:addons/purchase_stock_price_variance/models/stock_picking.py:0 +#, python-format +msgid "" +"Price variance exceeding a threshold detected for the following products:\n" +"\n" msgstr "" +"以下の製品でしきい値を超える価格差が検出されました:\n" +"\n" #. module: purchase_stock_price_variance #: model:ir.model,name:purchase_stock_price_variance.model_product_template msgid "Product" msgstr "プロダクト" +#. module: purchase_stock_price_variance +#: model:ir.model,name:purchase_stock_price_variance.model_product_category +msgid "Product Category" +msgstr "プロダクトカテゴリ" + #. module: purchase_stock_price_variance #. odoo-python +#: code:addons/purchase_stock_price_variance/models/product_template.py:0 +#: code:addons/purchase_stock_price_variance/models/product_template.py:0 +#: code:addons/purchase_stock_price_variance/models/res_company.py:0 #: code:addons/purchase_stock_price_variance/models/res_company.py:0 #, python-format msgid "The threshold values cannot be negative." -msgstr "" +msgstr "しきい値は負の値にはできません。" #. module: purchase_stock_price_variance #: model:ir.model,name:purchase_stock_price_variance.model_stock_picking @@ -150,10 +196,13 @@ msgstr "運送" #. module: purchase_stock_price_variance #. odoo-python +#: code:addons/purchase_stock_price_variance/models/product_category.py:0 +#: code:addons/purchase_stock_price_variance/models/product_template.py:0 +#: code:addons/purchase_stock_price_variance/models/stock_picking.py:0 #: code:addons/purchase_stock_price_variance/models/stock_picking.py:0 #, python-format msgid "" "You do not have permission to modify the 'Bypass Price Variance Check' " "field. Please contact an administrator or a user with the appropriate " "permissions." -msgstr "" +msgstr "「価格差異チェックをバイパス」のフィールドを変更する権限がありません。管理者または適切な権限を持つユーザーにお問い合わせください。" diff --git a/purchase_stock_price_variance/models/res_company.py b/purchase_stock_price_variance/models/res_company.py index f8557230..39d4d360 100644 --- a/purchase_stock_price_variance/models/res_company.py +++ b/purchase_stock_price_variance/models/res_company.py @@ -11,13 +11,13 @@ class ResCompany(models.Model): enable_price_variance_error = fields.Boolean() price_variance_threshold_percent = fields.Float( help="Maximum variance (in percent) allowable between the product's standard price" - " and purchase receipt unit price." + " and purchase receipt unit price. " "Setting this to zero means this threshold will not be checked." ) price_variance_threshold_amount = fields.Monetary( help="Maximum allowable variance (in monetary amount, based on company currency)" - " between the product's standard price and the purchase receipt unit price." - "Setting this to zero means this threshold will not be checked." + " between the product's standard price and the purchase receipt unit price. " + "Setting this to zero means this threshold will not be checked.", ) @api.constrains( From 3ab992ed1a79c21d3de208f61bda2dede350af00 Mon Sep 17 00:00:00 2001 From: Aungkokolin1997 Date: Wed, 12 Mar 2025 01:55:06 +0000 Subject: [PATCH 3/4] reflect oca changes --- purchase_stock_price_variance/README.rst | 6 +++--- purchase_stock_price_variance/models/res_company.py | 6 +++--- purchase_stock_price_variance/readme/CONFIGURE.md | 6 +++--- .../security/purchase_stock_price_variance_security.xml | 5 ++++- .../static/description/index.html | 6 +++--- .../tests/test_purchase_stock_price_variance.py | 8 +++----- 6 files changed, 19 insertions(+), 18 deletions(-) diff --git a/purchase_stock_price_variance/README.rst b/purchase_stock_price_variance/README.rst index 7e59fe4c..38c17c29 100644 --- a/purchase_stock_price_variance/README.rst +++ b/purchase_stock_price_variance/README.rst @@ -42,7 +42,7 @@ the stock if needed. Configuration ============= -1. Navigate to Inventory > Configuration > Settings. +1. Navigate to *Inventory > Configuration > Settings*. 2. Find and enable the 'Enable Price Variance Error' option to activate this feature. An error will occur if the price difference exceeds the threshold when receiving the product. @@ -55,10 +55,10 @@ Configuration - **Price Variance Threshold Amount**: Default maximum variance for all products. -4. Go to Inventory > Configuration > Product Categories. +4. Go to *Inventory > Configuration > Product Categories*. 5. Enable **Bypass Price Variance Check** to skip the error check for the products under this category. -6. Go to Inventory > Products and open the product. +6. Go to *Inventory > Products* and open the product. 7. Click on the Inventory tab and configure the following fields. If the threshold value is set to 0, the threshold will refer to the global value. diff --git a/purchase_stock_price_variance/models/res_company.py b/purchase_stock_price_variance/models/res_company.py index 39d4d360..f8557230 100644 --- a/purchase_stock_price_variance/models/res_company.py +++ b/purchase_stock_price_variance/models/res_company.py @@ -11,13 +11,13 @@ class ResCompany(models.Model): enable_price_variance_error = fields.Boolean() price_variance_threshold_percent = fields.Float( help="Maximum variance (in percent) allowable between the product's standard price" - " and purchase receipt unit price. " + " and purchase receipt unit price." "Setting this to zero means this threshold will not be checked." ) price_variance_threshold_amount = fields.Monetary( help="Maximum allowable variance (in monetary amount, based on company currency)" - " between the product's standard price and the purchase receipt unit price. " - "Setting this to zero means this threshold will not be checked.", + " between the product's standard price and the purchase receipt unit price." + "Setting this to zero means this threshold will not be checked." ) @api.constrains( diff --git a/purchase_stock_price_variance/readme/CONFIGURE.md b/purchase_stock_price_variance/readme/CONFIGURE.md index f2c68947..49c979c5 100644 --- a/purchase_stock_price_variance/readme/CONFIGURE.md +++ b/purchase_stock_price_variance/readme/CONFIGURE.md @@ -1,13 +1,13 @@ -1. Navigate to Inventory > Configuration > Settings. +1. Navigate to *Inventory > Configuration > Settings*. 2. Find and enable the 'Enable Price Variance Error' option to activate this feature. An error will occur if the price difference exceeds the threshold when receiving the product. 3. Set the following global values to apply if no specific value is set at the product level. If the threshold value is set to 0, this threshold will not be checked. * **Price Variance Threshold Percent**: Default percentage variance for all products. * **Price Variance Threshold Amount**: Default maximum variance for all products. -4. Go to Inventory > Configuration > Product Categories. +4. Go to *Inventory > Configuration > Product Categories*. 5. Enable **Bypass Price Variance Check** to skip the error check for the products under this category. -6. Go to Inventory > Products and open the product. +6. Go to *Inventory > Products* and open the product. 7. Click on the Inventory tab and configure the following fields. If the threshold value is set to 0, the threshold will refer to the global value. * **Bypass Price Variance Check**: Enable this to skip the error check for this specific product. diff --git a/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml b/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml index eca7bb12..c424d39f 100644 --- a/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml +++ b/purchase_stock_price_variance/security/purchase_stock_price_variance_security.xml @@ -3,6 +3,9 @@ Manage Price Variance Check - + diff --git a/purchase_stock_price_variance/static/description/index.html b/purchase_stock_price_variance/static/description/index.html index cf498a55..db22ebe6 100644 --- a/purchase_stock_price_variance/static/description/index.html +++ b/purchase_stock_price_variance/static/description/index.html @@ -391,7 +391,7 @@

Purchase Stock Price Variance

Configuration

    -
  1. Navigate to Inventory > Configuration > Settings.
  2. +
  3. Navigate to Inventory > Configuration > Settings.
  4. Find and enable the ‘Enable Price Variance Error’ option to activate this feature. An error will occur if the price difference exceeds the threshold when receiving the product.
  5. @@ -404,10 +404,10 @@

    Configuration

    all products. -
  6. Go to Inventory > Configuration > Product Categories.
  7. +
  8. Go to Inventory > Configuration > Product Categories.
  9. Enable Bypass Price Variance Check to skip the error check for the products under this category.
  10. -
  11. Go to Inventory > Products and open the product.
  12. +
  13. Go to Inventory > Products and open the product.
  14. Click on the Inventory tab and configure the following fields. If the threshold value is set to 0, the threshold will refer to the global value.
      diff --git a/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py b/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py index a21de6a4..06347ec6 100644 --- a/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py +++ b/purchase_stock_price_variance/tests/test_purchase_stock_price_variance.py @@ -1,6 +1,7 @@ # Copyright 2025 Quartile (https://www.quartile.co) # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command from odoo.exceptions import UserError from odoo.tests.common import TransactionCase @@ -31,14 +32,12 @@ def create_purchase_order(self, price_unit=100): { "partner_id": self.supplier.id, "order_line": [ - ( - 0, - 0, + Command.create( { "product_id": self.product.product_variant_id.id, "product_qty": 1, "price_unit": price_unit, - }, + } ) ], } @@ -65,7 +64,6 @@ def test_01_normal_workflow_no_error(self): po = self.create_purchase_order() po.button_confirm() picking = po.picking_ids - self.assertTrue(picking) self.validate_picking(picking) self.check_chatter_message(picking, False) From 52e9b307cf6871b71857d603d50a289d041d2274 Mon Sep 17 00:00:00 2001 From: nobuQuartile Date: Wed, 12 Mar 2025 08:59:51 +0000 Subject: [PATCH 4/4] upd translation --- purchase_stock_price_variance/i18n/ja.po | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/purchase_stock_price_variance/i18n/ja.po b/purchase_stock_price_variance/i18n/ja.po index a8e1999b..bfd0b5b8 100644 --- a/purchase_stock_price_variance/i18n/ja.po +++ b/purchase_stock_price_variance/i18n/ja.po @@ -44,14 +44,14 @@ msgstr "価格差エラーを有効化" msgid "" "Enable the feature that triggers an error when receiving a product if\n" " the price difference exceeds the threshold." -msgstr "受領時に価格差がしきい値を超えた場合にエラーを発生させる機能を有効化します。" +msgstr "入荷時に価格差がしきい値を超えた場合にエラーを発生させる機能を有効化します。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_stock_picking__bypass_price_variance_check msgid "" "If enabled, no error is raised for price variance between the product's " "standard price and purchase receipt unit price." -msgstr "有効にすると、商品の標準価格と購買受領単価の間の価格差によるエラーは発生しません。" +msgstr "有効にすると、商品の標準価格と購買単価の間の価格差によるエラーは発生しません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_category__bypass_price_variance_check @@ -59,7 +59,7 @@ msgid "" "If enabled, the products under this category will not raise an error for " "price variance between the product's standard price and the purchase receipt" " unit price." -msgstr "有効にすると、このカテゴリ内の製品は、標準価格と購買受領単価の価格差によるエラーを発生させません。" +msgstr "有効にすると、このカテゴリ内の製品は、標準価格と購買単価の価格差によるエラーを発生させません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__bypass_price_variance_check @@ -67,7 +67,7 @@ msgstr "有効にすると、このカテゴリ内の製品は、標準価格と msgid "" "If enabled, this product will not raise an error for price variance between " "the product's standard price and the purchase receipt unit price." -msgstr "有効にすると、この製品は、標準価格と購買受領単価の価格差によるエラーを発生させません。" +msgstr "有効にすると、この製品は、標準価格と購買単価の価格差によるエラーを発生させません。" #. module: purchase_stock_price_variance #: model:res.groups,name:purchase_stock_price_variance.group_manage_price_variance_check @@ -82,7 +82,7 @@ msgid "" " unit price.\n" " Keeping it at zero means that this threshold will not be checked." msgstr "" -"製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。\n" +"製品の標準価格と購買単価の間で許容される最大の価格差(会社の通貨単位)。\n" " 0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance @@ -92,7 +92,7 @@ msgid "" "Maximum allowable variance (in monetary amount, based on company currency) " "between the product's standard price and the purchase receipt unit price. " "Setting this to zero means the threshold will refer to the global setting." -msgstr "製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このグローバル設定が利用されます。" +msgstr "製品の標準価格と購買単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このグローバル設定が利用されます。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_amount @@ -101,7 +101,7 @@ msgid "" "Maximum allowable variance (in monetary amount, based on company currency) " "between the product's standard price and the purchase receipt unit price. " "Setting this to zero means this threshold will not be checked." -msgstr "製品の標準価格と購買受領単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このしきい値はチェックされません。" +msgstr "製品の標準価格と購買単価の間で許容される最大の価格差(会社の通貨単位)。0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance #: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_stock_config_settings @@ -109,7 +109,7 @@ msgid "" "Maximum variance (in percent) allowable between the product's standard\n" " price and purchase receipt unit price.\n" " Keeping it at zero means that this threshold will not be checked." -msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" +msgstr "製品の標準価格に対する購買単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_product_product__price_variance_threshold_percent @@ -118,7 +118,7 @@ msgid "" "Maximum variance (in percent) allowable between the product's standard price" " and purchase receipt unit price. Setting this to zero means the threshold " "will refer to the global setting." -msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0 に設定すると、このグローバル設定が利用されます。" +msgstr "製品の標準価格に対する購買単価の許容される最大差異(パーセント)。0 に設定すると、このグローバル設定が利用されます。" #. module: purchase_stock_price_variance #: model:ir.model.fields,help:purchase_stock_price_variance.field_res_company__price_variance_threshold_percent @@ -127,7 +127,7 @@ msgid "" "Maximum variance (in percent) allowable between the product's standard price" " and purchase receipt unit price.Setting this to zero means this threshold " "will not be checked." -msgstr "製品の標準価格に対する購買受領単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" +msgstr "製品の標準価格に対する購買単価の許容される最大差異(パーセント)。0に設定すると、このしきい値はチェックされません。" #. module: purchase_stock_price_variance #: model_terms:ir.ui.view,arch_db:purchase_stock_price_variance.view_template_property_form