diff --git a/sale_loyalty_auto_refresh/README.rst b/sale_loyalty_auto_refresh/README.rst new file mode 100644 index 00000000..3467c2bf --- /dev/null +++ b/sale_loyalty_auto_refresh/README.rst @@ -0,0 +1,137 @@ +==================== +Auto Refresh Coupons +==================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:133096428fab5ae09fcaa35b8da33f24d667399972235fc7e8842692fbc2eb41 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--promotion-lightgray.png?logo=github + :target: https://github.com/OCA/sale-promotion/tree/16.0/sale_loyalty_auto_refresh + :alt: OCA/sale-promotion +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/sale-promotion-16-0/sale-promotion-16-0-sale_loyalty_auto_refresh + :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/sale-promotion&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module allows to auto apply the programs without the need of the user intervention. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +You can set this feature on or off in every company. To do so: + +#. Go to *Sales > Configuration > Settings* +#. In the *Pricing* section you'll find the option *Auto refresh promotions*. + +The auto-refresh in the backend is triggered over a minimum set of fields changes. If +you want to extend the list of that fields: + +#. Go to *Settings > Technical > Config parameters* +#. Add or update the key: + + - For `sale.order`: `sale_loyalty_auto_refresh.sale_order_triggers` + - For `sale.order.line`: `sale_loyalty_auto_refresh.sale_order_line_triggers` +#. In every add the fields seperated by commas that you want to add to the recomputation + triggers. + +⚠️ After configuring or removing a trigger a restart of Odoo is recommended so the +depends are reloaded properly. Anyway it isn't mandatory and the module detects the +new triggers so the auto-refresh works as expected as soon as they are set. + +Usage +===== + +You need to configure a *Promotion program* with the option *Program trigger* set to +*Automatic* (shown in Debug mode only, read-only computed field). This can be done in *Sales > Products > Discount & Loyalty*. + +Now, make a quotation that fulfill the promotion condition and the promotion will be +automatically applied. + +Known issues / Roadmap +====================== + +* This module should be ported to OCA in v13 as Odoo released enterprise modules and + they are now on the community side. + +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 +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* `Tecnativa `_: + + * David Vidal + * Pilar Vargas + +* `Camptocamp `_: + + * Silvio Gregorini + +* `Trobz `_: + + * Nguyen Minh Chien + +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-chienandalu| image:: https://github.com/chienandalu.png?size=40px + :target: https://github.com/chienandalu + :alt: chienandalu +.. |maintainer-SilvioC2C| image:: https://github.com/SilvioC2C.png?size=40px + :target: https://github.com/SilvioC2C + :alt: SilvioC2C + +Current `maintainers `__: + +|maintainer-chienandalu| |maintainer-SilvioC2C| + +This module is part of the `OCA/sale-promotion `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/sale_loyalty_auto_refresh/__init__.py b/sale_loyalty_auto_refresh/__init__.py new file mode 100644 index 00000000..9b429614 --- /dev/null +++ b/sale_loyalty_auto_refresh/__init__.py @@ -0,0 +1,2 @@ +from . import models +from . import wizard diff --git a/sale_loyalty_auto_refresh/__manifest__.py b/sale_loyalty_auto_refresh/__manifest__.py new file mode 100644 index 00000000..159219b5 --- /dev/null +++ b/sale_loyalty_auto_refresh/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2021 Tecnativa - David Vidal +# Copyright 2021 Camptocamp - Silvio Gregorini +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Auto Refresh Coupons", + "summary": "Allows to auto-apply the coupons with no user intervention", + "version": "16.0.1.0.0", + "development_status": "Production/Stable", + "category": "Website", + "website": "https://github.com/OCA/sale-promotion", + "author": "Tecnativa, Camptocamp, Odoo Community Association (OCA)", + "maintainers": ["chienandalu", "SilvioC2C"], + "license": "AGPL-3", + "depends": ["sale_loyalty"], + "data": ["views/res_config_settings_views.xml"], +} diff --git a/sale_loyalty_auto_refresh/i18n/es.po b/sale_loyalty_auto_refresh/i18n/es.po new file mode 100644 index 00000000..1f27edae --- /dev/null +++ b/sale_loyalty_auto_refresh/i18n/es.po @@ -0,0 +1,99 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_loyalty_auto_refresh +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 12.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2023-11-08 13:38+0000\n" +"Last-Translator: Ivorra78 \n" +"Language-Team: \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: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_coupon_refresh_mixin__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order_line__auto_refresh_coupon_triggers_data +msgid "Auto Refresh Coupon Triggers Data" +msgstr "Actualizar Automáticamente los Datos de los Activadores de Cupones" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Auto Refresh Coupons" +msgstr "Auto actualizar ofertas" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto refresh coupons" +msgstr "Auto actualizar ofertas" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto-refresh coupons" +msgstr "Auto actualizar ofertas" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Autorefresh coupon lines in the backorder" +msgstr "Auto actualizar las líneas de descuento en backorder" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_company +msgid "Companies" +msgstr "Compañías" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_config_settings +msgid "Config Settings" +msgstr "Ajustes" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_refresh_mixin +msgid "Mixin class for sale coupon auto-refresh features" +msgstr "Clase mixta de actualización automática de cupones de descuento" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_apply_code +msgid "Sales Coupon Apply Code" +msgstr "Cupón de descuento Aplicar código" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order +msgid "Sales Order" +msgstr "Orden de Venta" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order_line +msgid "Sales Order Line" +msgstr "Línea de Orden de Venta" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"When the sale order is updated, auto-refresh the promotion programs which " +"are set to auto apply" +msgstr "" +"Cuando se actualice un pedido de venta, auto actualizar los programas de " +"oferta configurados para auto aplicarse" + +#~ msgid "Sale Order" +#~ msgstr "Pedido de Venta" diff --git a/sale_loyalty_auto_refresh/i18n/fr.po b/sale_loyalty_auto_refresh/i18n/fr.po new file mode 100644 index 00000000..f1ebcde0 --- /dev/null +++ b/sale_loyalty_auto_refresh/i18n/fr.po @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_loyalty_auto_refresh +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-09-18 14:34+0000\n" +"Last-Translator: Rémi \n" +"Language-Team: none\n" +"Language: fr\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=2; plural=n > 1;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_coupon_refresh_mixin__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order_line__auto_refresh_coupon_triggers_data +msgid "Auto Refresh Coupon Triggers Data" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Auto Refresh Coupons" +msgstr "Mise à jour automatique des promotions" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto refresh coupons" +msgstr "Mise à jour automatique des promotions" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto-refresh coupons" +msgstr "Mise à jour automatique des promotions" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Autorefresh coupon lines in the backorder" +msgstr "Mise à jour automatique des promotions" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_company +msgid "Companies" +msgstr "Sociétés" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_config_settings +msgid "Config Settings" +msgstr "Configuration" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_refresh_mixin +msgid "Mixin class for sale coupon auto-refresh features" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_apply_code +msgid "Sales Coupon Apply Code" +msgstr "Utiliser le code promotionnel" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order +msgid "Sales Order" +msgstr "Commandes" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order_line +msgid "Sales Order Line" +msgstr "Ligne de Commande" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"When the sale order is updated, auto-refresh the promotion programs which " +"are set to auto apply" +msgstr "" +"Quand le devis est mis à jour, recalcule automatiquement les programmes de " +"promotions configurés pour application automatique" + +#~ msgid "Display Name" +#~ msgstr "Nom affiché" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Date de dernière modification" diff --git a/sale_loyalty_auto_refresh/i18n/it.po b/sale_loyalty_auto_refresh/i18n/it.po new file mode 100644 index 00000000..dbd0e099 --- /dev/null +++ b/sale_loyalty_auto_refresh/i18n/it.po @@ -0,0 +1,105 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_loyalty_auto_refresh +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2022-04-28 10:05+0000\n" +"Last-Translator: Francesco Foresti \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.3.2\n" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_coupon_refresh_mixin__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order_line__auto_refresh_coupon_triggers_data +msgid "Auto Refresh Coupon Triggers Data" +msgstr "Dati trigger aggiornamento automatic coupons" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Auto Refresh Coupons" +msgstr "Aggiornamento automatico coupons" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto refresh coupons" +msgstr "Aggiornamento automatico coupons" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto-refresh coupons" +msgstr "Aggiornamento automatico coupons" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Autorefresh coupon lines in the backorder" +msgstr "Aggiorna automaticamente righe coupon nell'ordine residuo" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_company +msgid "Companies" +msgstr "Aziende" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_config_settings +msgid "Config Settings" +msgstr "Impostazioni configurazione" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_refresh_mixin +msgid "Mixin class for sale coupon auto-refresh features" +msgstr "Classe mixin per funzionalità aggiornamento automatico coupon" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_apply_code +msgid "Sales Coupon Apply Code" +msgstr "Applica codice coupon vendite" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order +msgid "Sales Order" +msgstr "Ordine di vendita" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order_line +msgid "Sales Order Line" +msgstr "Riga ordine di vendita" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"When the sale order is updated, auto-refresh the promotion programs which " +"are set to auto apply" +msgstr "" +"Quando l'ordine di vendita è aggiornato, aggiorna automaticamente le " +"promozioni che sono impostate ad \"applica automaticamente\"" + +#~ msgid "Display Name" +#~ msgstr "Nome Visualizzato" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "Ultima modifica il" diff --git a/sale_loyalty_auto_refresh/i18n/sale_loyalty_auto_refresh.pot b/sale_loyalty_auto_refresh/i18n/sale_loyalty_auto_refresh.pot new file mode 100644 index 00000000..156ae77a --- /dev/null +++ b/sale_loyalty_auto_refresh/i18n/sale_loyalty_auto_refresh.pot @@ -0,0 +1,89 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_loyalty_auto_refresh +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 15.0\n" +"Report-Msgid-Bugs-To: \n" +"Last-Translator: \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_coupon_refresh_mixin__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order_line__auto_refresh_coupon_triggers_data +msgid "Auto Refresh Coupon Triggers Data" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Auto Refresh Coupons" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto refresh coupons" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto-refresh coupons" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Autorefresh coupon lines in the backorder" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_company +msgid "Companies" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_config_settings +msgid "Config Settings" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_refresh_mixin +msgid "Mixin class for sale coupon auto-refresh features" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_apply_code +msgid "Sales Coupon Apply Code" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order +msgid "Sales Order" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order_line +msgid "Sales Order Line" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"When the sale order is updated, auto-refresh the promotion programs which " +"are set to auto apply" +msgstr "" diff --git a/sale_loyalty_auto_refresh/i18n/zh_CN.po b/sale_loyalty_auto_refresh/i18n/zh_CN.po new file mode 100644 index 00000000..5df26786 --- /dev/null +++ b/sale_loyalty_auto_refresh/i18n/zh_CN.po @@ -0,0 +1,103 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * sale_loyalty_auto_refresh +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 14.0\n" +"Report-Msgid-Bugs-To: \n" +"PO-Revision-Date: 2021-09-02 04:50+0000\n" +"Last-Translator: 黎伟杰 <674416404@qq.com>\n" +"Language-Team: none\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 4.3.2\n" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"" +msgstr "" +"" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_coupon_refresh_mixin__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon_triggers_data +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order_line__auto_refresh_coupon_triggers_data +msgid "Auto Refresh Coupon Triggers Data" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,field_description:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Auto Refresh Coupons" +msgstr "自动刷新优惠券" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto refresh coupons" +msgstr "自动刷新优惠券" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "Auto-refresh coupons" +msgstr "自动刷新优惠券" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_company__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_res_config_settings__auto_refresh_coupon +#: model:ir.model.fields,help:sale_loyalty_auto_refresh.field_sale_order__auto_refresh_coupon +msgid "Autorefresh coupon lines in the backorder" +msgstr "自动刷新延期交货中的优惠券行" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_company +msgid "Companies" +msgstr "公司" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_res_config_settings +msgid "Config Settings" +msgstr "配置设置" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_refresh_mixin +msgid "Mixin class for sale coupon auto-refresh features" +msgstr "" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_coupon_apply_code +msgid "Sales Coupon Apply Code" +msgstr "销售优惠券申请代码" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order +msgid "Sales Order" +msgstr "销售订单" + +#. module: sale_loyalty_auto_refresh +#: model:ir.model,name:sale_loyalty_auto_refresh.model_sale_order_line +msgid "Sales Order Line" +msgstr "销售订单行" + +#. module: sale_loyalty_auto_refresh +#: model_terms:ir.ui.view,arch_db:sale_loyalty_auto_refresh.res_config_settings_view_form +msgid "" +"When the sale order is updated, auto-refresh the promotion programs which " +"are set to auto apply" +msgstr "当销售订单更新时,自动刷新设置为自动应用的促销计划" + +#~ msgid "Display Name" +#~ msgstr "显示名称" + +#~ msgid "ID" +#~ msgstr "ID" + +#~ msgid "Last Modified on" +#~ msgstr "最后修改日" diff --git a/sale_loyalty_auto_refresh/migrations/post-migration.py b/sale_loyalty_auto_refresh/migrations/post-migration.py new file mode 100644 index 00000000..3c9a901e --- /dev/null +++ b/sale_loyalty_auto_refresh/migrations/post-migration.py @@ -0,0 +1,18 @@ +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from openupgradelib import openupgrade + + +def update_parameter_key(env): + parameters = env["ir.config_parameter"].search( + [("key", "like", "sale_coupon_auto_refresh.")] + ) + for parameter in parameters: + parameter.key = (parameter.key).replace( + "sale_coupon_auto_refresh.", "sale_loyalty_auto_refresh." + ) + + +@openupgrade.migrate() +def migrate(env, version): + update_parameter_key(env) diff --git a/sale_loyalty_auto_refresh/models/__init__.py b/sale_loyalty_auto_refresh/models/__init__.py new file mode 100644 index 00000000..e9c56cd5 --- /dev/null +++ b/sale_loyalty_auto_refresh/models/__init__.py @@ -0,0 +1,5 @@ +from . import res_config_settings +from . import res_company +from . import sale_coupon_refresh_mixin +from . import sale_order +from . import sale_order_line diff --git a/sale_loyalty_auto_refresh/models/res_company.py b/sale_loyalty_auto_refresh/models/res_company.py new file mode 100644 index 00000000..ebd9e059 --- /dev/null +++ b/sale_loyalty_auto_refresh/models/res_company.py @@ -0,0 +1,12 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class Company(models.Model): + _inherit = "res.company" + + auto_refresh_coupon = fields.Boolean( + string="Auto Refresh Coupons", + help="Autorefresh coupon lines in the backorder", + ) diff --git a/sale_loyalty_auto_refresh/models/res_config_settings.py b/sale_loyalty_auto_refresh/models/res_config_settings.py new file mode 100644 index 00000000..3a24d30e --- /dev/null +++ b/sale_loyalty_auto_refresh/models/res_config_settings.py @@ -0,0 +1,12 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo import fields, models + + +class ResConfigSettings(models.TransientModel): + _inherit = "res.config.settings" + + auto_refresh_coupon = fields.Boolean( + related="company_id.auto_refresh_coupon", + readonly=False, + ) diff --git a/sale_loyalty_auto_refresh/models/sale_coupon_refresh_mixin.py b/sale_loyalty_auto_refresh/models/sale_coupon_refresh_mixin.py new file mode 100644 index 00000000..41e6d8a5 --- /dev/null +++ b/sale_loyalty_auto_refresh/models/sale_coupon_refresh_mixin.py @@ -0,0 +1,88 @@ +# Copyright 2021 Tecnativa - David Vidal +# Copyright 2021 Camptocamp - Silvio Gregorini +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class SaleCouponRefreshMixin(models.AbstractModel): + _name = "sale.coupon.refresh.mixin" + _description = "Mixin class for sale coupon auto-refresh features" + + auto_refresh_coupon_triggers_data = fields.Binary( + attachment=False, + compute="_compute_auto_refresh_coupon_triggers_data", + store=False, + ) + + @api.model + def _get_auto_refresh_coupons_triggers(self) -> set: + """Returns set of fields which trigger the recomputation. + + Configure additional triggers via config parameters, setting them up + as list of fields separated by commas. For example, for sale.order, + the param key would be sale_loyalty_auto_refresh.sale_order_triggers, + and the value something like: "warehouse_id,carrier_id". + + The method is overriden in the proper modules to set some basic triggers though + """ + additional_triggers = ( + self.env["ir.config_parameter"] + .sudo() + .get_param("sale_loyalty_auto_refresh.%s_triggers" % (self._table), "") + .replace(" ", "") + .split(",") + ) + return {x for x in additional_triggers if x in self._fields} + + @api.depends(lambda self: list(self._get_auto_refresh_coupons_triggers())) + def _compute_auto_refresh_coupon_triggers_data(self): + triggers = self._get_auto_refresh_coupons_triggers() + for rec in self: + data = dict() + for dotted_field_name in triggers: + val = rec.mapped(dotted_field_name) + if isinstance(val, models.AbstractModel): + val = val.ids + data[dotted_field_name] = val + rec.auto_refresh_coupon_triggers_data = data + + def _read_recs_data(self) -> list: + """Reads `auto_refresh_coupon_triggers_data` for all records in `self` + + :return: list of dicts: + + [{"id": x, "auto_refresh_coupon_triggers_data": y}] + + each dict representing a different record (as a result + of `self.read()`) + The list is sorted by "id" key. + """ + self.invalidate_recordset(["auto_refresh_coupon_triggers_data"]) + return sorted( + self.read(["auto_refresh_coupon_triggers_data"]), key=lambda d: d["id"] + ) + + @api.model + def _new_trigger(self) -> set: + """Until we restart Odoo, we won't get new triggers from params. This method + ensures that no trigger is missed in the meantime""" + field_depends, _ = self._fields.get( + "auto_refresh_coupon_triggers_data" + ).get_depends(self) + triggers = self._get_auto_refresh_coupons_triggers() + return {x for x in triggers if x not in field_depends} + + def _check_skip_refresh(self): + """Checks whether refresh should be skipped + + Hook method to be overridden if necessary + :return: True if auto-refresh should be skipped + """ + ctx = self.env.context + # Checking for `website_id` because `website_sale_coupon` already + # refreshes coupons on every cart_update and every checkout + # controller reload + # NB: no need to add `website_sale_coupon` as dependency since we + # only use it for this context flag + return ctx.get("skip_auto_refresh_coupons") or ctx.get("website_id") diff --git a/sale_loyalty_auto_refresh/models/sale_order.py b/sale_loyalty_auto_refresh/models/sale_order.py new file mode 100644 index 00000000..0fea92f9 --- /dev/null +++ b/sale_loyalty_auto_refresh/models/sale_order.py @@ -0,0 +1,96 @@ +# Copyright 2021 Tecnativa - David Vidal +# Copyright 2021 Camptocamp - Silvio Gregorini +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import api, fields, models +from odoo.exceptions import UserError, ValidationError + +logger = logging.getLogger(__name__) + + +class SaleOrder(models.Model): + _name = "sale.order" + _inherit = ["sale.order", "sale.coupon.refresh.mixin"] + + # Used in UI to hide the manual button + auto_refresh_coupon = fields.Boolean( + related="company_id.auto_refresh_coupon", + ) + + @api.model_create_multi + def create(self, vals_list): + if self._check_skip_refresh(): + return super().create(vals_list) + + self_ctx = self.with_context(skip_auto_refresh_coupons=True) + orders = super(SaleOrder, self_ctx).create(vals_list) + orders._auto_refresh_coupons() + return orders + + def write(self, vals): + if self._check_skip_refresh(): + return super().write(vals) + + old_data = self._read_recs_data() + self_ctx = self.with_context(skip_auto_refresh_coupons=True) + res = super(SaleOrder, self_ctx).write(vals) + new_data = self._read_recs_data() + # Until we restart Odoo, we won't get new triggers from params. Once restarted + # the method will return an empty set. + new_triggers = self._new_trigger() + if old_data != new_data or any(x in new_triggers for x in vals): + self._auto_refresh_coupons() + return res + + def _auto_refresh_coupons(self): + orders = self.with_context(skip_auto_refresh_coupons=True).filtered( + type(self)._allow_recompute_coupon_lines + ) + for order in orders: + order._update_programs_and_rewards() + order.action_apply_rewards() + + def action_apply_rewards(self): + self.ensure_one() + claimable_rewards = self._get_claimable_rewards() + for coupon, reward in claimable_rewards.items(): + try: + self._apply_program_reward(reward, coupon) + self._update_programs_and_rewards() + except (UserError, ValidationError) as e: + # Ignore exception errors to unblock the user when creating/writing + logger.debug(e) + + def _allow_recompute_coupon_lines(self): + """Check if reward lines in ``self`` can be recomputed automatically. + + Hook method, to be overridden for custom behaviours. + + :return: True if the current SO allows automatic recomputation for + reward lines, False otherwise. + """ + self.ensure_one() + return self.auto_refresh_coupon and self.state in ("draft", "sent") + + @api.model + def _get_auto_refresh_coupons_triggers(self) -> set: + triggers = super()._get_auto_refresh_coupons_triggers() + triggers.update( + { + "order_line.auto_refresh_coupon_triggers_data", + "partner_id", + } + ) + return triggers + + def action_open_reward_wizard(self): + return super( + SaleOrder, self.with_context(skip_auto_refresh_coupons=True) + ).action_open_reward_wizard() + + def _update_programs_and_rewards(self): + return super( + SaleOrder, self.with_context(skip_auto_refresh_coupons=True) + )._update_programs_and_rewards() diff --git a/sale_loyalty_auto_refresh/models/sale_order_line.py b/sale_loyalty_auto_refresh/models/sale_order_line.py new file mode 100644 index 00000000..b77e343e --- /dev/null +++ b/sale_loyalty_auto_refresh/models/sale_order_line.py @@ -0,0 +1,66 @@ +# Copyright 2021 Tecnativa - David Vidal +# Copyright 2021 Camptocamp - Silvio Gregorini +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import api, models + +logger = logging.getLogger(__name__) + + +class SaleOrderLine(models.Model): + _name = "sale.order.line" + _inherit = ["sale.order.line", "sale.coupon.refresh.mixin"] + + @api.model_create_multi + def create(self, vals_list): + if self._check_skip_refresh(): + return super().create(vals_list) + + self_ctx = self.with_context(skip_auto_refresh_coupons=True) + lines = super(SaleOrderLine, self_ctx).create(vals_list) + lines.order_id._auto_refresh_coupons() + return lines + + def write(self, vals): + if self._check_skip_refresh(): + return super().write(vals) + + old_data = self._read_recs_data() + old_orders = self.order_id + self_ctx = self.with_context(skip_auto_refresh_coupons=True) + res = super(SaleOrderLine, self_ctx).write(vals) + new_data = self._read_recs_data() + new_orders = self.order_id + # Until we restart Odoo, we won't get new triggers from params. Once restarted + # the method will return an empty set. + new_triggers = self._new_trigger() + if old_data != new_data or any(x in new_triggers for x in vals): + (old_orders | new_orders)._auto_refresh_coupons() + return res + + def unlink(self): + if self._check_skip_refresh(): + return super().unlink() + + orders = self.order_id + self_ctx = self.with_context(skip_auto_refresh_coupons=True) + res = super(SaleOrderLine, self_ctx).unlink() + orders._auto_refresh_coupons() + return res + + @api.model + def _get_auto_refresh_coupons_triggers(self) -> set: + triggers = super()._get_auto_refresh_coupons_triggers() + triggers.update( + { + "discount", + "product_id", + "price_unit", + "product_uom", + "product_uom_qty", + "tax_id", + } + ) + return triggers diff --git a/sale_loyalty_auto_refresh/readme/CONFIGURE.rst b/sale_loyalty_auto_refresh/readme/CONFIGURE.rst new file mode 100644 index 00000000..c730d72a --- /dev/null +++ b/sale_loyalty_auto_refresh/readme/CONFIGURE.rst @@ -0,0 +1,19 @@ +You can set this feature on or off in every company. To do so: + +#. Go to *Sales > Configuration > Settings* +#. In the *Pricing* section you'll find the option *Auto refresh promotions*. + +The auto-refresh in the backend is triggered over a minimum set of fields changes. If +you want to extend the list of that fields: + +#. Go to *Settings > Technical > Config parameters* +#. Add or update the key: + + - For `sale.order`: `sale_loyalty_auto_refresh.sale_order_triggers` + - For `sale.order.line`: `sale_loyalty_auto_refresh.sale_order_line_triggers` +#. In every add the fields seperated by commas that you want to add to the recomputation + triggers. + +⚠️ After configuring or removing a trigger a restart of Odoo is recommended so the +depends are reloaded properly. Anyway it isn't mandatory and the module detects the +new triggers so the auto-refresh works as expected as soon as they are set. diff --git a/sale_loyalty_auto_refresh/readme/CONTRIBUTORS.rst b/sale_loyalty_auto_refresh/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000..7285fdfe --- /dev/null +++ b/sale_loyalty_auto_refresh/readme/CONTRIBUTORS.rst @@ -0,0 +1,12 @@ +* `Tecnativa `_: + + * David Vidal + * Pilar Vargas + +* `Camptocamp `_: + + * Silvio Gregorini + +* `Trobz `_: + + * Nguyen Minh Chien diff --git a/sale_loyalty_auto_refresh/readme/DESCRIPTION.rst b/sale_loyalty_auto_refresh/readme/DESCRIPTION.rst new file mode 100644 index 00000000..c89a3786 --- /dev/null +++ b/sale_loyalty_auto_refresh/readme/DESCRIPTION.rst @@ -0,0 +1 @@ +This module allows to auto apply the programs without the need of the user intervention. diff --git a/sale_loyalty_auto_refresh/readme/ROADMAP.rst b/sale_loyalty_auto_refresh/readme/ROADMAP.rst new file mode 100644 index 00000000..51340aae --- /dev/null +++ b/sale_loyalty_auto_refresh/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* This module should be ported to OCA in v13 as Odoo released enterprise modules and + they are now on the community side. diff --git a/sale_loyalty_auto_refresh/readme/USAGE.rst b/sale_loyalty_auto_refresh/readme/USAGE.rst new file mode 100644 index 00000000..4973c425 --- /dev/null +++ b/sale_loyalty_auto_refresh/readme/USAGE.rst @@ -0,0 +1,5 @@ +You need to configure a *Promotion program* with the option *Program trigger* set to +*Automatic* (shown in Debug mode only, read-only computed field). This can be done in *Sales > Products > Discount & Loyalty*. + +Now, make a quotation that fulfill the promotion condition and the promotion will be +automatically applied. diff --git a/sale_loyalty_auto_refresh/static/description/icon.png b/sale_loyalty_auto_refresh/static/description/icon.png new file mode 100644 index 00000000..3a0328b5 Binary files /dev/null and b/sale_loyalty_auto_refresh/static/description/icon.png differ diff --git a/sale_loyalty_auto_refresh/static/description/index.html b/sale_loyalty_auto_refresh/static/description/index.html new file mode 100644 index 00000000..56b34b38 --- /dev/null +++ b/sale_loyalty_auto_refresh/static/description/index.html @@ -0,0 +1,476 @@ + + + + + + +Auto Refresh Coupons + + + +
+

