Source code for ferrosoft.apps.ferrobase.forms.model_forms

#  Copyright (c) 2025 Ferrosoft GmbH. All rights reserved.

from django import forms
from django.contrib.auth.models import Group, Permission
from django.utils.translation import gettext_lazy as _

from ferrosoft.apps.ferrobase.models import (
    User,
    Language,
    IdSequenceConfig,
    Organization,
    Tenant,
    SubscriptionPlan,
    CompanySite,
    FeatureAssignment,
    APIToken,
)
from ferrosoft.apps.ferrobase.services.tenant_mgm import (
    add_tenant,
    TenantOptions,
    STANDARD_FIXTURES,
)


[docs] class APITokenForm(forms.ModelForm): """Form for displaying an API token's name field. Token creation is intentionally blocked at the form level; tokens must be generated through ``APIToken.create`` so that the JWT is returned to the caller. """
[docs] class Meta: model = APIToken fields = [ "name", ]
[docs] def save(self, commit=True): raise RuntimeError("Token must not be created via form")
[docs] class CompanySiteForm(forms.ModelForm): """Form for creating and updating ``CompanySite`` records. Renders ``additional_lines`` as a compact two-row textarea. """
[docs] class Meta: model = CompanySite fields = [ "code", "name", "salutation", "first_name", "last_name", "company", "additional_lines", "street", "house_no", "city", "postal_code", "country", ] widgets = { "additional_lines": forms.Textarea(attrs={"rows": 2}), }
[docs] class FeatureAssignmentForm(forms.ModelForm): """Form for assigning an ``AppFeature`` to a ``SubscriptionPlan`` with an optional limit. The plan field is hidden because it is set programmatically from the parent subscription context. """
[docs] class Meta: model = FeatureAssignment fields = [ "plan", "feature", "limit", ] widgets = { "plan": forms.HiddenInput(), }
[docs] class IDSequenceForm(forms.ModelForm): """Form for configuring a named ``IdSequenceConfig`` entry (prefix and padding)."""
[docs] class Meta: model = IdSequenceConfig fields = [ "name", "prefix", "padding_amount", ]
[docs] class OrganizationForm(forms.ModelForm): """Form for creating and updating ``Organization`` master records."""
[docs] class Meta: model = Organization fields = [ "name", "contact_email", "contact_first_name", "contact_last_name", "subscription", ]
[docs] class SubscriptionPlanForm(forms.ModelForm): """Form for editing ``SubscriptionPlan`` tier settings (name, tonnage cap, feature flag)."""
[docs] class Meta: model = SubscriptionPlan fields = [ "name", "max_tonnage", "enable_all_features", ]
[docs] class TenantForm(forms.ModelForm): """Form for creating and updating ``Tenant`` records. When ``enable_add_tenant=True`` is passed at instantiation, ``save`` delegates to ``add_tenant`` (which provisions the tenant database and loads fixtures) instead of the standard ``ModelForm.save``. This flag is only meaningful for new tenants; updates use the standard path regardless. """
[docs] class Meta: model = Tenant fields = [ "organization", "name", "active", "expiry_date", ] widgets = { "organization": forms.HiddenInput(), "expiry_date": forms.DateTimeInput( attrs={"type": "datetime-local"}, format="%Y-%m-%dT%H:%M", ), }
language = forms.ModelChoiceField( help_text=_("Language of built-in data catalogs"), queryset=Language.objects.get_supported(), required=True, ) def __init__(self, *args, **kwargs): self.enable_add_tenant = kwargs.pop("enable_add_tenant", False) super().__init__(*args, **kwargs)
[docs] def save(self, commit=True): if not self.enable_add_tenant: # Use normal logic, since add_tenant is for creation only. return super().save(commit) if not commit: # add_tenant is very commit-y, cannot use it noncommittally. return super().save(commit) data = self.cleaned_data language = data.pop("language") return add_tenant( TenantOptions( id=None, fixtures=STANDARD_FIXTURES, language=language.iso_code, **data, ) )
[docs] class UserPasswordForm(forms.ModelForm): """Base form mixin that adds an optional password field to any ``User`` form. If the password field is left empty, the existing password is not changed. """ password = forms.CharField( label=_("Password"), help_text=_("Leave empty to not create or update password"), widget=forms.PasswordInput(), required=False, )
[docs] def save(self, commit=True): user = super().save(commit) password = self.cleaned_data.get("password", "") if password != "": user.set_password(password) if commit: user.save(update_fields=["password"]) return user
[docs] class UserCreationForm(UserPasswordForm): """Form for creating new ``User`` accounts. The organization field is hidden and fixed to the caller's organization unless ``allow_organization_selection=True`` is passed (for superusers). """
[docs] class Meta: model = User fields = ["username", "email", "organization"]
def __init__(self, *args, **kwargs): self._organization = kwargs.pop("organization") self._allow_organization_selection = kwargs.pop("allow_organization_selection") super().__init__(*args, **kwargs) if not self._allow_organization_selection: self.fields["organization"].required = False self.fields["organization"].widget = forms.HiddenInput()
[docs] def save(self, commit=True): user = super().save(commit=False) if not self._allow_organization_selection: user.organization = self._organization if commit: user.save() return user
[docs] class UserUpdateForm(UserPasswordForm): """Form for editing an existing ``User`` account's profile and preferences."""
[docs] class Meta: model = User fields = [ "username", "is_active", "first_name", "last_name", "email", "language", "timezone", "color_theme", ]
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["language"].queryset = Language.objects.get_supported()
[docs] class UserGroupsForm(forms.ModelForm): """Form for managing a user's Django group memberships via checkboxes."""
[docs] class Meta: model = User fields = ["groups"]
groups = forms.ModelMultipleChoiceField( label=_("Groups"), required=False, queryset=Group.objects.all(), widget=forms.CheckboxSelectMultiple(), )
[docs] class GroupPermissionsForm(forms.ModelForm): """Form for assigning Django permissions to a ``Group`` via checkboxes."""
[docs] class Meta: model = Group fields = ["permissions"]
permissions = forms.ModelMultipleChoiceField( label=_("Permissions"), required=False, queryset=Permission.objects.select_related("content_type"), widget=forms.CheckboxSelectMultiple(), )