diff --git a/.copier-answers.yml b/.copier-answers.yml index 3684ea739..7f8991fa6 100644 --- a/.copier-answers.yml +++ b/.copier-answers.yml @@ -1,7 +1,8 @@ # Do NOT update manually; changes here will be overwritten by Copier -_commit: v1.17.2 +_commit: v1.21.1 _src_path: gh:oca/oca-addons-repo-template ci: GitHub +convert_readme_fragments_to_markdown: false generate_requirements_txt: true github_check_license: true github_ci_extra_env: {} @@ -19,4 +20,6 @@ repo_description: Odoo addons for handling promotions on the sales funnel. repo_name: Sales promotion management repo_slug: sale-promotion repo_website: https://github.com/OCA/sale-promotion +use_pyproject_toml: false +use_ruff: false diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 1693a1253..fa17fcd4e 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Stale PRs and issues policy - uses: actions/stale@v4 + uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} # General settings. @@ -48,7 +48,7 @@ jobs: # * Issues that are pending more information # * Except Issues marked as "no stale" - name: Needs more information stale issues policy - uses: actions/stale@v4 + uses: actions/stale@v9 with: repo-token: ${{ secrets.GITHUB_TOKEN }} ascending: true diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e1af7438f..3bf18e843 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,7 +63,9 @@ jobs: run: oca_init_test_database - name: Run tests run: oca_run_tests - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} - name: Update .pot files run: oca_export_and_push_pot https://x-access-token:${{ secrets.GIT_PUSH_TOKEN }}@github.com/${{ github.repository }} if: ${{ matrix.makepot == 'true' && github.event_name == 'push' && github.repository_owner == 'OCA' }} diff --git a/.gitignore b/.gitignore index 9c283fd41..0090721f5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,7 @@ __pycache__/ *.py[cod] /.venv /.pytest_cache +/.ruff_cache # C extensions *.so diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dc0359633..fb7feef67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,6 +14,10 @@ exclude: | ^docs/_templates/.*\.html$| # Don't bother non-technical authors with formatting issues in docs readme/.*\.(rst|md)$| + # Ignore build and dist directories in addons + /build/|/dist/| + # Ignore test files in addons + /tests/samples/.*| # You don't usually want a bot to modify your legal texts (LICENSE.*|COPYING.*) default_language_version: @@ -35,7 +39,7 @@ repos: language: fail files: '[a-zA-Z0-9_]*/i18n/en\.po$' - repo: https://github.com/oca/maintainer-tools - rev: 969238e47c07d0c40573acff81d170f63245d738 + rev: 9a170331575a265c092ee6b24b845ec508e8ef75 hooks: # update the NOT INSTALLABLE ADDONS section above - id: oca-update-pre-commit-excluded-addons @@ -48,6 +52,7 @@ repos: - --org-name=OCA - --repo-name=sale-promotion - --if-source-changed + - --keep-source-digest - repo: https://github.com/OCA/odoo-pre-commit-hooks rev: v0.0.25 hooks: diff --git a/loyalty_partner_birthdate/__init__.py b/loyalty_partner_birthdate/__init__.py new file mode 100644 index 000000000..9a7e03ede --- /dev/null +++ b/loyalty_partner_birthdate/__init__.py @@ -0,0 +1 @@ +from . import models \ No newline at end of file diff --git a/loyalty_partner_birthdate/__manifest__.py b/loyalty_partner_birthdate/__manifest__.py new file mode 100644 index 000000000..761ec6fe4 --- /dev/null +++ b/loyalty_partner_birthdate/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Loyalty Partner Birthdate", + "version": "16.0.1.0.0", + "category": "Sale", + "author": "Moka", + "website": "https://github.com/OCA/sale-promotion", + "summary": "Implement a cron job to launch the generation of loyalty where conditions are set on the partner's birthdate.", + "depends": ["loyalty", "loyalty_setup_validity", "partner_contact_birthdate"], + "installable": True, + "auto_install": False, + "license": "AGPL-3", + "data": ["views/loyalty_program_views_inherit.xml", "data/ir_cron_data.xml"], +} \ No newline at end of file diff --git a/loyalty_partner_birthdate/data/ir_cron_data.xml b/loyalty_partner_birthdate/data/ir_cron_data.xml new file mode 100644 index 000000000..a6e729a7c --- /dev/null +++ b/loyalty_partner_birthdate/data/ir_cron_data.xml @@ -0,0 +1,16 @@ + + + + Birthday Loyalty Cron + + ir.actions.server + code + model.generate_birthday_loyalty_cards() + 1 + days + -1 + + + + + diff --git a/loyalty_partner_birthdate/i18n/fr.po b/loyalty_partner_birthdate/i18n/fr.po new file mode 100644 index 000000000..80b1f9802 --- /dev/null +++ b/loyalty_partner_birthdate/i18n/fr.po @@ -0,0 +1,77 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * loyalty_partner_birthdate +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-24 11:32+0000\n" +"PO-Revision-Date: 2024-04-24 11:32+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: loyalty_partner_birthdate +#: model:ir.model.fields.selection,name:loyalty_partner_birthdate.selection__loyalty_program__birthday_trigger_mode__after +msgid "After Birthday" +msgstr "Après l'anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields.selection,name:loyalty_partner_birthdate.selection__loyalty_program__birthday_trigger_mode__before +msgid "Before Birthday" +msgstr "Avant l'anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,field_description:loyalty_partner_birthdate.field_loyalty_program__birthday_check_days +msgid "Birthday Check Days" +msgstr "Jours d'écarts" + +#. module: loyalty_partner_birthdate +#: model:ir.actions.server,name:loyalty_partner_birthdate.ir_cron_birthday_rewards_ir_actions_server +#: model:ir.cron,cron_name:loyalty_partner_birthdate.ir_cron_birthday_rewards +msgid "Birthday Loyalty Cron" +msgstr "Cron de remise sur les anniversaires" + +#. module: loyalty_partner_birthdate +#: model_terms:ir.ui.view,arch_db:loyalty_partner_birthdate.loyalty_program_view_form_inherit +msgid "Birthday Trigger" +msgstr "Mode anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,field_description:loyalty_partner_birthdate.field_loyalty_program__birthday_trigger_mode +msgid "Birthday Trigger Mode" +msgstr "Mode de déclenchement" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,field_description:loyalty_partner_birthdate.field_loyalty_program__birthday_trigger_enabled +msgid "Enable Birthday Trigger" +msgstr "Activer le mode anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,help:loyalty_partner_birthdate.field_loyalty_program__birthday_trigger_enabled +msgid "Enable to trigger the discount based on birthday." +msgstr "Activer pour basé la remise sur une condition d'anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields.selection,name:loyalty_partner_birthdate.selection__loyalty_program__birthday_trigger_mode__exact +msgid "Exact Birthday" +msgstr "Jour exact" + +#. module: loyalty_partner_birthdate +#: model:ir.model,name:loyalty_partner_birthdate.model_loyalty_program +msgid "Loyalty program" +msgstr "Règle de fidélité" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,help:loyalty_partner_birthdate.field_loyalty_program__birthday_check_days +msgid "Number of days before or after the birthday to check." +msgstr "Nombre de jours d'écarts à vérifier avant ou après l'anniversaire" + +#. module: loyalty_partner_birthdate +#: model:ir.model.fields,help:loyalty_partner_birthdate.field_loyalty_program__birthday_trigger_mode +msgid "Trigger the discount before, on, or after the birthday." +msgstr "Lancer la remise avant, pendant ou après l'anniversaire" diff --git a/loyalty_partner_birthdate/models/__init__.py b/loyalty_partner_birthdate/models/__init__.py new file mode 100644 index 000000000..bc8a74118 --- /dev/null +++ b/loyalty_partner_birthdate/models/__init__.py @@ -0,0 +1 @@ +from . import loyalty_program_inherit \ No newline at end of file diff --git a/loyalty_partner_birthdate/models/loyalty_program_inherit.py b/loyalty_partner_birthdate/models/loyalty_program_inherit.py new file mode 100644 index 000000000..ce9257987 --- /dev/null +++ b/loyalty_partner_birthdate/models/loyalty_program_inherit.py @@ -0,0 +1,107 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import _, api, fields, models +import logging +from datetime import datetime, timedelta +from dateutil.relativedelta import relativedelta + +class LoyaltyProgram(models.Model): + _inherit = 'loyalty.program' + + birthday_trigger_enabled = fields.Boolean('Enable Birthday Trigger', + help="Enable to trigger the discount based on birthday.") + + birthday_trigger_mode = fields.Selection([ + ('before', 'Before Birthday'), + ('exact', 'Exact Birthday'), + ('after', 'After Birthday'), + ], string='Birthday Trigger Mode', default='before', + help="Trigger the discount before, on, or after the birthday.") + + birthday_check_days = fields.Integer('Birthday Check Days', default=7, + help="Number of days before or after the birthday to check.") + + @api.model + def _is_partner_birthday_within_range(self, partner): + """Check if partner's birthday is within the specified range.""" + if not self.birthday_trigger_enabled: + return False + + today = datetime.now().date() + birthday = partner.birthdate + if not birthday: + return False + + if self.birthday_trigger_mode == 'before': + deadline_date = today + timedelta(days=self.birthday_check_days) + elif self.birthday_trigger_mode == 'exact': + deadline_date = today + else: + deadline_date = today - timedelta(days=self.birthday_check_days) + + return deadline_date + + def _compute_amount(self, currency_to): + self.ensure_one() + + deadline_date = self._is_partner_birthday_within_range(self) + + if not deadline_date: + return super()._compute_amount(currency_to) + + if self.birthday_trigger_mode == 'exact': + valid_partners = self.env['res.partner'].search([('birthdate', '=', deadline_date)]) + elif self.birthday_trigger_mode == 'before': + valid_partners = self.env['res.partner'].search([('birthdate', '<=', deadline_date)]) + else: + valid_partners = self.env['res.partner'].search([('birthdate', '>=', deadline_date)]) + + valid_amount = super()._compute_amount(currency_to) + + if self.program_type == 'birthday' and valid_partners: + valid_amount *= len(valid_partners) + + return valid_amount + + @api.model + def generate_birthday_loyalty_cards(self): + """Cron method to generate birthday loyalty cards.""" + birthday_rules = self.search([('birthday_trigger_enabled', '=', True)]) + for rule in birthday_rules: + valid_partners = self.env['res.partner'].search([('birthdate_date', '!=', False)]) + + today = datetime.now().date() + if rule.birthday_trigger_mode == 'before': + target_date = today + relativedelta(days=rule.birthday_check_days) + valid_partners = valid_partners.filtered(lambda partner: + partner.birthdate_date.month == target_date.month and + partner.birthdate_date.day == target_date.day + ) + elif rule.birthday_trigger_mode == 'exact': + valid_partners = valid_partners.filtered(lambda partner: + partner.birthdate_date.month == today.month and + partner.birthdate_date.day == today.day + ) + elif rule.birthday_trigger_mode == 'after': + target_date = today - relativedelta(days=rule.birthday_check_days) + valid_partners = valid_partners.filtered(lambda partner: + partner.birthdate_date.month == target_date.month and + partner.birthdate_date.day == target_date.day + ) + + + for partner in valid_partners: + try: + loyalty_card = self.env['loyalty.card'].create({ + 'program_id': rule.id, + 'partner_id': partner.id, + 'points' : 1 + }) + except Exception as e: + logging.error(f"Error creating loyalty card for partner {partner.id}: {e}") + + + diff --git a/loyalty_partner_birthdate/readme.md b/loyalty_partner_birthdate/readme.md new file mode 100644 index 000000000..4b6450e25 --- /dev/null +++ b/loyalty_partner_birthdate/readme.md @@ -0,0 +1,32 @@ +loyalty_partner_birthdate +========= + +Allow to setup loyalty based on partner's birthdate (before, exact or after) by using a cron + +Bug Tracker +=========== + +Bugs are tracked on GitHub Issues https://github.com/Moka-Tourisme/sale-promotion/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 + +* Moka Tourisme + +## Contributors + +* Horvat Damien : https://github.com/PlantBasedStudio + +## Maintainers +This module is maintained by Moka. + + +This module is a addon for the Odoo/addons/loyalty https://github.com/odoo/odoo/tree/16.0/addons/loyalty> project on GitHub. +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. \ No newline at end of file diff --git a/loyalty_partner_birthdate/views/loyalty_program_views_inherit.xml b/loyalty_partner_birthdate/views/loyalty_program_views_inherit.xml new file mode 100644 index 000000000..8bd0b206c --- /dev/null +++ b/loyalty_partner_birthdate/views/loyalty_program_views_inherit.xml @@ -0,0 +1,26 @@ + + + + + loyalty.program.view.form.inherit + loyalty.program + + + + + + + + + + + + \ No newline at end of file diff --git a/loyalty_setup_validity/README.rst b/loyalty_setup_validity/README.rst new file mode 100644 index 000000000..6a6817f1e --- /dev/null +++ b/loyalty_setup_validity/README.rst @@ -0,0 +1,74 @@ +====================== +Loyalty Setup Validity +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:f8dd509d9d06a7632d937198a7bdd4f1ea6481f953ce334738621e81f86bae43 + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fsale--promotion-lightgray.png?logo=github + :target: https://github.com/OCA/sale-promotion/tree/16.0/loyalty_setup_validity + :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-loyalty_setup_validity + :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| + +Normally, the loyalty program is based on a fixed validity date. With this module, you +can choose between a fixed date or a date generated within a period of time after the +loyalty has been generated (for example, after a visit to the point of sale, a customer +can obtain a discount for 30 days). + +**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 +~~~~~~~ + +* Moka + +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/sale-promotion `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/loyalty_setup_validity/__init__.py b/loyalty_setup_validity/__init__.py new file mode 100644 index 000000000..0650744f6 --- /dev/null +++ b/loyalty_setup_validity/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/loyalty_setup_validity/__manifest__.py b/loyalty_setup_validity/__manifest__.py new file mode 100644 index 000000000..7fd613e7d --- /dev/null +++ b/loyalty_setup_validity/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). +{ + "name": "Loyalty Setup Validity", + "version": "16.0.1.0.0", + "category": "Sale", + "author": "Moka, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/sale-promotion", + "summary": ( + "Allow to define a fixed validity or a validity after" + " the generation date of a loyalty card." + ), + "depends": ["loyalty"], + "installable": True, + "auto_install": False, + "license": "AGPL-3", + "data": ["views/loyalty_program_inherit.xml"], +} diff --git a/loyalty_setup_validity/i18n/fr.po b/loyalty_setup_validity/i18n/fr.po new file mode 100644 index 000000000..3dc07445a --- /dev/null +++ b/loyalty_setup_validity/i18n/fr.po @@ -0,0 +1,46 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * loyalty_setup_validity +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2024-04-23 14:58+0000\n" +"PO-Revision-Date: 2024-04-23 14:58+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: loyalty_setup_validity +#: model:ir.model.fields.selection,name:loyalty_setup_validity.selection__loyalty_program__validity_type__after_activation +msgid "After Activation" +msgstr "Après génération" + +#. module: loyalty_setup_validity +#: model:ir.model.fields.selection,name:loyalty_setup_validity.selection__loyalty_program__validity_type__fixed +msgid "Fixed Date" +msgstr "A date fixe" + +#. module: loyalty_setup_validity +#: model:ir.model,name:loyalty_setup_validity.model_loyalty_card +msgid "Loyalty Coupon" +msgstr "Bon de fidélité" + +#. module: loyalty_setup_validity +#: model:ir.model,name:loyalty_setup_validity.model_loyalty_program +msgid "Loyalty Program" +msgstr "Programme de fidelité" + +#. module: loyalty_setup_validity +#: model:ir.model.fields,field_description:loyalty_setup_validity.field_loyalty_program__validity_duration +msgid "Validity Duration (days)" +msgstr "Durée de la validité (en jours)" + +#. module: loyalty_setup_validity +#: model:ir.model.fields,field_description:loyalty_setup_validity.field_loyalty_program__validity_type +msgid "Validity Type" +msgstr "Type de validité" diff --git a/loyalty_setup_validity/models/__init__.py b/loyalty_setup_validity/models/__init__.py new file mode 100644 index 000000000..8ea34659b --- /dev/null +++ b/loyalty_setup_validity/models/__init__.py @@ -0,0 +1,2 @@ +from . import loyalty_card +from . import loyalty_program diff --git a/loyalty_setup_validity/models/loyalty_card.py b/loyalty_setup_validity/models/loyalty_card.py new file mode 100644 index 000000000..6aedd86e8 --- /dev/null +++ b/loyalty_setup_validity/models/loyalty_card.py @@ -0,0 +1,22 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from datetime import timedelta + +from odoo import fields, models + + +class LoyaltyCard(models.Model): + _inherit = "loyalty.card" + + def create(self, vals_list): + res = super().create(vals_list) + if res.program_id.validity_type == "fixed": + # import pdb; pdb.set_trace() + res.expiration_date = res.program_id.date_to + else: + res.expiration_date = fields.Date.today() + timedelta( + days=res.program_id.validity_duration + ) + return res diff --git a/loyalty_setup_validity/models/loyalty_card_inherit.py b/loyalty_setup_validity/models/loyalty_card_inherit.py new file mode 100644 index 000000000..1db6f6c63 --- /dev/null +++ b/loyalty_setup_validity/models/loyalty_card_inherit.py @@ -0,0 +1,19 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from datetime import timedelta + + +class LoyaltyCard(models.Model): + _inherit = "loyalty.card" + + + def create(self, vals_list): + res = super().create(vals_list) + if res.program_id.validity_type == 'fixed': + res.expiration_date = res.program_id.date_to + else: + res.expiration_date = fields.Date.today() + timedelta(days=res.program_id.validity_duration) + return res diff --git a/loyalty_setup_validity/models/loyalty_program.py b/loyalty_setup_validity/models/loyalty_program.py new file mode 100644 index 000000000..6e88cc19d --- /dev/null +++ b/loyalty_setup_validity/models/loyalty_program.py @@ -0,0 +1,23 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + + +from odoo import fields, models + + +class LoyaltyProgram(models.Model): + _inherit = "loyalty.program" + + VALIDITY_TYPE_SELECTION = [ + ("fixed", "Fixed Date"), + ("after_activation", "After Activation"), + ] + + validity_type = fields.Selection( + VALIDITY_TYPE_SELECTION, + default="fixed", + required=True, + ) + + validity_duration = fields.Integer(string="Validity Duration (days)", default=30) diff --git a/loyalty_setup_validity/models/loyalty_program_inherit.py b/loyalty_setup_validity/models/loyalty_program_inherit.py new file mode 100644 index 000000000..fd0dc946e --- /dev/null +++ b/loyalty_setup_validity/models/loyalty_program_inherit.py @@ -0,0 +1,37 @@ +# Copyright 2024 Moka Tourisme (https://www.mokatourisme.fr/). +# @author Damien Horvat +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import _, api, fields, models +from datetime import timedelta + + +class LoyaltyProgram(models.Model): + _inherit = 'loyalty.program' + + VALIDITY_TYPE_SELECTION = [ + ('fixed', 'Fixed Date'), + ('after_activation', 'After Activation'), + ] + + validity_type = fields.Selection( + VALIDITY_TYPE_SELECTION, + default='fixed', + string='Validity Type', + required=True, + ) + + validity_duration = fields.Integer( + string='Validity Duration (days)', + default=30 + ) + + @api.depends('program_type', 'validity_type') + def _compute_from_program_type(self): + super(LoyaltyProgram, self)._compute_from_program_type() + + for program in self: + if program.validity_type == 'fixed': + program.date_to = fields.Date.today() + else: + program.date_to = fields.Date.today() + timedelta(days=program.validity_duration) diff --git a/loyalty_setup_validity/readme/AUTHORS.rst b/loyalty_setup_validity/readme/AUTHORS.rst new file mode 100644 index 000000000..3f85077b0 --- /dev/null +++ b/loyalty_setup_validity/readme/AUTHORS.rst @@ -0,0 +1 @@ +Moka Tourisme \ No newline at end of file diff --git a/loyalty_setup_validity/readme/CONTRIBUTORS.rst b/loyalty_setup_validity/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..e69de29bb diff --git a/loyalty_setup_validity/readme/DESCRIPTION.rst b/loyalty_setup_validity/readme/DESCRIPTION.rst new file mode 100644 index 000000000..0d83f74b5 --- /dev/null +++ b/loyalty_setup_validity/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +Normally, the loyalty program is based on a fixed validity date. With this module, you +can choose between a fixed date or a date generated within a period of time after the +loyalty has been generated (for example, after a visit to the point of sale, a customer +can obtain a discount for 30 days). \ No newline at end of file diff --git a/loyalty_setup_validity/static/description/index.html b/loyalty_setup_validity/static/description/index.html new file mode 100644 index 000000000..169d7c5e0 --- /dev/null +++ b/loyalty_setup_validity/static/description/index.html @@ -0,0 +1,420 @@ + + + + + + +Loyalty Setup Validity + + + +
+