Auto Refresh Coupons

+ + +

Production/Stable License: AGPL-3 OCA/sale-promotion Translate me on Weblate Try me on Runboat

+

This module allows to auto apply the programs without the need of the user intervention.

+

Table of contents

+ +
+

Configuration

+

You can set this feature on or off in every company. To do so:

+
    +
  1. Go to Sales > Configuration > Settings
  2. +
  3. In the Pricing section you’ll find the option Auto refresh promotions.
  4. +
+

The auto-refresh in the backend is triggered over a minimum set of fields changes. If +you want to extend the list of that fields:

+
    +
  1. Go to Settings > Technical > Config parameters
  2. +
  3. Add or update the key:
      +
    • For sale.order: sale_loyalty_auto_refresh.sale_order_triggers
    • +
    • For sale.order.line: sale_loyalty_auto_refresh.sale_order_line_triggers
    • +
    +
  4. +
  5. In every add the fields seperated by commas that you want to add to the recomputation +triggers.
  6. +
+

⚠️ After configuring or removing a trigger a restart of Odoo is recommended so the +depends are reloaded properly. Anyway it isn’t mandatory and the module detects the +new triggers so the auto-refresh works as expected as soon as they are set.

+
+
+

Usage

+

You need to configure a Promotion program with the option Program trigger set to +Automatic (shown in Debug mode only, read-only computed field). This can be done in Sales > Products > Discount & Loyalty.

