From 8778c5b412ffb8636d95f151ff21efa80891106f Mon Sep 17 00:00:00 2001 From: Carmen Bianca BAKKER Date: Thu, 23 Nov 2023 17:13:16 +0100 Subject: [PATCH] [IMP] membership_[type,custom_date]: Add restraint on date_from and date_to on membership line This was a bit tricky to get right, architecturally, but I think I arrived at the correct design decision. On the whole, the new restriction makes sense. Following from the fact that dates are mandatory on 'fixed dates' (read: default) membership products, and following from the fact that dates are always set on the membership lines of 'variable period' membership products, membership lines should _always_ have values for date_from and date_to. The fact that these fields are not already required is a strange design decision. The constraint in membership_type _effectively_ sets required=True on these fields. However, there is a use-case for memberships that do not have an end date (using the 'custom' membership product). For those scenarios, we add a toggle on the product (exclusive to 'custom' products) on whether to apply the constraint. Signed-off-by: Carmen Bianca BAKKER --- membership_custom_date/__manifest__.py | 1 + membership_custom_date/models/__init__.py | 1 + .../models/membership_membership_line.py | 19 ++++++++++++++++++ .../models/product_template.py | 8 ++++++++ .../views/product_template_views.xml | 20 +++++++++++++++++++ membership_type/models/__init__.py | 1 + .../models/membership_membership_line.py | 18 +++++++++++++++++ 7 files changed, 68 insertions(+) create mode 100644 membership_custom_date/models/membership_membership_line.py create mode 100644 membership_custom_date/views/product_template_views.xml create mode 100644 membership_type/models/membership_membership_line.py diff --git a/membership_custom_date/__manifest__.py b/membership_custom_date/__manifest__.py index 31e83254..34d297f0 100644 --- a/membership_custom_date/__manifest__.py +++ b/membership_custom_date/__manifest__.py @@ -20,6 +20,7 @@ ], "excludes": [], "data": [ + "views/product_template_views.xml", "wizard/membership_invoice_views.xml", ], "demo": [], diff --git a/membership_custom_date/models/__init__.py b/membership_custom_date/models/__init__.py index 8afbbed9..c45790b7 100644 --- a/membership_custom_date/models/__init__.py +++ b/membership_custom_date/models/__init__.py @@ -3,3 +3,4 @@ # SPDX-License-Identifier: AGPL-3.0-or-later from . import product_template +from . import membership_membership_line diff --git a/membership_custom_date/models/membership_membership_line.py b/membership_custom_date/models/membership_membership_line.py new file mode 100644 index 00000000..3ec10a73 --- /dev/null +++ b/membership_custom_date/models/membership_membership_line.py @@ -0,0 +1,19 @@ +# SPDX-FileCopyrightText: 2023 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from odoo import api, models + + +class MembershipLine(models.Model): + _inherit = "membership.membership_line" + + @api.constrains( + "membership_id", "membership_id.dates_mandatory", "date_from", "date_to" + ) + def _check_mandatory_dates(self): + lines = self.filtered( + lambda line: line.membership_id.membership_type != "custom" + or line.membership_id.dates_mandatory + ) + return super(MembershipLine, lines)._check_mandatory_dates() diff --git a/membership_custom_date/models/product_template.py b/membership_custom_date/models/product_template.py index 41edd977..20546686 100644 --- a/membership_custom_date/models/product_template.py +++ b/membership_custom_date/models/product_template.py @@ -14,10 +14,18 @@ class ProductTemplate(models.Model): ], ondelete={"custom": "set default"}, ) + dates_mandatory = fields.Boolean( + string="Mandatory dates", + default=True, + help="Membership lines that use this product must have a start and end date.", + ) @api.model def _correct_vals_membership_type(self, vals): vals = super()._correct_vals_membership_type(vals) if vals.get("membership_type") == "custom": vals["membership_date_from"] = vals["membership_date_to"] = False + # TODO: should we set dates_mandatory back to True if switching away + # from custom? At the moment this variable is not used _at all_ for + # non-custom memberships. return vals diff --git a/membership_custom_date/views/product_template_views.xml b/membership_custom_date/views/product_template_views.xml new file mode 100644 index 00000000..4b2070ad --- /dev/null +++ b/membership_custom_date/views/product_template_views.xml @@ -0,0 +1,20 @@ + + + + + Membership Products (custom type) + product.template + + + + + + + + diff --git a/membership_type/models/__init__.py b/membership_type/models/__init__.py index 00802a0c..83f86207 100644 --- a/membership_type/models/__init__.py +++ b/membership_type/models/__init__.py @@ -3,3 +3,4 @@ # SPDX-License-Identifier: AGPL-3.0-or-later from . import product_template +from . import membership_membership_line diff --git a/membership_type/models/membership_membership_line.py b/membership_type/models/membership_membership_line.py new file mode 100644 index 00000000..e99faad4 --- /dev/null +++ b/membership_type/models/membership_membership_line.py @@ -0,0 +1,18 @@ +# SPDX-FileCopyrightText: 2023 Coop IT Easy SC +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +from odoo import _, api, models +from odoo.exceptions import ValidationError + + +class MembershipLine(models.Model): + _inherit = "membership.membership_line" + + @api.constrains("date_from", "date_to") + def _check_mandatory_dates(self): + for line in self: + if not line.date_from or not line.date_to: + raise ValidationError( + _("Error: the start and end dates are mandatory.") + )