diff --git a/.copier-answers.yml b/.copier-answers.yml index d2f75bfc61f..0ea1c8c996e 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,5 +1,5 @@ # Do NOT update manually; changes here will be overwritten by Copier -_commit: v1.29 +_commit: v1.35 _src_path: git+https://github.com/OCA/oca-addons-repo-template additional_ruff_rules: [] ci: GitHub diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000000..e0d56685a95 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +test-requirements.txt merge=union diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a06488079fe..529462e9bc0 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: makepot: "true" services: postgres: - image: postgres:12.0 + image: postgres:12 env: POSTGRES_USER: odoo POSTGRES_PASSWORD: odoo diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dfc161f8fab..fa1dcbe4e0c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -39,11 +39,11 @@ repos: language: fail files: '[a-zA-Z0-9_]*/i18n/en\.po$' - repo: https://github.com/sbidoul/whool - rev: v1.2 + rev: v1.3 hooks: - id: whool-init - repo: https://github.com/oca/maintainer-tools - rev: bf9ecb9938b6a5deca0ff3d870fbd3f33341fded + rev: b89f767503be6ab2b11e4f50a7557cb20066e667 hooks: # update the NOT INSTALLABLE ADDONS section above - id: oca-update-pre-commit-excluded-addons @@ -95,6 +95,7 @@ repos: additional_dependencies: - "eslint@9.12.0" - "eslint-plugin-jsdoc@50.3.1" + - "globals@16.0.0" - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.6.0 hooks: diff --git a/.pylintrc b/.pylintrc index 7c62b6d2edd..d103ffcd9a5 100644 --- a/.pylintrc +++ b/.pylintrc @@ -25,19 +25,25 @@ disable=all enable=anomalous-backslash-in-string, api-one-deprecated, api-one-multi-together, - assignment-from-none, - attribute-deprecated, class-camelcase, - dangerous-default-value, dangerous-view-replace-wo-priority, - development-status-allowed, duplicate-id-csv, - duplicate-key, duplicate-xml-fields, duplicate-xml-record-id, eval-referenced, - eval-used, incoherent-interpreter-exec-perm, + openerp-exception-warning, + redundant-modulename-xml, + relative-import, + rst-syntax-error, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + assignment-from-none, + attribute-deprecated, + dangerous-default-value, + development-status-allowed, + duplicate-key, + eval-used, license-allowed, manifest-author-string, manifest-deprecated-key, @@ -48,56 +54,50 @@ enable=anomalous-backslash-in-string, method-inverse, method-required-super, method-search, - openerp-exception-warning, pointless-statement, pointless-string-statement, print-used, redundant-keyword-arg, - redundant-modulename-xml, reimported, - relative-import, return-in-init, - rst-syntax-error, sql-injection, too-few-format-args, translation-field, translation-required, unreachable, use-vim-comment, - wrong-tabs-instead-of-spaces, - xml-syntax-error, - attribute-string-redundant, character-not-valid-in-resource-link, - consider-merging-classes-inherited, - context-overridden, create-user-wo-reset-password, dangerous-filter-wo-user, dangerous-qweb-replace-wo-priority, deprecated-data-xml-node, deprecated-openerp-xml-node, duplicate-po-message-definition, - except-pass, file-not-used, + missing-newline-extrafiles, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + str-format-used, + unnecessary-utf8-coding-comment, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + attribute-string-redundant, + consider-merging-classes-inherited, + context-overridden, + except-pass, invalid-commit, manifest-maintainers-list, - missing-newline-extrafiles, missing-readme, missing-return, odoo-addons-relative-import, - old-api7-method-defined, - po-msgstr-variables, - po-syntax-error, renamed-field-parameter, resource-not-exist, - str-format-used, test-folder-imported, translation-contains-variable, translation-positional-used, - unnecessary-utf8-coding-comment, website-manifest-key-not-valid-uri, - xml-attribute-translatable, - xml-deprecated-qweb-directive, - xml-deprecated-tree-attribute, external-request-timeout, # messages that do not cause the lint step to fail consider-merging-classes-inherited, @@ -114,7 +114,8 @@ enable=anomalous-backslash-in-string, old-api7-method-defined, redefined-builtin, too-complex, - unnecessary-utf8-coding-comment + unnecessary-utf8-coding-comment, + manifest-external-assets [REPORTS] diff --git a/.pylintrc-mandatory b/.pylintrc-mandatory index 018fd61cdd7..73674c04d42 100644 --- a/.pylintrc-mandatory +++ b/.pylintrc-mandatory @@ -17,19 +17,25 @@ disable=all enable=anomalous-backslash-in-string, api-one-deprecated, api-one-multi-together, - assignment-from-none, - attribute-deprecated, class-camelcase, - dangerous-default-value, dangerous-view-replace-wo-priority, - development-status-allowed, duplicate-id-csv, - duplicate-key, duplicate-xml-fields, duplicate-xml-record-id, eval-referenced, - eval-used, incoherent-interpreter-exec-perm, + openerp-exception-warning, + redundant-modulename-xml, + relative-import, + rst-syntax-error, + wrong-tabs-instead-of-spaces, + xml-syntax-error, + assignment-from-none, + attribute-deprecated, + dangerous-default-value, + development-status-allowed, + duplicate-key, + eval-used, license-allowed, manifest-author-string, manifest-deprecated-key, @@ -40,56 +46,50 @@ enable=anomalous-backslash-in-string, method-inverse, method-required-super, method-search, - openerp-exception-warning, pointless-statement, pointless-string-statement, print-used, redundant-keyword-arg, - redundant-modulename-xml, reimported, - relative-import, return-in-init, - rst-syntax-error, sql-injection, too-few-format-args, translation-field, translation-required, unreachable, use-vim-comment, - wrong-tabs-instead-of-spaces, - xml-syntax-error, - attribute-string-redundant, character-not-valid-in-resource-link, - consider-merging-classes-inherited, - context-overridden, create-user-wo-reset-password, dangerous-filter-wo-user, dangerous-qweb-replace-wo-priority, deprecated-data-xml-node, deprecated-openerp-xml-node, duplicate-po-message-definition, - except-pass, file-not-used, + missing-newline-extrafiles, + old-api7-method-defined, + po-msgstr-variables, + po-syntax-error, + str-format-used, + unnecessary-utf8-coding-comment, + xml-attribute-translatable, + xml-deprecated-qweb-directive, + xml-deprecated-tree-attribute, + attribute-string-redundant, + consider-merging-classes-inherited, + context-overridden, + except-pass, invalid-commit, manifest-maintainers-list, - missing-newline-extrafiles, missing-readme, missing-return, odoo-addons-relative-import, - old-api7-method-defined, - po-msgstr-variables, - po-syntax-error, renamed-field-parameter, resource-not-exist, - str-format-used, test-folder-imported, translation-contains-variable, translation-positional-used, - unnecessary-utf8-coding-comment, website-manifest-key-not-valid-uri, - xml-attribute-translatable, - xml-deprecated-qweb-directive, - xml-deprecated-tree-attribute, external-request-timeout [REPORTS] diff --git a/README.md b/README.md index 87c79704de6..f074c8c0def 100644 --- a/README.md +++ b/README.md @@ -21,13 +21,14 @@ Available addons ---------------- addon | version | maintainers | summary --- | --- | --- | --- +[product_abc_classification](product_abc_classification/) | 18.0.1.0.0 | | ABC classification for sales and warehouse management [product_assortment](product_assortment/) | 18.0.1.0.1 | | Adds the ability to manage products assortment [product_attachment_zipped_download](product_attachment_zipped_download/) | 18.0.1.0.0 | victoralmau | Product Attachment Zipped Download [product_attribute_archive](product_attribute_archive/) | 18.0.1.0.0 | | Add an active field on product attributes [product_attribute_value_avoid_auto_fill](product_attribute_value_avoid_auto_fill/) | 18.0.1.0.0 | | Add option allow filling automatically the values [product_attribute_value_menu](product_attribute_value_menu/) | 18.0.1.0.0 | | Product attributes values tree and form. Import attribute values. [product_barcode_required](product_barcode_required/) | 18.0.1.0.0 | simahawk | Make product barcode required when enabled -[product_catalog_stock](product_catalog_stock/) | 18.0.1.0.0 | | Use the product catalog on stock pickings +[product_catalog_stock](product_catalog_stock/) | 18.0.1.0.1 | | Use the product catalog on stock pickings [product_category_active](product_category_active/) | 18.0.1.0.0 | | Add option to archive product categories [product_category_code](product_category_code/) | 18.0.1.0.0 | rousseldenis | Allows to define a code on product categories [product_category_name_translatable](product_category_name_translatable/) | 18.0.1.0.0 | | Translate Product Category Names @@ -35,12 +36,14 @@ addon | version | maintainers | summary [product_category_tag](product_category_tag/) | 18.0.1.0.0 | ppyczko | Add tags to product categories [product_category_type](product_category_type/) | 18.0.1.0.0 | legalsylvain | Add Type field on Product Categories to distinguish between parent and final categories [product_category_uom](product_category_uom/) | 18.0.1.0.0 | | Define default product UoM at product category level +[product_code_mandatory](product_code_mandatory/) | 18.0.1.0.0 | | Set Product Internal Reference as a required field [product_code_unique](product_code_unique/) | 18.0.1.0.0 | | Set Product Internal Reference as Unique [product_company_default](product_company_default/) | 18.0.1.0.0 | | Product Company Default [product_cost_security](product_cost_security/) | 18.0.1.0.0 | sergio-teruel rafaelbn yajo | Product cost security restriction view -[product_customerinfo](product_customerinfo/) | 18.0.1.1.0 | luisg123v | Allows to define prices for customers in the products +[product_customerinfo](product_customerinfo/) | 18.0.1.2.0 | luisg123v | Allows to define prices for customers in the products [product_dimension](product_dimension/) | 18.0.1.0.0 | | Product Dimension [product_drained_weight](product_drained_weight/) | 18.0.1.0.0 | | Add 'Drained Weight' on product models +[product_form_pricelist](product_form_pricelist/) | 18.0.1.0.0 | | Show/edit pricelist in product form [product_get_price_helper](product_get_price_helper/) | 18.0.1.1.0 | | This module provides a helper function to compute product prices. [product_list_price_from_pricelist](product_list_price_from_pricelist/) | 18.0.1.0.0 | carlos-lopez-tecnativa | Compute product sales price from a pricelist [product_logistics_uom](product_logistics_uom/) | 18.0.1.1.0 | hparfr | Configure product weights and volume UoM @@ -49,31 +52,37 @@ addon | version | maintainers | summary [product_manufacturer](product_manufacturer/) | 18.0.1.0.0 | | Adds manufacturers and attributes on the product view. [product_medical](product_medical/) | 18.0.1.0.0 | | Base structure to handle medical products [product_multi_category](product_multi_category/) | 18.0.1.0.0 | | Product - Many Categories +[product_multi_price](product_multi_price/) | 18.0.1.0.2 | | Product Multi Price [product_net_weight](product_net_weight/) | 18.0.1.0.0 | legalsylvain | Add 'Net Weight' on product models [product_origin](product_origin/) | 18.0.1.0.0 | rousseldenis legalsylvain | Adds the origin of the product +[product_packaging_archive](product_packaging_archive/) | 18.0.1.0.0 | | Add an active field on product packaging [product_packaging_calculator](product_packaging_calculator/) | 18.0.1.0.0 | | Compute product quantity to pick by packaging [product_packaging_calculator_packaging_level](product_packaging_calculator_packaging_level/) | 18.0.1.0.0 | | Glue module for packaging level [product_packaging_dimension](product_packaging_dimension/) | 18.0.1.0.0 | | Manage packaging dimensions and weight -[product_packaging_level](product_packaging_level/) | 18.0.1.0.0 | | This module binds a product packaging to a packaging level +[product_packaging_level](product_packaging_level/) | 18.0.1.1.0 | | This module binds a product packaging to a packaging level [product_packaging_level_salable](product_packaging_level_salable/) | 18.0.1.0.1 | | Product Packaging level salable [product_packaging_level_vendor](product_packaging_level_vendor/) | 18.0.1.0.0 | | Allows to mark a packaging level as vendor specific [product_packaging_unit_price_calculator](product_packaging_unit_price_calculator/) | 18.0.1.0.0 | | Wizard to calculate a unit price from a packaging price [product_pricelist_alternative](product_pricelist_alternative/) | 18.0.1.0.0 | | Calculate product price based on alternative pricelists [product_pricelist_by_contact](product_pricelist_by_contact/) | 18.0.1.0.0 | | Product Pricelist Per Contact -[product_pricelist_direct_print](product_pricelist_direct_print/) | 18.0.1.0.0 | legalsylvain | Print price list from menu option, product templates, products variants or price lists +[product_pricelist_direct_print](product_pricelist_direct_print/) | 18.0.1.0.1 | legalsylvain | Print price list from menu option, product templates, products variants or price lists [product_pricelist_direct_print_company_group](product_pricelist_direct_print_company_group/) | 18.0.1.0.0 | | Print Pricelist items using the company group model [product_pricelist_direct_print_website_sale](product_pricelist_direct_print_website_sale/) | 18.0.1.0.0 | CarlosRoca13 | Extend Product Pricelist Direct Print for filter by public categories -[product_pricelist_direct_print_xlsx](product_pricelist_direct_print_xlsx/) | 18.0.1.0.0 | | Print price list in XLSX format +[product_pricelist_direct_print_xlsx](product_pricelist_direct_print_xlsx/) | 18.0.1.0.2 | | Print price list in XLSX format [product_pricelist_fixed_currency_rate](product_pricelist_fixed_currency_rate/) | 18.0.1.0.0 | LoisRForgeFlow kobros-tech | Set a fixed currency rate between pricelists +[product_pricelist_item_list_view](product_pricelist_item_list_view/) | 18.0.1.0.0 | LoisRForgeFlow | View and search the list of pricelist items +[product_pricelist_margin](product_pricelist_margin/) | 18.0.1.0.0 | | This module shows the product's cost and margin from the pricelists. [product_pricelist_revision](product_pricelist_revision/) | 18.0.1.0.0 | | Product Pricelist Revision [product_pricelist_supplierinfo](product_pricelist_supplierinfo/) | 18.0.1.1.0 | luisg123v | Allows to create priceslists based on supplier info -[product_print_category](product_print_category/) | 18.0.1.0.0 | legalsylvain | Define print categories for products and automate products print, when data has changed +[product_print_category](product_print_category/) | 18.0.1.0.1 | legalsylvain | Define print categories for products and automate products print, when data has changed [product_product_template_link](product_product_template_link/) | 18.0.1.0.0 | | Adds a button in product to view the template [product_route_mto](product_route_mto/) | 18.0.1.0.0 | jbaudoux | This module allows to compute if a product is an 'MTO' one from its configured routes [product_sale_manufactured_for](product_sale_manufactured_for/) | 18.0.1.0.0 | | Allows to indicate in products that they were made specifically for some customers. -[product_secondary_unit](product_secondary_unit/) | 18.0.1.0.1 | sergio-teruel | Set a secondary unit per product -[product_sequence](product_sequence/) | 18.0.1.0.0 | | Product Sequence +[product_sale_team](product_sale_team/) | 18.0.1.0.0 | | Sale Team for products +[product_secondary_unit](product_secondary_unit/) | 18.0.1.1.0 | sergio-teruel | Set a secondary unit per product +[product_sequence](product_sequence/) | 18.0.1.0.1 | | Product Sequence [product_set](product_set/) | 18.0.1.2.1 | | Product set +[product_simple_seasonality](product_simple_seasonality/) | 18.0.1.0.0 | bealdav kevinkhao | Product seasonality [product_state](product_state/) | 18.0.1.0.0 | emagdalenaC2i | Module introducing a state field on product template [product_state_sale](product_state_sale/) | 18.0.1.0.0 | | This module add the use of Product State in Sale [product_state_stock_base](product_state_stock_base/) | 18.0.1.0.0 | | This module add the use of Product State in Stock @@ -88,7 +97,8 @@ addon | version | maintainers | summary [product_tags_code](product_tags_code/) | 18.0.1.0.0 | | This addon allow to add code on products tags [product_total_weight_from_packaging](product_total_weight_from_packaging/) | 18.0.1.0.0 | | Compute estimated weight based on product's packaging weights [product_uom_updatable](product_uom_updatable/) | 18.0.1.0.0 | | allows products uom to be modified after be used in a stock picking if the product uom is of the same category -[product_variant_route_mto](product_variant_route_mto/) | 18.0.1.0.0 | mmequignon jbaudoux | Allow to individually set variants as MTO +[product_usability](product_usability/) | 18.0.1.0.0 | legalsylvain | Adds missing menu entries for Product module and adds extra groups to fine-tune access rights +[product_variant_route_mto](product_variant_route_mto/) | 18.0.1.0.1 | mmequignon jbaudoux | Allow to individually set variants as MTO [purchase_product_template_tags](purchase_product_template_tags/) | 18.0.1.0.0 | ivantodorovich | Show product tags menu in Purchase app [sale_product_template_tags](sale_product_template_tags/) | 18.0.1.0.0 | ivantodorovich | Show product tags menu in Sale app [stock_lot_production_date](stock_lot_production_date/) | 18.0.1.0.0 | atchuthan sebalix | Stock Lot Production Date diff --git a/eslint.config.cjs b/eslint.config.cjs index 0d5731f89a8..dd0cbe0aef0 100644 --- a/eslint.config.cjs +++ b/eslint.config.cjs @@ -1,3 +1,4 @@ +var globals = require('globals'); jsdoc = require("eslint-plugin-jsdoc"); const config = [{ @@ -16,6 +17,8 @@ const config = [{ openerp: "readonly", owl: "readonly", luxon: "readonly", + QUnit: "readonly", + ...globals.browser, }, ecmaVersion: 2024, @@ -191,7 +194,7 @@ const config = [{ }, }, { - files: ["**/*.esm.js"], + files: ["**/*.esm.js", "**/*test.js"], languageOptions: { ecmaVersion: 2024, diff --git a/product_abc_classification/README.rst b/product_abc_classification/README.rst new file mode 100644 index 00000000000..cc67bd9ddd4 --- /dev/null +++ b/product_abc_classification/README.rst @@ -0,0 +1,119 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================== +Product Abc Classification +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:f602d3cbe4b034e608e4a5b554b3532e87e682d94cb1ee8ba499905258e348c3 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_abc_classification + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_abc_classification + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This modules provides the bases to build ABC analysis (or ABC +classification) addons. These classification are used by inventory +management teams to help identify the most important products in their +portfolio and ensure they prioritize managing them above those less +valuable. + +Managers will create a profile with several levels (percentages) and +then the profiled products will automatically get a corresponding level +using the ABC classification. + +The addon *product_abc_classification_sale_stock* defines a computation +profile based on the number of sale order line delivered by product. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +To use this module, you need to: + +#. Go to Inventory menu, then to Configuration/Products/ABC +Classification Profile and create a profile with levels, knowing that +the sum of all levels in the profile should sum 100 and all the levels +should be different. + +#. Later you should go to product categories or product variants, and +assign them a profile. Then the cron classification will proceed to +assign to these products one of the profile's levels. + +NOTE: If you profile (or unprofile) a product category, then all its +child categories and products will be profiled (or unprofiled). + +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 +------- + +* ACSONE SA/NV +* ForgeFlow + +Contributors +------------ + +- Miquel Raïch +- Lindsay Marion +- Laurent Mignon +- Denis Roussel +- Hoang Diep + +Other credits +------------- + +The migration of this module from 17.0 to 18.0 was financially supported +by Camptocamp + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_abc_classification/__init__.py b/product_abc_classification/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_abc_classification/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_abc_classification/__manifest__.py b/product_abc_classification/__manifest__.py new file mode 100644 index 00000000000..e4a4ea074ab --- /dev/null +++ b/product_abc_classification/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2020 ForgeFlow +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Product Abc Classification", + "summary": """ + ABC classification for sales and warehouse management""", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV, ForgeFlow, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "depends": ["product", "stock"], + "data": [ + "views/abc_classification_product_level.xml", + "views/abc_classification_profile.xml", + "views/product_template.xml", + "views/product_product.xml", + "views/product_category.xml", + "security/ir.model.access.csv", + "data/ir_cron.xml", + ], +} diff --git a/product_abc_classification/data/ir_cron.xml b/product_abc_classification/data/ir_cron.xml new file mode 100644 index 00000000000..a17da478cc4 --- /dev/null +++ b/product_abc_classification/data/ir_cron.xml @@ -0,0 +1,12 @@ + + + + Perform the product ABC Classification + + 1 + months + + model._cron_compute_abc_classification() + code + + diff --git a/product_abc_classification/i18n/es.po b/product_abc_classification/i18n/es.po new file mode 100644 index 00000000000..564cf2df8dd --- /dev/null +++ b/product_abc_classification/i18n/es.po @@ -0,0 +1,465 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_abc_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-12 15:36+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: none\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage +msgid "% Indicator" +msgstr "% Indicador" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage_products +msgid "% Products" +msgstr "% Productos" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.product_template_form_view +msgid "ABC Classification" +msgstr "Clasificación ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_level +msgid "ABC Classification Level" +msgstr "Nivel de clasificación ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "ABC Classification Product Level" +msgstr "Clasificación ABC Nivel de producto" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_profile_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_profile_config_stock +msgid "ABC Classification profiles" +msgstr "Perfiles de clasificación ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "ABC Profile" +msgstr "Perfil ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_product_level +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_product_level_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_product_level_ids +msgid "Abc Classification Product Level" +msgstr "Clasificación Abc Nivel de producto" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_profile +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__allowed_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_profile_ids +msgid "Abc Classification Profile" +msgstr "Perfil de clasificación Abc" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Abc classification" +msgstr "Clasificación Abc" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "Action Needed" +msgstr "Necesita Acción" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Additional Information" +msgstr "Información Adicional" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_attachment_count +msgid "Attachment Count" +msgstr "Recuento de Archivos Adjuntos" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "Auto Apply Computed Value" +msgstr "Aplicar automáticamente el valor calculado" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "" +"Check this if you want to apply the computed level on each product that has " +"this profile." +msgstr "" +"Marque esta casilla si desea aplicar el nivel calculado a cada producto que " +"tenga este perfil." + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_level__name +msgid "Classification A, B or C" +msgstr "Clasificación A, B o C" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__level_id +msgid "Classification level" +msgstr "Nivel de clasificación" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "Classification level is mandatory" +msgstr "El nivel de clasificación es obligatorio" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Classification not in sync with computed" +msgstr "Clasificación no sincronizada con el cálculo" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Computation" +msgstr "Cómputo" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__computed_level_id +msgid "Computed classification level" +msgstr "Nivel de clasificación computado" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "Computed level differs from the specified level" +msgstr "El nivel computado difiere del especificado" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Computed level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"El nivel calculado debe pertenecer al mismo perfil de clasificación que el " +"del producto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_date +msgid "Created on" +msgstr "Creado el" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__display_name +msgid "Display Name" +msgstr "Mostrar Nombre" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_follower_ids +msgid "Followers" +msgstr "Seguidores" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguidores/as (Socios)" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Group By" +msgstr "Agrupar Por" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__has_message +msgid "Has Message" +msgstr "Tiene mensaje" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__id +msgid "ID" +msgstr "ID (identificación)" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__flag +msgid "" +"If True, this means that the manual classification is different from the " +"computed one" +msgstr "" +"Si es True, significa que la clasificación manual es diferente de la " +"calculada" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Si está marcada, nuevos mensajes requieren su atención." + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "si está marcada, algunos mensajes tienen un error de entrega." + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_is_follower +msgid "Is Follower" +msgstr "Es Seguidor/a" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile____last_update +msgid "Last Modified on" +msgstr "Última Modificación el" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_uid +msgid "Last Updated by" +msgstr "Última actualización por" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_date +msgid "Last Updated on" +msgstr "Última Actualización el" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__level_ids +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Level" +msgstr "Nivel" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_level_name_uniq +#, python-format +msgid "Level name must be unique by profile" +msgstr "El nombre del nivel debe ser único por perfil" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Levels" +msgstr "Niveles" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_main_attachment_id +msgid "Main Attachment" +msgstr "Adjunto Principal" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__manual_level_id +msgid "Manual classification level" +msgstr "Nivel de clasificación manual" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Manual level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"El nivel manual debe pertenecer al mismo perfil de clasificación que el " +"nivel de producto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "Message Delivery error" +msgstr "Error en entrega de mensaje" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_ids +msgid "Messages" +msgstr "Mensajes" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__name +msgid "Name" +msgstr "Nombre" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of Actions" +msgstr "Número de Acciones" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of errors" +msgstr "Número de errores" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Número de mensajes que requieren una acción" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Número de mensajes con error de entrega" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_product_level_product_level_uniq +#, python-format +msgid "Only one level by profile by product allowed" +msgstr "Sólo se permite un nivel por perfil y producto" + +#. module: product_abc_classification +#: model:ir.actions.server,name:product_abc_classification.ir_cron_product_abc_classification_ir_actions_server +#: model:ir.cron,cron_name:product_abc_classification.ir_cron_product_abc_classification +msgid "Perform the product ABC Classification" +msgstr "Realizar la Clasificación ABC del producto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__period +msgid "Period on which to compute the classification (Days)" +msgstr "Periodo sobre el que se computa la clasificación (Días)" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_template +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_id +msgid "Product" +msgstr "Producto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_count +msgid "Product Count" +msgstr "Recuento de productos" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_product +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_variant_ids +msgid "Product Variant" +msgstr "Variante de producto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_tmpl_id +msgid "Product template" +msgstr "Plantilla Producto" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Products" +msgstr "Productos" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_product_level_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_product_level_config_stock +msgid "Products ABC Classification" +msgstr "Clasificación ABC de productos" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__profile_id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_id +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Profile" +msgstr "Perfil" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Profile Information" +msgstr "Información del perfil" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_profile_name_uniq +#, python-format +msgid "Profile name must be unique" +msgstr "El nombre del perfil debe ser único" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage cannot be greater than 100." +msgstr "El porcentaje no puede ser superior a 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products cannot be greater than 100." +msgstr "El porcentaje de productos no puede ser superior a 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products should be a positive number." +msgstr "El porcentaje de productos debe ser un número positivo." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage should be a positive number." +msgstr "El porcentaje debe ser un número positivo." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The percentages of the levels must be unique." +msgstr "Los porcentajes de los niveles deben ser únicos." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the percentages of the levels should be 100." +msgstr "La suma de los porcentajes de los niveles debe ser 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the products percentages of the levels should be 100." +msgstr "" +"La suma de los porcentajes de los productos de los niveles debe ser 100." + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_type +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__profile_type +msgid "Type of ABC classification" +msgstr "Tipo de clasificación ABC" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website Messages" +msgstr "Mensajes de la Página web" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website communication history" +msgstr "Historial de la comunicación en la web" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "e.g. Sale Profile" +msgstr "p. ej. Perfil de venta" + +#~ msgid "SMS Delivery error" +#~ msgstr "Error en la entrega del SMS" diff --git a/product_abc_classification/i18n/fr.po b/product_abc_classification/i18n/fr.po new file mode 100644 index 00000000000..55923a743ee --- /dev/null +++ b/product_abc_classification/i18n/fr.po @@ -0,0 +1,487 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_abc_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 10.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2021-02-15 16:46+0000\n" +"PO-Revision-Date: 2021-02-15 16:46+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage +msgid "% Indicator" +msgstr "% KPI" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage_products +msgid "% Products" +msgstr "% Articles" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.product_template_form_view +msgid "ABC Classification" +msgstr "Classification ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_level +#, fuzzy +msgid "ABC Classification Level" +msgstr "Classe / Niveau" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "ABC Classification Product Level" +msgstr "Niveau de classification ABC des articles" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_profile_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_profile_config_stock +msgid "ABC Classification profiles" +msgstr "Profils de classification ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "ABC Profile" +msgstr "Profil ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_product_level +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_product_level_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_product_level_ids +msgid "Abc Classification Product Level" +msgstr "Niveau de classification" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_profile +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__allowed_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_profile_ids +msgid "Abc Classification Profile" +msgstr "Profil de classification ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Abc classification" +msgstr "Classification ABC" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Additional Information" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +#, fuzzy +msgid "Auto Apply Computed Value" +msgstr "Appliquer automatiquement la classification calculée" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "" +"Check this if you want to apply the computed level on each product that has " +"this profile." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_level__name +msgid "Classification A, B or C" +msgstr "Classification A, B ou C" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__level_id +msgid "Classification level" +msgstr "Classe / Niveau" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "Classification level is mandatory" +msgstr "La classe / niveau est obligatoire" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Classification not in sync with computed" +msgstr "Classes ABC manuelle et calculée divergentes" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Computation" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__computed_level_id +msgid "Computed classification level" +msgstr "Classe calculée" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "Computed level differs from the specified level" +msgstr "La class calculée diverge de la valeur spécifiée" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Computed level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"La classe calculée doit utiliser le même profil de classification que celui " +"défini sur le produit" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_uid +msgid "Created by" +msgstr "Créé par" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_date +msgid "Created on" +msgstr "Créé le" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__display_name +msgid "Display Name" +msgstr "Nom affiché" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Group By" +msgstr "Grouper par" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__has_message +msgid "Has Message" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__id +msgid "ID" +msgstr "ID" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__flag +msgid "" +"If True, this means that the manual classification is different from the " +"computed one" +msgstr "" +"Si coché, indique que la classe attribuée manuellement au produit diverge de " +"la classe calculée par le système." + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile____last_update +msgid "Last Modified on" +msgstr "Dernière modification le" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_uid +msgid "Last Updated by" +msgstr "Dernière mise à jour par" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_date +msgid "Last Updated on" +msgstr "Dernière mise à jour le" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__level_ids +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Level" +msgstr "Niveau" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_level_name_uniq +#, python-format +msgid "Level name must be unique by profile" +msgstr "Le nom de la classe doit être unique par profil" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +#, fuzzy +msgid "Levels" +msgstr "Niveau" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_main_attachment_id +msgid "Main Attachment" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__manual_level_id +msgid "Manual classification level" +msgstr "Classe (Valeur à utiliser)" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Manual level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"La classe à utiliser doit utiliser le même profil de classification que " +"celui défini sur le produit" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_ids +msgid "Messages" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__name +msgid "Name" +msgstr "Nom" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_product_level_product_level_uniq +#, python-format +msgid "Only one level by profile by product allowed" +msgstr "Une classe de classification ABC par profil et par produit autorisée." + +#. module: product_abc_classification +#: model:ir.actions.server,name:product_abc_classification.ir_cron_product_abc_classification_ir_actions_server +#: model:ir.cron,cron_name:product_abc_classification.ir_cron_product_abc_classification +#, fuzzy +msgid "Perform the product ABC Classification" +msgstr "Classification ABC des articles" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__period +msgid "Period on which to compute the classification (Days)" +msgstr "Période référence pour le calcul de la classification (Nbr jours)" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_template +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_id +msgid "Product" +msgstr "Article" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_count +#, fuzzy +msgid "Product Count" +msgstr "Article" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_product +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_variant_ids +#, fuzzy +msgid "Product Variant" +msgstr "Modèle de produit" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_tmpl_id +msgid "Product template" +msgstr "Modèle de produit" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +#, fuzzy +msgid "Products" +msgstr "Article" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_product_level_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_product_level_config_stock +msgid "Products ABC Classification" +msgstr "Classification ABC des articles" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__profile_id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_id +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Profile" +msgstr "Profil" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +#, fuzzy +msgid "Profile Information" +msgstr "Profil" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_profile_name_uniq +#, python-format +msgid "Profile name must be unique" +msgstr "Le nom du profil doit être unique" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage cannot be greater than 100." +msgstr "Le pourcentage ne peut pas dépasser 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products cannot be greater than 100." +msgstr "Le pourcentage d'articles' ne peut pas dépasser 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products should be a positive number." +msgstr "Le pourcentage d'articles' doit être un nombre positif." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage should be a positive number." +msgstr "Le pourcentage doit être un nombre positif." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The percentages of the levels must be unique." +msgstr "" +"Les valeurs de pourcentage des différentes classes doivent être uniques pour " +"un même profil." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the percentages of the levels should be 100." +msgstr "La somme des pourcentages ne doit pas dépasser 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the products percentages of the levels should be 100." +msgstr "La somme des pourcentages d'articles ne doit pas dépasser 100." + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_type +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__profile_type +msgid "Type of ABC classification" +msgstr "Type de classification ABC" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "e.g. Sale Profile" +msgstr "" + +#~ msgid "ABC Profiles" +#~ msgstr "Profils ABC" + +#~ msgid "Abc classification product level ids" +#~ msgstr "Classes ABC" + +#~ msgid "Abc classification profile ids" +#~ msgstr "Profils ABC" + +#~ msgid "Based on the count of delivered sale order line by product" +#~ msgstr "Basé sur le total des lignes de vente par article" + +#~ msgid "Level ids" +#~ msgstr "Classes" + +#~ msgid "abc.classification.level" +#~ msgstr "Classe de classification ABC" diff --git a/product_abc_classification/i18n/it.po b/product_abc_classification/i18n/it.po new file mode 100644 index 00000000000..d40d109c122 --- /dev/null +++ b/product_abc_classification/i18n/it.po @@ -0,0 +1,461 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_abc_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-10-29 18:37+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage +msgid "% Indicator" +msgstr "% indicatore" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage_products +msgid "% Products" +msgstr "% prodotti" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.product_template_form_view +msgid "ABC Classification" +msgstr "Classificazione ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_level +msgid "ABC Classification Level" +msgstr "Livello classificazione ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "ABC Classification Product Level" +msgstr "Livello prodotto classificazione ABC" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_profile_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_profile_config_stock +msgid "ABC Classification profiles" +msgstr "Profili classificazione ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "ABC Profile" +msgstr "Profilo ABC" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_product_level +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_product_level_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_product_level_ids +msgid "Abc Classification Product Level" +msgstr "Livello ABC classificazione prodotto" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_profile +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__allowed_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_profile_ids +msgid "Abc Classification Profile" +msgstr "Profilo classificazione ABC" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Abc classification" +msgstr "Classificazione ABC" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "Action Needed" +msgstr "Azione richiesta" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Additional Information" +msgstr "Informazioni supplementari" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_attachment_count +msgid "Attachment Count" +msgstr "Conteggio allegati" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "Auto Apply Computed Value" +msgstr "Applica automaticamente valore calcolato" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "" +"Check this if you want to apply the computed level on each product that has " +"this profile." +msgstr "" +"Selezionare se si vuole applicare il livello calcolato ad ogni prodotto che " +"ha questo profilo." + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_level__name +msgid "Classification A, B or C" +msgstr "Classificazione A, B o C" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__level_id +msgid "Classification level" +msgstr "Licello classificazione" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "Classification level is mandatory" +msgstr "Il livello classificazione è obbligatorio" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Classification not in sync with computed" +msgstr "Classificazione non sincronizzata con il calcolo" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Computation" +msgstr "Calcolo" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__computed_level_id +msgid "Computed classification level" +msgstr "Livello classificazione calcolato" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "Computed level differs from the specified level" +msgstr "Il livello calcolato è diverso dal livello indicato" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Computed level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"Il livello calcolato deve essere nello stesso profilo di classificazione " +"presente nel livello prodotto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_follower_ids +msgid "Followers" +msgstr "Seguito da" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_partner_ids +msgid "Followers (Partners)" +msgstr "Seguito da (partner)" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Group By" +msgstr "Raggruppa per" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__has_message +msgid "Has Message" +msgstr "Ha un messaggio" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__id +msgid "ID" +msgstr "ID" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__flag +msgid "" +"If True, this means that the manual classification is different from the " +"computed one" +msgstr "" +"Se vero, questo significa che la classificazione manuale è diversa da quella " +"calcolata" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "If checked, new messages require your attention." +msgstr "Se selezionata, nuovi messaggi richiedono attenzione." + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "Se selezionata, alcuni messaggi hanno un errore di consegna." + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_is_follower +msgid "Is Follower" +msgstr "Segue" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level____last_update +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__level_ids +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Level" +msgstr "Livello" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_level_name_uniq +#, python-format +msgid "Level name must be unique by profile" +msgstr "Il livello deve essere univoco per profilo" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Levels" +msgstr "Livelli" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_main_attachment_id +msgid "Main Attachment" +msgstr "Allegato principale" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__manual_level_id +msgid "Manual classification level" +msgstr "Livello classificazione manuale" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#, python-format +msgid "" +"Manual level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" +"Il livello manuale deve essere nello stesso profilo di classificazione " +"presente nel livello prodotto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "Message Delivery error" +msgstr "Errore di consegna messaggio" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_ids +msgid "Messages" +msgstr "Messaggi" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__name +msgid "Name" +msgstr "Nome" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of Actions" +msgstr "Numero di azioni" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of errors" +msgstr "Numero di errori" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "Numero di messaggi che richiedono un'azione" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "Numero di messaggi con errore di consegna" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_product_level_product_level_uniq +#, python-format +msgid "Only one level by profile by product allowed" +msgstr "Consentto solo un livello per profilo per prodotto" + +#. module: product_abc_classification +#: model:ir.actions.server,name:product_abc_classification.ir_cron_product_abc_classification_ir_actions_server +#: model:ir.cron,cron_name:product_abc_classification.ir_cron_product_abc_classification +msgid "Perform the product ABC Classification" +msgstr "Eseguire la classificazione ABC prodotto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__period +msgid "Period on which to compute the classification (Days)" +msgstr "Periodo nel quale calcolare la classificazione (giorni)" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_template +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_id +msgid "Product" +msgstr "Prodotto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_count +msgid "Product Count" +msgstr "Conteggio prodotti" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_product +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_variant_ids +msgid "Product Variant" +msgstr "Variante prodotto" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_tmpl_id +msgid "Product template" +msgstr "Modello prodotto" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Products" +msgstr "Prodotti" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_product_level_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_product_level_config_stock +msgid "Products ABC Classification" +msgstr "Classificazione ABC prodotti" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__profile_id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_id +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Profile" +msgstr "Profilo" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Profile Information" +msgstr "Informazioni profilo" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_profile_name_uniq +#, python-format +msgid "Profile name must be unique" +msgstr "Il nome profilo deve essere univoco" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage cannot be greater than 100." +msgstr "La percentuale non può essere superiore a 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products cannot be greater than 100." +msgstr "La percentuale di prodotti non può essere superiore a 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage of products should be a positive number." +msgstr "La percentuale di prodotti deve essere un numero positivo." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +#, python-format +msgid "The percentage should be a positive number." +msgstr "La percentuale deve essere un numero positivo." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The percentages of the levels must be unique." +msgstr "La percentuale dei livelli deve essere univoca." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the percentages of the levels should be 100." +msgstr "La somma delle percentuali dei livelli deve essere 100." + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +#, python-format +msgid "The sum of the products percentages of the levels should be 100." +msgstr "La somma delle percentuali dei prodotti dei livelli deve essere 100." + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_type +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__profile_type +msgid "Type of ABC classification" +msgstr "Tipo classificazione ABC" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website Messages" +msgstr "Messaggi sito web" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website communication history" +msgstr "Cronologia comunicazioni sito web" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "e.g. Sale Profile" +msgstr "es. Profilo vendite" diff --git a/product_abc_classification/i18n/product_abc_classification.pot b/product_abc_classification/i18n/product_abc_classification.pot new file mode 100644 index 00000000000..91a2cce0482 --- /dev/null +++ b/product_abc_classification/i18n/product_abc_classification.pot @@ -0,0 +1,451 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_abc_classification +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage +msgid "% Indicator" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__percentage_products +msgid "% Products" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +msgid "%s (copy)" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.view_product_category_form +msgid "-> Apply to Products" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.product_template_form_view +#: model_terms:ir.ui.view,arch_db:product_abc_classification.view_product_category_form +msgid "ABC Classification" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_level +msgid "ABC Classification Level" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "ABC Classification Product Level" +msgstr "" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_profile_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_profile_config_stock +msgid "ABC Classification profiles" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "ABC Profile" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_product_level +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_product_level_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_product_level_ids +msgid "Abc Classification Product Level" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_abc_classification_profile +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__allowed_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_category__abc_classification_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_profile_ids +#: model:ir.model.fields,field_description:product_abc_classification.field_product_template__abc_classification_profile_ids +msgid "Abc Classification Profile" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_product_product__abc_classification_profile_updatable_from_category +msgid "Abc Classification Profile Updatable From Category" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Abc classification" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "Action Needed" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Additional Information" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_attachment_count +msgid "Attachment Count" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "Auto Apply Computed Value" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_profile__auto_apply_computed_value +msgid "" +"Check this if you want to apply the computed level on each product that has " +"this profile." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_level__name +msgid "Classification A, B or C" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__level_id +msgid "Classification level" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +msgid "Classification level is mandatory" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Classification not in sync with computed" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Computation" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__computed_level_id +msgid "Computed classification level" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_form_view +msgid "Computed level differs from the specified level" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +msgid "" +"Computed level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_uid +msgid "Created by" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__create_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__create_date +msgid "Created on" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__display_name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__display_name +msgid "Display Name" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_follower_ids +msgid "Followers" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_partner_ids +msgid "Followers (Partners)" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Group By" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__has_message +msgid "Has Message" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__id +msgid "ID" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__flag +msgid "" +"If True, this means that the manual classification is different from the " +"computed one" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction +msgid "If checked, new messages require your attention." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "If checked, some messages have a delivery error." +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_is_follower +msgid "Is Follower" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_uid +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__write_date +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__level_ids +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Level" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_level_name_uniq +msgid "Level name must be unique by profile" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Levels" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__manual_level_id +msgid "Manual classification level" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_product_level.py:0 +msgid "" +"Manual level must be in the same classifiation profile as the one on the " +"product level" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error +msgid "Message Delivery error" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_ids +msgid "Messages" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__name +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__name +msgid "Name" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of Actions" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of errors" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_needaction_counter +msgid "Number of messages requiring action" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__message_has_error_counter +msgid "Number of messages with delivery error" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_product_level_product_level_uniq +msgid "Only one level by profile by product allowed" +msgstr "" + +#. module: product_abc_classification +#: model:ir.actions.server,name:product_abc_classification.ir_cron_product_abc_classification_ir_actions_server +msgid "Perform the product ABC Classification" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__period +msgid "Period on which to compute the classification (Days)" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_template +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_id +msgid "Product" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_category +msgid "Product Category" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_count +msgid "Product Count" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model,name:product_abc_classification.model_product_product +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__product_variant_ids +msgid "Product Variant" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__product_tmpl_id +msgid "Product template" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Products" +msgstr "" + +#. module: product_abc_classification +#: model:ir.actions.act_window,name:product_abc_classification.abc_classification_product_level_action +#: model:ir.ui.menu,name:product_abc_classification.menu_abc_classification_product_level_config_stock +msgid "Products ABC Classification" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_level__profile_id +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_id +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_product_level_search_view +msgid "Profile" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "Profile Information" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.constraint,message:product_abc_classification.constraint_abc_classification_profile_name_uniq +msgid "Profile name must be unique" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__rating_ids +msgid "Ratings" +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +msgid "The percentage cannot be greater than 100." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +msgid "The percentage of products cannot be greater than 100." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +msgid "The percentage of products should be a positive number." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_level.py:0 +msgid "The percentage should be a positive number." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +msgid "The percentages of the levels must be unique." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +msgid "The sum of the percentages of the levels should be 100." +msgstr "" + +#. module: product_abc_classification +#. odoo-python +#: code:addons/product_abc_classification/models/abc_classification_profile.py:0 +msgid "The sum of the products percentages of the levels should be 100." +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.view_product_category_form +msgid "This will apply to all products in the category" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__profile_type +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_profile__profile_type +msgid "Type of ABC classification" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,field_description:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website Messages" +msgstr "" + +#. module: product_abc_classification +#: model:ir.model.fields,help:product_abc_classification.field_abc_classification_product_level__website_message_ids +msgid "Website communication history" +msgstr "" + +#. module: product_abc_classification +#: model_terms:ir.ui.view,arch_db:product_abc_classification.abc_classification_profile_form_view +msgid "e.g. Sale Profile" +msgstr "" diff --git a/product_abc_classification/models/__init__.py b/product_abc_classification/models/__init__.py new file mode 100644 index 00000000000..bc793feeb5d --- /dev/null +++ b/product_abc_classification/models/__init__.py @@ -0,0 +1,6 @@ +from . import abc_classification_profile +from . import abc_classification_level +from . import product_category +from . import product_template +from . import product_product +from . import abc_classification_product_level diff --git a/product_abc_classification/models/abc_classification_level.py b/product_abc_classification/models/abc_classification_level.py new file mode 100644 index 00000000000..2189024d3d1 --- /dev/null +++ b/product_abc_classification/models/abc_classification_level.py @@ -0,0 +1,53 @@ +# Copyright 2020 ForgeFlow +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class AbcClassificationLevel(models.Model): + _name = "abc.classification.level" + _description = "ABC Classification Level" + _order = "percentage desc, id desc" + _rec_name = "name" + + percentage_products = fields.Float(default=0.0, required=True, string="% Products") + percentage = fields.Float(default=0.0, required=True, string="% Indicator") + profile_id = fields.Many2one("abc.classification.profile", ondelete="cascade") + + name = fields.Char(help="Classification A, B or C", required=True) + + _sql_constraints = [ + ( + "name_uniq", + "UNIQUE(profile_id, name)", + "Level name must be unique by profile", + ) + ] + + @api.constrains("percentage") + def _check_percentage(self): + for level in self: + if level.percentage > 100.0: + raise ValidationError( + self.env._("The percentage cannot be greater than 100.") + ) + if level.percentage <= 0.0: + raise ValidationError( + self.env._("The percentage should be a positive number.") + ) + + @api.constrains("percentage_products") + def _check_percentage_products(self): + for level in self: + if level.percentage_products > 100.0: + raise ValidationError( + self.env._("The percentage of products cannot be greater than 100.") + ) + if level.percentage_products <= 0.0: + raise ValidationError( + self.env._( + "The percentage of products should be a positive number." + ) + ) diff --git a/product_abc_classification/models/abc_classification_product_level.py b/product_abc_classification/models/abc_classification_product_level.py new file mode 100644 index 00000000000..505642afb2d --- /dev/null +++ b/product_abc_classification/models/abc_classification_product_level.py @@ -0,0 +1,176 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class AbcClassificationProductLevel(models.Model): + _name = "abc.classification.product.level" + _inherit = "mail.thread" + _description = "Abc Classification Product Level" + _rec_name = "level_id" + + manual_level_id = fields.Many2one( + "abc.classification.level", + string="Manual classification level", + tracking=True, + domain="[('profile_id', '=', profile_id)]", + ) + computed_level_id = fields.Many2one( + "abc.classification.level", + string="Computed classification level", + readonly=True, + ) + level_id = fields.Many2one( + "abc.classification.level", + string="Classification level", + compute="_compute_level_id", + store=True, + domain="[('profile_id', '=', profile_id)]", + ) + flag = fields.Boolean( + default=False, + compute="_compute_flag", + string="If True, this means that the manual classification is " + "different from the computed one", + store=True, + index=True, + ) + product_id = fields.Many2one( + "product.product", + string="Product", + index=True, + required=True, + ondelete="cascade", + ) + product_tmpl_id = fields.Many2one( + "product.template", + string="Product template", + index=True, + readonly=True, + ) + # percentage + profile_id = fields.Many2one( + "abc.classification.profile", + string="Profile", + required=True, + ) + profile_type = fields.Selection( + related="profile_id.profile_type", + readonly=True, + store=True, + ) + allowed_profile_ids = fields.Many2many( + comodel_name="abc.classification.profile", + related="product_id.abc_classification_profile_ids", + ) + + _sql_constraints = [ + ( + "product_level_uniq", + "UNIQUE(profile_id, product_id)", + "Only one level by profile by product allowed", + ) + ] + + @api.constrains("computed_level_id", "manual_level_id", "product_id") + def _check_level(self): + for rec in self: + if not rec.computed_level_id and not rec.manual_level_id: + raise ValidationError(self.env._("Classification level is mandatory")) + if ( + rec.computed_level_id + and rec.computed_level_id.profile_id != rec.profile_id + ): + raise ValidationError( + self.env._( + "Computed level must be in the same classifiation " + "profile as the one on the product level" + ) + ) + if rec.manual_level_id and rec.manual_level_id.profile_id != rec.profile_id: + raise ValidationError( + self.env._( + "Manual level must be in the same classifiation " + "profile as the one on the product level" + ) + ) + + @api.onchange("product_tmpl_id") + def _onchange_product_tmpl_id(self): + for rec in self.filtered( + lambda a: a.product_tmpl_id.product_variant_count == 1 + ): + rec.product_id = rec.product_tmpl_id.product_variant_id + + @api.depends("level_id", "profile_id") + def _compute_display_name(self): + for record in self: + record.display_name = f"{record.profile_id.name}: {record.level_id.name}" + + @api.depends("manual_level_id", "computed_level_id") + def _compute_level_id(self): + for rec in self: + if rec.manual_level_id: + rec.level_id = rec.manual_level_id + else: + rec.level_id = rec.computed_level_id + + @api.depends("manual_level_id", "computed_level_id") + def _compute_flag(self): + for rec in self: + rec.flag = ( + rec.computed_level_id and rec.manual_level_id != rec.computed_level_id + ) + + @api.model_create_multi + def create(self, vals_list): + for vals in vals_list: + if "manual_level_id" not in vals and "computed_level_id" in vals: + # at creation the manual level is set to the same value as the + # computed one + vals["manual_level_id"] = vals["computed_level_id"] + + if "profile_id" in vals: + profile = self.env["abc.classification.profile"].browse( + vals["profile_id"] + ) + if profile.auto_apply_computed_value and "computed_level_id" in vals: + vals["manual_level_id"] = vals["computed_level_id"] + return super().create(vals_list) + + def write(self, vals): + """ + We apply the manual level to the product level if + computed level is modified and only for profiles with + auto_apply_computed_value = =True + """ + values = vals.copy() + new_self = self + if "computed_level_id" in values: + profile_obj = self.env["abc.classification.profile"] + target_profile_id = ( + profile_obj.browse(values["profile_id"]).filtered( + "auto_apply_computed_value" + ) + if "profile_id" in values + else profile_obj.browse() + ) + if target_profile_id: + # If the profile of levels should be changed at the same time + # and has auto_apply_computed_value True + # So, we can apply change to the whole recordset + values["manual_level_id"] = values["computed_level_id"] + else: + # If profile is not modified, filter levels per profile + # if it has auto_apply_computed_value True and modify only + # those + auto_applied_profiles_levels = self.filtered( + lambda level: level.profile_id.auto_apply_computed_value + ) + new_self = self - auto_applied_profiles_levels + super( + AbcClassificationProductLevel, auto_applied_profiles_levels + ).write(dict(values, manual_level_id=values["computed_level_id"])) + return super(AbcClassificationProductLevel, new_self).write(values) diff --git a/product_abc_classification/models/abc_classification_profile.py b/product_abc_classification/models/abc_classification_profile.py new file mode 100644 index 00000000000..996186af797 --- /dev/null +++ b/product_abc_classification/models/abc_classification_profile.py @@ -0,0 +1,145 @@ +# Copyright 2020 ForgeFlow +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from psycopg2.extensions import AsIs + +from odoo import api, fields, models +from odoo.exceptions import ValidationError + + +class AbcClassificationProfile(models.Model): + _name = "abc.classification.profile" + _description = "Abc Classification Profile" + _rec_name = "name" + + name = fields.Char(required=True) + level_ids = fields.One2many( + comodel_name="abc.classification.level", inverse_name="profile_id" + ) + profile_type = fields.Selection( + selection=[], + string="Type of ABC classification", + index=True, + required=True, + ) + period = fields.Integer( + default=365, + string="Period on which to compute the classification (Days)", + required=True, + ) + + product_variant_ids = fields.Many2many( + comodel_name="product.product", + relation="abc_classification_profile_product_rel", + column1="profile_id", + column2="product_id", + index=True, + ) + product_count = fields.Integer(compute="_compute_product_count", readonly=True) + + auto_apply_computed_value = fields.Boolean( + default=False, + help="Check this if you want to apply " + "the computed level on each product that has this " + "profile.", + ) + + _sql_constraints = [("name_uniq", "UNIQUE(name)", "Profile name must be unique")] + + @api.constrains("level_ids") + def _check_levels(self): + for profile in self: + percentages = profile.level_ids.mapped("percentage") + total = sum(percentages) + if profile.level_ids and total != 100.0: + raise ValidationError( + self.env._( + "The sum of the percentages of the levels should be 100." + ) + ) + if profile.level_ids and len({}.fromkeys(percentages)) != len(percentages): + raise ValidationError( + self.env._("The percentages of the levels must be unique.") + ) + percentage_productss = profile.level_ids.mapped("percentage_products") + total = sum(percentage_productss) + if profile.level_ids and total != 100.0: + raise ValidationError( + self.env._( + "The sum of the products percentages of the levels " + "should be 100." + ) + ) + + def _compute_abc_classification(self): + raise NotImplementedError() + + @api.depends("product_variant_ids") + def _compute_product_count(self): + for profile in self: + profile.product_count = len(profile.product_variant_ids) + + def action_view_products(self): + products = self.mapped("product_variant_ids") + action = self.env["ir.actions.act_window"]._for_xml_id( + "product.product_variant_action" + ) + del action["context"] + if len(products) > 1: + action["domain"] = [("id", "in", products.ids)] + elif len(products) == 1: + form_view = [ + (self.env.ref("product.product_variant_easy_edit_view").id, "form") + ] + if "views" in action: + action["views"] = form_view + [ + (state, view) for state, view in action["views"] if view != "form" + ] + else: + action["views"] = form_view + action["res_id"] = products.id + else: + action = {"type": "ir.actions.act_window_close"} + return action + + @api.model + def _cron_compute_abc_classification(self): + self.search([])._compute_abc_classification() + + def write(self, vals): + res = super().write(vals) + if "auto_apply_computed_value" in vals and vals["auto_apply_computed_value"]: + self._auto_apply_computed_value_for_product_levels() + return res + + def _auto_apply_computed_value_for_product_levels(self): + level_ids = [] + for rec in self: + self.env.cr.execute( + """ + UPDATE %(table)s + SET manual_level_id = computed_level_id + WHERE profile_id = %(profile_id)s + RETURNING id + + """, + { + "table": AsIs(self.env["abc.classification.product.level"]._table), + "profile_id": rec.id, + }, + ) + level_ids.extend(r[0] for r in self.env.cr.fetchall()) + modified_levels = self.env["abc.classification.product.level"].browse(level_ids) + modified_levels.invalidate_recordset(fnames=["manual_level_id"]) + # mark field as modified and trigger recompute of dependent fields. + modified_levels.modified(["manual_level_id"]) + modified_levels._recompute_recordset() + + def copy_data(self, default=None): + default = dict(default or {}) + vals_list = super().copy_data(default=default) + for profile, vals in zip(self, vals_list, strict=False): + if "name" not in default: + vals["name"] = self.env._("%s (copy)", profile.name) + return vals_list diff --git a/product_abc_classification/models/product_category.py b/product_abc_classification/models/product_category.py new file mode 100644 index 00000000000..39626a00599 --- /dev/null +++ b/product_abc_classification/models/product_category.py @@ -0,0 +1,34 @@ +# Copyright 2024 ForgeFlow +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductCategory(models.Model): + _inherit = "product.category" + + abc_classification_profile_ids = fields.Many2many( + comodel_name="abc.classification.profile", + relation="abc_classification_profile_product_categ_rel", + column1="categ_id", + column2="profile_id", + index=True, + ) + + def update_product_abc_classification_profile(self): + category_products = self.env["product.product"]._read_group( + [ + ("abc_classification_profile_updatable_from_category", "=", True), + ("categ_id", "in", self.ids), + ], + ["categ_id"], + ["id:recordset"], + ) + for categ, products in category_products: + products.write( + { + "abc_classification_profile_ids": [ + (6, 0, categ.abc_classification_profile_ids.ids) + ] + } + ) diff --git a/product_abc_classification/models/product_product.py b/product_abc_classification/models/product_product.py new file mode 100644 index 00000000000..31c79263d73 --- /dev/null +++ b/product_abc_classification/models/product_product.py @@ -0,0 +1,48 @@ +# Copyright 2020 ForgeFlow +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + abc_classification_product_level_ids = fields.One2many( + "abc.classification.product.level", index=True, inverse_name="product_id" + ) + abc_classification_profile_ids = fields.Many2many( + comodel_name="abc.classification.profile", + relation="abc_classification_profile_product_rel", + column1="product_id", + column2="profile_id", + index=True, + ) + abc_classification_profile_updatable_from_category = fields.Boolean(default=True) + + def _update_abc_classification_profile_from_category(self): + for rec in self: + category = rec.categ_id + if ( + not rec.abc_classification_profile_ids + and category.abc_classification_profile_ids + ): + rec.abc_classification_profile_ids = ( + category.abc_classification_profile_ids + ) + + @api.model_create_multi + def create(self, vals_list): + res = super().create(vals_list) + res._update_abc_classification_profile_from_category() + return res + + def write(self, vals): + res = super().write(vals) + if vals.get("categ_id"): + self._update_abc_classification_profile_from_category() + return res + + @api.onchange("categ_id") + def _onchange_categ_id_abc_classification(self): + self._update_abc_classification_profile_from_category() diff --git a/product_abc_classification/models/product_template.py b/product_abc_classification/models/product_template.py new file mode 100644 index 00000000000..48c01bbc47d --- /dev/null +++ b/product_abc_classification/models/product_template.py @@ -0,0 +1,70 @@ +# Copyright 2020 ForgeFlow +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + abc_classification_profile_ids = fields.Many2many( + "abc.classification.profile", + compute="_compute_abc_classification_profile_ids", + inverse="_inverse_abc_classification_profile_ids", + store=True, + ) + abc_classification_product_level_ids = fields.One2many( + "abc.classification.product.level", + compute="_compute_abc_classification_product_level_ids", + inverse="_inverse_abc_classification_product_level_ids", + inverse_name="product_tmpl_id", + store=True, + ) + + @api.depends( + "product_variant_ids", + "product_variant_ids.abc_classification_profile_ids", + ) + def _compute_abc_classification_profile_ids(self): + unique_variants = self.filtered( + lambda template: len(template.product_variant_ids) == 1 + ) + for template in unique_variants: + template.abc_classification_profile_ids = ( + template.product_variant_ids.abc_classification_profile_ids + ) + for template in self - unique_variants: + template.abc_classification_profile_ids = False + + @api.depends( + "product_variant_ids", + "product_variant_ids.abc_classification_product_level_ids", + ) + def _compute_abc_classification_product_level_ids(self): + unique_variants = self.filtered( + lambda template: len(template.product_variant_ids) == 1 + ) + for template in unique_variants: + variants = template.product_variant_ids + template.abc_classification_product_level_ids = ( + variants.abc_classification_product_level_ids + ) + for template in self - unique_variants: + template.abc_classification_product_level_ids = False + + def _inverse_abc_classification_profile_ids(self): + for template in self: + if len(template.product_variant_ids) == 1: + variants = template.product_variant_ids + variants.abc_classification_profile_ids = ( + template.abc_classification_profile_ids + ) + + def _inverse_abc_classification_product_level_ids(self): + for template in self: + if len(template.product_variant_ids) == 1: + variants = template.product_variant_ids + variants.abc_classification_product_level_ids = ( + template.abc_classification_product_level_ids + ) diff --git a/product_abc_classification/pyproject.toml b/product_abc_classification/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_abc_classification/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_abc_classification/readme/CONTRIBUTORS.md b/product_abc_classification/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..9b83a45f72f --- /dev/null +++ b/product_abc_classification/readme/CONTRIBUTORS.md @@ -0,0 +1,5 @@ +- Miquel Raïch \<\> +- Lindsay Marion \<\> +- Laurent Mignon \<\> +- Denis Roussel \<\> +- Hoang Diep \<\> \ No newline at end of file diff --git a/product_abc_classification/readme/CREDITS.md b/product_abc_classification/readme/CREDITS.md new file mode 100644 index 00000000000..fd7da320a35 --- /dev/null +++ b/product_abc_classification/readme/CREDITS.md @@ -0,0 +1 @@ +The migration of this module from 17.0 to 18.0 was financially supported by Camptocamp \ No newline at end of file diff --git a/product_abc_classification/readme/DESCRIPTION.md b/product_abc_classification/readme/DESCRIPTION.md new file mode 100644 index 00000000000..c636be2ab6a --- /dev/null +++ b/product_abc_classification/readme/DESCRIPTION.md @@ -0,0 +1,12 @@ +This modules provides the bases to build ABC analysis (or ABC +classification) addons. These classification are used by inventory +management teams to help identify the most important products in their +portfolio and ensure they prioritize managing them above those less +valuable. + +Managers will create a profile with several levels (percentages) and +then the profiled products will automatically get a corresponding level +using the ABC classification. + +The addon *product_abc_classification_sale_stock* defines a computation +profile based on the number of sale order line delivered by product. diff --git a/product_abc_classification/readme/USAGE.md b/product_abc_classification/readme/USAGE.md new file mode 100644 index 00000000000..bdf7aec4a4a --- /dev/null +++ b/product_abc_classification/readme/USAGE.md @@ -0,0 +1,13 @@ +To use this module, you need to: + +#\. Go to Inventory menu, then to Configuration/Products/ABC +Classification Profile and create a profile with levels, knowing that +the sum of all levels in the profile should sum 100 and all the levels +should be different. + +#\. Later you should go to product categories or product variants, and +assign them a profile. Then the cron classification will proceed to +assign to these products one of the profile's levels. + +NOTE: If you profile (or unprofile) a product category, then all its +child categories and products will be profiled (or unprofiled). diff --git a/product_abc_classification/security/ir.model.access.csv b/product_abc_classification/security/ir.model.access.csv new file mode 100644 index 00000000000..9283b353960 --- /dev/null +++ b/product_abc_classification/security/ir.model.access.csv @@ -0,0 +1,7 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_abc_classification_profile_user,abc.classification.profile.user,model_abc_classification_profile,base.group_user,1,0,0,0 +access_abc_classification_profile_manager,abc.classification.profile.manager,model_abc_classification_profile,stock.group_stock_manager,1,1,1,1 +access_abc_classification_level_user,abc.classification.level.user,model_abc_classification_level,base.group_user,1,0,0,0 +access_abc_classification_level_manager,abc.classification.level.manager,model_abc_classification_level,stock.group_stock_manager,1,1,1,1 +access_abc_classification_product_level_user,abc.classification.product.level.user,model_abc_classification_product_level,base.group_user,1,0,0,0 +access_abc_classification_product_level_manager,abc.classification.product.level.manager,model_abc_classification_product_level,stock.group_stock_manager,1,1,0,0 diff --git a/product_abc_classification/static/description/icon.png b/product_abc_classification/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_abc_classification/static/description/icon.png differ diff --git a/product_abc_classification/static/description/index.html b/product_abc_classification/static/description/index.html new file mode 100644 index 00000000000..bfaff2880f6 --- /dev/null +++ b/product_abc_classification/static/description/index.html @@ -0,0 +1,463 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Product Abc Classification