+

Now, make a quotation that fulfill the promotion condition and the promotion will be +automatically applied.

+
+
+

Known issues / Roadmap

+
    +
  • This module should be ported to OCA in v13 as Odoo released enterprise modules and +they are now on the community side.
  • +
+
+
+

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
  • +
  • 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.

+

Current maintainers:

+

chienandalu SilvioC2C

+

This module is part of the OCA/sale-promotion project on GitHub.

+

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

+
+
+
+ + diff --git a/sale_loyalty_auto_refresh/tests/__init__.py b/sale_loyalty_auto_refresh/tests/__init__.py new file mode 100644 index 00000000..02f4873d --- /dev/null +++ b/sale_loyalty_auto_refresh/tests/__init__.py @@ -0,0 +1 @@ +from . import test_sale_loyalty_auto_refresh diff --git a/sale_loyalty_auto_refresh/tests/test_sale_loyalty_auto_refresh.py b/sale_loyalty_auto_refresh/tests/test_sale_loyalty_auto_refresh.py new file mode 100644 index 00000000..80d593fb --- /dev/null +++ b/sale_loyalty_auto_refresh/tests/test_sale_loyalty_auto_refresh.py @@ -0,0 +1,220 @@ +# Copyright 2021 Tecnativa - David Vidal +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +from odoo.tests import Form, common + + +class TestWebsiteSaleCouponAutorefresh(common.TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env["loyalty.program"].search([]).write({"active": False}) + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.pricelist = cls.env["product.pricelist"].create( + { + "name": "Test pricelist", + "item_ids": [ + ( + 0, + 0, + { + "applied_on": "3_global", + "compute_price": "formula", + "base": "list_price", + }, + ) + ], + } + ) + cls.partner = cls.env["res.partner"].create( + {"name": "Mr. Odoo", "property_product_pricelist": cls.pricelist.id} + ) + cls.product = cls.env["product.product"].create({"name": "Test"}) + loyalty_program_form = Form( + cls.env["loyalty.program"], + view="sale_loyalty.loyalty_program_view_form_inherit_sale_loyalty", + ) + loyalty_program_form.name = "Test Discount Program" + loyalty_program_form.program_type = "promotion" + cls.loyalty_program = loyalty_program_form.save() + cls.loyalty_program.applies_on = "current" + cls.loyalty_program.trigger = "auto" + reward = cls.loyalty_program.reward_ids + reward.reward_type = "discount" + reward.discount = 50 + reward.discount_mode = "percent" + reward.discount_applicability = "order" + cls.loyalty_program.rule_ids.minimum_amount = 100 + cls.loyalty_program.company_id.auto_refresh_coupon = True + # Let's configure an extra trigger + cls.env["ir.config_parameter"].set_param( + "sale_loyalty_auto_refresh.sale_order_triggers", "note" + ) + + def test_01_sale_coupon_auto_refresh_on_create(self): + """Checks reward line proper creation after product line is added""" + sale_form = Form(self.env["sale.order"]) + sale_form.partner_id = self.partner + + # Create a product line that will trigger a reward line creation + # (minimum amount >= 100 => create a reward line) + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 1 + line_form.price_unit = 150 + sale = sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertAlmostEqual(-75, discount_line.price_unit) + + def test_02_sale_coupon_auto_refresh_on_update(self): + """Checks reward line proper update after product line is modified""" + sale_form = Form(self.env["sale.order"]) + sale_form.partner_id = self.partner + + # Create a product line that will NOT trigger a reward line creation + # (minimum amount < 100 => do not create a reward line) + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 1 + line_form.price_unit = 1 + sale = sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertFalse(bool(discount_line)) + + # Update product line in order to trigger reward line creation + # (minimum amount >= 100 => create a reward line) + sale_form = Form(sale.with_context(skip_auto_refresh_coupons=False)) + with sale_form.order_line.edit(index=0) as line_form: + line_form.product_uom_qty = 10 + line_form.price_unit = 20 + sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertEqual(1, len(discount_line)) + self.assertAlmostEqual(-100, discount_line.price_unit) + + # Create another product line that will trigger a reward line update + # (total amount has changed => reward line price unit must change) + sale_form = Form(sale.with_context(skip_auto_refresh_coupons=False)) + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 1 + line_form.price_unit = 40 + sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertEqual(1, len(discount_line)) + self.assertAlmostEqual(-120, discount_line.price_unit) + + # Update product lines in order to delete reward line + # (minimum amount < 100 => delete reward line) + sale_form = Form(sale.with_context(skip_auto_refresh_coupons=False)) + with sale_form.order_line.edit(index=0) as line_form: + line_form.product_uom_qty = 1 + line_form.price_unit = 1 + with sale_form.order_line.edit(index=2) as line_form: + line_form.product_uom_qty = 1 + line_form.price_unit = 1 + sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertFalse(bool(discount_line)) + + def test_03_sale_coupon_auto_refresh_on_delete(self): + """Checks reward line proper deletion after product line is deleted""" + sale_form = Form(self.env["sale.order"]) + sale_form.partner_id = self.partner + + # Create a product line that will trigger a reward line creation + # (minimum amount >= 100 => create a reward line) + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 1 + line_form.price_unit = 1000 + sale = sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertEqual(1, len(discount_line)) + + # Delete the product line that triggered the reward line creation + # (minimum amount < 100 => delete reward line) + sale_form = Form(sale.with_context(skip_auto_refresh_coupons=False)) + sale_form.order_line.remove(index=0) + sale = sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertFalse(bool(discount_line)) + + def test_04_sale_coupon_auto_refresh_custom_triggers(self): + """Checks reward line proper update after product line is modified""" + self.env.company.auto_refresh_coupon = False + sale_form = Form(self.env["sale.order"]) + sale_form.partner_id = self.partner + # Create a product line that would trigger the reward but we disabled it by + # context + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 10 + line_form.price_unit = 20 + sale = sale_form.save() + discount_line = sale.order_line.filtered("is_reward_line") + self.assertFalse(bool(discount_line)) + self.env.company.auto_refresh_coupon = True + sale.with_context(skip_auto_refresh_coupons=False).note = "Refresh!" + # The promotions recompute is triggered an thus we get our reward + discount_line = sale.order_line.filtered("is_reward_line") + self.assertEqual(1, len(discount_line), "There should be a reward line") + self.assertAlmostEqual(-100, discount_line.price_unit) + + def test_05_multi_programs(self): + promo_60 = self.loyalty_program.copy( + { + "reward_ids": [ + ( + 0, + 0, + { + "reward_type": "discount", + "discount": 60, + "discount_mode": "percent", + "discount_applicability": "order", + }, + ) + ] + } + ) + reward_product = self.env["product.product"].create({"name": "Reward Product"}) + promo_prod = self.loyalty_program.copy( + { + "reward_ids": [ + ( + 0, + 0, + { + "reward_type": "product", + "reward_product_id": reward_product.id, + "reward_product_qty": 1, + "required_points": 1, + }, + ) + ] + } + ) + sale_form = Form(self.env["sale.order"]) + sale_form.partner_id = self.partner + # Create a product line that would trigger the reward but we disabled it by + # context + with sale_form.order_line.new() as line_form: + line_form.product_id = self.product + line_form.product_uom_qty = 10 + line_form.price_unit = 20 + sale = sale_form.save() + self.assertTrue(sale.coupon_point_ids) + line_loyalty_program = sale.order_line.filtered( + lambda line: line.reward_id == self.loyalty_program.reward_ids + ) + line_promo_60 = sale.order_line.filtered( + lambda line: line.reward_id == promo_60.reward_ids + ) + line_promo_prod = sale.order_line.filtered( + lambda line: line.reward_id == promo_prod.reward_ids + ) + self.assertFalse( + line_loyalty_program + ) # Promo 60% is better, no select promo 50% + self.assertTrue(line_promo_60) + self.assertTrue(line_promo_prod) diff --git a/sale_loyalty_auto_refresh/views/res_config_settings_views.xml b/sale_loyalty_auto_refresh/views/res_config_settings_views.xml new file mode 100644 index 00000000..09dabe2d --- /dev/null +++ b/sale_loyalty_auto_refresh/views/res_config_settings_views.xml @@ -0,0 +1,37 @@ + + + + res.config.settings + + + +
+
+ +
+
+
+
+
+
+
+
diff --git a/sale_loyalty_auto_refresh/wizard/__init__.py b/sale_loyalty_auto_refresh/wizard/__init__.py new file mode 100644 index 00000000..b52b2b27 --- /dev/null +++ b/sale_loyalty_auto_refresh/wizard/__init__.py @@ -0,0 +1,2 @@ +from . import sale_loyalty_coupon_wizard +from . import sale_loyalty_reward_wizard diff --git a/sale_loyalty_auto_refresh/wizard/sale_loyalty_coupon_wizard.py b/sale_loyalty_auto_refresh/wizard/sale_loyalty_coupon_wizard.py new file mode 100644 index 00000000..d7bcf364 --- /dev/null +++ b/sale_loyalty_auto_refresh/wizard/sale_loyalty_coupon_wizard.py @@ -0,0 +1,11 @@ +from odoo import models + + +class SaleLoyaltyCouponWizard(models.TransientModel): + _inherit = "sale.loyalty.coupon.wizard" + + def action_apply(self): + """Avoid discarding the coupon before the end of the process""" + return super( + SaleLoyaltyCouponWizard, self.with_context(skip_auto_refresh_coupons=True) + ).action_apply() diff --git a/sale_loyalty_auto_refresh/wizard/sale_loyalty_reward_wizard.py b/sale_loyalty_auto_refresh/wizard/sale_loyalty_reward_wizard.py new file mode 100644 index 00000000..aab4a7e8 --- /dev/null +++ b/sale_loyalty_auto_refresh/wizard/sale_loyalty_reward_wizard.py @@ -0,0 +1,11 @@ +from odoo import models + + +class SaleLoyaltyRewardWizard(models.TransientModel): + _inherit = "sale.loyalty.reward.wizard" + + def action_apply(self): + """Avoid discarding the coupon before the end of the process""" + return super( + SaleLoyaltyRewardWizard, self.with_context(skip_auto_refresh_coupons=True) + ).action_apply() diff --git a/setup/sale_loyalty_auto_refresh/odoo/addons/sale_loyalty_auto_refresh b/setup/sale_loyalty_auto_refresh/odoo/addons/sale_loyalty_auto_refresh new file mode 120000 index 00000000..1862b3f2 --- /dev/null +++ b/setup/sale_loyalty_auto_refresh/odoo/addons/sale_loyalty_auto_refresh @@ -0,0 +1 @@ +../../../../sale_loyalty_auto_refresh \ No newline at end of file diff --git a/setup/sale_loyalty_auto_refresh/setup.py b/setup/sale_loyalty_auto_refresh/setup.py new file mode 100644 index 00000000..28c57bb6 --- /dev/null +++ b/setup/sale_loyalty_auto_refresh/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)