diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f2fef1236cd9..ebbd9e4a1985 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,17 +1,24 @@ exclude: | (?x) # NOT INSTALLABLE ADDONS + ^sale_blanket_order_revision/| # END NOT INSTALLABLE ADDONS # Files and folders generated by bots, to avoid loops ^setup/|/static/description/index\.html$| # We don't want to mess with tool-generated files - .svg$|/tests/([^/]+/)?cassettes/| + .svg$|/tests/([^/]+/)?cassettes/|^.copier-answers.yml$|^.github/| # Maybe reactivate this when all README files include prettier ignore tags? ^README\.md$| # Library files can have extraneous formatting (even minimized) /static/(src/)?lib/| # Repos using Sphinx to generate docs don't need prettying ^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: @@ -27,15 +34,33 @@ repos: entry: found forbidden files; remove them language: fail files: "\\.rej$" + - id: en-po-files + name: en.po files cannot exist + entry: found a en.po file + language: fail + files: '[a-zA-Z0-9_]*/i18n/en\.po$' - repo: https://github.com/oca/maintainer-tools - rev: ab1d7f6 + rev: 1b216173c7d11cf682492aefc149f02627068174 hooks: # update the NOT INSTALLABLE ADDONS section above - id: oca-update-pre-commit-excluded-addons - id: oca-fix-manifest-website args: ["https://github.com/OCA/sale-workflow"] + - id: oca-gen-addon-readme + args: + - --addons-dir=. + - --branch=14.0 + - --org-name=OCA + - --repo-name=sale-workflow + - --if-source-changed + - --keep-source-digest + - repo: https://github.com/OCA/odoo-pre-commit-hooks + rev: v0.0.31 + hooks: + - id: oca-checks-odoo-module + - id: oca-checks-po - repo: https://github.com/myint/autoflake - rev: v1.4 + rev: v2.3.1 hooks: - id: autoflake args: @@ -46,11 +71,11 @@ repos: - --remove-duplicate-keys - --remove-unused-variables - repo: https://github.com/psf/black - rev: 20.8b1 + rev: 24.4.2 hooks: - id: black - repo: https://github.com/pre-commit/mirrors-prettier - rev: v2.1.2 + rev: v4.0.0-alpha.8 hooks: - id: prettier name: prettier (with plugin-xml) @@ -61,7 +86,7 @@ repos: - --plugin=@prettier/plugin-xml files: \.(css|htm|html|js|json|jsx|less|md|scss|toml|ts|xml|yaml|yml)$ - repo: https://github.com/pre-commit/mirrors-eslint - rev: v7.8.1 + rev: v9.8.0 hooks: - id: eslint verbose: true @@ -69,7 +94,7 @@ repos: - --color - --fix - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v3.2.0 + rev: v4.6.0 hooks: - id: trailing-whitespace # exclude autogenerated files @@ -91,12 +116,12 @@ repos: - id: mixed-line-ending args: ["--fix=lf"] - repo: https://github.com/asottile/pyupgrade - rev: v2.7.2 + rev: v3.17.0 hooks: - id: pyupgrade args: ["--keep-percent-format"] - repo: https://github.com/PyCQA/isort - rev: 5.5.1 + rev: 5.13.2 hooks: - id: isort name: isort except __init__.py @@ -104,7 +129,7 @@ repos: - --settings=. exclude: /__init__\.py$ - repo: https://github.com/acsone/setuptools-odoo - rev: 2.6.0 + rev: "3.3" hooks: - id: setuptools-odoo-make-default - id: setuptools-odoo-get-requirements @@ -113,25 +138,21 @@ repos: - requirements.txt - --header - "# generated from manifests external_dependencies" - - repo: https://gitlab.com/PyCQA/flake8 - rev: 3.8.3 + - repo: https://github.com/PyCQA/flake8 + rev: 7.1.0 hooks: - id: flake8 name: flake8 additional_dependencies: ["flake8-bugbear==20.1.4"] - - repo: https://github.com/PyCQA/pylint - rev: pylint-2.5.3 + - repo: https://github.com/OCA/pylint-odoo + rev: v9.1.2 hooks: - - id: pylint + - id: pylint_odoo name: pylint with optional checks args: - --rcfile=.pylintrc - --exit-zero verbose: true - additional_dependencies: &pylint_deps - - pylint-odoo==3.5.0 - - id: pylint - name: pylint with mandatory checks + - id: pylint_odoo args: - --rcfile=.pylintrc-mandatory - additional_dependencies: *pylint_deps diff --git a/sale_partner_primeship/README.rst b/sale_partner_primeship/README.rst index 5bf905efc3da..d48ee82e05eb 100644 --- a/sale_partner_primeship/README.rst +++ b/sale_partner_primeship/README.rst @@ -2,32 +2,39 @@ Sale Partner Primeship ====================== -.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! This file is generated by oca-gen-addon-readme !! !! changes will be overwritten. !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:4a8b2bd09f624001cb742f00bfe88a35f7c7ba7dceca566dae0bb4ed0d49e56e + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! .. |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 - :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html - :alt: License: LGPL-3 +.. |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--workflow-lightgray.png?logo=github :target: https://github.com/OCA/sale-workflow/tree/14.0/sale_partner_primeship :alt: OCA/sale-workflow .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/sale-workflow-14-0/sale-workflow-14-0-sale_partner_primeship :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png - :target: https://runbot.odoo-community.org/runbot/167/14.0 - :alt: Try me on Runbot +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/sale-workflow&target_branch=14.0 + :alt: Try me on Runboat -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module adds a concept of primeship for partners. +A primeship is basically a simple membership very easy to use. This primeship is activated on the confirmation of a sale containing -a primeship activation product for a customizable duration. +a primeship activation product for a customizable duration expressed in months. +It is automatically deactivated when the duration expires. +You can then check if the primeship is active for a particular customer +and take actions based on it. **Table of contents** @@ -44,7 +51,7 @@ go to the product form Sales tab and tick the Activates primeship checkbox: You can then set a primeship duration. -You can see current primeship availability for a customer: +You can see current primeship availability for a customer: .. figure:: https://raw.githubusercontent.com/OCA/sale-workflow/14.0/sale_partner_primeship/static/description/partner-with-primeship.png @@ -57,7 +64,7 @@ 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 smashing it by providing a detailed and welcomed +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. @@ -76,6 +83,7 @@ Contributors * `Akretion `_: * Florian Mounier + * Kevin Roche * Olivier Nibart Maintainers diff --git a/sale_partner_primeship/__manifest__.py b/sale_partner_primeship/__manifest__.py index 3dc512125949..d7154c078253 100644 --- a/sale_partner_primeship/__manifest__.py +++ b/sale_partner_primeship/__manifest__.py @@ -1,4 +1,5 @@ # Copyright 2021 Akretion - Florian Mounier +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). { "name": "Sale Partner Primeship", "summary": """Allow you to manage time limited prime memberships @@ -16,5 +17,5 @@ "security/sale_partner_primeship.xml", "data/ir_cron.xml", ], - "license": "LGPL-3", + "license": "AGPL-3", } diff --git a/sale_partner_primeship/models/product_template.py b/sale_partner_primeship/models/product_template.py index 36976e23c129..181e6e56714e 100644 --- a/sale_partner_primeship/models/product_template.py +++ b/sale_partner_primeship/models/product_template.py @@ -1,3 +1,6 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from odoo import fields, models diff --git a/sale_partner_primeship/models/res_partner.py b/sale_partner_primeship/models/res_partner.py index ac6cf59b5d12..e203a4c1cbbd 100644 --- a/sale_partner_primeship/models/res_partner.py +++ b/sale_partner_primeship/models/res_partner.py @@ -1,3 +1,7 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2023 Akretion France (http://www.akretion.com/) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from odoo import api, fields, models @@ -10,8 +14,13 @@ class ResPartner(models.Model): required=True, ) + # store True allow to filter on active_primeship. + # There is a cron job to set it to False when the customer has no active + # primeship anymore. active_primeship = fields.Boolean( - string="Active Primeship", compute="_compute_active_primeship", store=True + string="Active Primeship", + compute="_compute_active_primeship", + store=True, ) primeship_count = fields.Integer( string="Primeships Count", compute="_compute_primeship_count" diff --git a/sale_partner_primeship/models/sale_order.py b/sale_partner_primeship/models/sale_order.py index 1ea4500d2521..54b4ca545516 100644 --- a/sale_partner_primeship/models/sale_order.py +++ b/sale_partner_primeship/models/sale_order.py @@ -1,3 +1,7 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2024 Akretion France (http://www.akretion.com/) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from dateutil.relativedelta import relativedelta from odoo import api, fields, models @@ -6,8 +10,9 @@ class SaleOrder(models.Model): _inherit = "sale.order" - def action_confirm(self): - rv = super().action_confirm() + def _action_confirm(self): + super()._action_confirm() + sale_primeship = self.env["sale.primeship"] for record in self: partner = record.partner_id.commercial_partner_id @@ -28,22 +33,35 @@ def action_confirm(self): start = primeship.end_date end = start + relativedelta(months=duration) - self.env["sale.primeship"].create( - { - "start_date": start, - "end_date": end, - "partner_id": partner.id, - "order_line_id": line.id, - } - ) - return rv + vals = { + "start_date": start, + "end_date": end, + "partner_id": partner.id, + "order_line_id": line.id, + # this is to reactivate a maybe deactivated existing primeship + "active": True, + } + if line.primeship_id: + # Hm... something seems to have gone wrong here, + # but we handle it nonetheless. + line.primeship_id.write(vals) + else: + # We may have a deactivated primeship because of an order + # cancellation. + primeship = sale_primeship.with_context( + active_test=False, + ).search([("order_line_id", "=", line.id)]) + if primeship: + primeship.write(vals) + else: + sale_primeship.create(vals) + + return True def action_cancel(self): rv = super().action_cancel() - for record in self: record.order_line.mapped("primeship_id").active = False - return rv @@ -65,8 +83,7 @@ class SaleOrderLine(models.Model): @api.depends("primeship_ids") def _compute_primeship_id(self): for record in self: - if record.primeship_ids: - record.primeship_id = record.primeship_ids[0] + record.primeship_id = record.primeship_ids[:1] def _inverse_primeship_id(self): for record in self: @@ -78,10 +95,10 @@ def _inverse_primeship_id(self): record.primeship_id.order_line_id = record - # Update invoice start/end dates def _prepare_invoice_line(self, **optional_values): - # Set invoice start/end dates to primeship start/end dates - # In case of multi quantity, this assumes continuous date ranges + """Update invoice start/end dates. + Set invoice start/end dates to primeship start/end dates + In case of multi quantity, this assumes continuous date ranges.""" self.ensure_one() res = super()._prepare_invoice_line(**optional_values) if self.primeship_id: diff --git a/sale_partner_primeship/models/sale_primeship.py b/sale_partner_primeship/models/sale_primeship.py index 0e98a66af750..d70ed45ae90e 100644 --- a/sale_partner_primeship/models/sale_primeship.py +++ b/sale_partner_primeship/models/sale_primeship.py @@ -1,3 +1,7 @@ +# Copyright 2021 Akretion France (http://www.akretion.com/) +# Copyright 2024 Akretion France (http://www.akretion.com/) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + from odoo import _, api, fields, models from odoo.exceptions import ValidationError @@ -19,16 +23,23 @@ class SalePrimeship(models.Model): ondelete="cascade", index=True, ) - order_line_id = fields.Many2one( comodel_name="sale.order.line", string="Sale Order Line", ) - order_id = fields.Many2one(string="Sale Order", related="order_line_id.order_id") current = fields.Boolean(string="Currently Active", compute="_compute_current") + _sql_constraints = [ + # Constraint for One2one impl of "sale.order.line".primeship_id + ( + "unique_order_line", + "UNIQUE(order_line_id)", + "A sale order line can only have one primeship!", + ) + ] + @api.depends("start_date", "end_date") def _compute_name(self): for record in self: diff --git a/sale_partner_primeship/readme/CONTRIBUTORS.rst b/sale_partner_primeship/readme/CONTRIBUTORS.rst index a4d0ad92299d..eac4144055f7 100644 --- a/sale_partner_primeship/readme/CONTRIBUTORS.rst +++ b/sale_partner_primeship/readme/CONTRIBUTORS.rst @@ -1,3 +1,5 @@ * `Akretion `_: * Florian Mounier + * Kevin Roche + * Olivier Nibart diff --git a/sale_partner_primeship/readme/DESCRIPTION.rst b/sale_partner_primeship/readme/DESCRIPTION.rst index e2e920f2f9fc..4f4bd4b2b3ca 100644 --- a/sale_partner_primeship/readme/DESCRIPTION.rst +++ b/sale_partner_primeship/readme/DESCRIPTION.rst @@ -1,3 +1,7 @@ This module adds a concept of primeship for partners. +A primeship is basically a simple membership very easy to use. This primeship is activated on the confirmation of a sale containing -a primeship activation product for a customizable duration. +a primeship activation product for a customizable duration expressed in months. +It is automatically deactivated when the duration expires. +You can then check if the primeship is active for a particular customer +and take actions based on it. \ No newline at end of file diff --git a/sale_partner_primeship/static/description/index.html b/sale_partner_primeship/static/description/index.html index f44010436bb3..192692416d3b 100644 --- a/sale_partner_primeship/static/description/index.html +++ b/sale_partner_primeship/static/description/index.html @@ -1,20 +1,20 @@ - + - + Sale Partner Primeship