Loyalty Setup Validity

+ + +

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

+

Normally, the loyalty program is based on a fixed validity date. With this module, you +can choose between a fixed date or a date generated within a period of time after the +loyalty has been generated (for example, after a visit to the point of sale, a customer +can obtain a discount for 30 days).

+

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

+
    +
  • Moka
  • +
+
+
+

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/sale-promotion project on GitHub.

+

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

+
+
+
+ + diff --git a/loyalty_setup_validity/tests/__init__.py b/loyalty_setup_validity/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/loyalty_setup_validity/tests/test_loyalty.py b/loyalty_setup_validity/tests/test_loyalty.py new file mode 100644 index 000000000..32ae79e7c --- /dev/null +++ b/loyalty_setup_validity/tests/test_loyalty.py @@ -0,0 +1,46 @@ +from freezegun import freeze_time + +from odoo import fields +from odoo.fields import Command +from odoo.tests import TransactionCase, tagged + + +@tagged("post_install", "-at_install") +class TestLoyalty(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.program = cls.env["loyalty.program"].create( + { + "name": "Test Program", + "reward_ids": [ + Command.create( + { + "description": "Test Product", + } + ), + ], + "validity_type": "after_activation", + "validity_duration": 30, + } + ) + + @freeze_time("2024-04-25") + def test_validity_duration(self): + card = self.env["loyalty.card"].create( + { + "program_id": self.program.id, + } + ) + self.assertEqual(card.expiration_date, fields.Date.from_string("2024-05-25")) + + @freeze_time("2024-04-25") + def test_fixed(self): + self.program.validity_type = "fixed" + self.program.date_to = fields.Date.from_string("2024-05-01") + card = self.env["loyalty.card"].create( + { + "program_id": self.program.id, + } + ) + self.assertEqual(card.expiration_date, fields.Date.from_string("2024-05-01")) diff --git a/loyalty_setup_validity/views/loyalty_program_inherit.xml b/loyalty_setup_validity/views/loyalty_program_inherit.xml new file mode 100644 index 000000000..56f9f6827 --- /dev/null +++ b/loyalty_setup_validity/views/loyalty_program_inherit.xml @@ -0,0 +1,44 @@ + + + + + + loyalty.program.view.form.inherit + loyalty.program + + + + + + 0 + {'invisible': [('validity_type', '=', 'after_activation')]} + + + + + + + + + + loyalty.program.view.tree.inherit + loyalty.program + + + + + + + + + + diff --git a/setup/loyalty_setup_validity/odoo/addons/loyalty_setup_validity b/setup/loyalty_setup_validity/odoo/addons/loyalty_setup_validity new file mode 120000 index 000000000..886f9eb21 --- /dev/null +++ b/setup/loyalty_setup_validity/odoo/addons/loyalty_setup_validity @@ -0,0 +1 @@ +../../../../loyalty_setup_validity \ No newline at end of file diff --git a/setup/loyalty_setup_validity/setup.py b/setup/loyalty_setup_validity/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/loyalty_setup_validity/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +)