Source code for shuup.front.apps.customer_information.forms

import six
from django import forms
from django.conf import settings
from django.contrib import messages
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
from enumfields import EnumField
from registration.signals import user_registered

from shuup.core.fields import LanguageFormField
from shuup.core.models import (
    CompanyContact,
    MutableAddress,
    PersonContact,
    SavedAddress,
    SavedAddressRole,
    SavedAddressStatus,
    get_company_contact,
    get_person_contact,
)
from shuup.front.forms.widget import PictureDnDUploaderWidget
from shuup.front.utils.companies import company_registration_requires_approval
from shuup.utils.form_group import FormGroup
from shuup.utils.importing import cached_load

from .notify_events import CompanyAccountCreated


[docs] class PersonContactForm(forms.ModelForm): language = LanguageFormField(label=_("Language"), required=False)
[docs] class Meta: model = PersonContact fields = ( "first_name", "last_name", "phone", "email", "gender", "language", "marketing_permission", "timezone", "picture", )
[docs] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) for field in ("first_name", "last_name", "email"): self.fields[field].required = True self.initial["language"] = self.instance.language if settings.SHUUP_CUSTOMER_INFORMATION_ALLOW_PICTURE_UPLOAD: self.fields["picture"].widget = PictureDnDUploaderWidget(clearable=True) else: self.fields.pop("picture") field_properties = settings.SHUUP_PERSON_CONTACT_FIELD_PROPERTIES for field, properties in field_properties.items(): for prop in properties: setattr(self.fields[field], prop, properties[prop])
[docs] def save(self, commit=True): self.instance.language = self.cleaned_data["language"] return super().save(commit)
[docs] class CompanyContactForm(forms.ModelForm):
[docs] class Meta: model = CompanyContact fields = ( "name", "tax_number", "phone", "email", "marketing_permission", "picture", )
[docs] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) if settings.SHUUP_CUSTOMER_INFORMATION_ALLOW_PICTURE_UPLOAD: self.fields["picture"].widget = PictureDnDUploaderWidget(clearable=True) else: self.fields.pop("picture") for field in ("name", "tax_number", "email"): self.fields[field].required = True if not kwargs.get("instance"): self.fields["email"].help_text = _("Will become default user email when linked.")
[docs] def clean_tax_number(self): """ Clean Tax Number. This is done because we want to prevent duplicates in the front-end. """ tax_number = self.cleaned_data["tax_number"] company = CompanyContact.objects.filter(tax_number=tax_number).first() if company: error_message = _("Given Tax Number already exists. Please contact support.") if not self.instance.pk: raise ValidationError(error_message, code="existing_tax_number") elif company.pk != self.instance.pk: raise ValidationError(error_message, code="existing_tax_number") return tax_number
[docs] class SavedAddressForm(forms.Form): title = forms.CharField(max_length=255, label=_("Address Title")) role = EnumField(SavedAddressRole, default=SavedAddressRole.SHIPPING).formfield(label=_("Address Type")) status = EnumField(SavedAddressStatus, default=SavedAddressStatus.ENABLED).formfield(label=_("Address Status"))
[docs] class CustomerInformationFormGroup(FormGroup): address_forms = ["billing", "shipping"]
[docs] def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super().__init__(*args, **kwargs) contact = get_person_contact(self.request.user) address_form_class = cached_load("SHUUP_ADDRESS_MODEL_FORM") for form_name in self.address_forms: self.add_form_def( form_name, address_form_class, kwargs={"instance": getattr(contact, f"default_{form_name}_address")}, ) self.add_form_def("contact", PersonContactForm, kwargs={"instance": contact})
[docs] def save(self): contact = self.forms["contact"].save() user = contact.user if "billing" in self.forms: billing_address = self.forms["billing"].save() if billing_address.pk != contact.default_billing_address_id: # Identity changed due to immutability contact.default_billing_address = billing_address if "shipping" in self.forms: shipping_address = self.forms["shipping"].save() if shipping_address.pk != contact.default_shipping_address_id: # Identity changed due to immutability contact.default_shipping_address = shipping_address if not bool(get_company_contact(self.request.user)): # Only update user details for non-company members user.email = contact.email user.first_name = contact.first_name user.last_name = contact.last_name user.save() contact.save() return contact
[docs] class CompanyInformationFormGroup(FormGroup): address_forms = ["billing", "shipping"]
[docs] def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") super().__init__(*args, **kwargs) user = self.request.user company = get_company_contact(user) person = get_person_contact(user) address_form_class = cached_load("SHUUP_ADDRESS_MODEL_FORM") for form_name in self.address_forms: self.add_form_def( form_name, address_form_class, kwargs={"instance": _get_default_address_for_contact(company, f"default_{form_name}_address", person)}, ) self.add_form_def("contact", CompanyContactForm, kwargs={"instance": company})
[docs] def save(self): company = self.forms["contact"].save(commit=False) is_new = not bool(company.pk) company.save() user = self.request.user # TODO: Should this check if contact will be created? Or should we expect create always? person = get_person_contact(user) person.add_to_shop(self.request.shop) company.members.add(person) company.add_to_shop(self.request.shop) if "billing" in self.forms: billing_address = self.forms["billing"].save() if billing_address.pk != company.default_billing_address_id: # Identity changed due to immutability company.default_billing_address = billing_address if "shipping" in self.forms: shipping_address = self.forms["shipping"].save() if shipping_address.pk != company.default_shipping_address_id: # Identity changed due to immutability company.default_shipping_address = shipping_address message = _("Company information was saved.") # If company registration requires activation, # company will be created as inactive. if is_new and company_registration_requires_approval(self.request.shop): company.is_active = False message = _("Company information was saved. Please follow the instructions sent to your email address.") messages.success(self.request, message) company.save() if is_new: user_registered.send(sender=self.__class__, user=self.request.user, request=self.request) CompanyAccountCreated(contact=company, customer_email=company.email).run(shop=self.request.shop) return company
[docs] class AddressBookFormGroup(FormGroup): saved_address_form = SavedAddressForm
[docs] def __init__(self, *args, **kwargs): self.request = kwargs.pop("request") self.instance = kwargs.pop("instance") super().__init__(*args, **kwargs) address_kwargs = {} saved_address_kwargs = {} if self.instance: address_kwargs["instance"] = self.instance.address saved_address_kwargs["initial"] = { "role": self.instance.role, "status": self.instance.status, "title": self.instance.title, } self.add_form_def("address", cached_load("SHUUP_ADDRESS_MODEL_FORM"), kwargs=address_kwargs) self.add_form_def("saved_address", self.saved_address_form, kwargs=saved_address_kwargs)
[docs] def save(self): address_form = self.forms["address"] if self.instance: # expect old address = MutableAddress.objects.get(pk=self.instance.address.pk) for k, v in six.iteritems(address_form.cleaned_data): setattr(address, k, v) address.save() else: address = address_form.save() owner = self.request.customer saf = self.forms["saved_address"] saved_address, updated = SavedAddress.objects.update_or_create( owner=owner, address=address, defaults={ "title": saf.cleaned_data.get("title"), "role": saf.cleaned_data.get("role"), "status": saf.cleaned_data.get("status"), }, ) return saved_address
def _get_default_address_for_contact(contact, address_attr, fallback_contact): if contact and getattr(contact, address_attr, None): return getattr(contact, address_attr) if fallback_contact and getattr(fallback_contact, address_attr, None): return getattr(fallback_contact, address_attr) return None