diff --git a/.forgejo/workflows/renovate.yaml b/.forgejo/workflows/renovate.yaml index 709b132..34df542 100644 --- a/.forgejo/workflows/renovate.yaml +++ b/.forgejo/workflows/renovate.yaml @@ -19,7 +19,7 @@ jobs: node-version: "22" - name: Renovate - uses: https://github.com/renovatebot/github-action@v43.0.5 + uses: https://github.com/renovatebot/github-action@v43.0.2 with: token: ${{ secrets.RENOVATE_TOKEN }} env: diff --git a/docs/modules/ROOT/pages/web-portal-billingentity.adoc b/docs/modules/ROOT/pages/web-portal-billingentity.adoc index 0b485c8..cd7b662 100644 --- a/docs/modules/ROOT/pages/web-portal-billingentity.adoc +++ b/docs/modules/ROOT/pages/web-portal-billingentity.adoc @@ -17,9 +17,9 @@ Search is done this way: When choosing to add a new billing address, two new records are created in the Odoo `res.partner` model: -* A record with the field `is_company = False` +* A record with the field `company_type = company` * A record with the following field configuration: -** `is_company = False` +** `company_type = person` ** `type = invoice` ** `parent_id = company_id` diff --git a/pyproject.toml b/pyproject.toml index 3ad42a1..a2804e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "argon2-cffi>=25.1.0", "cryptography>=45.0.5", "django==5.2.4", - "django-allauth>=65.10.0", + "django-allauth>=65.9.0", "django-fernet-encrypted-fields>=0.3.0", "django-scopes>=2.0.0", "django-storages[s3]>=1.14.6", @@ -20,7 +20,7 @@ dependencies = [ "pyjwt>=2.10.1", "requests>=2.32.4", "rules>=3.5", - "sentry-sdk[django]>=2.33.0", + "sentry-sdk[django]>=2.32.0", "urlman>=2.0.2", ] diff --git a/renovate.json b/renovate.json index b72dd71..727bdf6 100644 --- a/renovate.json +++ b/renovate.json @@ -11,8 +11,7 @@ "matchFileNames": [ ".forgejo/workflows/*.yml", ".forgejo/workflows/*.yaml" - ], - "automerge": true + ] }, { "matchManagers": [ diff --git a/src/servala/core/models/organization.py b/src/servala/core/models/organization.py index 57cd660..a9dcd4e 100644 --- a/src/servala/core/models/organization.py +++ b/src/servala/core/models/organization.py @@ -4,7 +4,6 @@ from django.conf import settings from django.db import models, transaction from django.utils.functional import cached_property from django.utils.text import slugify -from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from django_scopes import ScopedManager, scopes_disabled @@ -75,14 +74,6 @@ class Organization(ServalaModelMixin, models.Model): user=user, organization=self, role=OrganizationRole.OWNER ) - def add_support_message(self, message): - support_message = _( - "Need help? We're happy to help via the support form." - ).format(support_url=self.urls.support) - return mark_safe( - f'{message} {support_message}' - ) - @classmethod @transaction.atomic def create_organization(cls, instance, owner): @@ -156,8 +147,8 @@ class BillingEntity(ServalaModelMixin, models.Model): ) # Odoo IDs are nullable for creation, should never be null in practice - # The company ID points at a record of type res.partner with is_company=True - # The invoice ID points at a record of type res.partner with is_company=False, + # The company ID points at a record of type res.partner with company_type=company + # The invoice ID points at a record of type res.partner with company_type=person, # type=invoice, parent_id=company_id (the invoice address). odoo_company_id = models.IntegerField(null=True) odoo_invoice_id = models.IntegerField(null=True) @@ -175,8 +166,8 @@ class BillingEntity(ServalaModelMixin, models.Model): """ Creates a BillingEntity and corresponding Odoo records. - This method creates a `res.partner` record in Odoo with `is_company=True` - for the main company, and another `res.partner` record with `is_company=False` + This method creates a `res.partner` record in Odoo with `company_type='company'` + for the main company, and another `res.partner` record with `company_type='person'` and `type='invoice'` (linked via `parent_id` to the first record) for the invoice address. The IDs of these Odoo records are stored in the BillingEntity. @@ -196,14 +187,14 @@ class BillingEntity(ServalaModelMixin, models.Model): instance = cls.objects.create(name=name) company_payload = { "name": odoo_data.get("company_name", name), - "is_company": True, + "company_type": "company", } company_id = CLIENT.execute("res.partner", "create", [company_payload]) instance.odoo_company_id = company_id invoice_address_payload = { "name": name, - "is_company": False, + "company_type": "person", "type": "invoice", "parent_id": company_id, } @@ -258,10 +249,10 @@ class BillingEntity(ServalaModelMixin, models.Model): "invoice_address": None, } - company_fields = ["name", "is_company"] + company_fields = ["name", "company_type"] invoice_address_fields = [ "name", - "is_company", + "company_type", "type", "parent_id", "street", diff --git a/src/servala/core/models/service.py b/src/servala/core/models/service.py index ba1871d..362661b 100644 --- a/src/servala/core/models/service.py +++ b/src/servala/core/models/service.py @@ -1,7 +1,5 @@ import copy -import html import json -import re import kubernetes import rules @@ -12,7 +10,6 @@ from django.core.exceptions import ValidationError from django.db import IntegrityError, models, transaction from django.utils import timezone from django.utils.functional import cached_property -from django.utils.safestring import mark_safe from django.utils.translation import gettext_lazy as _ from encrypted_fields.fields import EncryptedJSONField from kubernetes import client, config @@ -574,7 +571,7 @@ class ServiceInstance(ServalaModelMixin, models.Model): unique_together = [("name", "organization", "context")] rules_permissions = { "view": rules.is_staff | perms.is_organization_member, - "change": rules.is_staff | perms.is_organization_admin, + "change": rules.is_staff | perms.is_organization_member, "delete": rules.is_staff | perms.is_organization_admin, "add": rules.is_authenticated, } @@ -606,58 +603,6 @@ class ServiceInstance(ServalaModelMixin, models.Model): spec_data = prune_empty_data(spec_data) return spec_data - @classmethod - def _format_kubernetes_error(cls, error_message): - if not error_message: - return {"message": "", "errors": None, "has_list": False} - - error_message = str(error_message).strip() - - # Pattern to match validation errors in brackets like [error1, error2, error3] - pattern = r"\[([^\]]+)\]" - match = re.search(pattern, error_message) - - if not match: - return {"message": error_message, "errors": None, "has_list": False} - - errors_text = match.group(1).strip() - - if "," not in errors_text: - return {"message": error_message, "errors": None, "has_list": False} - - errors = [error.strip().strip("\"'") for error in errors_text.split(",")] - errors = [error for error in errors if error] - - if len(errors) <= 1: - return {"message": error_message, "errors": None, "has_list": False} - - base_message = re.sub(pattern, "", error_message).strip() - base_message = base_message.rstrip(":").strip() - - return {"message": base_message, "errors": errors, "has_list": True} - - @classmethod - def _safe_format_error(cls, error_data): - if not isinstance(error_data, dict): - return html.escape(str(error_data)) - - if not error_data.get("has_list", False): - return html.escape(error_data.get("message", "")) - - message = html.escape(error_data.get("message", "")) - errors = error_data.get("errors", []) - - if not errors: - return message - - escaped_errors = [html.escape(str(error)) for error in errors] - error_items = "".join(f"