+ +

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

This modules provides the bases to build ABC analysis (or ABC +classification) addons. These classification are used by inventory +management teams to help identify the most important products in their +portfolio and ensure they prioritize managing them above those less +valuable.

+

Managers will create a profile with several levels (percentages) and +then the profiled products will automatically get a corresponding level +using the ABC classification.

+

The addon product_abc_classification_sale_stock defines a computation +profile based on the number of sale order line delivered by product.

+

Table of contents

+ +
+

Usage

+

To use this module, you need to:

+

#. Go to Inventory menu, then to Configuration/Products/ABC +Classification Profile and create a profile with levels, knowing that +the sum of all levels in the profile should sum 100 and all the levels +should be different.

+

#. Later you should go to product categories or product variants, and +assign them a profile. Then the cron classification will proceed to +assign to these products one of the profile’s levels.

+

NOTE: If you profile (or unprofile) a product category, then all its +child categories and products will be profiled (or unprofiled).

+
+
+

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

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

Contributors

+ +
+
+

Other credits

+

The migration of this module from 17.0 to 18.0 was financially supported +by Camptocamp

+
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/product-attribute project on GitHub.

+

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

+
+
+
+
+ + diff --git a/product_abc_classification/tests/__init__.py b/product_abc_classification/tests/__init__.py new file mode 100644 index 00000000000..8292c06ca32 --- /dev/null +++ b/product_abc_classification/tests/__init__.py @@ -0,0 +1,3 @@ +from . import test_abc_classification_product_level +from . import test_abc_classification_profile +from . import test_product diff --git a/product_abc_classification/tests/common.py b/product_abc_classification/tests/common.py new file mode 100644 index 00000000000..1311f3f2c65 --- /dev/null +++ b/product_abc_classification/tests/common.py @@ -0,0 +1,136 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.fields import Command +from odoo.tests.common import TransactionCase + + +class ABCClassificationCase(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + # add a fake profile_type + cls.ABCClassificationProfile = cls.env["abc.classification.profile"] + cls.ABCClassificationProfile._fields["profile_type"].selection = [ + ("test_type", "Test Type") + ] + cls.ABCClassificationProfile._fields["profile_type"]._selection = { + "test_type", + "Test Type", + } + cls.classification_profile = cls.ABCClassificationProfile.create( + {"name": "Profile test", "profile_type": "test_type"} + ) + + +class ABCClassificationLevelCase(ABCClassificationCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "a", + }, + ), + ( + 0, + 0, + { + "percentage": 40, + "percentage_products": 60, + "name": "b", + }, + ), + ] + } + ) + + levels = cls.classification_profile.level_ids + cls.classification_level_a = levels.filtered(lambda level: level.name == "a") + cls.classification_level_b = levels.filtered(lambda level: level.name == "b") + cls.classification_profile_bis = cls.ABCClassificationProfile.create( + { + "name": "Profile test bis", + "profile_type": "test_type", + "level_ids": [ + ( + 0, + 0, + { + "percentage": 80, + "percentage_products": 40, + "name": "a", + }, + ), + ( + 0, + 0, + { + "percentage": 20, + "percentage_products": 60, + "name": "b", + }, + ), + ], + } + ) + levels = cls.classification_profile_bis.level_ids + cls.classification_level_bis_a = levels.filtered( + lambda level: level.name == "a" + ) + + cls.classification_level_bis_b = levels.filtered( + lambda level: level.name == "b" + ) + # create a template with one variant adn declare attributes to create + # another variant on demand + cls.size_attr = cls.env["product.attribute"].create( + { + "name": "Size", + "create_variant": "no_variant", + "value_ids": [(0, 0, {"name": "S"}), (0, 0, {"name": "M"})], + } + ) + cls.size_attr_value_s = cls.size_attr.value_ids[0] + cls.size_attr_value_m = cls.size_attr.value_ids[1] + cls.uom_unit = cls.env.ref("uom.product_uom_unit") + cls.product_template = cls.env["product.template"].create( + { + "name": "Test sized", + "uom_id": cls.uom_unit.id, + "uom_po_id": cls.uom_unit.id, + "attribute_line_ids": [ + ( + 0, + 0, + { + "attribute_id": cls.size_attr.id, + "value_ids": [(6, 0, cls.size_attr.value_ids.ids)], + }, + ) + ], + } + ) + cls.product_product = cls.product_template.product_variant_ids + cls.ProductLevel = cls.env["abc.classification.product.level"] + + @classmethod + def _create_variant(cls, size_value): + return cls.env["product.product"].create( + { + "product_tmpl_id": cls.product_template.id, + "product_template_attribute_value_ids": [ + Command.set( + size_value.pav_attribute_line_ids.product_template_value_ids.ids + ) + ], + } + ) diff --git a/product_abc_classification/tests/test_abc_classification_product_level.py b/product_abc_classification/tests/test_abc_classification_product_level.py new file mode 100644 index 00000000000..b995424feb0 --- /dev/null +++ b/product_abc_classification/tests/test_abc_classification_product_level.py @@ -0,0 +1,365 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from psycopg2 import IntegrityError + +from odoo.exceptions import ValidationError +from odoo.tools import mute_logger + +from .common import ABCClassificationLevelCase + + +class TestABCClassificationProductLevel(ABCClassificationLevelCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product_1 = cls.env["product.product"].create( + { + "name": "Test 1", + "uom_id": cls.uom_unit.id, + "uom_po_id": cls.uom_unit.id, + } + ) + cls.product_level = cls.ProductLevel.create( + { + "product_id": cls.product_product.id, + "computed_level_id": cls.classification_level_a.id, + "profile_id": cls.classification_profile.id, + } + ) + + @classmethod + def _create_product_levels(cls): + product_2 = cls.env["product.product"].create( + { + "name": "Test 2", + "uom_id": cls.uom_unit.id, + "uom_po_id": cls.uom_unit.id, + } + ) + + product_3 = cls.env["product.product"].create( + { + "name": "Test 3", + "uom_id": cls.uom_unit.id, + "uom_po_id": cls.uom_unit.id, + } + ) + cls.ProductLevel.create( + { + "product_id": product_2.id, + "manual_level_id": cls.classification_level_b.id, + "computed_level_id": cls.classification_level_a.id, + "profile_id": cls.classification_profile.id, + } + ) + cls.ProductLevel.create( + { + "product_id": product_3.id, + "manual_level_id": cls.classification_level_b.id, + "computed_level_id": cls.classification_level_a.id, + "profile_id": cls.classification_profile.id, + } + ) + + def test_00(self): + """ + Test case: + Create a classification product level with only a computed_level_id + Expected result: + A instance is created with: + * the manual_level_id and level_id set + * flag is False since manual and computd are the same + + """ + level = self.ProductLevel.create( + { + "product_id": self.product_1.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + self.assertEqual(level.manual_level_id, self.classification_level_a) + self.assertEqual(level.level_id, self.classification_level_a) + self.assertFalse(level.flag) + + def test_01(self): + """ + Test case: + Create product level with only a manual level + + A creation if a product level is created without computed value + the computed value is never taken into account + Expected result: + A new level is create with: + * computed_level_id = False + * level_id = manual_level_id + * flag = False + """ + level = self.ProductLevel.create( + { + "product_id": self.product_1.id, + "manual_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + self.assertFalse(level.computed_level_id) + self.assertEqual(level.manual_level_id, self.classification_level_a) + self.assertEqual(level.level_id, self.classification_level_a) + self.assertFalse(level.flag) + + def test_02(self): + """ + Data: + An existing classification level with computed = manual + Test case: + 1. Change manual_level_id to an other value than the computed one + 2. Reset manual_level_id to the computed one + Expected result: + 1. level_id === manual =! computed and flag is true + 2 level_id == manual == computed and flag is true + ValidationError + """ + self.assertFalse(self.product_level.flag) + self.assertEqual( + self.product_level.manual_level_id, + self.product_level.computed_level_id, + ) + self.assertEqual( + self.product_level.computed_level_id, self.classification_level_a + ) + self.assertEqual(self.product_level.level_id, self.classification_level_a) + # 1 + self.product_level.manual_level_id = self.classification_level_b + self.assertEqual(self.product_level.level_id, self.classification_level_b) + self.assertTrue(self.product_level.flag) + # 2 + self.product_level.manual_level_id = self.product_level.computed_level_id + self.assertEqual(self.product_level.level_id, self.classification_level_a) + self.assertFalse(self.product_level.flag) + + @mute_logger("odoo.sql_db") + def test_03(self): + """ + Data: + An existing product level + Test case: + Create a new product level for the same product and the same profile + Expected result: + IntegrityError (level name must be unique by profile and product) + """ + with self.assertRaises(IntegrityError): + self.ProductLevel.create( + { + "product_id": self.product_product.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + + def test_04(self): + """ + Data: + An existing product level + Test case: + 1. Link a manual level from an other profile + 2. Link a computed level from an other profile + Expected result: + 1. and 2. Validation error (All the levels must share the same + profile as the one on the product level) + """ + with self.assertRaises(ValidationError), self.env.cr.savepoint(): + self.product_level.write( + { + "manual_level_id": self.classification_level_b.id, + "computed_level_id": self.classification_level_bis_a.id, + } + ) + with self.assertRaises(ValidationError), self.env.cr.savepoint(): + self.product_level.write( + { + "manual_level_id": self.classification_level_bis_a.id, + "computed_level_id": self.classification_level_a.id, + } + ) + self.product_level.write( + { + "manual_level_id": self.classification_level_bis_a.id, + "computed_level_id": self.classification_level_bis_a.id, + "profile_id": self.classification_profile_bis.id, + } + ) + + def test_05(self): + """ + Test case: + Create a product level without computed nor manual level + Expected result: + Validation error (at least a value for one of these fields is + expected) + """ + with self.assertRaises(ValidationError): + self.ProductLevel.create( + { + "product_id": self.product_1.id, + "profile_id": self.classification_profile.id, + } + ) + + def test_06_update_product_level_with_auto_compute(self): + self.classification_profile_bis.auto_apply_computed_value = True + self.product_level.write( + { + "computed_level_id": self.classification_level_bis_a.id, + "profile_id": self.classification_profile_bis.id, + } + ) + + self.assertEqual( + self.product_level.manual_level_id, + self.product_level.computed_level_id, + ) + self.assertEqual( + self.product_level.computed_level_id, self.classification_level_bis_a + ) + self.assertEqual(self.product_level.level_id, self.classification_level_bis_a) + + self.product_level.write( + { + "computed_level_id": self.classification_level_bis_b.id, + } + ) + self.assertEqual( + self.product_level.manual_level_id, + self.product_level.computed_level_id, + ) + self.assertEqual( + self.product_level.computed_level_id, self.classification_level_bis_b + ) + self.assertEqual(self.product_level.level_id, self.classification_level_bis_b) + + def test_07_update_product_level_without_auto_compute(self): + self.classification_profile.auto_apply_computed_value = False + self.product_level.write( + { + "manual_level_id": self.classification_level_b.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + + self.assertNotEqual( + self.product_level.manual_level_id, + self.product_level.computed_level_id, + ) + self.assertEqual( + self.product_level.computed_level_id, self.classification_level_a + ) + self.assertEqual( + self.product_level.manual_level_id, self.classification_level_b + ) + self.assertEqual(self.product_level.level_id, self.classification_level_b) + + self.product_level.write( + { + "manual_level_id": self.classification_level_a.id, + "computed_level_id": self.classification_level_b.id, + } + ) + + self.assertNotEqual( + self.product_level.manual_level_id, + self.product_level.computed_level_id, + ) + self.assertEqual( + self.product_level.computed_level_id, self.classification_level_b + ) + self.assertEqual( + self.product_level.manual_level_id, self.classification_level_a + ) + self.assertEqual(self.product_level.level_id, self.classification_level_a) + + def test_08_update_recordset_with__autocompute(self): + self._create_product_levels() + self.classification_profile.auto_apply_computed_value = True + + levels = self.ProductLevel.search( + [("profile_id", "=", self.classification_profile.id)] + ) + levels.write( + { + "manual_level_id": self.classification_level_a.id, + "computed_level_id": self.classification_level_b.id, + } + ) + + for level in levels: + self.assertEqual(level.manual_level_id, level.computed_level_id) + self.assertEqual(level.manual_level_id, self.classification_level_b) + self.assertEqual(level.computed_level_id, self.classification_level_b) + self.assertEqual(level.level_id, self.classification_level_b) + + def test_09_update_recordset_and_change_profile(self): + self._create_product_levels() + self.classification_profile_bis.auto_apply_computed_value = True + + levels = self.ProductLevel.search( + [("profile_id", "=", self.classification_profile.id)] + ) + levels.write( + { + "computed_level_id": self.classification_level_bis_a.id, + "profile_id": self.classification_profile_bis.id, + } + ) + + for level in levels: + self.assertEqual(level.manual_level_id, level.computed_level_id) + self.assertEqual(level.manual_level_id, self.classification_level_bis_a) + self.assertEqual(level.computed_level_id, self.classification_level_bis_a) + self.assertEqual(level.level_id, self.classification_level_bis_a) + + def test_10_create_product_level_for_profile_auto_assign(self): + self.classification_profile.auto_apply_computed_value = True + level = self.ProductLevel.create( + { + "product_id": self.product_1.id, + "manual_level_id": self.classification_level_b.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + self.assertEqual(level.manual_level_id, level.computed_level_id) + self.assertEqual(level.manual_level_id, self.classification_level_a) + self.assertEqual(level.computed_level_id, self.classification_level_a) + self.assertEqual(level.level_id, self.classification_level_a) + + def test_11_auto_apply_computed_level(self): + self._create_product_levels() + + levels = self.ProductLevel.search( + [("profile_id", "=", self.classification_profile.id)] + ) + level0 = levels[0] + level1 = levels[1] + level2 = levels[2] + self.assertEqual(level0.manual_level_id, level0.computed_level_id) + self.assertEqual(level0.manual_level_id, self.classification_level_a) + self.assertEqual(level0.computed_level_id, self.classification_level_a) + self.assertEqual(level0.level_id, self.classification_level_a) + + self.assertNotEqual(level1.manual_level_id, level1.computed_level_id) + self.assertEqual(level1.manual_level_id, self.classification_level_b) + self.assertEqual(level1.computed_level_id, self.classification_level_a) + self.assertEqual(level1.level_id, self.classification_level_b) + + self.assertNotEqual(level2.manual_level_id, level2.computed_level_id) + self.assertEqual(level2.manual_level_id, self.classification_level_b) + self.assertEqual(level2.computed_level_id, self.classification_level_a) + self.assertEqual(level2.level_id, self.classification_level_b) + + self.classification_profile.auto_apply_computed_value = True + for level in levels: + self.assertEqual(level.manual_level_id, self.classification_level_a) + self.assertEqual(level.computed_level_id, self.classification_level_a) + self.assertEqual(level.level_id, self.classification_level_a) diff --git a/product_abc_classification/tests/test_abc_classification_profile.py b/product_abc_classification/tests/test_abc_classification_profile.py new file mode 100644 index 00000000000..68044ba97bf --- /dev/null +++ b/product_abc_classification/tests/test_abc_classification_profile.py @@ -0,0 +1,303 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from psycopg2 import IntegrityError + +from odoo.exceptions import ValidationError +from odoo.tools.misc import mute_logger + +from .common import ABCClassificationCase + + +class TestABCClassificationProfile(ABCClassificationCase): + def test_00(self): + """ + Data: + A test profile + Test case: + Assign levels for a total of 100% + Expected result: + OK + """ + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 40, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + self.assertEqual(len(self.classification_profile.level_ids), 2) + + def test_01(self): + """ + Data: + A test profile + Test case: + Assign levels for a total < 100% + Expected result: + ValidationError + """ + with self.assertRaises(ValidationError): + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 30, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + + def test_02(self): + """ + Data: + A test profile + Test case: + Assign levels for a total > 100% + Expected result: + ValidationError + """ + with self.assertRaises(ValidationError): + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 50, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + + def test_03(self): + """ + Data: + A test profile + Test case: + Assign levels for a total = 100% but with same percentage + Expected result: + ValidationError + """ + with self.assertRaises(ValidationError): + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 50, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 50, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + + def test_04(self): + """ + Data: + A test profile + Test case: + Assign levels for a total = 100% but with one level with negative + percentage and one level exceeding 100% + Expected result: + ValidationError + """ + with self.assertRaises(ValidationError): + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 150, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": -50, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + + @mute_logger("odoo.sql_db") + def test_05(self): + """ + Data: + A test profile + Test case: + Assign levels for a total = 100% but with same name + Expected result: + IntegrityError (level name must be unique by profile) + """ + with self.assertRaises(IntegrityError): + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 40, + "percentage_products": 60, + "name": "A", + }, + ), + ] + } + ) + + def test_06(self): + """ + Data: + A test profile with 2 levels A and B + Test case: + Create a new profile with the same level name + Expected result: + Profile created without error since the level name is unique by + profile + """ + self.classification_profile.write( + { + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 40, + "percentage_products": 60, + "name": "B", + }, + ), + ] + } + ) + new_profile = self.ABCClassificationProfile.create( + { + "name": "New Profile test", + "profile_type": "test_type", + "level_ids": [ + ( + 0, + 0, + { + "percentage": 60, + "percentage_products": 40, + "name": "A", + }, + ), + ( + 0, + 0, + { + "percentage": 40, + "percentage_products": 60, + "name": "B", + }, + ), + ], + } + ) + self.assertTrue(new_profile) + + @mute_logger("odoo.sql_db") + def test_07(self): + """ + Data: + A test profile + Test case: + Create a new profile with the same name + Expected result: + IntegrityError (profile name must be unique by profile) + """ + with self.assertRaises(IntegrityError): + self.ABCClassificationProfile.create( + { + "name": self.classification_profile.name, + "profile_type": "test_type", + } + ) diff --git a/product_abc_classification/tests/test_product.py b/product_abc_classification/tests/test_product.py new file mode 100644 index 00000000000..350fd2b9e0c --- /dev/null +++ b/product_abc_classification/tests/test_product.py @@ -0,0 +1,179 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from .common import ABCClassificationLevelCase + + +class TestProduct(ABCClassificationLevelCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + + def test_00(self): + """ + Data: + A product template with one variant. + Test Case: + 1. Associate a classification profile to the template + 2. Unset the classifiation profile + Expected: + 1. The classification profile is also associated to the variant + 2. The classification profile no more associated to the variant + """ + self.assertFalse(self.product_template.abc_classification_profile_ids) + self.assertFalse(self.product_product.abc_classification_profile_ids) + # 1 + self.product_template.abc_classification_profile_ids = ( + self.classification_profile + ) + self.assertEqual( + self.product_product.abc_classification_profile_ids, + self.classification_profile, + ) + # 2 + self.product_template.abc_classification_profile_ids = False + self.assertFalse(self.product_product.abc_classification_profile_ids) + + def test_01(self): + """ + Data: + A product template with two variants (without profiles). + Test Case: + 1. Associate a classification profile to the template + Expected: + The classification profile is not associated to the variant + """ + self._create_variant(self.size_attr_value_m) + variants = self.product_template.product_variant_ids + self.assertEqual(len(variants), 2) + self.assertFalse(variants.mapped("abc_classification_profile_ids")) + self.product_template.abc_classification_profile_ids = ( + self.classification_profile + ) + self.assertFalse(variants.mapped("abc_classification_profile_ids")) + + def test_02(self): + """ + Data: + A product template with one variant + Test Case: + 1 Associate a product level to the variant + 2 unlink the level + Expected result: + 1 The product level is also associated to the template + 2 No more level associated to the template + """ + product_level = self.ProductLevel.create( + { + "product_id": self.product_product.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + self.assertEqual( + self.product_product.abc_classification_product_level_ids, + product_level, + ) + self.assertEqual( + self.product_template.abc_classification_product_level_ids, + product_level, + ) + product_level.unlink() + + self.assertFalse(self.product_product.abc_classification_product_level_ids) + self.assertFalse(self.product_template.abc_classification_product_level_ids) + + def test_03(self): + """ + Data: + A product template with two variants + Test Case: + Associate a product level to one variant + Expected result: + The product level is not associated to the template + """ + new_variant = self._create_variant(self.size_attr_value_m) + variants = self.product_template.product_variant_ids + self.assertEqual(len(variants), 2) + product_level = self.ProductLevel.create( + { + "product_id": new_variant.id, + "computed_level_id": self.classification_level_a.id, + "profile_id": self.classification_profile.id, + } + ) + self.assertEqual( + new_variant.abc_classification_product_level_ids, + product_level, + ) + self.assertFalse(self.product_template.abc_classification_product_level_ids) + + def test_04(self): + """ + Data: + A product template + Test case: + Check if resource id in action is the product variant one + """ + self.product_template.abc_classification_profile_ids = ( + self.classification_profile + ) + action = self.classification_profile.action_view_products() + self.assertEqual(action["res_id"], self.product_template.product_variant_ids.id) + + def test_05(self): + """ + Data: + A product template with two variants + Test case: + Check if doamin in action is the product variants ids + """ + self._create_variant(self.size_attr_value_m) + self.product_template.product_variant_ids.abc_classification_profile_ids = ( + self.classification_profile + ) + action = self.classification_profile.action_view_products() + self.assertEqual( + action["domain"], + [("id", "in", self.product_template.product_variant_ids.ids)], + ) + + def test_06(self): + """ + Data: + A product template with one variant + Test Case: + Associate a classification profile to the category + Expected result: + The variant is associated to the classification profile + """ + self.product_template.categ_id.abc_classification_profile_ids = ( + self.classification_profile + ) + self.product_product._onchange_categ_id_abc_classification() + self.assertEqual( + self.product_product.abc_classification_profile_ids, + self.classification_profile, + ) + + def test_07(self): + """ + Data: + A product template with one variant + Test Case: + 1 Create new category + 2 Associate a classification profile to the category + 3 Create new product + Expected result: + The product is associated to the classification profile + """ + new_category = self.env["product.category"].create( + {"name": "Test Category ABC"} + ) + new_category.abc_classification_profile_ids = self.classification_profile_bis + new_template = self.env["product.template"].create( + {"name": "Test Template ABC", "categ_id": new_category.id} + ) + self.assertEqual( + new_template.abc_classification_profile_ids, self.classification_profile_bis + ) diff --git a/product_abc_classification/views/abc_classification_product_level.xml b/product_abc_classification/views/abc_classification_product_level.xml new file mode 100644 index 00000000000..9629c8efa8b --- /dev/null +++ b/product_abc_classification/views/abc_classification_product_level.xml @@ -0,0 +1,98 @@ + + + + + abc.classification.product.level.form (in product_abc_classification) + abc.classification.product.level + +
+ + + + + + + + + + + + + + + + + +
+
+ + abc.classification.product.level.tree (in product_abc_classification) + abc.classification.product.level + + + + + + + + + + + + abc.classification.product.level.search (in product_abc_classification) + abc.classification.product.level + + + + + + + + + + + + + + + + Products ABC Classification + abc.classification.product.level + list,form + {'search_default_group_by_level': 1} + + +
diff --git a/product_abc_classification/views/abc_classification_profile.xml b/product_abc_classification/views/abc_classification_profile.xml new file mode 100644 index 00000000000..5af737940c6 --- /dev/null +++ b/product_abc_classification/views/abc_classification_profile.xml @@ -0,0 +1,84 @@ + + + + + abc.classification.profile.form (in product_abc_classification) + abc.classification.profile + +
+ +
+ +
+
+

+ +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ + abc.classification.profile.tree (in product_abc_classification) + abc.classification.profile + + + + + + + + ABC Classification profiles + abc.classification.profile + list,form + + +
diff --git a/product_abc_classification/views/product_category.xml b/product_abc_classification/views/product_category.xml new file mode 100644 index 00000000000..ff03f63168a --- /dev/null +++ b/product_abc_classification/views/product_category.xml @@ -0,0 +1,27 @@ + + + + + product.category.form - product_abc_classification + product.category + + + + + + + + + + + + + + + + + + + + + + + + + product.template + + +
+ !product_form_pricelist.group_no_list_price +
+ +
+
+ + + product.template + + + + + !product_form_pricelist.group_no_list_price + + + + + + product.template + + + + !product_form_pricelist.group_no_list_price + + + +
diff --git a/product_form_pricelist/views/product_view.xml b/product_form_pricelist/views/product_view.xml new file mode 100644 index 00000000000..609719ffdb2 --- /dev/null +++ b/product_form_pricelist/views/product_view.xml @@ -0,0 +1,60 @@ + + + + product.product + + + + !product_form_pricelist.group_no_list_price + + + + + + product.product + + + + !product_form_pricelist.group_no_list_price + + + + + + product.product + + + + + + + + product.product + + + + + !product_form_pricelist.group_no_list_price + + + !product_form_pricelist.group_no_list_price + + + + diff --git a/product_form_pricelist/views/res_config_settings_view.xml b/product_form_pricelist/views/res_config_settings_view.xml new file mode 100644 index 00000000000..174dffb5ec1 --- /dev/null +++ b/product_form_pricelist/views/res_config_settings_view.xml @@ -0,0 +1,19 @@ + + + + res.config.settings + + + + + +
+ Hide 'Sales Price' in product form +
+
+
+
+
+
diff --git a/product_multi_price/README.rst b/product_multi_price/README.rst new file mode 100644 index 00000000000..8b63f959583 --- /dev/null +++ b/product_multi_price/README.rst @@ -0,0 +1,126 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +=================== +Product Multi Price +=================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:2d7a323dc3855c70eb9191d4b830d31b63fa8462c02836a11245bfcc9cbe8887 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_multi_price + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_multi_price + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to set multiple prices to products and base pricelist +rules on them. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +To configure multiple prices you need to set multi prices field names +first. To do so, you need admin permissions. Then go to: + +1. *Settings > Technical > Database Structure > Price Field Names* +2. Create the multi price fields you need. + +If you have multiple companies, you can assign independent field sets +for each one. + +Note: 'Show multi prices' access group must be checked to be able to add +multiple prices in the product form view. + +Usage +===== + +To use this module, you need to: + +1. Go to the product page. +2. In the general tab, there's a list called *Other Prices*. +3. You can add one for every price name available. + +To base pricelist rules on that fields, in the pricelist: + +1. Add a rule and choose *formula* as the computing method. +2. In the *Based on* dropdown list, select *Other Price*. +3. A new list appear: *Other Price Name*. Pick the one you need. +4. Configure the formula. +5. Now the rule is based on that price for the products that have it + configured. Otherwise, it will return 0. + +Known issues / Roadmap +====================== + +- Add mechanisms that allow to set multiprices values from external + flows. For example: having AVCO, FIFO and Standard prices computed + simultaneously in this table. + +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 +------- + +* Tecnativa + +Contributors +------------ + +- `Tecnativa `__ + + - David Vidal + - Pedro M. Baeza + - Ernesto Tejeda + - Sergio Teruel + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_multi_price/__init__.py b/product_multi_price/__init__.py new file mode 100644 index 00000000000..cc6b6354ad8 --- /dev/null +++ b/product_multi_price/__init__.py @@ -0,0 +1,2 @@ +from . import models +from .hooks import post_init_hook diff --git a/product_multi_price/__manifest__.py b/product_multi_price/__manifest__.py new file mode 100644 index 00000000000..4797e8ad072 --- /dev/null +++ b/product_multi_price/__manifest__.py @@ -0,0 +1,22 @@ +# Copyright 2020 Tecnativa - David Vidal +# Copyright 2020 Tecnativa - Pedro M. Baeza +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Product Multi Price", + "version": "18.0.1.0.2", + "author": "Tecnativa," "Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "category": "Product Management", + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "security/ir.model.access.csv", + "security/multi_price_security.xml", + "views/multi_price_views.xml", + "views/product_pricelist_views.xml", + "views/product_views.xml", + ], + "demo": ["demo/multi_price_demo_data.xml"], + "post_init_hook": "post_init_hook", + "installable": True, +} diff --git a/product_multi_price/demo/multi_price_demo_data.xml b/product_multi_price/demo/multi_price_demo_data.xml new file mode 100644 index 00000000000..9d9efab5fde --- /dev/null +++ b/product_multi_price/demo/multi_price_demo_data.xml @@ -0,0 +1,7 @@ + + + + price_1 + + + diff --git a/product_multi_price/hooks.py b/product_multi_price/hooks.py new file mode 100644 index 00000000000..b89701425f9 --- /dev/null +++ b/product_multi_price/hooks.py @@ -0,0 +1,11 @@ +# Copyright 2020 Tecnativa - Ernesto Tejeda +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +def post_init_hook(env): + group_id = env.ref("product_multi_price.group_show_multi_prices").id + default_user = env.ref("base.default_user") + user = ( + env["res.users"].with_context(active_test=False).search([("share", "=", False)]) + ) + (user - default_user).write({"groups_id": [(4, group_id, None)]}) diff --git a/product_multi_price/i18n/ca.po b/product_multi_price/i18n/ca.po new file mode 100644 index 00000000000..4661aee34da --- /dev/null +++ b/product_multi_price/i18n/ca.po @@ -0,0 +1,184 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-02-23 18:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: none\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" +"No es pot assignar un nom de camp a un producte dues vegades per a la " +"mateixa empresa" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price: The base price will be the cost price.\n" +"Other Pricelist: Computation of the base price based on another Pricelist." +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basat en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Companyia" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Creat per" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Creat el" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nom visible" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Darrera actualització per" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Darrera actualització el" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Opcions de registre de preus múltiples" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nom" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Altre preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Nom de l'altre preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Altres preus" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Preu" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name_text +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nom del camp del preu" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Noms de camps de preus" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regla de tarifa" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "Els noms dels preus han de ser únics per empresa" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Producte" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "Preu múltiple de producte" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Preus múltiples de productes" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Mostra preus múltiples" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Sales Price: The base price will be the Sales Price.\n" +#~ "Cost Price : The base price will be the cost price.\n" +#~ "Other Pricelist : Computation of the base price based on another " +#~ "Pricelist." +#~ msgstr "" +#~ "Preu base de càlcul.\n" +#~ "Preu de venda: el preu base serà el preu de venda.\n" +#~ "Preu de cost: el preu base serà el preu de cost.\n" +#~ "Una altra llista de preus: càlcul del preu base basat en una altra llista " +#~ "de preus." + +#~ msgid "Last Modified on" +#~ msgstr "Darrera modificació el" + +#~ msgid "Pricelist" +#~ msgstr "Tarifa" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producte" + +#~ msgid "Product Multi Price Field Name" +#~ msgstr "Nom del camp del preu múltiple del producte" diff --git a/product_multi_price/i18n/es.po b/product_multi_price/i18n/es.po new file mode 100644 index 00000000000..f3182b944ea --- /dev/null +++ b/product_multi_price/i18n/es.po @@ -0,0 +1,204 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-04-09 08:52+0000\n" +"PO-Revision-Date: 2021-02-23 18:45+0000\n" +"Last-Translator: claudiagn \n" +"Language-Team: \n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "No puede haber un nombre de campo repetido en la misma compañía" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price: The base price will be the cost price.\n" +"Other Pricelist: Computation of the base price based on another Pricelist." +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basado en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Compañía" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Creado por" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Creado en" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nombre mostrado" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Última actualización de" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Última actualización en" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Opciones de registro de precios múltiples" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nombre" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Otro precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Nombre del otro precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Otros precios" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Precio" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name_text +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nombre de Campo de Precio" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Nombres de Campo de Precio" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regla de tarifa" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "Los Nombres de Precio deben ser únicos para cada compañía" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Producto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "Multi Precio de Producto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Múltiples Precios de Producto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Muestra precios múltiples" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Sales Price: The base price will be the Sales Price.\n" +#~ "Cost Price : The base price will be the cost price.\n" +#~ "Other Pricelist : Computation of the base price based on another " +#~ "Pricelist." +#~ msgstr "" +#~ "Precio base de cálculo.\n" +#~ "Precio de venta: el precio base será el precio de venta.\n" +#~ "Precio de costo: el precio base será el precio de costo.\n" +#~ "Otra lista de precios: cálculo del precio base basado en otra lista de " +#~ "precios." + +#~ msgid "Last Modified on" +#~ msgstr "Última modificación en" + +#~ msgid "Pricelist" +#~ msgstr "Tarifa" + +#~ msgid "Product Template" +#~ msgstr "Plantilla de producto" + +#~ msgid "Product Multi Price Field Name" +#~ msgstr "Nombre de Campo de Multi Precio de Producto" + +#~ msgid "Cost" +#~ msgstr "Coste" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Precio de coste con impuesto incluido" + +#~ msgid "Other Pricelist" +#~ msgstr "Otra tarifa" + +#~ msgid "Partner Prices on the product form" +#~ msgstr "Precios de socios en el formulario de producto" + +#~ msgid "Prices based on supplier info" +#~ msgstr "Precios basados en la información del proveedor" + +#~ msgid "Public Price" +#~ msgstr "Precio público" + +#~ msgid "product.multi.price.name" +#~ msgstr "product.multi.price.name" diff --git a/product_multi_price/i18n/it.po b/product_multi_price/i18n/it.po new file mode 100644 index 00000000000..892e0403d48 --- /dev/null +++ b/product_multi_price/i18n/it.po @@ -0,0 +1,201 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2026-01-10 08:29+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" +"Un nome di campo non può essere assegnato a un prodotto due volte per la " +"stessa azienda" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price: The base price will be the cost price.\n" +"Other Pricelist: Computation of the base price based on another Pricelist." +msgstr "" +"Prezzo base per il calcolo.\n" +"Prezzo di vendita: il prezzo base sarà il prezzo di vendita.\n" +"Prezzo di costo: il prezzo base sarà il prezzo di costo.\n" +"Altri listini prezzi: il calcolo del prezzo base sarà basato su un altro " +"listino prezzi." + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Basato su" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Azienda" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Opzioni record prezzo multiplo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Nome" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Altro prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Altro nome prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Altri prezzi" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Prezzo" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name_text +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Nome campo prezzo" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Nomi campi prezzo" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regola listino prezzi" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "I nomi dei prezzi devono essere unici per azienda" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Prodotto" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "Prezzi multipli prodotto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Prezzi multipli prodotto" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "Variante prodotto" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Mostrare prezzi multipli" + +#~ msgid "" +#~ "Base price for computation.\n" +#~ "Sales Price: The base price will be the Sales Price.\n" +#~ "Cost Price : The base price will be the cost price.\n" +#~ "Other Pricelist : Computation of the base price based on another " +#~ "Pricelist." +#~ msgstr "" +#~ "Prezzo base per il calcolo.\n" +#~ "Prezzo di vendita: il prezzo base sarà il prezzo di vendita.\n" +#~ "Prezzo di costo: il prezzo base sarà il prezzo di costo.\n" +#~ "Altri listini prezzi: il calcolo del prezzo base sarà basato su un altro " +#~ "listino prezzi." + +#~ msgid "Last Modified on" +#~ msgstr "Ultima modifica il" + +#~ msgid "Pricelist" +#~ msgstr "Listino" + +#~ msgid "Product Template" +#~ msgstr "Modello prodotto" + +#~ msgid "Cost" +#~ msgstr "Costo" + +#~ msgid "Cost Price Tax Included" +#~ msgstr "Prezzo di costo imposte incluse" + +#~ msgid "Other Pricelist" +#~ msgstr "Altro listino" + +#~ msgid "Prices based on supplier info" +#~ msgstr "Prezzi basati sulle informazioni del fornitore" + +#~ msgid "Public Price" +#~ msgstr "Prezzo al pubblico" diff --git a/product_multi_price/i18n/nl.po b/product_multi_price/i18n/nl.po new file mode 100644 index 00000000000..c1ab3de5a99 --- /dev/null +++ b/product_multi_price/i18n/nl.po @@ -0,0 +1,167 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-11-14 17:27+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "A field name cannot be assigned to a product twice for the same company" +msgstr "" +"Een veldnaam kan niet tweemaal aan een product worden toegewezen voor " +"hetzelfde bedrijf" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price: The base price will be the cost price.\n" +"Other Pricelist: Computation of the base price based on another Pricelist." +msgstr "" +"Basis voor berekening.\n" +"Verkoopprijs: De basisprijs is de Verkoopprijs.\n" +"Kostprijs: De basisprijs is de kostprijs.\n" +"Andere Prijslijst: Berekening van de basisprijs gebaseerd op een andere " +"Prijslijst." + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "Gebaseerd op" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "Bedrijf" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "Aangemaakt door" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "Aangemaakt op" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "Weergavenaam" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "ID" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "Laatst bijgewerkt door" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "Laatst bijgewerkt op" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "Multiprijs recordopties" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "Naam" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "Andere prijs" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "Naam andere prijs" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "Andere prijzen" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "Prijs" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name_text +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "Naam prijsveld" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "Namen prijsvelden" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Prijslijstregel" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "Prijsnamen moeten uniek zijn per bedrijf" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "Product" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "Product multiprijs" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "Meerdere productprijzen" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "Productvariant" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "Toon multiprijzen" + +#~ msgid "Pricelist" +#~ msgstr "Prijslijst" diff --git a/product_multi_price/i18n/product_multi_price.pot b/product_multi_price/i18n/product_multi_price.pot new file mode 100644 index 00000000000..739509826ff --- /dev/null +++ b/product_multi_price/i18n/product_multi_price.pot @@ -0,0 +1,155 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_multi_price +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_multi_price_uniq +msgid "" +"A field name cannot be assigned to a product twice for the same company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,help:product_multi_price.field_product_pricelist_item__base +msgid "" +"Base price for computation.\n" +"Sales Price: The base price will be the Sales Price.\n" +"Cost Price: The base price will be the cost price.\n" +"Other Pricelist: Computation of the base price based on another Pricelist." +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__base +msgid "Based on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__company_id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__company_id +msgid "Company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_uid +msgid "Created by" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__create_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__create_date +msgid "Created on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__display_name +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__display_name +msgid "Display Name" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__id +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__id +msgid "ID" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_uid +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__write_date +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price_name +msgid "Multi Price Record Options" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name +msgid "Name" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields.selection,name:product_multi_price.selection__product_pricelist_item__base__multi_price +msgid "Other Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_pricelist_item__multi_price_name +msgid "Other Price Name" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_product__price_ids +#: model:ir.model.fields,field_description:product_multi_price.field_product_template__price_ids +msgid "Other Prices" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__price +msgid "Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__name_text +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price_name__name +msgid "Price Field Name" +msgstr "" + +#. module: product_multi_price +#: model:ir.actions.act_window,name:product_multi_price.action_multi_price_name_config +#: model:ir.ui.menu,name:product_multi_price.multi_price_name_menu +msgid "Price Field Names" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_multi_price +#: model:ir.model.constraint,message:product_multi_price.constraint_product_multi_price_name_multi_price_name_uniq +msgid "Prices Names must be unique per company" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_template +#: model:ir.model.fields,field_description:product_multi_price.field_product_multi_price__product_id +msgid "Product" +msgstr "" + +#. module: product_multi_price +#: model_terms:ir.ui.view,arch_db:product_multi_price.product_multi_price_form_view +msgid "Product Multi Price" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_multi_price +msgid "Product Multiple Prices" +msgstr "" + +#. module: product_multi_price +#: model:ir.model,name:product_multi_price.model_product_product +msgid "Product Variant" +msgstr "" + +#. module: product_multi_price +#: model:res.groups,name:product_multi_price.group_show_multi_prices +msgid "Show multi prices" +msgstr "" diff --git a/product_multi_price/models/__init__.py b/product_multi_price/models/__init__.py new file mode 100644 index 00000000000..b0fa0aa6da9 --- /dev/null +++ b/product_multi_price/models/__init__.py @@ -0,0 +1,4 @@ +from . import product_multi_price +from . import product_pricelist +from . import product_product +from . import product_template diff --git a/product_multi_price/models/product_multi_price.py b/product_multi_price/models/product_multi_price.py new file mode 100644 index 00000000000..ce146f52ff1 --- /dev/null +++ b/product_multi_price/models/product_multi_price.py @@ -0,0 +1,59 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class ProductMultiPrice(models.Model): + _name = "product.multi.price" + _rec_name = "name_text" + _description = "Product Multiple Prices" + + name = fields.Many2one("product.multi.price.name", required=True) + name_text = fields.Char(related="name.name") + product_id = fields.Many2one( + comodel_name="product.product", + required=True, + ondelete="cascade", + ) + price = fields.Float( + digits="Product Price", + ) + company_id = fields.Many2one( + comodel_name="res.company", + related="name.company_id", + store=True, + readonly=True, + ) + + _sql_constraints = [ + ( + "multi_price_uniq", + "unique(name, product_id, company_id)", + "A field name cannot be assigned to a product twice for the same " + "company", + ), + ] + + +class ProductMultiPriceName(models.Model): + _name = "product.multi.price.name" + _description = "Multi Price Record Options" + + @api.model + def _get_company(self): + return self._context.get("company_id", self.env.company) + + name = fields.Char(required=True, string="Price Field Name") + company_id = fields.Many2one( + comodel_name="res.company", + required=True, + default=lambda self: self._get_company(), + ) + + _sql_constraints = [ + ( + "multi_price_name_uniq", + "unique(name, company_id)", + "Prices Names must be unique per company", + ), + ] diff --git a/product_multi_price/models/product_pricelist.py b/product_multi_price/models/product_pricelist.py new file mode 100644 index 00000000000..b0d3b5c2bb5 --- /dev/null +++ b/product_multi_price/models/product_pricelist.py @@ -0,0 +1,24 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ProductPricelistItem(models.Model): + _inherit = "product.pricelist.item" + + base = fields.Selection( + selection_add=[("multi_price", "Other Price")], + ondelete={"multi_price": "set default"}, + ) + multi_price_name = fields.Many2one( + comodel_name="product.multi.price.name", + string="Other Price Name", + ) + + def _compute_price(self, product, quantity, uom, date, currency=None): + # Recompute price after calling the atomic super method for + # getting proper prices when based on multi price. + price = super()._compute_price(product, quantity, uom, date, currency) + if self.compute_price == "formula" and self.base == "multi_price": + price = product._get_multiprice_pricelist_price(self) + return price diff --git a/product_multi_price/models/product_product.py b/product_multi_price/models/product_product.py new file mode 100644 index 00000000000..b61d8f10829 --- /dev/null +++ b/product_multi_price/models/product_product.py @@ -0,0 +1,67 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models, tools + + +class ProductProduct(models.Model): + _inherit = "product.product" + + price_ids = fields.One2many( + comodel_name="product.multi.price", + inverse_name="product_id", + string="Other Prices", + ) + + def _convert_to_price_uom(self, price): + qty_uom_id = self._context.get("uom") or self.uom_id.id + price_uom = self.env["uom.uom"].browse([qty_uom_id]) + return self.uom_id._compute_price(price, price_uom) + + def _get_multiprice_pricelist_price(self, rule): + """Method for getting the price from multi price.""" + self.ensure_one() + company = rule.company_id or self.env.user.company_id + price = ( + self.env["product.multi.price"] + .sudo() + .search( + [ + ("company_id", "=", company.id), + ("name", "=", rule.multi_price_name.id), + ("product_id", "=", self.id), + ] + ) + .price + or 0 + ) + if price: + # We have to replicate this logic in this method as pricelist + # method are atomic and we can't hack inside. + # Verbatim copy of part of product.pricelist._compute_price_rule. + price_limit = price + price = (price - (price * (rule.price_discount / 100))) or 0.0 + if rule.price_round: + price = tools.float_round(price, precision_rounding=rule.price_round) + if rule.price_surcharge: + price_surcharge = self._convert_to_price_uom(rule.price_surcharge) + price += price_surcharge + if rule.price_min_margin: + price_min_margin = self._convert_to_price_uom(rule.price_min_margin) + price = max(price, price_limit + price_min_margin) + if rule.price_max_margin: + price_max_margin = self._convert_to_price_uom(rule.price_max_margin) + price = min(price, price_limit + price_max_margin) + return price + + def _price_compute( + self, price_type, uom=None, currency=None, company=None, date=False + ): + """Return temporary prices when computation is done for multi price for + avoiding error on super method. We will later fill these with the + correct values. + """ + if price_type == "multi_price": + return dict.fromkeys(self.ids, 1.0) + return super()._price_compute( + price_type, uom=uom, currency=currency, company=company, date=date + ) diff --git a/product_multi_price/models/product_template.py b/product_multi_price/models/product_template.py new file mode 100644 index 00000000000..9649c90621f --- /dev/null +++ b/product_multi_price/models/product_template.py @@ -0,0 +1,56 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import api, fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + price_ids = fields.One2many( + comodel_name="product.multi.price", + compute="_compute_price_ids", + inverse="_inverse_price_ids", + string="Other Prices", + ) + + @api.depends("product_variant_ids", "product_variant_ids.price_ids") + def _compute_price_ids(self): + for p in self: + if len(p.product_variant_ids) == 1: + p.price_ids = p.product_variant_ids.price_ids + else: + p.price_ids = False + + def _inverse_price_ids(self): + for p in self: + if len(p.product_variant_ids) == 1: + p.product_variant_ids.price_ids = p.price_ids + + def _get_multiprice_pricelist_price(self, rule): + if len(self.product_variant_ids) == 1: + return self.product_variant_ids._get_multiprice_pricelist_price(rule) + return 0 + + @api.model_create_multi + def create(self, vals_list): + """Overwrite creation for rewriting the prices (if set and having only + one variant), after the variant creation, that is performed in super. + """ + templates = super().create(vals_list) + for template, vals in zip(templates, vals_list, strict=False): + if vals.get("price_ids"): + template.write({"price_ids": vals.get("price_ids")}) + return templates + + def _price_compute( + self, price_type, uom=None, currency=None, company=None, date=False + ): + """Return temporary prices when computation is done for multi price for + avoiding error on super method. We will later fill these with the + correct values. + """ + if price_type == "multi_price": + return dict.fromkeys(self.ids, 1.0) + return super()._price_compute( + price_type, uom=uom, currency=currency, company=company, date=date + ) diff --git a/product_multi_price/pyproject.toml b/product_multi_price/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_multi_price/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_multi_price/readme/CONFIGURE.md b/product_multi_price/readme/CONFIGURE.md new file mode 100644 index 00000000000..135d751dbc2 --- /dev/null +++ b/product_multi_price/readme/CONFIGURE.md @@ -0,0 +1,11 @@ +To configure multiple prices you need to set multi prices field names +first. To do so, you need admin permissions. Then go to: + +1. *Settings \> Technical \> Database Structure \> Price Field Names* +2. Create the multi price fields you need. + +If you have multiple companies, you can assign independent field sets +for each one. + +Note: 'Show multi prices' access group must be checked to be able to add +multiple prices in the product form view. diff --git a/product_multi_price/readme/CONTRIBUTORS.md b/product_multi_price/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..9d4928b87b2 --- /dev/null +++ b/product_multi_price/readme/CONTRIBUTORS.md @@ -0,0 +1,5 @@ +- [Tecnativa](https://www.tecnativa.com) + - David Vidal + - Pedro M. Baeza + - Ernesto Tejeda + - Sergio Teruel diff --git a/product_multi_price/readme/DESCRIPTION.md b/product_multi_price/readme/DESCRIPTION.md new file mode 100644 index 00000000000..c76055a6eb9 --- /dev/null +++ b/product_multi_price/readme/DESCRIPTION.md @@ -0,0 +1,2 @@ +This module allows to set multiple prices to products and base pricelist +rules on them. diff --git a/product_multi_price/readme/ROADMAP.md b/product_multi_price/readme/ROADMAP.md new file mode 100644 index 00000000000..8d2dd0c7fc9 --- /dev/null +++ b/product_multi_price/readme/ROADMAP.md @@ -0,0 +1,3 @@ +- Add mechanisms that allow to set multiprices values from external + flows. For example: having AVCO, FIFO and Standard prices computed + simultaneously in this table. diff --git a/product_multi_price/readme/USAGE.md b/product_multi_price/readme/USAGE.md new file mode 100644 index 00000000000..a53c436dbcf --- /dev/null +++ b/product_multi_price/readme/USAGE.md @@ -0,0 +1,14 @@ +To use this module, you need to: + +1. Go to the product page. +2. In the general tab, there's a list called *Other Prices*. +3. You can add one for every price name available. + +To base pricelist rules on that fields, in the pricelist: + +1. Add a rule and choose *formula* as the computing method. +2. In the *Based on* dropdown list, select *Other Price*. +3. A new list appear: *Other Price Name*. Pick the one you need. +4. Configure the formula. +5. Now the rule is based on that price for the products that have it + configured. Otherwise, it will return 0. diff --git a/product_multi_price/security/ir.model.access.csv b/product_multi_price/security/ir.model.access.csv new file mode 100644 index 00000000000..603077c94d3 --- /dev/null +++ b/product_multi_price/security/ir.model.access.csv @@ -0,0 +1,4 @@ +"id","name","model_id:id","group_id:id","perm_read","perm_write","perm_create","perm_unlink" +multi_price,product.multi.price,model_product_multi_price,base.group_user,1,1,1,1 +multi_price_name_read,product.multi.price.name,model_product_multi_price_name,base.group_user,1,0,0,0 +multi_price_name_admin,product.multi.price.name,model_product_multi_price_name,base.group_system,1,1,1,1 diff --git a/product_multi_price/security/multi_price_security.xml b/product_multi_price/security/multi_price_security.xml new file mode 100644 index 00000000000..7f73c76ce5e --- /dev/null +++ b/product_multi_price/security/multi_price_security.xml @@ -0,0 +1,27 @@ + + + + + Show multi prices + + + + + + Multiple Price multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + Multiple Price Field Name multi-company + + + ['|',('company_id','=',False),('company_id','in',company_ids)] + + + diff --git a/product_multi_price/static/description/icon.png b/product_multi_price/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_multi_price/static/description/icon.png differ diff --git a/product_multi_price/static/description/index.html b/product_multi_price/static/description/index.html new file mode 100644 index 00000000000..1663b63735a --- /dev/null +++ b/product_multi_price/static/description/index.html @@ -0,0 +1,478 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Product Multi Price

+ +

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

This module allows to set multiple prices to products and base pricelist +rules on them.

+

Table of contents

+ +
+

Configuration

+

To configure multiple prices you need to set multi prices field names +first. To do so, you need admin permissions. Then go to:

+
    +
  1. Settings > Technical > Database Structure > Price Field Names
  2. +
  3. Create the multi price fields you need.
  4. +
+

If you have multiple companies, you can assign independent field sets +for each one.

+

Note: ‘Show multi prices’ access group must be checked to be able to add +multiple prices in the product form view.

+
+
+

Usage

+

To use this module, you need to:

+
    +
  1. Go to the product page.
  2. +
  3. In the general tab, there’s a list called Other Prices.
  4. +
  5. You can add one for every price name available.
  6. +
+

To base pricelist rules on that fields, in the pricelist:

+
    +
  1. Add a rule and choose formula as the computing method.
  2. +
  3. In the Based on dropdown list, select Other Price.
  4. +
  5. A new list appear: Other Price Name. Pick the one you need.
  6. +
  7. Configure the formula.
  8. +
  9. Now the rule is based on that price for the products that have it +configured. Otherwise, it will return 0.
  10. +
+
+
+

Known issues / Roadmap

+
    +
  • Add mechanisms that allow to set multiprices values from external +flows. For example: having AVCO, FIFO and Standard prices computed +simultaneously in this table.
  • +
+
+
+

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

+
    +
  • Tecnativa
  • +
+
+
+

Contributors

+
    +
  • Tecnativa
      +
    • David Vidal
    • +
    • Pedro M. Baeza
    • +
    • Ernesto Tejeda
    • +
    • Sergio Teruel
    • +
    +
  • +
+
+
+

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/product-attribute project on GitHub.

+

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

+
+
+
+
+ + diff --git a/product_multi_price/tests/__init__.py b/product_multi_price/tests/__init__.py new file mode 100644 index 00000000000..03b7c618dfc --- /dev/null +++ b/product_multi_price/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_multi_price diff --git a/product_multi_price/tests/test_product_multi_price.py b/product_multi_price/tests/test_product_multi_price.py new file mode 100644 index 00000000000..96e5d5b4f46 --- /dev/null +++ b/product_multi_price/tests/test_product_multi_price.py @@ -0,0 +1,122 @@ +# Copyright 2020 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import Command, fields +from odoo.tests.common import TransactionCase + + +class TestProductMultiPrice(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.price_name_obj = cls.env["product.multi.price.name"] + cls.price_field_1 = cls.price_name_obj.create({"name": "test_field_1"}) + cls.price_field_2 = cls.price_name_obj.create({"name": "test_field_2"}) + prod_tmpl_obj = cls.env["product.template"] + cls.prod_1 = prod_tmpl_obj.create( + { + "name": "Test Product Template", + "price_ids": [ + Command.create({"name": cls.price_field_1.id, "price": 5.5}), + Command.create({"name": cls.price_field_2.id, "price": 20.0}), + ], + } + ) + cls.prod_att_1 = cls.env["product.attribute"].create({"name": "Color"}) + cls.prod_attr1_v1 = cls.env["product.attribute.value"].create( + {"name": "red", "attribute_id": cls.prod_att_1.id} + ) + cls.prod_attr1_v2 = cls.env["product.attribute.value"].create( + {"name": "blue", "attribute_id": cls.prod_att_1.id} + ) + cls.prod_2 = prod_tmpl_obj.create( + { + "name": "Test Product 2 With Variants", + "attribute_line_ids": [ + Command.create( + { + "attribute_id": cls.prod_att_1.id, + "value_ids": [ + Command.set( + [cls.prod_attr1_v1.id, cls.prod_attr1_v2.id] + ) + ], + }, + ) + ], + } + ) + cls.prod_prod_2_1 = cls.prod_2.product_variant_ids[0] + cls.prod_prod_2_2 = cls.prod_2.product_variant_ids[1] + cls.prod_prod_2_1.write( + { + "price_ids": [ + Command.create({"name": cls.price_field_1.id, "price": 6.6}), + Command.create({"name": cls.price_field_2.id, "price": 7.7}), + ], + } + ) + cls.prod_prod_2_2.write( + { + "price_ids": [ + Command.create({"name": cls.price_field_1.id, "price": 8.8}), + Command.create({"name": cls.price_field_2.id, "price": 9.9}), + ], + } + ) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Test pricelist", + "item_ids": [ + Command.create( + { + "compute_price": "formula", + "base": "multi_price", + "multi_price_name": cls.price_field_1.id, + "price_discount": 10, + "display_applied_on": "1_product", + }, + ) + ], + } + ) + + def test_product_multi_price_pricelist(self): + """Pricelists based on multi prices for templates or variants""" + price = self.prod_1.with_context( + pricelist=self.pricelist.id + )._get_contextual_price() + self.assertAlmostEqual(price, 4.95) + price = self.prod_prod_2_1.with_context( + pricelist=self.pricelist.id + )._get_contextual_price() + self.assertAlmostEqual(price, 5.94) + price = self.prod_prod_2_2.with_context( + pricelist=self.pricelist.id + )._get_contextual_price() + self.assertAlmostEqual(price, 7.92) + + def test_product_multi_price_pricelist_item(self): + """Pricelists based on multi prices using the pricelist items""" + pricelist_item = self.pricelist.item_ids[0] + today = fields.Date.context_today(self.env.user) + price = pricelist_item._compute_price( + self.prod_1, + 1.0, + self.prod_1.uom_id, + today, + ) + self.assertAlmostEqual(price, 4.95) + price = pricelist_item._compute_price( + self.prod_prod_2_1, + 1.0, + self.prod_prod_2_1.uom_id, + today, + ) + self.assertAlmostEqual(price, 5.94) + price = pricelist_item._compute_price( + self.prod_prod_2_2, + 1.0, + self.prod_prod_2_2.uom_id, + today, + ) + self.assertAlmostEqual(price, 7.92) diff --git a/product_multi_price/views/multi_price_views.xml b/product_multi_price/views/multi_price_views.xml new file mode 100644 index 00000000000..aa9eb35b361 --- /dev/null +++ b/product_multi_price/views/multi_price_views.xml @@ -0,0 +1,72 @@ + + + + product.multi.price + + + + + + + + + + + product.multi.price + +
+ + + + + + + + +
+
+
+ + product.multi.price + primary + + + + + + bottom + + + + + product.multi.price.name + + + + + + + + + Price Field Names + product.multi.price.name + {} + + + +
diff --git a/product_multi_price/views/product_pricelist_views.xml b/product_multi_price/views/product_pricelist_views.xml new file mode 100644 index 00000000000..35161de64f7 --- /dev/null +++ b/product_multi_price/views/product_pricelist_views.xml @@ -0,0 +1,17 @@ + + + + product.pricelist.item + + + + + + + + diff --git a/product_multi_price/views/product_views.xml b/product_multi_price/views/product_views.xml new file mode 100644 index 00000000000..c5a64673c3c --- /dev/null +++ b/product_multi_price/views/product_views.xml @@ -0,0 +1,30 @@ + + + + product.template + + + + + + + + + product.product + + + + + + + + diff --git a/product_packaging_archive/README.rst b/product_packaging_archive/README.rst new file mode 100644 index 00000000000..2bf2b583581 --- /dev/null +++ b/product_packaging_archive/README.rst @@ -0,0 +1,80 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================= +Product Packaging Archive +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:9a2b03216467cb37f7bc500d0c7448840e53fa9d247d8f9668dada282951dc08 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_packaging_archive + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_packaging_archive + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to archive product packaging. + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Camptocamp + +Contributors +------------ + +- Thierry Ducrest + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_packaging_archive/__init__.py b/product_packaging_archive/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_packaging_archive/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_packaging_archive/__manifest__.py b/product_packaging_archive/__manifest__.py new file mode 100644 index 00000000000..f7555c64e47 --- /dev/null +++ b/product_packaging_archive/__manifest__.py @@ -0,0 +1,15 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +{ + "name": "Product Packaging Archive", + "summary": """Add an active field on product packaging""", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "Camptocamp, Odoo Community Association (OCA)", + "depends": ["product"], + "data": [ + "views/product_packaging.xml", + ], + "website": "https://github.com/OCA/product-attribute", +} diff --git a/product_packaging_archive/i18n/it.po b/product_packaging_archive/i18n/it.po new file mode 100644 index 00000000000..9e80495640d --- /dev/null +++ b/product_packaging_archive/i18n/it.po @@ -0,0 +1,33 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_packaging_archive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-12-11 10:42+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_packaging_archive +#: model:ir.model.fields,field_description:product_packaging_archive.field_product_packaging__active +msgid "Active" +msgstr "Attivo" + +#. module: product_packaging_archive +#: model_terms:ir.ui.view,arch_db:product_packaging_archive.product_packaging_form_view_inherit +#: model_terms:ir.ui.view,arch_db:product_packaging_archive.product_packaging_search_view_inherit +msgid "Archived" +msgstr "In archivio" + +#. module: product_packaging_archive +#: model:ir.model,name:product_packaging_archive.model_product_packaging +msgid "Product Packaging" +msgstr "Imballaggio prodotto" diff --git a/product_packaging_archive/i18n/product_packaging_archive.pot b/product_packaging_archive/i18n/product_packaging_archive.pot new file mode 100644 index 00000000000..bad3d4bd92a --- /dev/null +++ b/product_packaging_archive/i18n/product_packaging_archive.pot @@ -0,0 +1,30 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_packaging_archive +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_packaging_archive +#: model:ir.model.fields,field_description:product_packaging_archive.field_product_packaging__active +msgid "Active" +msgstr "" + +#. module: product_packaging_archive +#: model_terms:ir.ui.view,arch_db:product_packaging_archive.product_packaging_form_view_inherit +#: model_terms:ir.ui.view,arch_db:product_packaging_archive.product_packaging_search_view_inherit +msgid "Archived" +msgstr "" + +#. module: product_packaging_archive +#: model:ir.model,name:product_packaging_archive.model_product_packaging +msgid "Product Packaging" +msgstr "" diff --git a/product_packaging_archive/models/__init__.py b/product_packaging_archive/models/__init__.py new file mode 100644 index 00000000000..2c4d9a88a37 --- /dev/null +++ b/product_packaging_archive/models/__init__.py @@ -0,0 +1 @@ +from . import product_packaging diff --git a/product_packaging_archive/models/product_packaging.py b/product_packaging_archive/models/product_packaging.py new file mode 100644 index 00000000000..5152fbc0fce --- /dev/null +++ b/product_packaging_archive/models/product_packaging.py @@ -0,0 +1,10 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import fields, models + + +class ProductPackaging(models.Model): + _inherit = "product.packaging" + + active = fields.Boolean(default=True) diff --git a/product_packaging_archive/pyproject.toml b/product_packaging_archive/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_packaging_archive/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_packaging_archive/readme/CONTRIBUTORS.md b/product_packaging_archive/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..62ceaf42fc5 --- /dev/null +++ b/product_packaging_archive/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Thierry Ducrest \<\> diff --git a/product_packaging_archive/readme/DESCRIPTION.md b/product_packaging_archive/readme/DESCRIPTION.md new file mode 100644 index 00000000000..10adc56da20 --- /dev/null +++ b/product_packaging_archive/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module allows to archive product packaging. diff --git a/product_packaging_archive/static/description/icon.png b/product_packaging_archive/static/description/icon.png new file mode 100644 index 00000000000..1dcc49c24f3 Binary files /dev/null and b/product_packaging_archive/static/description/icon.png differ diff --git a/product_packaging_archive/static/description/index.html b/product_packaging_archive/static/description/index.html new file mode 100644 index 00000000000..f1e9231119f --- /dev/null +++ b/product_packaging_archive/static/description/index.html @@ -0,0 +1,429 @@ + + + + + +README.rst + + + +
+ + + +Odoo Community Association + +
+

Product Packaging Archive

+ +

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

This module allows to archive product packaging.

+

Table of contents

+ +
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Maintainers

+

This module is maintained by the OCA.

+ +Odoo Community Association + +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

This module is part of the OCA/product-attribute project on GitHub.

+

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

+
+
+
+
+ + diff --git a/product_packaging_archive/tests/__init__.py b/product_packaging_archive/tests/__init__.py new file mode 100644 index 00000000000..b10d0adf924 --- /dev/null +++ b/product_packaging_archive/tests/__init__.py @@ -0,0 +1 @@ +from . import test_product_packaging_archive diff --git a/product_packaging_archive/tests/test_product_packaging_archive.py b/product_packaging_archive/tests/test_product_packaging_archive.py new file mode 100644 index 00000000000..1893b33c8d6 --- /dev/null +++ b/product_packaging_archive/tests/test_product_packaging_archive.py @@ -0,0 +1,29 @@ +# Copyright 2025 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + + +from odoo.addons.base.tests.common import BaseCommon + + +class TestProductPackagingArchive(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product = cls.env["product.product"].create({"name": "Test Product"}) + cls.packaging_1 = cls.env["product.packaging"].create( + { + "name": "Packaging 1", + "product_id": cls.product.id, + } + ) + + def test_packaging_archive(self): + packaging = self.env["product.packaging"].search( + [("id", "=", self.packaging_1.id)] + ) + self.assertTrue(packaging) + self.packaging_1.active = False + packaging = self.env["product.packaging"].search( + [("id", "=", self.packaging_1.id)] + ) + self.assertFalse(packaging) diff --git a/product_packaging_archive/views/product_packaging.xml b/product_packaging_archive/views/product_packaging.xml new file mode 100644 index 00000000000..b1b8efd89ab --- /dev/null +++ b/product_packaging_archive/views/product_packaging.xml @@ -0,0 +1,33 @@ + + + + product.packaging.form.view.inherit + product.packaging + + + + + + + + + + product.packaging.search.view.inherit + product.packaging + + + + + + + + diff --git a/product_packaging_level/README.rst b/product_packaging_level/README.rst index 01cbc1b9ab7..8d1d82b025d 100644 --- a/product_packaging_level/README.rst +++ b/product_packaging_level/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ======================= Product Packaging Level ======================= @@ -7,13 +11,13 @@ Product Packaging Level !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:0aba50b41d778298eca63400fb08c8e42fe823c941b0fb790734367e2e5bc583 + !! source digest: sha256:27e3c09738782444af910b7e57d85502e2fc90a6c29327d923c596f32a007be9 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png :target: https://odoo-community.org/page/development-status :alt: Beta -.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html :alt: License: LGPL-3 .. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github diff --git a/product_packaging_level/__manifest__.py b/product_packaging_level/__manifest__.py index ca3d26a3d3f..99a08977d9a 100644 --- a/product_packaging_level/__manifest__.py +++ b/product_packaging_level/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Product Packaging Level", - "version": "18.0.1.0.0", + "version": "18.0.1.1.0", "development_status": "Beta", "category": "Product", "summary": "This module binds a product packaging to a packaging level", diff --git a/product_packaging_level/static/description/index.html b/product_packaging_level/static/description/index.html index 74c02881f9f..1598fafe400 100644 --- a/product_packaging_level/static/description/index.html +++ b/product_packaging_level/static/description/index.html @@ -3,7 +3,7 @@ -Product Packaging Level +README.rst -
-

Product Packaging Level

+
+ + +Odoo Community Association + +
+

Product Packaging Level

-

Beta License: LGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

+

Beta License: LGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

This module binds a product packaging to a packaging level.

There are usually 3 levels:

    @@ -400,7 +405,7 @@

    Product Packaging Level

-

Usage

+

Usage

To create a new packaging level:

  1. Go to Inventory > Configuration > Products > Product Packaging @@ -409,7 +414,7 @@

    Usage

-

Bug Tracker

+

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 @@ -417,15 +422,15 @@

Bug Tracker

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

-

Credits

+

Credits

-

Authors

+

Authors

  • Camptocamp
-

Other credits

+

Other credits

The development and migration of this module has been financially supported by:

-

Maintainers

+

Maintainers

This module is maintained by the OCA.

Odoo Community Association @@ -460,5 +465,6 @@

Maintainers

+
diff --git a/product_packaging_level/views/product_packaging_view.xml b/product_packaging_level/views/product_packaging_view.xml index 2a4763bce4f..0d1b77057b0 100644 --- a/product_packaging_level/views/product_packaging_view.xml +++ b/product_packaging_level/views/product_packaging_view.xml @@ -35,7 +35,10 @@ 1 - name_policy != 'user_defined' + name_policy != 'user_defined' + + + diff --git a/product_pricelist_direct_print/README.rst b/product_pricelist_direct_print/README.rst index a653ff3bff1..5eeb84de085 100644 --- a/product_pricelist_direct_print/README.rst +++ b/product_pricelist_direct_print/README.rst @@ -11,7 +11,7 @@ Product Pricelist Direct Print !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:95226b4451545bcbfb63c1ffb5bc6d39fd01b2ce00ddfdd40fb929f0e5aa8dcd + !! source digest: sha256:59906ddc4c56bc5358664bfdbc0be952dfcd27ddb93a9d1bbfdeb2b1350fa910 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png diff --git a/product_pricelist_direct_print/__manifest__.py b/product_pricelist_direct_print/__manifest__.py index 79f3c38f733..abe875b6214 100644 --- a/product_pricelist_direct_print/__manifest__.py +++ b/product_pricelist_direct_print/__manifest__.py @@ -5,7 +5,7 @@ "name": "Product Pricelist Direct Print", "summary": "Print price list from menu option, product templates, " "products variants or price lists", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "category": "Product", "website": "https://github.com/OCA/product-attribute", "author": "Tecnativa, GRAP, Odoo Community Association (OCA)", diff --git a/product_pricelist_direct_print/i18n/es.po b/product_pricelist_direct_print/i18n/es.po index c3309c17d58..f78e91ee3f3 100644 --- a/product_pricelist_direct_print/i18n/es.po +++ b/product_pricelist_direct_print/i18n/es.po @@ -345,6 +345,11 @@ msgstr "" msgid "Name" msgstr "Nombre" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/fr.po b/product_pricelist_direct_print/i18n/fr.po index b7da9a98ea0..08cab214ab7 100644 --- a/product_pricelist_direct_print/i18n/fr.po +++ b/product_pricelist_direct_print/i18n/fr.po @@ -338,6 +338,11 @@ msgstr "" msgid "Name" msgstr "Nom" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/it.po b/product_pricelist_direct_print/i18n/it.po index f0dd75062df..11a7404f7a9 100644 --- a/product_pricelist_direct_print/i18n/it.po +++ b/product_pricelist_direct_print/i18n/it.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2025-09-17 10:59+0000\n" +"PO-Revision-Date: 2026-01-10 08:29+0000\n" "Last-Translator: mymage \n" "Language-Team: none\n" "Language: it\n" @@ -45,8 +45,8 @@ msgid "" " " msgstr "" "
\n" -"

Spettabile ,

\n" +"

Spettabile ,

\n" "

\n" " L'allegato è un documento PDF che contiene il\n" " listino .\n" @@ -56,8 +56,8 @@ msgstr "" "

Grazie,

\n" "\n" "

\n" -" \n" +" \n" " \n" " \n" "

\n" @@ -357,6 +357,11 @@ msgstr "Scadenza mia attività" msgid "Name" msgstr "Nome" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "Evento calendario attività successiva" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/nl.po b/product_pricelist_direct_print/i18n/nl.po index 214e9d01462..cb06c43631a 100644 --- a/product_pricelist_direct_print/i18n/nl.po +++ b/product_pricelist_direct_print/i18n/nl.po @@ -330,6 +330,11 @@ msgstr "" msgid "Name" msgstr "" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/nl_NL.po b/product_pricelist_direct_print/i18n/nl_NL.po index 3247a33ab27..13ec803ccc9 100644 --- a/product_pricelist_direct_print/i18n/nl_NL.po +++ b/product_pricelist_direct_print/i18n/nl_NL.po @@ -339,6 +339,11 @@ msgstr "Mijn activiteit deadline" msgid "Name" msgstr "Naam" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/product_pricelist_direct_print.pot b/product_pricelist_direct_print/i18n/product_pricelist_direct_print.pot index f01e39ecec8..8000de00255 100644 --- a/product_pricelist_direct_print/i18n/product_pricelist_direct_print.pot +++ b/product_pricelist_direct_print/i18n/product_pricelist_direct_print.pot @@ -326,6 +326,11 @@ msgstr "" msgid "Name" msgstr "" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/i18n/tr.po b/product_pricelist_direct_print/i18n/tr.po index 804206301ed..529d64abcb7 100644 --- a/product_pricelist_direct_print/i18n/tr.po +++ b/product_pricelist_direct_print/i18n/tr.po @@ -337,6 +337,11 @@ msgstr "" msgid "Name" msgstr "Adı" +#. module: product_pricelist_direct_print +#: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_calendar_event_id +msgid "Next Activity Calendar Event" +msgstr "" + #. module: product_pricelist_direct_print #: model:ir.model.fields,field_description:product_pricelist_direct_print.field_product_pricelist_print__activity_date_deadline msgid "Next Activity Deadline" diff --git a/product_pricelist_direct_print/static/description/index.html b/product_pricelist_direct_print/static/description/index.html index 652d33e794d..dfb0c428e31 100644 --- a/product_pricelist_direct_print/static/description/index.html +++ b/product_pricelist_direct_print/static/description/index.html @@ -372,7 +372,7 @@

Product Pricelist Direct Print

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:95226b4451545bcbfb63c1ffb5bc6d39fd01b2ce00ddfdd40fb929f0e5aa8dcd +!! source digest: sha256:59906ddc4c56bc5358664bfdbc0be952dfcd27ddb93a9d1bbfdeb2b1350fa910 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

Print price list from menu option, product templates, products variants diff --git a/product_pricelist_direct_print/wizards/product_pricelist_print.py b/product_pricelist_direct_print/wizards/product_pricelist_print.py index 0303cbac9f0..739ef74311b 100644 --- a/product_pricelist_direct_print/wizards/product_pricelist_print.py +++ b/product_pricelist_direct_print/wizards/product_pricelist_print.py @@ -312,38 +312,38 @@ def _compute_context_active_model(self): def get_products_domain(self): domain = [("sale_ok", "=", True)] if self.show_only_defined_products: - aux_domain = [] + aux_domain = [(0, "=", 1)] items_dic = {"categ_ids": [], "product_ids": [], "variant_ids": []} for item in self.pricelist_id.item_ids: if item.applied_on == "0_product_variant": items_dic["variant_ids"].append(item.product_id.id) if item.applied_on == "1_product": items_dic["product_ids"].append(item.product_tmpl_id.id) - if item.applied_on == "2_product_category" and item.categ_id.parent_id: + if item.applied_on == "2_product_category": items_dic["categ_ids"].append(item.categ_id.id) if items_dic["categ_ids"]: - aux_domain = expression.AND( + aux_domain = expression.OR( [aux_domain, [("categ_id", "in", items_dic["categ_ids"])]] ) if items_dic["product_ids"]: if self.show_variants: - aux_domain = expression.AND( + aux_domain = expression.OR( [ aux_domain, [("product_tmpl_id", "in", items_dic["product_ids"])], ] ) else: - aux_domain = expression.AND( + aux_domain = expression.OR( [aux_domain, [("id", "in", items_dic["product_ids"])]] ) if items_dic["variant_ids"]: if self.show_variants: - aux_domain = expression.AND( + aux_domain = expression.OR( [aux_domain, [("id", "in", items_dic["variant_ids"])]] ) else: - aux_domain = expression.AND( + aux_domain = expression.OR( [ aux_domain, [("product_variant_ids", "in", items_dic["variant_ids"])], diff --git a/product_pricelist_direct_print_xlsx/README.rst b/product_pricelist_direct_print_xlsx/README.rst index b66690ecf55..02d6b1113b4 100644 --- a/product_pricelist_direct_print_xlsx/README.rst +++ b/product_pricelist_direct_print_xlsx/README.rst @@ -11,7 +11,7 @@ Product Pricelist Direct Print (XLSX) !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:f5d143bf38101ee72a0a6201b25371ba95f402ee42c819011556a69473d202bf + !! source digest: sha256:0f7edad20ac09e9fb78de60a6ee62e9ae88e362fba9b420bbd129f81bda79750 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png @@ -80,6 +80,10 @@ Contributors - Sylvain LE GAL <`https://twitter.com/legalsylvain\\> >`__ +- `Versada `__ + + - Maciej Wichowski + Maintainers ----------- diff --git a/product_pricelist_direct_print_xlsx/__manifest__.py b/product_pricelist_direct_print_xlsx/__manifest__.py index 8516414d214..cca02ad0854 100644 --- a/product_pricelist_direct_print_xlsx/__manifest__.py +++ b/product_pricelist_direct_print_xlsx/__manifest__.py @@ -4,7 +4,7 @@ { "name": "Product Pricelist Direct Print (XLSX)", "summary": "Print price list in XLSX format", - "version": "18.0.1.0.0", + "version": "18.0.1.0.2", "category": "Product", "website": "https://github.com/OCA/product-attribute", "author": "Tecnativa, GRAP, Odoo Community Association (OCA)", diff --git a/product_pricelist_direct_print_xlsx/readme/CONTRIBUTORS.md b/product_pricelist_direct_print_xlsx/readme/CONTRIBUTORS.md index 139bddb5721..2d33334ac41 100644 --- a/product_pricelist_direct_print_xlsx/readme/CONTRIBUTORS.md +++ b/product_pricelist_direct_print_xlsx/readme/CONTRIBUTORS.md @@ -8,3 +8,5 @@ - Alexey Pelykh \ - [GRAP](http://www.grap.coop/): - Sylvain LE GAL \ +- [Versada](https://versada.eu) + - Maciej Wichowski \ diff --git a/product_pricelist_direct_print_xlsx/report/product_pricelist_xlsx.py b/product_pricelist_direct_print_xlsx/report/product_pricelist_xlsx.py index 5eb9298f12d..56408e0a123 100644 --- a/product_pricelist_direct_print_xlsx/report/product_pricelist_xlsx.py +++ b/product_pricelist_direct_print_xlsx/report/product_pricelist_xlsx.py @@ -8,84 +8,52 @@ class ProductPricelistXlsx(models.AbstractModel): _inherit = "report.report_xlsx.abstract" _description = "Abstract model to export as xlsx the product pricelist" + def generate_xlsx_report(self, workbook, data, objects): + book = objects[0].with_context( + lang=objects[0].lang + or self.env["res.users"].browse(objects[0].create_uid.id).lang + ) + formats = self._prepare_formats(workbook, book) + self = self.with_context( + lang=book.lang or self.env["res.users"].browse(book.create_uid.id).lang + ) + pricelist = book.get_pricelist_to_print() + sheet = self._create_product_pricelist_sheet(workbook, book, pricelist, formats) + sheet = self._fill_data(workbook, sheet, book, pricelist, formats) + def _get_lang(self, user_id, lang_code=False): if not lang_code: lang_code = self.env["res.users"].browse(user_id).lang return self.env["res.lang"]._lang_get(lang_code) - def _create_product_pricelist_sheet(self, workbook, book, pricelist): - title_format = workbook.add_format( - {"bold": 1, "border": 1, "align": "left", "valign": "vjustify"} - ) - header_format = workbook.add_format( - { - "bold": 1, - "border": 1, - "align": "center", - "valign": "vjustify", - "fg_color": "#F2F2F2", - } - ) - lang = self._get_lang(book.create_uid.id, lang_code=book.lang) - date_format = lang.date_format.replace("%d", "dd") - date_format = date_format.replace("%m", "mm") - date_format = date_format.replace("%Y", "YYYY") - date_format = date_format.replace("/", "-") - date_format = workbook.add_format({"num_format": date_format}) + def _create_product_pricelist_sheet(self, workbook, book, pricelist, formats): sheet = workbook.add_worksheet(self.env._("PRODUCTS")) - sheet.set_column("A:A", 45) - sheet.set_column("B:H", 15) # Title construction - sheet.write("A1", self.env._("Price List Name:"), title_format) + sheet.write("A1", self.env._("Price List Name:"), formats["title"]) if book.show_pricelist_name: sheet.write("A2", pricelist.name) else: sheet.write("A2", self.env._("Special Pricelist")) - sheet.write("B1", self.env._("Currency:"), title_format) + sheet.write("B1", self.env._("Currency:"), formats["title"]) sheet.write("B2", pricelist.currency_id.name) - sheet.write("D1", self.env._("Date:"), title_format) - sheet.write("D2", book.date, date_format) + sheet.write("D1", self.env._("Date:"), formats["title"]) + sheet.write("D2", book.date, formats["date"]) # Header construction if book.partner_id: - sheet.write(4, 0, book.partner_id.name, header_format) + sheet.write(4, 0, book.partner_id.name, formats["header"]) elif book.partner_ids: - sheet.write(4, 0, book.partner_ids[0].name, header_format) - next_col = 0 - sheet.write(5, next_col, self.env._("Description"), header_format) - next_col = self._add_extra_header(sheet, book, next_col, header_format) - if book.show_internal_category: - next_col += 1 - sheet.write(5, next_col, self.env._("Internal Category"), header_format) - if book.show_standard_price: - next_col += 1 - sheet.write(5, next_col, self.env._("Cost Price"), header_format) - if book.show_sale_price: - next_col += 1 - sheet.write(5, next_col, self.env._("Sale Price"), header_format) - next_col += 1 - sheet.write(5, next_col, self.env._("List Price"), header_format) - if book.show_product_uom: - next_col += 1 - sheet.write(5, next_col, self.env._("UoM"), header_format) + sheet.write(4, 0, book.partner_ids[0].name, formats["header"]) + header_row = self._prepare_header_row(book) + self._set_column_widths(sheet, header_row) + sheet.write_row(5, 0, header_row, formats["header"]) return sheet - def _add_extra_header(self, sheet, book, next_col, header_format): - return next_col - - def _fill_data(self, workbook, sheet, book, pricelist): - bold_format = workbook.add_format({"bold": 1}) - decimal_format = workbook.add_format({"num_format": "0.00"}) - decimal_bold_format = workbook.add_format({"num_format": "0.00", "bold": 1}) + def _fill_data(self, workbook, sheet, book, pricelist, formats): row = 6 - formats = { - "bold_format": bold_format, - "decimal_format": decimal_format, - "decimal_bold_format": decimal_bold_format, - } for group in book.get_groups_to_print(): if book.breakage_per_category: sheet.write( - row, 0, book.get_group_name(group["group_name"]), bold_format + row, 0, book.get_group_name(group["group_name"]), formats["bold"] ) row += 1 for product_data in group["products"]: @@ -95,47 +63,80 @@ def _fill_data(self, workbook, sheet, book, pricelist): if isinstance(product_data, dict) else product_data ) - next_col = 0 - sheet.write(row, next_col, product.display_name) - next_col = self._add_extra_info( - sheet, book, product, row, next_col, **formats - ) - if book.show_internal_category: - next_col += 1 - sheet.write(row, next_col, product.categ_id.display_name) - if book.show_standard_price: - next_col += 1 - sheet.write(row, next_col, product.standard_price, decimal_format) - if book.show_sale_price: - next_col += 1 - sheet.write(row, next_col, product.list_price, decimal_format) - next_col += 1 - sheet.write( - row, - next_col, - book.with_context(product=product).product_price, - decimal_bold_format, + row_with_formats = self._prepare_data_row_with_formats( + book, product, formats ) - if book.show_product_uom: - next_col += 1 - sheet.write(row, next_col, product.uom_id.name, bold_format) + for i, cell_with_format in enumerate(row_with_formats): + cell_value, format_ = cell_with_format + sheet.write(row, i, cell_value, format_) row += 1 if book.summary: - sheet.write(row, 0, self.env._("Summary:"), bold_format) + sheet.write(row, 0, self.env._("Summary:"), formats["bold"]) sheet.write(row + 1, 0, book.summary) return sheet - def _add_extra_info(self, sheet, book, product, row, next_col, **kw): - return next_col - - def generate_xlsx_report(self, workbook, data, objects): - book = objects[0].with_context( - lang=objects[0].lang - or self.env["res.users"].browse(objects[0].create_uid.id).lang + def _prepare_formats(self, workbook, book): + lang = self._get_lang(book.create_uid.id, lang_code=book.lang) + date_format = ( + lang.date_format.replace("%d", "dd") + .replace("%m", "mm") + .replace("%Y", "YYYY") + .replace("/", "-") ) - self = self.with_context( - lang=book.lang or self.env["res.users"].browse(book.create_uid.id).lang + return { + "title": workbook.add_format( + {"bold": 1, "border": 1, "align": "left", "valign": "vjustify"} + ), + "header": workbook.add_format( + { + "bold": 1, + "border": 1, + "align": "center", + "valign": "vjustify", + "fg_color": "#F2F2F2", + } + ), + "date": workbook.add_format({"num_format": date_format}), + "bold": workbook.add_format({"bold": 1}), + "decimal": workbook.add_format({"num_format": "0.00"}), + "decimal_bold": workbook.add_format({"num_format": "0.00", "bold": 1}), + } + + def _prepare_header_row(self, book): + _ = self.env._ + row = [_("Description")] + if book.show_internal_category: + row.append(_("Internal Category")) + if book.show_standard_price: + row.append(_("Cost Price")) + if book.show_sale_price: + row.append(_("Sale Price")) + row.append(_("List Price")) + if book.show_product_uom: + row.append(_("UoM")) + return row + + def _prepare_data_row_with_formats(self, book, product, formats): + row = [(product.display_name, None)] + if book.show_internal_category: + row.append((product.categ_id.display_name, None)) + if book.show_standard_price: + row.append((product.standard_price, formats["decimal"])) + if book.show_sale_price: + row.append((product.list_price, formats["decimal"])) + row.append( + ( + book.with_context(product=product).product_price, + formats["decimal_bold"], + ) ) - pricelist = book.get_pricelist_to_print() - sheet = self._create_product_pricelist_sheet(workbook, book, pricelist) - sheet = self._fill_data(workbook, sheet, book, pricelist) + if book.show_product_uom: + row.append((product.uom_id.name, formats["bold"])) + return row + + def _set_column_widths(self, sheet, header_row): + # Special label with wider column + description_label = self.env._("Description") + for i, label in enumerate(header_row): + width = 45 if label == description_label else 15 + sheet.set_column(i, i, width) diff --git a/product_pricelist_direct_print_xlsx/static/description/index.html b/product_pricelist_direct_print_xlsx/static/description/index.html index dd4f4468afe..499e6c771de 100644 --- a/product_pricelist_direct_print_xlsx/static/description/index.html +++ b/product_pricelist_direct_print_xlsx/static/description/index.html @@ -372,7 +372,7 @@

Product Pricelist Direct Print (XLSX)

!! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:f5d143bf38101ee72a0a6201b25371ba95f402ee42c819011556a69473d202bf +!! source digest: sha256:0f7edad20ac09e9fb78de60a6ee62e9ae88e362fba9b420bbd129f81bda79750 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

This module is based on the OCA module @@ -427,6 +427,10 @@

Contributors

<https://twitter.com/legalsylvain\> +
  • Versada +
  • diff --git a/product_pricelist_item_list_view/README.rst b/product_pricelist_item_list_view/README.rst new file mode 100644 index 00000000000..a268da9e8dc --- /dev/null +++ b/product_pricelist_item_list_view/README.rst @@ -0,0 +1,112 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================= +Pricelist rules list view +========================= + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6d9e7a99bbd3b275eaec7c7c2eab19fe317ad029a11dba6eaa024c89c3d2a2d7 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png + :target: https://odoo-community.org/page/development-status + :alt: Production/Stable +.. |badge2| image:: https://img.shields.io/badge/license-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_pricelist_item_list_view + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_pricelist_item_list_view + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a new menu item "Pricelist rules" to list and search +every pricelist rule. This is useful when you have many rules and you +want to search among them. For instance, if you have many fixed price +rules associated to product variants, without this module you could not +easily find a variant's price. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + + + +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 +------- + +* Agile Business Group +* ForgeFlow + +Contributors +------------ + +- `agilebg `__ + + - Lorenzo Battistini + +- `Studio73 `__ + + - Carlos Reyes + +Other credits +------------- + +The development and migration of this module has been financially +supported by: + +- agilebg + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-LoisRForgeFlow| image:: https://github.com/LoisRForgeFlow.png?size=40px + :target: https://github.com/LoisRForgeFlow + :alt: LoisRForgeFlow + +Current `maintainer `__: + +|maintainer-LoisRForgeFlow| + +This module is part of the `OCA/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_pricelist_item_list_view/__init__.py b/product_pricelist_item_list_view/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/product_pricelist_item_list_view/__manifest__.py b/product_pricelist_item_list_view/__manifest__.py new file mode 100644 index 00000000000..079da3bc0f0 --- /dev/null +++ b/product_pricelist_item_list_view/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright 2016 Lorenzo Battistini - Agile Business Group +# Copyright 2023 ForgeFlow S.L. (https://www.forgeflow.com) +# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). + +{ + "name": "Pricelist rules list view", + "summary": "View and search the list of pricelist items", + "version": "18.0.1.0.0", + "category": "Sales Management", + "website": "https://github.com/OCA/product-attribute", + "author": "Agile Business Group, ForgeFlow, Odoo Community Association (OCA)", + "maintainers": ["LoisRForgeFlow"], + "development_status": "Production/Stable", + "license": "LGPL-3", + "application": False, + "installable": True, + "depends": [ + "sale", + ], + "data": [ + "views/pricelist_view.xml", + ], +} diff --git a/product_pricelist_item_list_view/i18n/ca.po b/product_pricelist_item_list_view/i18n/ca.po new file mode 100644 index 00000000000..5e4df7578ad --- /dev/null +++ b/product_pricelist_item_list_view/i18n/ca.po @@ -0,0 +1,52 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-03 15:37+0000\n" +"PO-Revision-Date: 2017-11-03 15:37+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n" +"Language: ca\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "" + +#~ msgid "Product" +#~ msgstr "Producte" diff --git a/product_pricelist_item_list_view/i18n/de.po b/product_pricelist_item_list_view/i18n/de.po new file mode 100644 index 00000000000..670e06f88d8 --- /dev/null +++ b/product_pricelist_item_list_view/i18n/de.po @@ -0,0 +1,52 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-03 15:37+0000\n" +"PO-Revision-Date: 2017-11-03 15:37+0000\n" +"Last-Translator: OCA Transbot , 2017\n" +"Language-Team: German (https://www.transifex.com/oca/teams/23907/de/)\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "" + +#~ msgid "Product" +#~ msgstr "Produkt" diff --git a/product_pricelist_item_list_view/i18n/es.po b/product_pricelist_item_list_view/i18n/es.po new file mode 100644 index 00000000000..930fe22560a --- /dev/null +++ b/product_pricelist_item_list_view/i18n/es.po @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +# Translators: +# OCA Transbot , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-03 15:37+0000\n" +"PO-Revision-Date: 2023-11-15 20:38+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: Spanish (https://www.transifex.com/oca/teams/23907/es/)\n" +"Language: es\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "Fecha Finalización" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "Precio Expirado" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "Precio Futuro" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "Precio Vigente" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "Normas de Precios" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "Fecha de Inicio" + +#~ msgid "Product" +#~ msgstr "Producto" diff --git a/product_pricelist_item_list_view/i18n/fr.po b/product_pricelist_item_list_view/i18n/fr.po new file mode 100644 index 00000000000..416b4778ee8 --- /dev/null +++ b/product_pricelist_item_list_view/i18n/fr.po @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +# Translators: +# leemannd , 2017 +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 9.0c\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2017-11-03 15:37+0000\n" +"PO-Revision-Date: 2023-12-08 17:33+0000\n" +"Last-Translator: kbentaleb \n" +"Language-Team: French (https://www.transifex.com/oca/teams/23907/fr/)\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.17\n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "Date de fin" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "Prix expiré" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "Prix futur" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "Prix en cours" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "Règles de prix" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "Date de début" + +#~ msgid "Product" +#~ msgstr "Produit" diff --git a/product_pricelist_item_list_view/i18n/it.po b/product_pricelist_item_list_view/i18n/it.po new file mode 100644 index 00000000000..1b83be86b5d --- /dev/null +++ b/product_pricelist_item_list_view/i18n/it.po @@ -0,0 +1,47 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-01-27 21:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "Data fine" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "Pezzo scaduto" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "Prezzo futro" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "Prezzo in corso" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "Regole prezzi" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "Data inizio" diff --git a/product_pricelist_item_list_view/i18n/product_pricelist_item_list_view.pot b/product_pricelist_item_list_view/i18n/product_pricelist_item_list_view.pot new file mode 100644 index 00000000000..2f6a95c2ea0 --- /dev/null +++ b/product_pricelist_item_list_view/i18n/product_pricelist_item_list_view.pot @@ -0,0 +1,44 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_item_list_view +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "End Date" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Expired Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Future Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Ongoing Price" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model:ir.ui.menu,name:product_pricelist_item_list_view.product_pricelist_items_action_menu +msgid "Price Rules" +msgstr "" + +#. module: product_pricelist_item_list_view +#: model_terms:ir.ui.view,arch_db:product_pricelist_item_list_view.product_pricelist_item_view_search +msgid "Start Date" +msgstr "" diff --git a/product_pricelist_item_list_view/pyproject.toml b/product_pricelist_item_list_view/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_pricelist_item_list_view/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_pricelist_item_list_view/readme/CONTRIBUTORS.md b/product_pricelist_item_list_view/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..8f6068b496b --- /dev/null +++ b/product_pricelist_item_list_view/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [agilebg](https://www.agilebg.com/) + - Lorenzo Battistini \<\> +- [Studio73](https://www.studio73.es) + - Carlos Reyes \<\> diff --git a/product_pricelist_item_list_view/readme/CREDITS.md b/product_pricelist_item_list_view/readme/CREDITS.md new file mode 100644 index 00000000000..a4047d09c31 --- /dev/null +++ b/product_pricelist_item_list_view/readme/CREDITS.md @@ -0,0 +1,3 @@ +The development and migration of this module has been financially supported by: + +- agilebg diff --git a/product_pricelist_item_list_view/readme/DESCRIPTION.md b/product_pricelist_item_list_view/readme/DESCRIPTION.md new file mode 100644 index 00000000000..4e5a3c9ace4 --- /dev/null +++ b/product_pricelist_item_list_view/readme/DESCRIPTION.md @@ -0,0 +1,3 @@ +This module adds a new menu item "Pricelist rules" to list and search every pricelist rule. +This is useful when you have many rules and you want to search among them. +For instance, if you have many fixed price rules associated to product variants, without this module you could not easily find a variant's price. diff --git a/product_pricelist_item_list_view/readme/USAGE.md b/product_pricelist_item_list_view/readme/USAGE.md new file mode 100644 index 00000000000..8b137891791 --- /dev/null +++ b/product_pricelist_item_list_view/readme/USAGE.md @@ -0,0 +1 @@ + diff --git a/product_pricelist_item_list_view/static/description/icon.png b/product_pricelist_item_list_view/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_pricelist_item_list_view/static/description/icon.png differ diff --git a/product_pricelist_item_list_view/static/description/index.html b/product_pricelist_item_list_view/static/description/index.html new file mode 100644 index 00000000000..2ea8c3af2f3 --- /dev/null +++ b/product_pricelist_item_list_view/static/description/index.html @@ -0,0 +1,456 @@ + + + + + +README.rst + + + +
    + + + +Odoo Community Association + +
    +

    Pricelist rules list view

    + +

    Production/Stable License: LGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    This module adds a new menu item “Pricelist rules” to list and search +every pricelist rule. This is useful when you have many rules and you +want to search among them. For instance, if you have many fixed price +rules associated to product variants, without this module you could not +easily find a variant’s price.

    +

    Table of contents

    + +
    +

    Usage

    +
    +
    +

    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

    +
      +
    • Agile Business Group
    • +
    • ForgeFlow
    • +
    +
    +
    +

    Contributors

    + +
    +
    +

    Other credits

    +

    The development and migration of this module has been financially +supported by:

    +
      +
    • agilebg
    • +
    +
    +
    +

    Maintainers

    +

    This module is maintained by the OCA.

    + +Odoo Community Association + +

    OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

    +

    Current maintainer:

    +

    LoisRForgeFlow

    +

    This module is part of the OCA/product-attribute project on GitHub.

    +

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

    +
    +
    +
    +
    + + diff --git a/product_pricelist_item_list_view/views/pricelist_view.xml b/product_pricelist_item_list_view/views/pricelist_view.xml new file mode 100644 index 00000000000..c49d4deee17 --- /dev/null +++ b/product_pricelist_item_list_view/views/pricelist_view.xml @@ -0,0 +1,62 @@ + + + + product.pricelist.item.form + product.pricelist.item + + + + + + + + + + + + product.pricelist.item.search + product.pricelist.item + + + + + + + + + + + + + + + + + + + {'show_item_pricelist_id': 1} + + + + diff --git a/product_pricelist_margin/README.rst b/product_pricelist_margin/README.rst new file mode 100644 index 00000000000..0c2c281ee6a --- /dev/null +++ b/product_pricelist_margin/README.rst @@ -0,0 +1,96 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +======================== +Product Pricelist Margin +======================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:79a956055af86d377ffcc3e50021ebe96dd499f591be9153ac3e0f938d0c5e36 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_pricelist_margin + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_pricelist_margin + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module shows the product's cost and margin from the pricelists. The +margin is calculated as the difference between the price and the cost, +expressed as a percentage of the price. The price is based on the +computation applied from the current pricelist item. This allows the +user to make price simulations while editing the pricelist item. + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +- Go to "Sale > Products > Pricelists" +- Open a pricelist form +- There are 3 new columns on the "Price rules" list. + +|Pricelist Item| + +.. |Pricelist Item| image:: https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_pricelist_margin/static/description/pricelist_item.png + +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 +------- + +* Camptocamp + +Contributors +------------ + +- Nguyen Minh Chien +- Telmo Santos + +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/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_pricelist_margin/__init__.py b/product_pricelist_margin/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_pricelist_margin/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_pricelist_margin/__manifest__.py b/product_pricelist_margin/__manifest__.py new file mode 100644 index 00000000000..bb3656d098d --- /dev/null +++ b/product_pricelist_margin/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). +{ + "name": "Product Pricelist Margin", + "summary": "This module shows the product's cost and margin from the pricelists.", + "version": "18.0.1.0.0", + "category": "Product", + "website": "https://github.com/OCA/product-attribute", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": ["account"], + "data": [ + "views/product_pricelist_views.xml", + "views/product_pricelist_item_views.xml", + ], +} diff --git a/product_pricelist_margin/i18n/fr.pot b/product_pricelist_margin/i18n/fr.pot new file mode 100644 index 00000000000..7cd3d5a22bb --- /dev/null +++ b/product_pricelist_margin/i18n/fr.pot @@ -0,0 +1,45 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-03-20 08:44+0000\n" +"PO-Revision-Date: 2024-03-20 08:44+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: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__cost +msgid "Cost" +msgstr "Coût" + +#. module: product_pricelist_margin +#: model:ir.model.fields,help:product_pricelist_margin.field_product_pricelist_item__cost +msgid "" +"In Standard Price & AVCO: value of the product (automatically computed in AVCO).\n" +" In FIFO: value of the next unit that will leave the stock (automatically computed).\n" +" Used to value the product when the purchase cost is not known (e.g. inventory adjustment).\n" +" Used to compute margins on sale orders." +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin +msgid "Margin" +msgstr "Marge" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin_percent +msgid "Margin (%)" +msgstr "Marge (%)" + +#. module: product_pricelist_margin +#: model:ir.model,name:product_pricelist_margin.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Règle des listes des prix" diff --git a/product_pricelist_margin/i18n/it.po b/product_pricelist_margin/i18n/it.po new file mode 100644 index 00000000000..bd569c57c67 --- /dev/null +++ b/product_pricelist_margin/i18n/it.po @@ -0,0 +1,53 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-05-14 12:23+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__cost +msgid "Cost" +msgstr "Costo" + +#. module: product_pricelist_margin +#: model:ir.model.fields,help:product_pricelist_margin.field_product_pricelist_item__cost +msgid "" +"In Standard Price & AVCO: value of the product (automatically computed in AVCO).\n" +" In FIFO: value of the next unit that will leave the stock (automatically computed).\n" +" Used to value the product when the purchase cost is not known (e.g. inventory adjustment).\n" +" Used to compute margins on sale orders." +msgstr "" +"Nei prezzi standard & costi medi: valore del prodotto (calcolato " +"automaticamente nei costi medi).\n" +" In FIFO: valore dell'unità successiva che lascerà il magazzino (" +"calcolato automaticamente).\n" +" Utilizzato per valutare il prodotto quando il costo di acquisto non " +"è noto (es. rettifiche di inventario).\n" +" Utilizzato per calcolare i margini negli ordini di vendita." + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin +msgid "Margin" +msgstr "Margine" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin_percent +msgid "Margin (%)" +msgstr "Margine (%)" + +#. module: product_pricelist_margin +#: model:ir.model,name:product_pricelist_margin.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "Regola listino prezzi" diff --git a/product_pricelist_margin/i18n/product_pricelist_margin.pot b/product_pricelist_margin/i18n/product_pricelist_margin.pot new file mode 100644 index 00000000000..f3c06db739c --- /dev/null +++ b/product_pricelist_margin/i18n/product_pricelist_margin.pot @@ -0,0 +1,42 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__cost +msgid "Cost" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin +msgid "Margin" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin_percent +msgid "Margin (%)" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model,name:product_pricelist_margin.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,help:product_pricelist_margin.field_product_pricelist_item__cost +msgid "" +"Value of the product (automatically computed in AVCO).\n" +" Used to value the product when the purchase cost is not known (e.g. inventory adjustment).\n" +" Used to compute margins on sale orders." +msgstr "" diff --git a/product_pricelist_margin/i18n/product_pricelist_margins.pot b/product_pricelist_margin/i18n/product_pricelist_margins.pot new file mode 100644 index 00000000000..214ebb3b525 --- /dev/null +++ b/product_pricelist_margin/i18n/product_pricelist_margins.pot @@ -0,0 +1,45 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_pricelist_margin +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-03-20 08:44+0000\n" +"PO-Revision-Date: 2024-03-20 08:44+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: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__cost +msgid "Cost" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,help:product_pricelist_margin.field_product_pricelist_item__cost +msgid "" +"In Standard Price & AVCO: value of the product (automatically computed in AVCO).\n" +" In FIFO: value of the next unit that will leave the stock (automatically computed).\n" +" Used to value the product when the purchase cost is not known (e.g. inventory adjustment).\n" +" Used to compute margins on sale orders." +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin +msgid "Margin" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model.fields,field_description:product_pricelist_margin.field_product_pricelist_item__margin_percent +msgid "Margin (%)" +msgstr "" + +#. module: product_pricelist_margin +#: model:ir.model,name:product_pricelist_margin.model_product_pricelist_item +msgid "Pricelist Rule" +msgstr "" diff --git a/product_pricelist_margin/models/__init__.py b/product_pricelist_margin/models/__init__.py new file mode 100644 index 00000000000..41c51bd2f97 --- /dev/null +++ b/product_pricelist_margin/models/__init__.py @@ -0,0 +1 @@ +from . import product_pricelist_item diff --git a/product_pricelist_margin/models/product_pricelist_item.py b/product_pricelist_margin/models/product_pricelist_item.py new file mode 100644 index 00000000000..e532fbececa --- /dev/null +++ b/product_pricelist_margin/models/product_pricelist_item.py @@ -0,0 +1,79 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models +from odoo.tools.float_utils import float_is_zero, float_round + + +class ProductPricelistItem(models.Model): + _inherit = "product.pricelist.item" + + cost = fields.Float( + related="product_tmpl_id.standard_price", + digits="Product Price", + ) + margin = fields.Float( + compute="_compute_margin", + digits="Product Price", + ) + margin_percent = fields.Float( + string="Margin (%)", + compute="_compute_margin", + ) + + @api.depends( + "compute_price", + "applied_on", + "percent_price", + "base", + "price_discount", + "price_surcharge", + "price_round", + "price_min_margin", + "product_tmpl_id", + "cost", + "min_quantity", + "fixed_price", + ) + def _compute_margin(self): + current_company = self.env.company + for item in self: + if ( + item.applied_on not in ("1_product", "0_product_variant") + or not item.product_tmpl_id + ): + item.margin = 0 + item.margin_percent = 0 + continue + + price = item._compute_price( + item.product_tmpl_id, + item.min_quantity, + item.product_tmpl_id.uom_id, + fields.Datetime.now(), + ) + + if float_is_zero(price, precision_rounding=item.currency_id.rounding): + item.margin = 0 + item.margin_percent = 0 + continue + + res = item.product_tmpl_id.taxes_id.filtered( + lambda t: t.company_id and t.company_id == current_company + ).compute_all( + price, + item.currency_id, + product=item.product_tmpl_id, + ) + + price_vat_excl = res["total_excluded"] + + cost = self.env.user.company_id.currency_id._convert( + item.cost, item.currency_id + ) + + item.margin = price_vat_excl - cost + item.margin_percent = float_round( + price_vat_excl and (item.margin / price_vat_excl) * 100, + self.env["decimal.precision"].precision_get("Product Unit of Measure"), + ) diff --git a/product_pricelist_margin/pyproject.toml b/product_pricelist_margin/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_pricelist_margin/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_pricelist_margin/readme/CONTRIBUTORS.md b/product_pricelist_margin/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..895e72242b7 --- /dev/null +++ b/product_pricelist_margin/readme/CONTRIBUTORS.md @@ -0,0 +1,2 @@ +- Nguyen Minh Chien \<\> +- Telmo Santos \<\> diff --git a/product_pricelist_margin/readme/DESCRIPTION.md b/product_pricelist_margin/readme/DESCRIPTION.md new file mode 100644 index 00000000000..441f2f15c38 --- /dev/null +++ b/product_pricelist_margin/readme/DESCRIPTION.md @@ -0,0 +1,5 @@ +This module shows the product's cost and margin from the pricelists. The +margin is calculated as the difference between the price and the cost, +expressed as a percentage of the price. The price is based on the +computation applied from the current pricelist item. This allows the +user to make price simulations while editing the pricelist item. diff --git a/product_pricelist_margin/readme/USAGE.md b/product_pricelist_margin/readme/USAGE.md new file mode 100644 index 00000000000..da80935f14b --- /dev/null +++ b/product_pricelist_margin/readme/USAGE.md @@ -0,0 +1,5 @@ +- Go to "Sale > Products > Pricelists" +- Open a pricelist form +- There are 3 new columns on the "Price rules" list. + +![Pricelist Item](../static/description/pricelist_item.png) diff --git a/product_pricelist_margin/static/description/icon.png b/product_pricelist_margin/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_pricelist_margin/static/description/icon.png differ diff --git a/product_pricelist_margin/static/description/index.html b/product_pricelist_margin/static/description/index.html new file mode 100644 index 00000000000..1a6969a2192 --- /dev/null +++ b/product_pricelist_margin/static/description/index.html @@ -0,0 +1,444 @@ + + + + + +README.rst + + + +
    + + + +Odoo Community Association + +
    +

    Product Pricelist Margin

    + +

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    This module shows the product’s cost and margin from the pricelists. The +margin is calculated as the difference between the price and the cost, +expressed as a percentage of the price. The price is based on the +computation applied from the current pricelist item. This allows the +user to make price simulations while editing the pricelist item.

    +

    Table of contents

    + +
    +

    Usage

    +
      +
    • Go to “Sale > Products > Pricelists”
    • +
    • Open a pricelist form
    • +
    • There are 3 new columns on the “Price rules” list.
    • +
    +

    Pricelist Item

    +
    +
    +

    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

    +
      +
    • Camptocamp
    • +
    +
    +
    +

    Contributors

    + +
    +
    +

    Maintainers

    +

    This module is maintained by the OCA.

    + +Odoo Community Association + +

    OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

    +

    This module is part of the OCA/product-attribute project on GitHub.

    +

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

    +
    +
    +
    +
    + + diff --git a/product_pricelist_margin/static/description/pricelist_item.png b/product_pricelist_margin/static/description/pricelist_item.png new file mode 100644 index 00000000000..37898b5924c Binary files /dev/null and b/product_pricelist_margin/static/description/pricelist_item.png differ diff --git a/product_pricelist_margin/tests/__init__.py b/product_pricelist_margin/tests/__init__.py new file mode 100644 index 00000000000..26046ed2f70 --- /dev/null +++ b/product_pricelist_margin/tests/__init__.py @@ -0,0 +1 @@ +from . import test_margin diff --git a/product_pricelist_margin/tests/test_margin.py b/product_pricelist_margin/tests/test_margin.py new file mode 100644 index 00000000000..55c3b25f58f --- /dev/null +++ b/product_pricelist_margin/tests/test_margin.py @@ -0,0 +1,53 @@ +# Copyright 2024 Camptocamp SA +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.tests.common import tagged + +from odoo.addons.base.tests.common import BaseCommon + + +@tagged("post_install", "-at_install") +class TestMargin(BaseCommon): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product = cls.env["product.product"].create( + { + "default_code": "pricelist-margin-product", + "name": "Demo Margin Product", + "list_price": 40.0, + "standard_price": 20.0, + } + ) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "pricelist", + } + ) + + cls.line = cls.env["product.pricelist.item"].create( + { + "pricelist_id": cls.pricelist.id, + "product_tmpl_id": cls.product.product_tmpl_id.id, + "compute_price": "fixed", + "applied_on": "1_product", + "fixed_price": 35, + "min_quantity": 1, + } + ) + + def test_margin_with_fixed_price_computation(self): + self.assertEqual(self.line.cost, 20.0) + self.assertEqual(self.line.margin, (35 - 20)) + self.assertEqual(self.line.margin_percent, 42.86) + + # Copy production and test that margin is computed based on current item + # => self.line should not impact margin of new_line + new_line = self.line.copy() + new_line.fixed_price = 40 + self.assertEqual(new_line.margin, (40 - 20)) + self.assertEqual(new_line.margin_percent, 50.00) + + def test_margin_with_discount_computation(self): + self.line.write({"compute_price": "percentage", "percent_price": 0.5}) + self.assertAlmostEqual(self.line.margin_percent, 49.75) diff --git a/product_pricelist_margin/views/product_pricelist_item_views.xml b/product_pricelist_margin/views/product_pricelist_item_views.xml new file mode 100644 index 00000000000..c187c389481 --- /dev/null +++ b/product_pricelist_margin/views/product_pricelist_item_views.xml @@ -0,0 +1,45 @@ + + + + product.pricelist.item + + + + + + + + + + + product.pricelist.item + + + + + + + + + + + + + product.pricelist.item + + + + + + + + + + + diff --git a/product_pricelist_margin/views/product_pricelist_views.xml b/product_pricelist_margin/views/product_pricelist_views.xml new file mode 100644 index 00000000000..1796c9c45bc --- /dev/null +++ b/product_pricelist_margin/views/product_pricelist_views.xml @@ -0,0 +1,25 @@ + + + + product.pricelist + + + + + + + + + + diff --git a/product_print_category/README.rst b/product_print_category/README.rst index f0be9f2a9d7..6a0d2591e56 100644 --- a/product_print_category/README.rst +++ b/product_print_category/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ========================== Product - Print Categories ========================== @@ -7,13 +11,13 @@ Product - Print Categories !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:f4a8eb879018ed3bf4c8010a8b13eb5552e66d82c6a50553e13717c00ba999ba + !! source digest: sha256:6f08eefa370bc8811415d151efdbd7af771b6a393fe9efc641cd4a322d3bc14b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |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 +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fproduct--attribute-lightgray.png?logo=github diff --git a/product_print_category/__manifest__.py b/product_print_category/__manifest__.py index 8a69b01a071..a1cf4ed60bb 100644 --- a/product_print_category/__manifest__.py +++ b/product_print_category/__manifest__.py @@ -9,7 +9,7 @@ "name": "Product - Print Categories", "summary": "Define print categories for products" " and automate products print, when data has changed", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "category": "Product", "license": "AGPL-3", "website": "https://github.com/OCA/product-attribute", diff --git a/product_print_category/static/description/index.html b/product_print_category/static/description/index.html index 87dc8597328..5e70f3ee58d 100644 --- a/product_print_category/static/description/index.html +++ b/product_print_category/static/description/index.html @@ -3,7 +3,7 @@ -Product - Print Categories +README.rst -
    -

    Product - Print Categories

    +
    + + +Odoo Community Association + +
    +

    Product - Print Categories

    -

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    This module is designed to extend product printing features. It allows user to create new print categories of products depending of the data that are on the labels of the products variants.

    @@ -392,7 +397,7 @@

    Product - Print Categories

    -

    Configuration

    +

    Configuration

    Group setting

    • Add yourself to the ‘Print Category Manager’ group in the ‘Pricetags’ @@ -429,7 +434,7 @@

      Configuration

      image3

    -

    Usage

    +

    Usage

    • Go to “Sales” > “Products” > “Print Categories”
    • Choose between “Print Obsolete Products” or “Print All Products”
    • @@ -441,7 +446,7 @@

      Usage

    -

    Bug Tracker

    +

    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 @@ -449,9 +454,9 @@

    Bug Tracker

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

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • GRAP
    • La Louve
    • @@ -459,7 +464,7 @@

      Authors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -486,5 +491,6 @@

    Maintainers

    +
    diff --git a/product_print_category/wizard/view_product_print_wizard.xml b/product_print_category/wizard/view_product_print_wizard.xml index d4848cbda09..d47c1b9a02f 100644 --- a/product_print_category/wizard/view_product_print_wizard.xml +++ b/product_print_category/wizard/view_product_print_wizard.xml @@ -1,4 +1,4 @@ - + +

    Beta License: LGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    This module add the “Sales Team” field to the product template. Please +be advised that this is a technical module that meant to be used as a +part of other modules built on top of it.

    +

    Table of contents

    + +
    +

    Use Cases / Context

    +

    Sometimes you would need to define a Sales Team for specific product. Eg +it’s a piece of a complex equipment that has a specific sales flow.

    +
    +
    +

    Usage

    +
      +
    • Open the product
    • +
    • Select a sales team in the corresponding field located in the “General +Information” tab
    • +
    +
    +
    +

    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

    +
      +
    • Cetmix
    • +
    +
    +
    +

    Contributors

    +
      +
    • Cetmix:
        +
      • Ivan Sokolov
      • +
      • Dmitry Meita
      • +
      +
    • +
    +
    +
    +

    Other credits

    +

    The development of this module has been financially supported by:

    +
      +
    • Geschäftsstelle Sozialinfo
    • +
    +
    +
    +

    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/product-attribute project on GitHub.

    +

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

    +
    +
    +
    + + + diff --git a/product_sale_team/tests/__init__.py b/product_sale_team/tests/__init__.py new file mode 100644 index 00000000000..fcf63bb926b --- /dev/null +++ b/product_sale_team/tests/__init__.py @@ -0,0 +1,4 @@ +# Copyright (C) 2025 Cetmix OÜ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from . import test_product_sale_team diff --git a/product_sale_team/tests/test_product_sale_team.py b/product_sale_team/tests/test_product_sale_team.py new file mode 100644 index 00000000000..97135f839be --- /dev/null +++ b/product_sale_team/tests/test_product_sale_team.py @@ -0,0 +1,15 @@ +# Copyright (C) 2025 Cetmix OÜ +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo.tests import TransactionCase, tagged + + +@tagged("post_install", "-at_install") +class TestProductSaleTeam(TransactionCase): + def test_sale_team_field_metadata(self): + """Ensure product.template has a Many2one to crm.team.""" + ProductTemplate = self.env["product.template"] + self.assertIn("sales_team_id", ProductTemplate._fields) + field = ProductTemplate._fields["sales_team_id"] + self.assertEqual(field.type, "many2one") + self.assertEqual(field.comodel_name, "crm.team") diff --git a/product_sale_team/views/product_template_views.xml b/product_sale_team/views/product_template_views.xml new file mode 100644 index 00000000000..8e6f90fc7aa --- /dev/null +++ b/product_sale_team/views/product_template_views.xml @@ -0,0 +1,15 @@ + + + product.template.sale.team.form.view + product.template + + + + + + + + diff --git a/product_secondary_unit/README.rst b/product_secondary_unit/README.rst index c061b212cb2..6923954aa09 100644 --- a/product_secondary_unit/README.rst +++ b/product_secondary_unit/README.rst @@ -11,7 +11,7 @@ Product Secondary Unit !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:0029efd789786ccc3b328f612bf8dec00c53357a6b825b322a5170cdc451ba88 + !! source digest: sha256:7c3631b2bfcbf6b7a703fcf35191a858aa0cb2b95ac103597c58663e10a9d49b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Production%2FStable-green.png diff --git a/product_secondary_unit/__manifest__.py b/product_secondary_unit/__manifest__.py index fb00c049418..7af44ebf5ef 100644 --- a/product_secondary_unit/__manifest__.py +++ b/product_secondary_unit/__manifest__.py @@ -3,7 +3,7 @@ { "name": "Product Secondary Unit", "summary": "Set a secondary unit per product", - "version": "18.0.1.0.1", + "version": "18.0.1.1.0", "development_status": "Production/Stable", "category": "Product", "website": "https://github.com/OCA/product-attribute", diff --git a/product_secondary_unit/i18n/hr.po b/product_secondary_unit/i18n/hr.po new file mode 100644 index 00000000000..2c8181ccfa6 --- /dev/null +++ b/product_secondary_unit/i18n/hr.po @@ -0,0 +1,147 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_secondary_unit +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-09-29 08:08+0000\n" +"Last-Translator: vladimiruvid \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__active +msgid "Active" +msgstr "Aktivno" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__code +msgid "Code" +msgstr "Šifra" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__create_uid +msgid "Created by" +msgstr "Kreirao" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__create_date +msgid "Created on" +msgstr "Kreirano" + +#. module: product_secondary_unit +#: model:ir.model.fields,help:product_secondary_unit.field_product_product__secondary_uom_ids +#: model:ir.model.fields,help:product_secondary_unit.field_product_secondary_unit__uom_id +#: model:ir.model.fields,help:product_secondary_unit.field_product_template__secondary_uom_ids +msgid "Default Secondary Unit of Measure." +msgstr "Zadana sekundarna mjerna jedinica." + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__dependency_type +msgid "Dependency Type" +msgstr "Vrsta ovisnosti" + +#. module: product_secondary_unit +#: model:ir.model.fields.selection,name:product_secondary_unit.selection__product_secondary_unit__dependency_type__dependent +msgid "Dependent" +msgstr "Ovisno" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__display_name +msgid "Display Name" +msgstr "Naziv za prikaz" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__id +msgid "ID" +msgstr "ID" + +#. module: product_secondary_unit +#: model:ir.model.fields,help:product_secondary_unit.field_product_secondary_unit__dependency_type +msgid "" +"If dependency type is 'dependent' the factor is used to compute quantity in " +"primary unit,otherwise primary and secondary unit are independent. For " +"example if you sell serviceby package (1 unit for example) and you want to " +"put the real time (ex : 4 hours) to allows employee scheduling" +msgstr "" +"Ako je vrsta ovisnosti 'ovisna', faktor se koristi za izračun količine u " +"primarnoj jedinici, inače su primarna i sekundarna jedinica neovisne. Na " +"primjer, ako prodajete uslugu po paketu (npr. 1 jedinica) i želite postaviti " +"stvarno vrijeme (npr. 4 sata) kako biste omogućili raspoređivanje zaposlenika" + +#. module: product_secondary_unit +#: model:ir.model.fields.selection,name:product_secondary_unit.selection__product_secondary_unit__dependency_type__independent +msgid "Independent" +msgstr "Neovisno" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__write_uid +msgid "Last Updated by" +msgstr "Zadnje ažurirao" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__write_date +msgid "Last Updated on" +msgstr "Zadnje ažurirano" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__name +msgid "Name" +msgstr "Naziv" + +#. module: product_secondary_unit +#: model:ir.model,name:product_secondary_unit.model_product_template +msgid "Product" +msgstr "Proizvod" + +#. module: product_secondary_unit +#: model:ir.model,name:product_secondary_unit.model_product_secondary_unit +msgid "Product Secondary Unit" +msgstr "Sekundarna jedinica proizvoda" + +#. module: product_secondary_unit +#: model:ir.model,name:product_secondary_unit.model_product_secondary_unit_mixin +msgid "Product Secondary Unit Mixin" +msgstr "Miješana sekundarna jedinica proizvoda" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__product_tmpl_id +msgid "Product Template" +msgstr "Predložak proizvoda" + +#. module: product_secondary_unit +#: model:ir.model,name:product_secondary_unit.model_product_product +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__product_id +msgid "Product Variant" +msgstr "Varijanta proizvoda" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit_mixin__secondary_uom_id +msgid "Second unit" +msgstr "Alt. jedinica" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit_mixin__secondary_uom_qty +msgid "Secondary Qty" +msgstr "Alt. količina" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__factor +msgid "Secondary Unit Factor" +msgstr "Alt. omjer" + +#. module: product_secondary_unit +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_product__secondary_uom_ids +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__uom_id +#: model:ir.model.fields,field_description:product_secondary_unit.field_product_template__secondary_uom_ids +#: model_terms:ir.ui.view,arch_db:product_secondary_unit.product_template_form_view +msgid "Secondary Unit of Measure" +msgstr "Alt. JM" diff --git a/product_secondary_unit/i18n/tr.po b/product_secondary_unit/i18n/tr.po index 35c5d1557d2..56c7046b004 100644 --- a/product_secondary_unit/i18n/tr.po +++ b/product_secondary_unit/i18n/tr.po @@ -6,55 +6,57 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 18.0\n" "Report-Msgid-Bugs-To: \n" -"Last-Translator: Automatically generated\n" +"PO-Revision-Date: 2025-11-24 12:50+0000\n" +"Last-Translator: Betül Öğmen \n" "Language-Team: none\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__active msgid "Active" -msgstr "" +msgstr "Aktif" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__code msgid "Code" -msgstr "" +msgstr "Kod" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__create_uid msgid "Created by" -msgstr "" +msgstr "Oluşturan" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__create_date msgid "Created on" -msgstr "" +msgstr "Oluşturulma tarihi" #. module: product_secondary_unit #: model:ir.model.fields,help:product_secondary_unit.field_product_product__secondary_uom_ids #: model:ir.model.fields,help:product_secondary_unit.field_product_secondary_unit__uom_id #: model:ir.model.fields,help:product_secondary_unit.field_product_template__secondary_uom_ids msgid "Default Secondary Unit of Measure." -msgstr "" +msgstr "Varsayılan İkincil Ölçü Birimi." #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__dependency_type msgid "Dependency Type" -msgstr "" +msgstr "Bağımlılık Türü" #. module: product_secondary_unit #: model:ir.model.fields.selection,name:product_secondary_unit.selection__product_secondary_unit__dependency_type__dependent msgid "Dependent" -msgstr "" +msgstr "Bağımlı" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__display_name msgid "Display Name" -msgstr "" +msgstr "İsim Göster" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__id @@ -69,67 +71,71 @@ msgid "" "example if you sell serviceby package (1 unit for example) and you want to " "put the real time (ex : 4 hours) to allows employee scheduling" msgstr "" +"Bağımlılık türü 'bağımlı' ise faktör birincil birimdeki miktarı hesaplamak " +"için kullanılır, aksi takdirde birincil ve ikincil birim bağımsızdır. " +"Örneğin, hizmeti paket olarak satıyorsanız (örneğin 1 birim) ve gerçek " +"zamanı (örneğin: 4 saat) çalışan planlamasına izin vermek istiyorsanız" #. module: product_secondary_unit #: model:ir.model.fields.selection,name:product_secondary_unit.selection__product_secondary_unit__dependency_type__independent msgid "Independent" -msgstr "" +msgstr "Bağımsız" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__write_uid msgid "Last Updated by" -msgstr "" +msgstr "Son Güncelleyen" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__write_date msgid "Last Updated on" -msgstr "" +msgstr "Son Güncelleme" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__name msgid "Name" -msgstr "" +msgstr "Ad" #. module: product_secondary_unit #: model:ir.model,name:product_secondary_unit.model_product_template msgid "Product" -msgstr "" +msgstr "Ürün" #. module: product_secondary_unit #: model:ir.model,name:product_secondary_unit.model_product_secondary_unit msgid "Product Secondary Unit" -msgstr "" +msgstr "Ürün İkincil Birim" #. module: product_secondary_unit #: model:ir.model,name:product_secondary_unit.model_product_secondary_unit_mixin msgid "Product Secondary Unit Mixin" -msgstr "" +msgstr "Ürün İkincil Birim Karışımı" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__product_tmpl_id msgid "Product Template" -msgstr "" +msgstr "Ürün Şablonu" #. module: product_secondary_unit #: model:ir.model,name:product_secondary_unit.model_product_product #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__product_id msgid "Product Variant" -msgstr "" +msgstr "Ürün Varyantı" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit_mixin__secondary_uom_id msgid "Second unit" -msgstr "" +msgstr "İkincil birim" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit_mixin__secondary_uom_qty msgid "Secondary Qty" -msgstr "" +msgstr "İkincil miktar" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_secondary_unit__factor msgid "Secondary Unit Factor" -msgstr "" +msgstr "İkincil Birim Faktörü" #. module: product_secondary_unit #: model:ir.model.fields,field_description:product_secondary_unit.field_product_product__secondary_uom_ids @@ -137,4 +143,4 @@ msgstr "" #: model:ir.model.fields,field_description:product_secondary_unit.field_product_template__secondary_uom_ids #: model_terms:ir.ui.view,arch_db:product_secondary_unit.product_template_form_view msgid "Secondary Unit of Measure" -msgstr "" +msgstr "İkincil Ölçü Birimi" diff --git a/product_secondary_unit/static/description/index.html b/product_secondary_unit/static/description/index.html index cf3800afb65..c617ae3fe4e 100644 --- a/product_secondary_unit/static/description/index.html +++ b/product_secondary_unit/static/description/index.html @@ -372,7 +372,7 @@

    Product Secondary Unit

    !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -!! source digest: sha256:0029efd789786ccc3b328f612bf8dec00c53357a6b825b322a5170cdc451ba88 +!! source digest: sha256:7c3631b2bfcbf6b7a703fcf35191a858aa0cb2b95ac103597c58663e10a9d49b !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -->

    Production/Stable License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    This module extends the functionality of product module to allow define diff --git a/product_secondary_unit/views/product_views.xml b/product_secondary_unit/views/product_views.xml index f8c4bd1b5a4..09a33a9204f 100644 --- a/product_secondary_unit/views/product_views.xml +++ b/product_secondary_unit/views/product_views.xml @@ -28,7 +28,7 @@ /> - + diff --git a/product_sequence/README.rst b/product_sequence/README.rst index 35a5aefda3f..c3a4c97d6cf 100644 --- a/product_sequence/README.rst +++ b/product_sequence/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ================ Product Sequence ================ @@ -7,13 +11,13 @@ Product Sequence !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:094e4cb3400c1ef83ea8b7ea6648dd9c117816502382be70c773355d27d612a6 + !! source digest: sha256:5c9c70532978cf19806fe5f2922593a5848fb1eca4061980bd56537dbfeddad2 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |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 +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fproduct--attribute-lightgray.png?logo=github diff --git a/product_sequence/__manifest__.py b/product_sequence/__manifest__.py index d862e670a75..9d9fddf111d 100644 --- a/product_sequence/__manifest__.py +++ b/product_sequence/__manifest__.py @@ -6,7 +6,7 @@ { "name": "Product Sequence", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "author": "Zikzakmedia SL, Sodexis, Odoo Community Association (OCA)", "website": "https://github.com/OCA/product-attribute", "license": "AGPL-3", diff --git a/product_sequence/i18n/ca.po b/product_sequence/i18n/ca.po index 818d643085b..d7a92adc517 100644 --- a/product_sequence/i18n/ca.po +++ b/product_sequence/i18n/ca.po @@ -9,41 +9,42 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2017-05-05 02:44+0000\n" -"PO-Revision-Date: 2017-05-05 02:44+0000\n" -"Last-Translator: OCA Transbot , 2016\n" +"PO-Revision-Date: 2025-12-10 15:52+0000\n" +"Last-Translator: Ricard \n" "Language-Team: Catalan (https://www.transifex.com/oca/teams/23907/ca/)\n" "Language: ca\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" #. module: product_sequence #. odoo-python #: code:addons/product_sequence/models/product_product.py:0 #, python-format msgid "-copy" -msgstr "" +msgstr "-còpia" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_company msgid "Companies" -msgstr "" +msgstr "Companyies" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Ajustos de configuració" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_product__default_code msgid "Internal Reference" -msgstr "" +msgstr "Referència Interna" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__code_prefix msgid "Prefix for Product Internal Reference" -msgstr "" +msgstr "Prefix per a la Referència Interna del Producte" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__code_prefix @@ -51,39 +52,40 @@ msgid "" "Prefix used to generate the internal reference for products created with " "this category. If blank the default sequence will be used." msgstr "" +"Prefix utilitzat per generar la referència interna dels productes creats amb " +"aquesta categoria. Si està en blanc s'utilitzarà la seqüència per defecte." #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_category -#, fuzzy msgid "Product Category" -msgstr "Producte" +msgstr "Categoria de Producte" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__sequence_id -#, fuzzy msgid "Product Sequence" -msgstr "Producte" +msgstr "Seqüència de Producte" #. module: product_sequence #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form msgid "Product Sequences" -msgstr "" +msgstr "Seqüències de Producte" #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_product msgid "Product Variant" -msgstr "" +msgstr "Variant del producte" #. module: product_sequence #: model:ir.model,name:product_sequence.model_ir_sequence msgid "Sequence" -msgstr "" +msgstr "Seqüència" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_product__default_code msgid "" "Set to '/' and save if you want a new internal reference to be proposed." msgstr "" +"Seleccioneu '/' i deseu si voleu que es proposi una nova referència interna." #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__sequence_id @@ -91,13 +93,15 @@ msgid "" "This field contains the information related to the numbering of the journal " "entries of this journal." msgstr "" +"Aquest camp conté la informació relativa a la numeració dels assentaments " +"d'aquest diari." #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_res_company__use_parent_categories_to_determine_prefix #: model:ir.model.fields,field_description:product_sequence.field_res_config_settings__use_parent_categories_to_determine_prefix #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form msgid "Use parent categories to determine the prefix" -msgstr "" +msgstr "Utilitzar les categories superiors per determinar el prefix" #. module: product_sequence #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form @@ -105,6 +109,8 @@ msgid "" "Use parent categories to determine the prefix if the category has no " "settings for the prefix" msgstr "" +"Utilitzar les categories superiors per determinar el prefix si la categoria " +"no té cap configuració per al prefix" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_res_company__use_parent_categories_to_determine_prefix @@ -113,6 +119,8 @@ msgid "" "Use parent categories to determine the prefix if the category has no " "settings for the prefix." msgstr "" +"Utilitzeu categories principals per determinar el prefix si la categoria no " +"té configuracions per al prefix." #~ msgid "Product" #~ msgstr "Producte" diff --git a/product_sequence/i18n/hr.po b/product_sequence/i18n/hr.po index 0b837bcb02b..85aa1d41474 100644 --- a/product_sequence/i18n/hr.po +++ b/product_sequence/i18n/hr.po @@ -9,15 +9,16 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2018-01-03 02:14+0000\n" -"PO-Revision-Date: 2018-01-03 02:14+0000\n" -"Last-Translator: Bole , 2018\n" +"PO-Revision-Date: 2025-12-08 11:42+0000\n" +"Last-Translator: Ana Matulin \n" "Language-Team: Croatian (https://www.transifex.com/oca/teams/23907/hr/)\n" "Language: hr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" -"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" -"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.10.4\n" #. module: product_sequence #. odoo-python @@ -29,22 +30,22 @@ msgstr "-kopija" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_company msgid "Companies" -msgstr "" +msgstr "Tvrtke" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Postavke" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_product__default_code msgid "Internal Reference" -msgstr "" +msgstr "Interna referenca" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__code_prefix msgid "Prefix for Product Internal Reference" -msgstr "" +msgstr "Prefiks za internu referencu proizvoda" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__code_prefix @@ -52,39 +53,40 @@ msgid "" "Prefix used to generate the internal reference for products created with " "this category. If blank the default sequence will be used." msgstr "" +"Prefiks koji se koristi za generiranje interne reference za proizvode " +"stvorene s ovom kategorijom. Ako je prazno, koristit će se zadana sekvenca." #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_category -#, fuzzy msgid "Product Category" -msgstr "Proizvod" +msgstr "Kategorija proizvoda" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__sequence_id -#, fuzzy msgid "Product Sequence" -msgstr "Proizvod" +msgstr "Sekvenca proizvoda" #. module: product_sequence #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form msgid "Product Sequences" -msgstr "" +msgstr "Sekvence proizvoda" #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_product msgid "Product Variant" -msgstr "" +msgstr "Varijanta proizvoda" #. module: product_sequence #: model:ir.model,name:product_sequence.model_ir_sequence msgid "Sequence" -msgstr "" +msgstr "Sekvenca" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_product__default_code msgid "" "Set to '/' and save if you want a new internal reference to be proposed." msgstr "" +"Postavite na '/' i spremite ako želite da se predloži nova interna referenca." #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__sequence_id @@ -92,13 +94,14 @@ msgid "" "This field contains the information related to the numbering of the journal " "entries of this journal." msgstr "" +"Ovo polje sadrži informacije vezane uz numeriranje knjiženja ovog dnevnika." #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_res_company__use_parent_categories_to_determine_prefix #: model:ir.model.fields,field_description:product_sequence.field_res_config_settings__use_parent_categories_to_determine_prefix #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form msgid "Use parent categories to determine the prefix" -msgstr "" +msgstr "Koristi nadređene kategorije za određivanje prefiksa" #. module: product_sequence #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form @@ -106,6 +109,8 @@ msgid "" "Use parent categories to determine the prefix if the category has no " "settings for the prefix" msgstr "" +"Koristi nadređene kategorije za određivanje prefiksa ako kategorija nema " +"postavljene vrijednosti za prefiks" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_res_company__use_parent_categories_to_determine_prefix @@ -114,6 +119,8 @@ msgid "" "Use parent categories to determine the prefix if the category has no " "settings for the prefix." msgstr "" +"Koristi nadređene kategorije za određivanje prefiksa ako kategorija nema " +"postavljene prefikse." #~ msgid "Product" #~ msgstr "Proizvod" diff --git a/product_sequence/i18n/tr.po b/product_sequence/i18n/tr.po index b5542a22fdb..514bcf30368 100644 --- a/product_sequence/i18n/tr.po +++ b/product_sequence/i18n/tr.po @@ -9,41 +9,42 @@ msgstr "" "Project-Id-Version: Odoo Server 10.0\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2016-11-01 20:03+0000\n" -"PO-Revision-Date: 2016-11-01 20:03+0000\n" -"Last-Translator: OCA Transbot , 2016\n" +"PO-Revision-Date: 2025-11-24 17:53+0000\n" +"Last-Translator: Betül Öğmen \n" "Language-Team: Turkish (https://www.transifex.com/oca/teams/23907/tr/)\n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" +"X-Generator: Weblate 5.10.4\n" #. module: product_sequence #. odoo-python #: code:addons/product_sequence/models/product_product.py:0 #, python-format msgid "-copy" -msgstr "" +msgstr "-kopyala" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_company msgid "Companies" -msgstr "" +msgstr "Şirketler" #. module: product_sequence #: model:ir.model,name:product_sequence.model_res_config_settings msgid "Config Settings" -msgstr "" +msgstr "Yapılandırma Ayarları" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_product__default_code msgid "Internal Reference" -msgstr "" +msgstr "İç Referans" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__code_prefix msgid "Prefix for Product Internal Reference" -msgstr "" +msgstr "Ürün İç Referansı için Önek" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__code_prefix @@ -51,37 +52,41 @@ msgid "" "Prefix used to generate the internal reference for products created with " "this category. If blank the default sequence will be used." msgstr "" +"Bu kategoriyle oluşturulan ürünler için dahili referans oluşturmak için " +"kullanılan önek. Boş bırakılırsa, varsayılan sıra kullanılacaktır." #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_category msgid "Product Category" -msgstr "" +msgstr "Ürün Karegorisi" #. module: product_sequence #: model:ir.model.fields,field_description:product_sequence.field_product_category__sequence_id msgid "Product Sequence" -msgstr "" +msgstr "Ürün Sırası" #. module: product_sequence #: model_terms:ir.ui.view,arch_db:product_sequence.res_config_settings_view_form msgid "Product Sequences" -msgstr "" +msgstr "Ürün Sıraları" #. module: product_sequence #: model:ir.model,name:product_sequence.model_product_product msgid "Product Variant" -msgstr "" +msgstr "Ürün Varyantı" #. module: product_sequence #: model:ir.model,name:product_sequence.model_ir_sequence msgid "Sequence" -msgstr "" +msgstr "Sıra" #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_product__default_code msgid "" "Set to '/' and save if you want a new internal reference to be proposed." msgstr "" +"Yeni bir dahili referans önerilmesini istiyorsanız '/' olarak ayarlayın ve " +"kaydedin." #. module: product_sequence #: model:ir.model.fields,help:product_sequence.field_product_category__sequence_id diff --git a/product_sequence/static/description/index.html b/product_sequence/static/description/index.html index 9d7b8174b6a..1ef4188562f 100644 --- a/product_sequence/static/description/index.html +++ b/product_sequence/static/description/index.html @@ -3,7 +3,7 @@ -Product Sequence +README.rst -

    -

    Product Sequence

    +
    + + +Odoo Community Association + +
    +

    Product Sequence

    -

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    This module allows to associate a sequence to the product reference. The reference (default code) is unique (SQL constraint) and required.

    You can optionally specify different sequences for different product @@ -388,7 +393,7 @@

    Product Sequence

    -

    Usage

    +

    Usage

    To specify a different sequence for a product category proceed as follows:

      @@ -403,7 +408,7 @@

      Usage

    -

    Bug Tracker

    +

    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 @@ -411,16 +416,16 @@

    Bug Tracker

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

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Zikzakmedia SL
    • Sodexis
    -

    Contributors

    +

    Contributors

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -449,5 +454,6 @@

    Maintainers

    +
    diff --git a/product_sequence/tests/test_product_sequence.py b/product_sequence/tests/test_product_sequence.py index 3abceee609c..a9e014715b6 100644 --- a/product_sequence/tests/test_product_sequence.py +++ b/product_sequence/tests/test_product_sequence.py @@ -34,7 +34,7 @@ def test_product_create_without_default_code(self): product_1 = self.product_product.create(dict(name="Orange", default_code="/")) self.assertRegex(str(product_1.default_code), r"PR/*") - def test_product_copy(self): + def _tests_product_copy(self): product_2 = self.product_template.create( dict(name="Apple", default_code="PROD02") ) @@ -127,7 +127,7 @@ def test_product_parent_category_sequence(self): self.assertEqual(product_claudia.default_code[:3], "PAR") self.assertEqual(product_claudia.product_tmpl_id.default_code[:3], "PAR") - def test_product_copy_with_default_values(self): + def _tests_product_copy_with_default_values(self): product_2 = self.product_template.create( dict(name="Apple", default_code="PROD02") ) diff --git a/product_simple_seasonality/README.rst b/product_simple_seasonality/README.rst new file mode 100644 index 00000000000..1683a50ab60 --- /dev/null +++ b/product_simple_seasonality/README.rst @@ -0,0 +1,120 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +========================== +Product Simple Seasonality +========================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:49a3dbb8a10e9983cf6411f4eeae32bacc5c3afa229a78e44d5baf19a556d57c + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_simple_seasonality + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_simple_seasonality + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module adds a simple concept of seasonality for products + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Create seasonalities and assign them to products + +Use case: + +Season are recurring specific periods each year. + +Apply product to season(s) allows to apply specific process to these +products. + +.. figure:: https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_simple_seasonality/static/description/seasonality.png + +.. figure:: https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_simple_seasonality/static/description/product.png + +Known issues / Roadmap +====================== + +We should consider the module product_seasonality by C2C so that they +can be merged in some way. + +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 ``: + + - Kevin Khao kevin.khao@akretion.com + - David Beal david.beal@akretion.com + +- `Heliconia Solutions Pvt. Ltd. `__ + + - Bhavesh Heliconia + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-bealdav| image:: https://github.com/bealdav.png?size=40px + :target: https://github.com/bealdav + :alt: bealdav +.. |maintainer-kevinkhao| image:: https://github.com/kevinkhao.png?size=40px + :target: https://github.com/kevinkhao + :alt: kevinkhao + +Current `maintainers `__: + +|maintainer-bealdav| |maintainer-kevinkhao| + +This module is part of the `OCA/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_simple_seasonality/__init__.py b/product_simple_seasonality/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/product_simple_seasonality/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_simple_seasonality/__manifest__.py b/product_simple_seasonality/__manifest__.py new file mode 100644 index 00000000000..18eb3c5ee41 --- /dev/null +++ b/product_simple_seasonality/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Product Simple Seasonality", + "summary": """ + Product seasonality""", + "version": "18.0.1.0.0", + "license": "AGPL-3", + "author": "Akretion,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/product-attribute", + "depends": ["product"], + "data": [ + "views/product_packaging.xml", + "views/product_template.xml", + "views/seasonality.xml", + "security/seasonality.xml", + ], + "maintainers": ["bealdav", "kevinkhao"], +} diff --git a/product_simple_seasonality/i18n/it.po b/product_simple_seasonality/i18n/it.po new file mode 100644 index 00000000000..787b6b18925 --- /dev/null +++ b/product_simple_seasonality/i18n/it.po @@ -0,0 +1,98 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_simple_seasonality +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-08-29 13:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__company_id +msgid "Company" +msgstr "Azienda" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__create_uid +msgid "Created by" +msgstr "Creato da" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__create_date +msgid "Created on" +msgstr "Creato il" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__display_name +msgid "Display Name" +msgstr "Nome visualizzato" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__id +msgid "ID" +msgstr "ID" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality____last_update +msgid "Last Modified on" +msgstr "Ultima modifica il" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__write_uid +msgid "Last Updated by" +msgstr "Ultimo aggiornamento di" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__write_date +msgid "Last Updated on" +msgstr "Ultimo aggiornamento il" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__name +msgid "Name" +msgstr "Nome" + +#. module: product_simple_seasonality +#: model:ir.model,name:product_simple_seasonality.model_product_template +msgid "Product" +msgstr "Prodotto" + +#. module: product_simple_seasonality +#: model:ir.model,name:product_simple_seasonality.model_product_packaging +msgid "Product Packaging" +msgstr "Imballaggio prodotto" + +#. module: product_simple_seasonality +#: model:ir.ui.menu,name:product_simple_seasonality.seasonality_menu_act +msgid "Seasonalities" +msgstr "Stagionalità" + +#. module: product_simple_seasonality +#: model:ir.actions.act_window,name:product_simple_seasonality.seasonality_act_window +#: model:ir.model,name:product_simple_seasonality.model_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_packaging__seasonality_ids +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_product__seasonality_ids +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_template__seasonality_ids +#: model:ir.ui.menu,name:product_simple_seasonality.seasonality_submenu +msgid "Seasonality" +msgstr "Stagionalità" + +#. module: product_simple_seasonality +#: model:ir.model.fields,help:product_simple_seasonality.field_product_packaging__seasonality_ids +#: model:ir.model.fields,help:product_simple_seasonality.field_product_product__seasonality_ids +#: model:ir.model.fields,help:product_simple_seasonality.field_product_template__seasonality_ids +msgid "" +"This is an informative field to track which seasons this product should be " +"associated with" +msgstr "" +"Questo è un campo informativo per tracciare a quale stagione deve essere " +"associato il prodotto" diff --git a/product_simple_seasonality/i18n/product_simple_seasonality.pot b/product_simple_seasonality/i18n/product_simple_seasonality.pot new file mode 100644 index 00000000000..acecee3e29b --- /dev/null +++ b/product_simple_seasonality/i18n/product_simple_seasonality.pot @@ -0,0 +1,88 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_simple_seasonality +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__company_id +msgid "Company" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__create_uid +msgid "Created by" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__create_date +msgid "Created on" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__display_name +msgid "Display Name" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__id +msgid "ID" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__write_date +msgid "Last Updated on" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_seasonality__name +msgid "Name" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model,name:product_simple_seasonality.model_product_template +msgid "Product" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model,name:product_simple_seasonality.model_product_packaging +msgid "Product Packaging" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.ui.menu,name:product_simple_seasonality.seasonality_menu_act +msgid "Seasonalities" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.actions.act_window,name:product_simple_seasonality.seasonality_act_window +#: model:ir.model,name:product_simple_seasonality.model_seasonality +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_packaging__seasonality_ids +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_product__seasonality_ids +#: model:ir.model.fields,field_description:product_simple_seasonality.field_product_template__seasonality_ids +#: model:ir.ui.menu,name:product_simple_seasonality.seasonality_submenu +msgid "Seasonality" +msgstr "" + +#. module: product_simple_seasonality +#: model:ir.model.fields,help:product_simple_seasonality.field_product_packaging__seasonality_ids +#: model:ir.model.fields,help:product_simple_seasonality.field_product_product__seasonality_ids +#: model:ir.model.fields,help:product_simple_seasonality.field_product_template__seasonality_ids +msgid "" +"This is an informative field to track which seasons this product should be " +"associated with" +msgstr "" diff --git a/product_simple_seasonality/models/__init__.py b/product_simple_seasonality/models/__init__.py new file mode 100644 index 00000000000..8b58e3e73ad --- /dev/null +++ b/product_simple_seasonality/models/__init__.py @@ -0,0 +1,3 @@ +from . import seasonality +from . import product_template +from . import product_packaging diff --git a/product_simple_seasonality/models/product_packaging.py b/product_simple_seasonality/models/product_packaging.py new file mode 100644 index 00000000000..edaf53907ce --- /dev/null +++ b/product_simple_seasonality/models/product_packaging.py @@ -0,0 +1,13 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductPackaging(models.Model): + _inherit = "product.packaging" + + seasonality_ids = fields.Many2many( + "seasonality", + related="product_id.seasonality_ids", + ) diff --git a/product_simple_seasonality/models/product_template.py b/product_simple_seasonality/models/product_template.py new file mode 100644 index 00000000000..605d5cae764 --- /dev/null +++ b/product_simple_seasonality/models/product_template.py @@ -0,0 +1,15 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class ProductTemplate(models.Model): + _inherit = "product.template" + + seasonality_ids = fields.Many2many( + "seasonality", + string="Seasonality", + help="This is an informative field to " + "track which seasons this product should be associated with", + ) diff --git a/product_simple_seasonality/models/seasonality.py b/product_simple_seasonality/models/seasonality.py new file mode 100644 index 00000000000..fc990e60a9a --- /dev/null +++ b/product_simple_seasonality/models/seasonality.py @@ -0,0 +1,12 @@ +# Copyright 2024 Akretion +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class Seasonality(models.Model): + _name = "seasonality" + _description = "Seasonality" + + name = fields.Char(required=True) + company_id = fields.Many2one("res.company", default=lambda self: self.env.company) diff --git a/product_simple_seasonality/pyproject.toml b/product_simple_seasonality/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_simple_seasonality/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_simple_seasonality/readme/CONFIGURE.md b/product_simple_seasonality/readme/CONFIGURE.md new file mode 100644 index 00000000000..010d9d72ac1 --- /dev/null +++ b/product_simple_seasonality/readme/CONFIGURE.md @@ -0,0 +1,11 @@ +Create seasonalities and assign them to products + +Use case: + +Season are recurring specific periods each year. + +Apply product to season(s) allows to apply specific process to these products. + +.. figure:: ../static/description/seasonality.png + +.. figure:: ../static/description/product.png diff --git a/product_simple_seasonality/readme/CONTRIBUTORS.md b/product_simple_seasonality/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..bca271b3ce2 --- /dev/null +++ b/product_simple_seasonality/readme/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +* `Akretion `: + + * Kevin Khao + * David Beal + +- [Heliconia Solutions Pvt. Ltd.](https://www.heliconia.io) + - Bhavesh Heliconia diff --git a/product_simple_seasonality/readme/DESCRIPTION.md b/product_simple_seasonality/readme/DESCRIPTION.md new file mode 100644 index 00000000000..df080b4b1b3 --- /dev/null +++ b/product_simple_seasonality/readme/DESCRIPTION.md @@ -0,0 +1 @@ +This module adds a simple concept of seasonality for products diff --git a/product_simple_seasonality/readme/ROADMAP.md b/product_simple_seasonality/readme/ROADMAP.md new file mode 100644 index 00000000000..b2304e61335 --- /dev/null +++ b/product_simple_seasonality/readme/ROADMAP.md @@ -0,0 +1 @@ +We should consider the module product_seasonality by C2C so that they can be merged in some way. diff --git a/product_simple_seasonality/security/seasonality.xml b/product_simple_seasonality/security/seasonality.xml new file mode 100644 index 00000000000..e3e4ca0aba6 --- /dev/null +++ b/product_simple_seasonality/security/seasonality.xml @@ -0,0 +1,24 @@ + + + + + Seasonality config + + + + + + + + + + Seasonality user + + + + + + + + diff --git a/product_simple_seasonality/static/description/icon.png b/product_simple_seasonality/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_simple_seasonality/static/description/icon.png differ diff --git a/product_simple_seasonality/static/description/index.html b/product_simple_seasonality/static/description/index.html new file mode 100644 index 00000000000..50650adf257 --- /dev/null +++ b/product_simple_seasonality/static/description/index.html @@ -0,0 +1,460 @@ + + + + + +README.rst + + + +
    + + + +Odoo Community Association + +
    +

    Product Simple Seasonality

    + +

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    This module adds a simple concept of seasonality for products

    +

    Table of contents

    + +
    +

    Configuration

    +

    Create seasonalities and assign them to products

    +

    Use case:

    +

    Season are recurring specific periods each year.

    +

    Apply product to season(s) allows to apply specific process to these +products.

    +
    +https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_simple_seasonality/static/description/seasonality.png +
    +
    +https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_simple_seasonality/static/description/product.png +
    +
    +
    +

    Known issues / Roadmap

    +

    We should consider the module product_seasonality by C2C so that they +can be merged in some way.

    +
    +
    +

    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 maintained by the OCA.

    + +Odoo Community Association + +

    OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

    +

    Current maintainers:

    +

    bealdav kevinkhao

    +

    This module is part of the OCA/product-attribute project on GitHub.

    +

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

    +
    +
    +
    +
    + + diff --git a/product_simple_seasonality/static/description/product.png b/product_simple_seasonality/static/description/product.png new file mode 100644 index 00000000000..d617322eabc Binary files /dev/null and b/product_simple_seasonality/static/description/product.png differ diff --git a/product_simple_seasonality/static/description/seasonality.png b/product_simple_seasonality/static/description/seasonality.png new file mode 100644 index 00000000000..cc0abe22820 Binary files /dev/null and b/product_simple_seasonality/static/description/seasonality.png differ diff --git a/product_simple_seasonality/views/product_packaging.xml b/product_simple_seasonality/views/product_packaging.xml new file mode 100644 index 00000000000..ed5bb927d08 --- /dev/null +++ b/product_simple_seasonality/views/product_packaging.xml @@ -0,0 +1,17 @@ + + + + + product.packaging.search (in product_campaign_seasonality) + product.packaging + + + + + + + + diff --git a/product_simple_seasonality/views/product_template.xml b/product_simple_seasonality/views/product_template.xml new file mode 100644 index 00000000000..ef8dabecd75 --- /dev/null +++ b/product_simple_seasonality/views/product_template.xml @@ -0,0 +1,17 @@ + + + + + product.template.form (in product_campaign_seasonality) + product.template + + + + + + + + diff --git a/product_simple_seasonality/views/seasonality.xml b/product_simple_seasonality/views/seasonality.xml new file mode 100644 index 00000000000..b20bbc8f872 --- /dev/null +++ b/product_simple_seasonality/views/seasonality.xml @@ -0,0 +1,61 @@ + + + + + seasonality.form (in product_simple_seasonality) + seasonality + +
    + + + + + + +
    +
    +
    + + + seasonality.search (in product_simple_seasonality) + seasonality + + + + + + + + + + seasonality.tree (in product_simple_seasonality) + seasonality + + + + + + + + + + Seasonality + seasonality + list,form + [] + {} + + + + Seasonality + + + + + + Seasonalities + + + +
    diff --git a/product_state/i18n/nl.po b/product_state/i18n/nl.po index cdaa7969243..92880bc91e1 100644 --- a/product_state/i18n/nl.po +++ b/product_state/i18n/nl.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 14.0\n" "Report-Msgid-Bugs-To: \n" -"PO-Revision-Date: 2021-05-09 16:47+0000\n" +"PO-Revision-Date: 2025-11-20 22:18+0000\n" "Last-Translator: Bosd \n" "Language-Team: none\n" "Language: nl\n" @@ -14,12 +14,12 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: \n" "Plural-Forms: nplurals=2; plural=n != 1;\n" -"X-Generator: Weblate 4.3.2\n" +"X-Generator: Weblate 5.10.4\n" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_state__active msgid "Active" -msgstr "" +msgstr "Actief" #. module: product_state #: model_terms:ir.ui.view,arch_db:product_state.view_product_state_form @@ -39,7 +39,7 @@ msgstr "Aangemaakt op" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_state__default msgid "Default state" -msgstr "" +msgstr "Standaard status" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_state__description @@ -100,14 +100,14 @@ msgstr "Verouderd" #. module: product_state #: model:ir.model,name:product_state.model_product_template msgid "Product" -msgstr "" +msgstr "Product" #. module: product_state #: model:ir.actions.act_window,name:product_state.action_open_single_product_state #: model:ir.model,name:product_state.model_product_state #: model_terms:ir.ui.view,arch_db:product_state.product_state_search_form_view msgid "Product State" -msgstr "Product status" +msgstr "Product Status" #. module: product_state #: model:ir.model.constraint,message:product_state.constraint_product_state_code_unique @@ -117,13 +117,13 @@ msgstr "Product Status Code moet uniek zijn." #. module: product_state #: model:res.groups,name:product_state.group_product_state_manager msgid "Product State Manager" -msgstr "" +msgstr "Product Status Beheerder" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_product__state #: model:ir.model.fields,field_description:product_state.field_product_template__state msgid "Product Status" -msgstr "Product status" +msgstr "Product Status" #. module: product_state #: model_terms:ir.ui.view,arch_db:product_state.view_product_state_form @@ -135,7 +135,7 @@ msgstr "Producten" #: model:ir.model.fields,help:product_state.field_product_product__product_state_id #: model:ir.model.fields,help:product_state.field_product_template__product_state_id msgid "Select a state for this product" -msgstr "Selecteer een status voor dir product" +msgstr "Selecteer een status voor dit product" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_state__sequence @@ -153,7 +153,7 @@ msgstr "Status" #. module: product_state #: model:ir.model.fields,field_description:product_state.field_product_state__code msgid "State Code" -msgstr "Status code" +msgstr "Statuscode" #. module: product_state #: model_terms:ir.ui.view,arch_db:product_state.view_product_state_form @@ -164,24 +164,24 @@ msgstr "Statusnaam" #: model:ir.actions.act_window,name:product_state.action_open_state_products #: model:ir.model.fields,field_description:product_state.field_product_state__product_ids msgid "State Products" -msgstr "Product status" +msgstr "Status Producten" #. module: product_state #. odoo-python #: code:addons/product_state/models/product_template.py:0 msgid "The product state code %(product_state)s could not be found." -msgstr "" +msgstr "De product status code %(product_state)s kon niet gevonden worden." #. module: product_state #. odoo-python #: code:addons/product_state/models/product_state.py:0 msgid "There should be only one default state" -msgstr "" +msgstr "Er mag slechts één standaard status zijn" #. module: product_state #: model:ir.model.fields,help:product_state.field_product_state__sequence msgid "Used to order the States" -msgstr "" +msgstr "Gebruikt om de statussen te ordenen" #~ msgid "Last Modified on" #~ msgstr "Laatst gewijzigd op" diff --git a/product_state_sale/i18n/nl.po b/product_state_sale/i18n/nl.po new file mode 100644 index 00000000000..89d4cdaa00d --- /dev/null +++ b/product_state_sale/i18n/nl.po @@ -0,0 +1,22 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_state_sale +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-11-15 13:42+0000\n" +"Last-Translator: Bosd \n" +"Language-Team: none\n" +"Language: nl\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: product_state_sale +#: model:ir.ui.menu,name:product_state_sale.menu_product_state +msgid "Product States" +msgstr "Product Status" diff --git a/product_usability/README.rst b/product_usability/README.rst new file mode 100644 index 00000000000..b83fb05c9e5 --- /dev/null +++ b/product_usability/README.rst @@ -0,0 +1,138 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + +================================== +Product - Missing Menus and Groups +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:65aeece75f4053a9a1d80a47bd26c965eff9e7d634f38cb58c896059f1d0eca6 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/license-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%2Fproduct--attribute-lightgray.png?logo=github + :target: https://github.com/OCA/product-attribute/tree/18.0/product_usability + :alt: OCA/product-attribute +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/product-attribute-18-0/product-attribute-18-0-product_usability + :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/product-attribute&target_branch=18.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module extends the Odoo CE product module to fill gaps present in +the module. + +New Menu items +-------------- + +By default, when installing ``product`` module, a lot of menu items are +not created and are available only if other module are installed. For +exemple: + +- Manage product categories requires to install ``stock`` module, that + creates the menu entry \_"Inventory / Configuration / Product / + Product Categories"\_. +- Manage product tags requires to install ``sale_management`` module, + that creates the menu entry \_"Sale / Configuration / Products / + Tags"\_. + +This module so creates a new main menu item named 'Product' that +provides all menu entries to see and manage product, attributes, +pricelists, Units of Measure, etc. So that all the product configuration +is available in a unique place. + +|image1| + +New Access Rights +----------------- + +By default, to create product, attributes, pricelist, categories, User +should be member of a group that adds a lot of rights, like 'Inventory / +Manager' or 'Sale / Manager'. + +This module adds new Access rules to fine-tune access rights, creating +the following rules: + +- \_"Product Creation"\_: Allow to create Products + (``product.template``), Variants (``product.product``), Product + Template Attribute Lines (``product.template.attribute.line``) and + Product Template Attribute Values + (``product.template.attribute.value``) +- \_"Product Attribute Creation"\_: Allow to create Attributes + (``product.attribute``) and Values (``product.attribute.value``). +- \_"Product Tag Creation"\_: Allow to create Tags (``product.tag``) +- \_"Product Category Creation"\_: Allow to create Categories + (``product.category``) +- \_"Product Supplier Pricelist Creation"\_: Allow to create Supplier + Pricelists (``product.supplierinfo``) +- \_"Unit of Measure Creation"\_: Allow to create Unit of Measures + (``uom.uom``) and Unit of Measures Categories (``uom.category``) + +.. |image1| image:: https://raw.githubusercontent.com/OCA/product-attribute/18.0/product_usability/static/description/main_menu.png + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* GRAP + +Contributors +------------ + +- Sylvain LE GAL + <`https://twitter.com/legalsylvain\\> >`__ + +Maintainers +----------- + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-legalsylvain| image:: https://github.com/legalsylvain.png?size=40px + :target: https://github.com/legalsylvain + :alt: legalsylvain + +Current `maintainer `__: + +|maintainer-legalsylvain| + +This module is part of the `OCA/product-attribute `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/product_usability/__init__.py b/product_usability/__init__.py new file mode 100644 index 00000000000..8d2116c4265 --- /dev/null +++ b/product_usability/__init__.py @@ -0,0 +1 @@ +from .hooks import pre_init_hook diff --git a/product_usability/__manifest__.py b/product_usability/__manifest__.py new file mode 100644 index 00000000000..51ecd3e6e52 --- /dev/null +++ b/product_usability/__manifest__.py @@ -0,0 +1,23 @@ +# Copyright (C) 2024 - Today: GRAP (http://www.grap.coop) +# @author: Sylvain LE GAL (https://twitter.com/legalsylvain) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + "name": "Product - Missing Menus and Groups", + "version": "18.0.1.0.0", + "category": "Product", + "license": "AGPL-3", + "summary": "Adds missing menu entries for Product module and" + " adds extra groups to fine-tune access rights", + "author": "GRAP, Odoo Community Association (OCA)", + "maintainers": ["legalsylvain"], + "website": "https://github.com/OCA/product-attribute", + "depends": ["product"], + "data": [ + "security/res_groups.xml", + "security/ir.model.access.csv", + "views/menu.xml", + ], + "installable": True, + "pre_init_hook": "pre_init_hook", +} diff --git a/product_usability/hooks.py b/product_usability/hooks.py new file mode 100644 index 00000000000..3a1deede553 --- /dev/null +++ b/product_usability/hooks.py @@ -0,0 +1,7 @@ +# copyright David BEAL @ Akretion + + +def pre_init_hook(env): + # Rename the "Product Manager" group to a more matching name + # and avoid collision with current module + env.ref("product.group_product_manager").name = "Product Manager" diff --git a/product_usability/i18n/fr.po b/product_usability/i18n/fr.po new file mode 100644 index 00000000000..cd71055f325 --- /dev/null +++ b/product_usability/i18n/fr.po @@ -0,0 +1,99 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_usability +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-06-16 20:40+0000\n" +"PO-Revision-Date: 2024-06-16 20:40+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_attribute +msgid "Attributes" +msgstr "Attributs de produits" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_configuration +msgid "Configuration" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_pricelist +msgid "Pricelists" +msgstr "Listes de prix" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_attribute_creation +msgid "Product Attribute Creation" +msgstr "Création d'attribut de produit" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_category +msgid "Product Categories" +msgstr "Catégories de produits" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_category_creation +msgid "Product Category Creation" +msgstr "Création de catégorie de produit" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_creation +msgid "Product Creation" +msgstr "Création de produit" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_packaging +msgid "Product Packagings" +msgstr "Conditionnements de produit" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_supplierinfo_creation +msgid "Product Supplier Pricelist Creation" +msgstr "Création de tarification fournisseur de produit" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_tag_creation +msgid "Product Tag Creation" +msgstr "Création d'étiquette de produit" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_tag +msgid "Product Tags" +msgstr "Étiquettes de produit" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_product +msgid "Product Variants" +msgstr "Variantes de produit" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product +#: model:ir.ui.menu,name:product_usability.menu_product_main +#: model:ir.ui.menu,name:product_usability.menu_product_template +msgid "Products" +msgstr "Produits" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_uom +msgid "Units of Measure" +msgstr "Unités de mesure" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_category +msgid "Units of Measure Categories" +msgstr "Catégories d'unité de mesure" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_uom_creation +msgid "Units of Measure Creation" +msgstr "Création d'unité de mesure" diff --git a/product_usability/i18n/it.po b/product_usability/i18n/it.po new file mode 100644 index 00000000000..7be6c1e48b3 --- /dev/null +++ b/product_usability/i18n/it.po @@ -0,0 +1,99 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_usability +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2024-11-08 11:06+0000\n" +"Last-Translator: mymage \n" +"Language-Team: none\n" +"Language: it\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.6.2\n" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_attribute +msgid "Attributes" +msgstr "Attributi" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_configuration +msgid "Configuration" +msgstr "Configurazione" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_pricelist +msgid "Pricelists" +msgstr "Listini" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_attribute_creation +msgid "Product Attribute Creation" +msgstr "Creazione attributo prodotto" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_category +msgid "Product Categories" +msgstr "Categorie prodotto" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_category_creation +msgid "Product Category Creation" +msgstr "Creazione categoria prodotto" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_creation +msgid "Product Creation" +msgstr "Creazione prodotto" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_packaging +msgid "Product Packagings" +msgstr "Imballaggi prodotto" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_supplierinfo_creation +msgid "Product Supplier Pricelist Creation" +msgstr "Creazione listino fornitore prodotto" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_tag_creation +msgid "Product Tag Creation" +msgstr "Creazione etichetta prodotto" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_tag +msgid "Product Tags" +msgstr "Etichette prodotto" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_product +msgid "Product Variants" +msgstr "Varianti prodotto" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product +#: model:ir.ui.menu,name:product_usability.menu_product_main +#: model:ir.ui.menu,name:product_usability.menu_product_template +msgid "Products" +msgstr "Prodotti" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_uom +msgid "Units of Measure" +msgstr "Unità di misura" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_category +msgid "Units of Measure Categories" +msgstr "Categorie unità di misura" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_uom_creation +msgid "Units of Measure Creation" +msgstr "Creazione unità di misura" diff --git a/product_usability/i18n/product_usability.pot b/product_usability/i18n/product_usability.pot new file mode 100644 index 00000000000..9b1a5b640b1 --- /dev/null +++ b/product_usability/i18n/product_usability.pot @@ -0,0 +1,96 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_usability +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_attribute +msgid "Attributes" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_configuration +msgid "Configuration" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_pricelist +msgid "Pricelists" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_attribute_creation +msgid "Product Attribute Creation" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_category +msgid "Product Categories" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_category_creation +msgid "Product Category Creation" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_creation +msgid "Product Creation" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_packaging +msgid "Product Packagings" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_supplierinfo_creation +msgid "Product Supplier Pricelist Creation" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_product_tag_creation +msgid "Product Tag Creation" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_tag +msgid "Product Tags" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product_product +msgid "Product Variants" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_product +#: model:ir.ui.menu,name:product_usability.menu_product_main +#: model:ir.ui.menu,name:product_usability.menu_product_template +msgid "Products" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_uom +msgid "Units of Measure" +msgstr "" + +#. module: product_usability +#: model:ir.ui.menu,name:product_usability.menu_uom_category +msgid "Units of Measure Categories" +msgstr "" + +#. module: product_usability +#: model:res.groups,name:product_usability.group_uom_creation +msgid "Units of Measure Creation" +msgstr "" diff --git a/product_usability/pyproject.toml b/product_usability/pyproject.toml new file mode 100644 index 00000000000..4231d0cccb3 --- /dev/null +++ b/product_usability/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_usability/readme/CONTRIBUTORS.md b/product_usability/readme/CONTRIBUTORS.md new file mode 100644 index 00000000000..f29fa69a1ca --- /dev/null +++ b/product_usability/readme/CONTRIBUTORS.md @@ -0,0 +1 @@ +- Sylvain LE GAL \ diff --git a/product_usability/readme/DESCRIPTION.md b/product_usability/readme/DESCRIPTION.md new file mode 100644 index 00000000000..d74c9904a62 --- /dev/null +++ b/product_usability/readme/DESCRIPTION.md @@ -0,0 +1,44 @@ +This module extends the Odoo CE product module to fill gaps present in +the module. + +## New Menu items + +By default, when installing `product` module, a lot of menu items are +not created and are available only if other module are installed. For +exemple: + +- Manage product categories requires to install `stock` module, that + creates the menu entry \_"Inventory / Configuration / Product / + Product Categories"\_. +- Manage product tags requires to install `sale_management` module, that + creates the menu entry \_"Sale / Configuration / Products / Tags"\_. + +This module so creates a new main menu item named 'Product' that +provides all menu entries to see and manage product, attributes, +pricelists, Units of Measure, etc. So that all the product configuration +is available in a unique place. + +![](../static/description/main_menu.png) + +## New Access Rights + +By default, to create product, attributes, pricelist, categories, User +should be member of a group that adds a lot of rights, like 'Inventory / +Manager' or 'Sale / Manager'. + +This module adds new Access rules to fine-tune access rights, creating +the following rules: + +- \_"Product Creation"\_: Allow to create Products (`product.template`), + Variants (`product.product`), Product Template Attribute Lines + (`product.template.attribute.line`) and Product Template Attribute + Values (`product.template.attribute.value`) +- \_"Product Attribute Creation"\_: Allow to create Attributes + (`product.attribute`) and Values (`product.attribute.value`). +- \_"Product Tag Creation"\_: Allow to create Tags (`product.tag`) +- \_"Product Category Creation"\_: Allow to create Categories + (`product.category`) +- \_"Product Supplier Pricelist Creation"\_: Allow to create Supplier + Pricelists (`product.supplierinfo`) +- \_"Unit of Measure Creation"\_: Allow to create Unit of Measures + (`uom.uom`) and Unit of Measures Categories (`uom.category`) diff --git a/product_usability/security/ir.model.access.csv b/product_usability/security/ir.model.access.csv new file mode 100644 index 00000000000..e9b0c9ce0d6 --- /dev/null +++ b/product_usability/security/ir.model.access.csv @@ -0,0 +1,12 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_template_manager,product.template manager,product.model_product_template,group_product_creation,1,1,1,1 +access_product_product_manager,product.product manager,product.model_product_product,group_product_creation,1,1,1,1 +access_product_attribute_manager,product.attribute manager,product.model_product_attribute,group_product_attribute_creation,1,1,1,1 +access_product_attribute_value_manager,product.attribute.value manager,product.model_product_attribute_value,group_product_attribute_creation,1,1,1,1 +access_product_template_attribute_line_manager,product.template.attribute.line manager,product.model_product_template_attribute_line,group_product_creation,1,1,1,1 +access_product_template_attribute_value_manager,product.template.attribute.value manager,product.model_product_template_attribute_value,group_product_creation,1,1,1,1 +access_product_tag_manager,product.tag manager,product.model_product_tag,group_product_tag_creation,1,1,1,1 +access_product_category_manager,product.category manager,product.model_product_category,group_product_category_creation,1,1,1,1 +access_product_supplierinfo_manager,product.supplierinfo manager,product.model_product_supplierinfo,group_product_supplierinfo_creation,1,1,1,1 +access_uom_uom_manager,uom.uom manager,uom.model_uom_uom,group_uom_creation,1,1,1,1 +access_uom_category_manager,uom.category manager,uom.model_uom_category,group_uom_creation,1,1,1,1 diff --git a/product_usability/security/res_groups.xml b/product_usability/security/res_groups.xml new file mode 100644 index 00000000000..1f6cb56c837 --- /dev/null +++ b/product_usability/security/res_groups.xml @@ -0,0 +1,45 @@ + + + + + Product Creation + + + + + Product Attribute Creation + + + + + Product Tag Creation + + + + + Product Category Creation + + + + + Product Supplier Pricelist Creation + + + + + Units of Measure Creation + + + + + + + + diff --git a/product_usability/static/description/icon.png b/product_usability/static/description/icon.png new file mode 100644 index 00000000000..3a0328b516c Binary files /dev/null and b/product_usability/static/description/icon.png differ diff --git a/product_usability/static/description/index.html b/product_usability/static/description/index.html new file mode 100644 index 00000000000..73a06fb3f3d --- /dev/null +++ b/product_usability/static/description/index.html @@ -0,0 +1,471 @@ + + + + + +README.rst + + + +
    + + + +Odoo Community Association + +
    +

    Product - Missing Menus and Groups

    + +

    Beta License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    This module extends the Odoo CE product module to fill gaps present in +the module.

    +
    +

    New Menu items

    +

    By default, when installing product module, a lot of menu items are +not created and are available only if other module are installed. For +exemple:

    +
      +
    • Manage product categories requires to install stock module, that +creates the menu entry _”Inventory / Configuration / Product / +Product Categories”_.
    • +
    • Manage product tags requires to install sale_management module, +that creates the menu entry _”Sale / Configuration / Products / +Tags”_.
    • +
    +

    This module so creates a new main menu item named ‘Product’ that +provides all menu entries to see and manage product, attributes, +pricelists, Units of Measure, etc. So that all the product configuration +is available in a unique place.

    +

    image1

    +
    +
    +

    New Access Rights

    +

    By default, to create product, attributes, pricelist, categories, User +should be member of a group that adds a lot of rights, like ‘Inventory / +Manager’ or ‘Sale / Manager’.

    +

    This module adds new Access rules to fine-tune access rights, creating +the following rules:

    +
      +
    • _”Product Creation”_: Allow to create Products +(product.template), Variants (product.product), Product +Template Attribute Lines (product.template.attribute.line) and +Product Template Attribute Values +(product.template.attribute.value)
    • +
    • _”Product Attribute Creation”_: Allow to create Attributes +(product.attribute) and Values (product.attribute.value).
    • +
    • _”Product Tag Creation”_: Allow to create Tags (product.tag)
    • +
    • _”Product Category Creation”_: Allow to create Categories +(product.category)
    • +
    • _”Product Supplier Pricelist Creation”_: Allow to create Supplier +Pricelists (product.supplierinfo)
    • +
    • _”Unit of Measure Creation”_: Allow to create Unit of Measures +(uom.uom) and Unit of Measures Categories (uom.category)
    • +
    +

    Table of contents

    + +
    +

    Bug Tracker

    +

    Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

    +

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

    +
    + +
    +
    +

    Authors

    +
      +
    • GRAP
    • +
    +
    +
    +

    Contributors

    + +
    +
    +

    Maintainers

    +

    This module is maintained by the OCA.

    + +Odoo Community Association + +

    OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

    +

    Current maintainer:

    +

    legalsylvain

    +

    This module is part of the OCA/product-attribute project on GitHub.

    +

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

    +
    +
    +
    + + diff --git a/product_usability/static/description/main_menu.png b/product_usability/static/description/main_menu.png new file mode 100644 index 00000000000..e554eb69aca Binary files /dev/null and b/product_usability/static/description/main_menu.png differ diff --git a/product_usability/static/description/product_menu_icon.png b/product_usability/static/description/product_menu_icon.png new file mode 100644 index 00000000000..b22d85711c8 Binary files /dev/null and b/product_usability/static/description/product_menu_icon.png differ diff --git a/product_usability/static/description/product_menu_icon.svg b/product_usability/static/description/product_menu_icon.svg new file mode 100644 index 00000000000..efd14db6ac0 --- /dev/null +++ b/product_usability/static/description/product_menu_icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/product_usability/views/menu.xml b/product_usability/views/menu.xml new file mode 100644 index 00000000000..636fae1c661 --- /dev/null +++ b/product_usability/views/menu.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/product_variant_route_mto/README.rst b/product_variant_route_mto/README.rst index 6cb2928cb5d..98b0beba974 100644 --- a/product_variant_route_mto/README.rst +++ b/product_variant_route_mto/README.rst @@ -1,3 +1,7 @@ +.. image:: https://odoo-community.org/readme-banner-image + :target: https://odoo-community.org/get-involved?utm_source=readme + :alt: Odoo Community Association + ========================= Product Variant Route MTO ========================= @@ -7,13 +11,13 @@ Product Variant Route MTO !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !! source digest: sha256:05d176ec1f7bf87893bca915bd87346e248c55c1f634024018d88317b9b69b7b + !! source digest: sha256:1e2ade8c67362dc4af66c6252f7f9a1366afbb40433b0a38dff90c034544b417 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png :target: https://odoo-community.org/page/development-status :alt: Alpha -.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png +.. |badge2| image:: https://img.shields.io/badge/license-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%2Fproduct--attribute-lightgray.png?logo=github diff --git a/product_variant_route_mto/__manifest__.py b/product_variant_route_mto/__manifest__.py index 532f11e905e..bd5cb786e21 100644 --- a/product_variant_route_mto/__manifest__.py +++ b/product_variant_route_mto/__manifest__.py @@ -5,7 +5,7 @@ { "name": "Product Variant Route MTO", "summary": "Allow to individually set variants as MTO", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "development_status": "Alpha", "category": "Inventory", "website": "https://github.com/OCA/product-attribute", diff --git a/product_variant_route_mto/models/product_product.py b/product_variant_route_mto/models/product_product.py index 5a996394747..24e4a23d037 100644 --- a/product_variant_route_mto/models/product_product.py +++ b/product_variant_route_mto/models/product_product.py @@ -30,6 +30,7 @@ class ProductProduct(models.Model): domain="[('product_selectable', '=', True)]", store=False, search="_search_route_ids", + inverse="_inverse_route_ids", ) def _compute_is_mto(self): @@ -59,6 +60,19 @@ def _search_route_ids(self, operator, value): domain += [("product_tmpl_id.route_ids", operator, route_ids)] return domain + def _inverse_route_ids(self): + mto_routes = self.env["stock.route"].search([("is_mto", "=", True)]) + for product in self: + non_mto_routes = product.route_ids - mto_routes + if product.route_ids & mto_routes: + if not product.is_mto: + product.is_mto = True + else: + if product.is_mto: + product.is_mto = False + if product.product_tmpl_id.route_ids != non_mto_routes: + product.product_tmpl_id.route_ids = non_mto_routes + @api.constrains("is_mto") def _check_template_is_mto(self): for product in self: diff --git a/product_variant_route_mto/static/description/index.html b/product_variant_route_mto/static/description/index.html index 64266ae831f..6209ab6325c 100644 --- a/product_variant_route_mto/static/description/index.html +++ b/product_variant_route_mto/static/description/index.html @@ -3,7 +3,7 @@ -Product Variant Route MTO +README.rst -
    -

    Product Variant Route MTO

    +
    + + +Odoo Community Association + +
    +

    Product Variant Route MTO

    -

    Alpha License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    +

    Alpha License: AGPL-3 OCA/product-attribute Translate me on Weblate Try me on Runboat

    This module allows to set a product variant as MTO (enabling the Make To Order route on that variant only) while the related product is not MTO. However, you cannot mark a variant has non MTO when the template is MTO.

    @@ -393,7 +398,7 @@

    Product Variant Route MTO

    -

    Bug Tracker

    +

    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 @@ -401,15 +406,15 @@

    Bug Tracker

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

    -

    Credits

    +

    Credits

    -

    Authors

    +

    Authors

    • Camptocamp SA
    -

    Contributors

    +

    Contributors

    -

    Other credits

    +

    Other credits

    The development and migration of this module has been financially supported by:

    -

    Maintainers

    +

    Maintainers

    This module is maintained by the OCA.

    Odoo Community Association @@ -441,5 +446,6 @@

    Maintainers

    +
    diff --git a/product_variant_route_mto/tests/test_mto_variant.py b/product_variant_route_mto/tests/test_mto_variant.py index debbcb73f2d..d4632d632c9 100644 --- a/product_variant_route_mto/tests/test_mto_variant.py +++ b/product_variant_route_mto/tests/test_mto_variant.py @@ -2,6 +2,7 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl) import logging +from odoo import Command from odoo.exceptions import ValidationError from .common import TestMTOVariantCommon @@ -41,6 +42,14 @@ def test_variants_mto(self): self.remove_route(pen_template, self.mto_route) self.assertVariantsNotMTO(pens) + def test_variants_routes_updated(self): + blue_pen = self.blue_pen + self.assertVariantsNotMTO(blue_pen) + blue_pen.route_ids = [Command.link(self.mto_route.id)] + self.assertVariantsMTO(blue_pen) + blue_pen.route_ids = [Command.clear()] + self.assertVariantsNotMTO(blue_pen) + def test_template_routes_updated(self): # instanciate variables pen_template = self.template_pen diff --git a/purchase_product_template_tags/i18n/hr.po b/purchase_product_template_tags/i18n/hr.po new file mode 100644 index 00000000000..69448461c8c --- /dev/null +++ b/purchase_product_template_tags/i18n/hr.po @@ -0,0 +1,23 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * purchase_product_template_tags +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-12-08 12:56+0000\n" +"Last-Translator: Ana Matulin \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: purchase_product_template_tags +#: model:ir.ui.menu,name:purchase_product_template_tags.menu_product_template_tag +msgid "Tags" +msgstr "Oznake" diff --git a/sale_product_template_tags/i18n/hr.po b/sale_product_template_tags/i18n/hr.po new file mode 100644 index 00000000000..a0cd11cb174 --- /dev/null +++ b/sale_product_template_tags/i18n/hr.po @@ -0,0 +1,23 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_product_template_tags +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2025-12-08 12:56+0000\n" +"Last-Translator: Ana Matulin \n" +"Language-Team: none\n" +"Language: hr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && " +"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" +"X-Generator: Weblate 5.10.4\n" + +#. module: sale_product_template_tags +#: model:ir.ui.menu,name:sale_product_template_tags.menu_product_template_tag +msgid "Tags" +msgstr "Oznake" diff --git a/setup/_metapackage/pyproject.toml b/setup/_metapackage/pyproject.toml index 2fd09597647..0f17be8719f 100644 --- a/setup/_metapackage/pyproject.toml +++ b/setup/_metapackage/pyproject.toml @@ -1,7 +1,8 @@ [project] name = "odoo-addons-oca-product-attribute" -version = "18.0.20250917.0" +version = "18.0.20260108.0" dependencies = [ + "odoo-addon-product_abc_classification==18.0.*", "odoo-addon-product_assortment==18.0.*", "odoo-addon-product_attachment_zipped_download==18.0.*", "odoo-addon-product_attribute_archive==18.0.*", @@ -16,12 +17,14 @@ dependencies = [ "odoo-addon-product_category_tag==18.0.*", "odoo-addon-product_category_type==18.0.*", "odoo-addon-product_category_uom==18.0.*", + "odoo-addon-product_code_mandatory==18.0.*", "odoo-addon-product_code_unique==18.0.*", "odoo-addon-product_company_default==18.0.*", "odoo-addon-product_cost_security==18.0.*", "odoo-addon-product_customerinfo==18.0.*", "odoo-addon-product_dimension==18.0.*", "odoo-addon-product_drained_weight==18.0.*", + "odoo-addon-product_form_pricelist==18.0.*", "odoo-addon-product_get_price_helper==18.0.*", "odoo-addon-product_list_price_from_pricelist==18.0.*", "odoo-addon-product_logistics_uom==18.0.*", @@ -30,8 +33,10 @@ dependencies = [ "odoo-addon-product_manufacturer==18.0.*", "odoo-addon-product_medical==18.0.*", "odoo-addon-product_multi_category==18.0.*", + "odoo-addon-product_multi_price==18.0.*", "odoo-addon-product_net_weight==18.0.*", "odoo-addon-product_origin==18.0.*", + "odoo-addon-product_packaging_archive==18.0.*", "odoo-addon-product_packaging_calculator==18.0.*", "odoo-addon-product_packaging_calculator_packaging_level==18.0.*", "odoo-addon-product_packaging_dimension==18.0.*", @@ -46,15 +51,19 @@ dependencies = [ "odoo-addon-product_pricelist_direct_print_website_sale==18.0.*", "odoo-addon-product_pricelist_direct_print_xlsx==18.0.*", "odoo-addon-product_pricelist_fixed_currency_rate==18.0.*", + "odoo-addon-product_pricelist_item_list_view==18.0.*", + "odoo-addon-product_pricelist_margin==18.0.*", "odoo-addon-product_pricelist_revision==18.0.*", "odoo-addon-product_pricelist_supplierinfo==18.0.*", "odoo-addon-product_print_category==18.0.*", "odoo-addon-product_product_template_link==18.0.*", "odoo-addon-product_route_mto==18.0.*", "odoo-addon-product_sale_manufactured_for==18.0.*", + "odoo-addon-product_sale_team==18.0.*", "odoo-addon-product_secondary_unit==18.0.*", "odoo-addon-product_sequence==18.0.*", "odoo-addon-product_set==18.0.*", + "odoo-addon-product_simple_seasonality==18.0.*", "odoo-addon-product_state==18.0.*", "odoo-addon-product_state_sale==18.0.*", "odoo-addon-product_state_stock_base==18.0.*", @@ -69,6 +78,7 @@ dependencies = [ "odoo-addon-product_tags_code==18.0.*", "odoo-addon-product_total_weight_from_packaging==18.0.*", "odoo-addon-product_uom_updatable==18.0.*", + "odoo-addon-product_usability==18.0.*", "odoo-addon-product_variant_route_mto==18.0.*", "odoo-addon-purchase_product_template_tags==18.0.*", "odoo-addon-sale_product_template_tags==18.0.*",