Esempio n. 1
0
class ResetPasswordSerializer(serializers.Serializer):
    password = serializers.CharField(
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'},
        validators=[
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")),
            EnhancedPasswordStrengthFieldValidator()
        ])
    password_repeat = serializers.CharField(required=True,
                                            allow_blank=False,
                                            max_length=63,
                                            style={'input_type': 'password'})
    pr_access_code = serializers.CharField(required=True,
                                           allow_blank=False,
                                           max_length=255,
                                           style={'input_type': 'password'})

    def validate(self, clean_data):
        pr_access_code = clean_data['pr_access_code']
        try:
            clean_data['me'] = SharedUser.objects.get(
                pr_access_code=pr_access_code)
        except SharedUser.DoesNotExist:
            raise serializers.ValidationError(
                _("Password reset access code does not exist."))
        return clean_data
class StaffChangePasswordOperationSerializer(serializers.ModelSerializer):
    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=63,
        style={'input_type': 'password'},
        validators=[
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")),
            EnhancedPasswordStrengthFieldValidator()
        ])
    password_repeat = serializers.CharField(write_only=True,
                                            required=False,
                                            allow_blank=True,
                                            max_length=63,
                                            style={'input_type': 'password'})

    # Meta Information.
    class Meta:
        model = Staff
        fields = (
            'password',
            'password_repeat',
        )

    def update(self, instance, validated_data):
        """
        Override this function to include extra functionality.
        """
        #---------------------------
        # Update `SharedUser` object.
        #---------------------------
        # Update the password if required.
        password = validated_data.get('password', None)
        if password:
            instance.owner.set_password(password)
            logger.info("Updated the password.")

        # Save our instance.
        instance.owner.save()
        logger.info("Updated the staff member.")

        # Return our validated data.
        return instance
Esempio n. 3
0
class PartnerListCreateSerializer(serializers.ModelSerializer):
    # OVERRIDE THE MODEL FIELDS AND ENFORCE THE FOLLOWING CUSTOM VALIDATION RULES.
    given_name = serializers.CharField(required=True,
                                       allow_blank=False,
                                       validators=[])
    last_name = serializers.CharField(required=True,
                                      allow_blank=False,
                                      validators=[])
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(required=True,
                                            allow_blank=False,
                                            validators=[])
    address_region = serializers.CharField(required=True,
                                           allow_blank=False,
                                           validators=[])
    address_locality = serializers.CharField(required=True,
                                             allow_blank=False,
                                             validators=[])
    postal_code = serializers.CharField(required=True,
                                        allow_blank=False,
                                        validators=[])
    street_address = serializers.CharField(required=True,
                                           allow_blank=False,
                                           validators=[])

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=SharedUser.objects.all()),
        ],
        required=True,
    )

    # All comments are created by our `create` function and not by
    # `django-rest-framework`.
    # comments = PartnerCommentSerializer(many=True, read_only=True, allow_null=True)

    # This is a field used in the `create` function if the user enters a
    # comment. This field is *ONLY* to be used during the POST creation and
    # will be blank during GET.
    extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(allow_null=True, required=False)
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    # Attach with our foreign keys.
    how_hear = serializers.PrimaryKeyRelatedField(
        many=False,
        required=True,
        allow_null=False,
        queryset=HowHearAboutUsItem.objects.all())

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'},
        validators=[
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")),
            EnhancedPasswordStrengthFieldValidator()
        ])
    password_repeat = serializers.CharField(write_only=True,
                                            required=True,
                                            allow_blank=False,
                                            max_length=63,
                                            style={'input_type': 'password'})

    is_active = serializers.BooleanField(
        write_only=True,
        required=True,
        error_messages={"invalid": "Please pick either 'Yes' or 'No' choice."})

    #
    # Fields used for mapping to organizations.
    #

    organization_name = serializers.CharField(
        source="organization.name",
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        validators=[UniqueValidator(queryset=Organization.objects.all(), )],
    )
    organization_type_of = serializers.CharField(
        source="organization.type_of",
        write_only=True,
        required=True,
        allow_blank=True,
        max_length=63,
    )
    organization_address_country = serializers.CharField(
        source="organization.address_country",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
    )
    organization_address_locality = serializers.CharField(
        source="organization.address_locality",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
    )
    organization_address_region = serializers.CharField(
        source="organization.address_region",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
    )
    organization_post_office_box_number = serializers.CharField(
        source="organization.post_office_box_number",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
    )
    organization_postal_code = serializers.CharField(
        source="organization.postal_code",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
    )
    organization_street_address = serializers.CharField(
        source="organization.street_address",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
    )
    organization_street_address_extra = serializers.CharField(
        source="organization.street_address_extra",
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
    )

    # Meta Information.
    class Meta:
        model = Partner
        fields = (
            # Thing
            'id',
            'created',
            'last_modified',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',
            'description',

            # Misc (Read/Write)
            'is_active',
            'is_ok_to_email',
            'is_ok_to_text',
            'how_hear',

            # Misc (Read Only)
            # 'comments',
            'password',
            'password_repeat',

            # Misc (Write Only)
            'extra_comment',
            'organization_name',
            'organization_type_of',
            'organization_address_country',
            'organization_address_locality',
            'organization_address_region',
            'organization_post_office_box_number',
            'organization_postal_code',
            'organization_street_address',
            'organization_street_address_extra',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX
        )
        extra_kwargs = {
            "is_ok_to_email": {
                "error_messages": {
                    "invalid": "Please pick either 'Yes' or 'No' choice."
                }
            },
            "is_ok_to_text": {
                "error_messages": {
                    "invalid": "Please pick either 'Yes' or 'No' choice."
                }
            }
        }

    def validate_telephone(self, value):
        """
        Include validation on no-blanks
        """
        if value is None:
            raise serializers.ValidationError("This field may not be blank.")
        return value

    def validate_organization_type_of(self, value):
        """
        Include validation on no-blanks or "null" types
        """
        if value is None or value == "null":
            raise serializers.ValidationError("This field may not be blank.")
        return value

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            # 'comments'
        )
        return queryset

    @transaction.atomic
    def create(self, validated_data):
        """
        Override the `create` function to add extra functinality:

        - Create a `User` object in the public database.

        - Create a `SharedUser` object in the public database.

        - Create a `Partner` object in the tenant database.

        - If user has entered text in the 'extra_comment' field then we will
          a `Comment` object and attach it to the `Partner` object.

        - We will attach the staff user whom created this `Partner` object.
        """
        # Format our telephone(s)
        fax_number = validated_data.get('fax_number', None)
        if fax_number:
            fax_number = phonenumbers.parse(fax_number, "CA")
        telephone = validated_data.get('telephone', None)
        if telephone:
            telephone = phonenumbers.parse(telephone, "CA")
        other_telephone = validated_data.get('other_telephone', None)
        if other_telephone:
            other_telephone = phonenumbers.parse(other_telephone, "CA")

        validated_data['fax_number'] = fax_number
        validated_data['telephone'] = telephone
        validated_data['other_telephone'] = other_telephone

        #-------------------
        # Create our user.
        #-------------------
        email = validated_data.get('email', None)  # Extract our "email" field.
        owner = SharedUser.objects.create(
            first_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            email=email,
            franchise=self.context['franchise'],
            was_email_activated=True,
            is_active=validated_data['is_active'],
        )
        logger.info("Created shared user.")

        # Attach the user to the `Partner` group.
        owner.groups.add(ASSOCIATE_GROUP_ID)
        logger.info("Set shared user group.")

        # Update the password.
        password = validated_data.get('password', None)
        owner.set_password(password)
        owner.save()
        logger.info("Set shared user password.")

        #---------------------------------------------------
        # Create our `Partner` object in our tenant schema.
        #---------------------------------------------------
        # Create an "Partner".
        partner = Partner.objects.create(
            owner=owner,
            created_by=self.context['created_by'],
            last_modified_by=self.context['created_by'],
            description=validated_data['description'],

            # Profile
            given_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            middle_name=validated_data['middle_name'],
            birthdate=validated_data.get('birthdate', None),
            join_date=validated_data.get('join_date', None),
            gender=validated_data.get('gender', None),
            how_hear=validated_data.get('how_hear', None),

            # Misc
            is_ok_to_email=validated_data.get('is_ok_to_email', None),
            is_ok_to_text=validated_data.get('is_ok_to_text', None),
            created_from=self.context['created_from'],
            created_from_is_public=self.context['created_from_is_public'],

            # Contact Point
            area_served=validated_data.get('area_served', None),
            available_language=validated_data.get('available_language', None),
            contact_type=validated_data.get('contact_type', None),
            email=email,
            fax_number=fax_number,
            # 'hours_available', #TODO: IMPLEMENT.
            telephone=telephone,
            telephone_extension=validated_data.get('telephone_extension',
                                                   None),
            telephone_type_of=validated_data.get('telephone_type_of', None),
            other_telephone=other_telephone,
            other_telephone_extension=validated_data.get(
                'other_telephone_extension', None),
            other_telephone_type_of=validated_data.get(
                'other_telephone_type_of', None),

            # Postal Address
            address_country=validated_data.get('address_country', None),
            address_locality=validated_data.get('address_locality', None),
            address_region=validated_data.get('address_region', None),
            post_office_box_number=validated_data.get('post_office_box_number',
                                                      None),
            postal_code=validated_data.get('postal_code', None),
            street_address=validated_data.get('street_address', None),
            street_address_extra=validated_data.get('street_address_extra',
                                                    None),

            # Geo-coordinate
            elevation=validated_data.get('elevation', None),
            latitude=validated_data.get('latitude', None),
            longitude=validated_data.get('longitude', None),
            # 'location' #TODO: IMPLEMENT.
        )
        logger.info("Created partner.")

        #-----------------------------------
        # Create or update our Organization.
        #-----------------------------------
        organization_name = validated_data.get('organization_name', None)
        organization_type_of = validated_data.get('organization_type_of', None)
        organization_address_country = validated_data.get(
            'organization_address_country', None)
        organization_address_locality = validated_data.get(
            'organization_address_locality', None)
        organization_address_region = validated_data.get(
            'organization_address_region', None)
        organization_post_office_box_number = validated_data.get(
            'organization_post_office_box_number', None)
        organization_postal_code = validated_data.get(
            'organization_postal_code', None)
        organization_street_address = validated_data.get(
            'organization_street_address', None)
        organization_street_address_extra = validated_data.get(
            'organization_street_address_extra', None)

        if organization_name and organization_type_of:
            organization, created = Organization.objects.update_or_create(
                name=organization_name,
                type_of=organization_type_of,
                defaults={
                    'type_of': organization_type_of,
                    'name': organization_name,
                    'address_country': organization_address_country,
                    'address_locality': organization_address_locality,
                    'address_region': organization_address_region,
                    'post_office_box_number':
                    organization_post_office_box_number,
                    'postal_code': organization_postal_code,
                    'street_address': organization_street_address,
                    'street_address_extra': organization_street_address_extra,
                })
            if created:
                organization.owner = owner
                organization.save()
                logger.info("Created organization.")

            partner.organization = organization
            partner.save()
            logger.info("Attached created organization to partner.")

        #-----------------------------
        # Create our `Comment` object.
        #-----------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['created_by'],
                last_modified_by=self.context['created_by'],
                text=extra_comment,
                created_from=self.context['created_from'],
                created_from_is_public=self.context['created_from_is_public'])
            logger.info("Created comment.")

            PartnerComment.objects.create(
                about=partner,
                comment=comment,
            )
            logger.info("Attached comment to partner.")

        # Update validation data.
        # validated_data['comments'] = PartnerComment.objects.filter(partner=partner)
        validated_data['created_by'] = self.context['created_by']
        validated_data['last_modified_by'] = self.context['created_by']
        # validated_data['extra_comment'] = None
        validated_data['id'] = partner.id

        # Return our validated data.
        return validated_data
Esempio n. 4
0
class StaffRetrieveUpdateDestroySerializer(serializers.ModelSerializer):
    # owner = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
    given_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    last_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_region = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_locality = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    postal_code = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    street_address = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=Staff.objects.all()),

        ],
        required=False
    )
    personal_email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=Staff.objects.all()),

        ],
        required=False
    )

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=63,
        style={'input_type': 'password'},
        validators = [
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")
            ),
            EnhancedPasswordStrengthFieldValidator()
        ]
    )
    password_repeat = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=63,
        style={'input_type': 'password'}
    )
    is_active = serializers.BooleanField(
        write_only=True,
        required=True,
        error_messages={
            "invalid": _("Please pick either 'Yes' or 'No' choice.")
        }
    )

    # This field is used to assign the user to the group.
    account_type = serializers.CharField(
        write_only=True,
        allow_null=False,
        required=True
    )

    # # Attach with our foreign keys.
    # how_hear = serializers.PrimaryKeyRelatedField(
    #     many=False,
    #     required=True,
    #     allow_null=False,
    #     queryset=HowHearAboutUsItem.objects.all()
    # )

    # All comments are created by our `create` function and not by
    # # `django-rest-framework`.
    # comments = StaffCommentSerializer(many=True, read_only=True)
    #
    # # This is a field used in the `create` function if the user enters a
    # # comment. This field is *ONLY* to be used during the POST creation and
    # # will be blank during GET.
    # extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(allow_null=True, required=False)
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    emergency_contact_telephone = PhoneNumberField(allow_null=True, required=False)
    emergency_contact_alternative_telephone = PhoneNumberField(allow_null=True, required=False)

    # Meta Information.
    class Meta:
        model = Staff
        fields = (
            # Thing
            'id',
            'created',
            'last_modified',
            # 'owner',
            'description',
            'account_type',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',

            # Misc (Read/Write)
            'tags',
            'is_active',
            # # 'is_senior',
            # # 'is_support',
            # # 'job_info_read',
            # 'how_hear',
            #
            # # Misc (Read Only)
            # 'comments',
            #
            # # Misc (Write Only)
            'password',
            'password_repeat',
            # 'extra_comment',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'personal_email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX

            # Emergency Contact
            'emergency_contact_name',
            'emergency_contact_relationship',
            'emergency_contact_telephone',
            'emergency_contact_alternative_telephone'
        )

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            # 'comments'
            'tags',
        )
        return queryset

    def validate_account_type(self, value):
        """
        Include validation for valid choices.
        """
        account_type = int_or_none(value)
        if account_type is None:
            raise serializers.ValidationError("Please select a valid choice.")
        else:
            if account_type == FRONTLINE_GROUP_ID:
                return value

            last_modified_by = self.context['last_modified_by']
            if last_modified_by.is_management_or_executive_staff():
                return value
            raise serializers.ValidationError("You do not have permission to change the account type.")

    def validate_personal_email(self, value):
        """
        Include validation for valid choices.
        """
        if value is None or value == '':
            raise serializers.ValidationError("This field may not be blank.")
        return value

    @transaction.atomic
    def update(self, instance, validated_data):
        """
        Override this function to include extra functionality.
        """
        # For debugging purposes only.
        # print(validated_data)

        # Get our inputs.
        email = validated_data.get('email', instance.email)
        personal_email = validated_data.get('personal_email', None)

        #-------------------------------------
        # Bugfix: Created `SharedUser` object.
        #-------------------------------------
        if instance.owner is None:
            owner = SharedUser.objects.filter(email=email).first()
            if owner:
                instance.owner = owner
                instance.save()
                logger.info("BUGFIX: Attached existing shared user to staff.")
            else:
                instance.owner = SharedUser.objects.create(
                    first_name=validated_data['given_name'],
                    last_name=validated_data['last_name'],
                    email=email,
                    is_active=validated_data['is_active'],
                    franchise=self.context['franchise'],
                    was_email_activated=True
                )
                instance.save()
                logger.info("BUGFIX: Created shared user and attached to staff.")

        #---------------------------
        # Update `SharedUser` object.
        #---------------------------
        # Update the password if required.
        password = validated_data.get('password', None)
        if password:
            instance.owner.set_password(password)
            logger.info("Updated the password.")

        # Update the account.
        if email:
            instance.owner.email = email
            instance.owner.username = get_unique_username_from_email(email)
        instance.owner.first_name = validated_data.get('given_name', instance.owner.first_name)
        instance.owner.last_name = validated_data.get('last_name', instance.owner.last_name)
        instance.owner.is_active = validated_data.get('is_active', instance.owner.is_active)
        instance.owner.save()
        logger.info("Updated the shared user.")

        # Attach the user to the `group` group.
        account_type = validated_data.get('account_type', None)
        if account_type != "NaN":
            account_type = int(account_type)
            instance.owner.groups.set([account_type])
            logger.info("Updated the group membership.")

        #---------------------------
        # Update `Staff` object.
        #---------------------------
        # Person
        instance.description=validated_data.get('description', None)
        instance.given_name=validated_data.get('given_name', None)
        instance.last_name=validated_data.get('last_name', None)
        instance.middle_name=validated_data.get('middle_name', None)
        instance.birthdate=validated_data.get('birthdate', None)
        instance.join_date=validated_data.get('join_date', None)
        instance.gender=validated_data.get('gender', None)

        # Misc
        instance.hourly_salary_desired=validated_data.get('hourly_salary_desired', 0.00)
        instance.limit_special=validated_data.get('limit_special', None)
        instance.dues_date=validated_data.get('dues_date', None)
        instance.commercial_insurance_expiry_date=validated_data.get('commercial_insurance_expiry_date', None)
        instance.police_check=validated_data.get('police_check', None)
        instance.drivers_license_class=validated_data.get('drivers_license_class', None)
        # instance.how_hear=validated_data.get('how_hear', None)
        instance.last_modified_by = self.context['last_modified_by']
        instance.last_modified_from = self.context['last_modified_from']
        instance.last_modified_from_is_public = self.context['last_modified_from_is_public']
        # 'organizations', #TODO: IMPLEMENT.

        # Contact Point
        instance.area_served=validated_data.get('area_served', None)
        instance.available_language=validated_data.get('available_language', None)
        instance.contact_type=validated_data.get('contact_type', None)
        instance.email=email
        instance.personal_email=personal_email
        instance.fax_number=validated_data.get('fax_number', None)
        # 'hours_available', #TODO: IMPLEMENT.
        instance.telephone=validated_data.get('telephone', None)
        instance.telephone_extension=validated_data.get('telephone_extension', None)
        instance.telephone_type_of=validated_data.get('telephone_type_of', None)
        instance.other_telephone=validated_data.get('other_telephone', None)
        instance.other_telephone_extension=validated_data.get('other_telephone_extension', None)
        instance.other_telephone_type_of=validated_data.get('other_telephone_type_of', None)

        # Postal Address
        instance.address_country=validated_data.get('address_country', None)
        instance.address_locality=validated_data.get('address_locality', None)
        instance.address_region=validated_data.get('address_region', None)
        instance.post_office_box_number=validated_data.get('post_office_box_number', None)
        instance.postal_code=validated_data.get('postal_code', None)
        instance.street_address=validated_data.get('street_address', None)
        instance.street_address_extra=validated_data.get('street_address_extra', None)

        # Geo-coordinate
        instance.elevation=validated_data.get('elevation', None)
        instance.latitude=validated_data.get('latitude', None)
        instance.longitude=validated_data.get('longitude', None)
        # 'location' #TODO: IMPLEMENT.

        # Emergency contact.
        instance.emergency_contact_name=validated_data.get('emergency_contact_name', None)
        instance.emergency_contact_relationship=validated_data.get('emergency_contact_relationship', None)
        instance.emergency_contact_telephone=validated_data.get('emergency_contact_telephone', None)
        instance.emergency_contact_alternative_telephone=validated_data.get('emergency_contact_alternative_telephone', None)

        # Save our instance.
        instance.save()
        logger.info("Updated the staff member.")

        #------------------------
        # Set our `Tag` objects.
        #------------------------
        tags = validated_data.get('tags', None)
        if tags is not None:
            if len(tags) > 0:
                instance.tags.set(tags)

        #---------------------------
        # Attach our comment.
        #---------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['last_modified_by'],
                last_modified_by=self.context['last_modified_by'],
                text=extra_comment,
                created_from = self.context['last_modified_from'],
                created_from_is_public = self.context['last_modified_from_is_public']
            )
            staff_comment = StaffComment.objects.create(
                staff=instance,
                comment=comment,
            )

        #---------------------------
        # Update validation data.
        #---------------------------
        # validated_data['comments'] = StaffComment.objects.filter(staff=instance)
        validated_data['last_modified_by'] = self.context['last_modified_by']
        # validated_data['extra_comment'] = None

        # Return our validated data.
        return validated_data
Esempio n. 5
0
class StaffListCreateSerializer(serializers.ModelSerializer):
    # OVERRIDE THE MODEL FIELDS AND ENFORCE THE FOLLOWING CUSTOM VALIDATION RULES.
    given_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    last_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_region = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_locality = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    postal_code = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    street_address = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=SharedUser.objects.all()),

        ],
        required=True,
    )

    # All comments are created by our `create` function and not by
    # `django-rest-framework`.
    # comments = StaffCommentSerializer(many=True, read_only=True, allow_null=True)

    # This is a field used in the `create` function if the user enters a
    # comment. This field is *ONLY* to be used during the POST creation and
    # will be blank during GET.
    extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # This field is used to assign the user to the group.
    account_type = serializers.CharField(
        write_only=True,
        allow_null=False,
        required=True
    )

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(allow_null=True, required=False)
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    emergency_contact_telephone = PhoneNumberField(allow_null=True, required=False)
    emergency_contact_alternative_telephone = PhoneNumberField(allow_null=True, required=False)

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'},
        validators = [
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")
            ),
            EnhancedPasswordStrengthFieldValidator()
        ]
    )
    password_repeat = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'}
    )
    is_active = serializers.BooleanField(
        write_only=True,
        required=True,
        error_messages={
            "invalid": _("Please pick either 'Yes' or 'No' choice.")
        }
    )

    # Attach with our foreign keys.
    how_hear = serializers.PrimaryKeyRelatedField(
        many=False,
        required=True,
        allow_null=False,
        queryset=HowHearAboutUsItem.objects.all()
    )

    # Useful for determining if the user is active or not.
    state = serializers.IntegerField(read_only=True,source="owner.is_active")

    # Meta Information.
    class Meta:
        model = Staff
        fields = (
            # Thing
            'id',
            'created',
            'last_modified',
            'account_type',
            'description',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',

            # Misc (Read/Write)
            'tags',
            'is_active',
            'how_hear',
            'state',

            # # Misc (Read Only)
            # 'comments',

            # Misc (Write Only)
            'extra_comment',
            'password',
            'password_repeat',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'personal_email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX

            # Emergency Contact
            'emergency_contact_name',
            'emergency_contact_relationship',
            'emergency_contact_telephone',
            'emergency_contact_alternative_telephone'
        )

    def validate_telephone(self, value):
        """
        Include validation on no-blanks
        """
        if value is None:
            raise serializers.ValidationError("This field may not be blank.")
        return value

    def validate_account_type(self, value):
        """
        Include validation for valid choices.
        """
        account_type = int_or_none(value)
        if account_type is None:
            raise serializers.ValidationError("Please select a valid choice.")
        else:
            if account_type == FRONTLINE_GROUP_ID:
                return value

            created_by = self.context['created_by']
            if created_by.is_management_or_executive_staff():
                return value
            raise serializers.ValidationError("You do not have permission to change the account type.")

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            # 'comments'
            'tags',
        )
        return queryset

    @transaction.atomic
    def create(self, validated_data):
        """
        Override the `create` function to add extra functinality:

        - Create a `User` object in the public database.

        - Create a `SharedUser` object in the public database.

        - Create a `Staff` object in the tenant database.

        - If user has entered text in the 'extra_comment' field then we will
          a `Comment` object and attach it to the `Staff` object.

        - We will attach the staff user whom created this `Staff` object.
        """
        # Format our telephone(s)
        fax_number = validated_data.get('fax_number', None)
        if fax_number:
            fax_number = phonenumbers.parse(fax_number, "CA")
        telephone = validated_data.get('telephone', None)
        if telephone:
            telephone = phonenumbers.parse(telephone, "CA")
        other_telephone = validated_data.get('other_telephone', None)
        if other_telephone:
            other_telephone = phonenumbers.parse(other_telephone, "CA")

        validated_data['fax_number'] = fax_number
        validated_data['telephone'] = telephone
        validated_data['other_telephone'] = other_telephone

        # Extract our "email" field.
        email = validated_data.get('email', None)
        personal_email = validated_data.get('personal_email', None)

        #-------------------
        # Create our user.
        #-------------------

        owner = SharedUser.objects.create(
            first_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            email=email,
            is_active=validated_data['is_active'],
            franchise=self.context['franchise'],
            was_email_activated=True
        )
        logger.info("Created shared user.")

        # Attach the user to the `group` group.
        account_type = int_or_none(validated_data.get('account_type', None))
        if account_type:
            owner.groups.set([account_type])

        # Update the password.
        password = validated_data.get('password', None)
        owner.set_password(password)
        owner.save()

        #---------------------------------------------------
        # Create our `Staff` object in our tenant schema.
        #---------------------------------------------------

        # Create an "Staff".
        staff = Staff.objects.create(
            created_by=self.context['created_by'],
            last_modified_by=self.context['created_by'],
            description=validated_data.get('description', None),

            # Person
            given_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            middle_name=validated_data['middle_name'],
            birthdate=validated_data.get('birthdate', None),
            join_date=validated_data.get('join_date', None),
            gender=validated_data.get('gender', None),

            # Misc
            created_from = self.context['created_from'],
            created_from_is_public = self.context['created_from_is_public'],
            # . . .

            # Contact Point
            area_served=validated_data.get('area_served', None),
            available_language=validated_data.get('available_language', None),
            contact_type=validated_data.get('contact_type', None),
            email=email,
            personal_email=personal_email,
            fax_number=fax_number,
            # 'hours_available', #TODO: IMPLEMENT.
            telephone=telephone,
            telephone_extension=validated_data.get('telephone_extension', None),
            telephone_type_of=validated_data.get('telephone_type_of', None),
            other_telephone=other_telephone,
            other_telephone_extension=validated_data.get('other_telephone_extension', None),
            other_telephone_type_of=validated_data.get('other_telephone_type_of', None),

            # Postal Address
            address_country=validated_data.get('address_country', None),
            address_locality=validated_data.get('address_locality', None),
            address_region=validated_data.get('address_region', None),
            post_office_box_number=validated_data.get('post_office_box_number', None),
            postal_code=validated_data.get('postal_code', None),
            street_address=validated_data.get('street_address', None),
            street_address_extra=validated_data.get('street_address_extra', None),

            # Geo-coordinate
            elevation=validated_data.get('elevation', None),
            latitude=validated_data.get('latitude', None),
            longitude=validated_data.get('longitude', None),
            # 'location' #TODO: IMPLEMENT.

            # Emergency contact
            emergency_contact_name=validated_data.get('emergency_contact_name', None),
            emergency_contact_relationship=validated_data.get('emergency_contact_relationship', None),
            emergency_contact_telephone=validated_data.get('emergency_contact_telephone', None),
            emergency_contact_alternative_telephone=validated_data.get('emergency_contact_alternative_telephone', None),
        )
        logger.info("Created staff member.")

        # Update our staff again.
        staff.owner = owner
        staff.email = email
        staff.save()
        logger.info("Attached user object to staff member.")

        #------------------------
        # Set our `Tag` objects.
        #------------------------
        tags = validated_data.get('tags', None)
        if tags is not None:
            if len(tags) > 0:
                staff.tags.set(tags)

        #-----------------------------
        # Create our `Comment` object.
        #-----------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['created_by'],
                last_modified_by=self.context['created_by'],
                text=extra_comment,
                created_from = self.context['created_from'],
                created_from_is_public = self.context['created_from_is_public']
            )
            staff_comment = StaffComment.objects.create(
                about=staff,
                comment=comment,
            )

        # Update validation data.
        # validated_data['comments'] = StaffComment.objects.filter(staff=staff)
        validated_data['created_by'] = self.context['created_by']
        validated_data['last_modified_by'] = self.context['created_by']
        validated_data['extra_comment'] = None
        validated_data['id'] = staff.id

        # Return our validated data.
        return validated_data
Esempio n. 6
0
class AssociateListCreateSerializer(serializers.ModelSerializer):
    # OVERRIDE THE MODEL FIELDS AND ENFORCE THE FOLLOWING CUSTOM VALIDATION RULES.
    given_name = serializers.CharField(required=True,
                                       allow_blank=False,
                                       validators=[])
    last_name = serializers.CharField(required=True,
                                      allow_blank=False,
                                      validators=[])
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(required=True,
                                            allow_blank=False,
                                            validators=[])
    address_region = serializers.CharField(required=True,
                                           allow_blank=False,
                                           validators=[])
    address_locality = serializers.CharField(required=True,
                                             allow_blank=False,
                                             validators=[])
    postal_code = serializers.CharField(required=True,
                                        allow_blank=False,
                                        validators=[])
    street_address = serializers.CharField(required=True,
                                           allow_blank=False,
                                           validators=[])
    join_date = serializers.DateField(required=True, )

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[UniqueValidator(queryset=SharedUser.objects.all())],
        required=True,
    )

    # All comments are created by our `create` function and not by
    # `django-rest-framework`.
    # comments = AssociateCommentSerializer(many=True, read_only=True, allow_null=True)

    # This is a field used in the `create` function if the user enters a
    # comment. This field is *ONLY* to be used during the POST creation and
    # will be blank during GET.
    extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # # The skill_sets that this associate belongs to. We will return primary
    # # keys only. This field is read/write accessible.
    # skill_sets = serializers.PrimaryKeyRelatedField(many=True, queryset=SkillSet.objects.all(), allow_null=True)

    # assigned_skill_sets = SkillSetListCreateSerializer(many=True, read_only=True)

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(
        allow_null=False,
        required=True,
    )
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    emergency_contact_telephone = PhoneNumberField(allow_null=True,
                                                   required=False)
    emergency_contact_alternative_telephone = PhoneNumberField(allow_null=True,
                                                               required=False)

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'},
        validators=[
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")),
            EnhancedPasswordStrengthFieldValidator()
        ])
    password_repeat = serializers.CharField(write_only=True,
                                            required=True,
                                            allow_blank=False,
                                            max_length=63,
                                            style={'input_type': 'password'})

    is_active = serializers.BooleanField(
        write_only=True,
        required=True,
        error_messages={"invalid": "Please pick either 'Yes' or 'No' choice."})

    # Attach with our foreign keys.
    how_hear = serializers.PrimaryKeyRelatedField(
        many=False,
        required=True,
        allow_null=False,
        queryset=HowHearAboutUsItem.objects.all())

    # Useful for determining if the user is active or not.
    state = serializers.IntegerField(read_only=True, source="owner.is_active")

    # Meta Information.
    class Meta:
        model = Associate
        fields = (
            # Thing
            'id',
            'created',
            'last_modified',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',
            'description',
            'tax_id',

            # Misc (Read/Write)
            'is_active',
            'is_ok_to_email',
            'is_ok_to_text',
            'hourly_salary_desired',
            'limit_special',
            'dues_date',
            'commercial_insurance_expiry_date',
            'auto_insurance_expiry_date',
            'wsib_number',
            'wsib_insurance_date',
            'police_check',
            'drivers_license_class',
            'vehicle_types',  # many-to-many
            'how_hear',
            'how_hear_other',
            'skill_sets',  # many-to-many
            'tags',  # many-to-many
            'insurance_requirements',  # many-to-many

            # Misc (Read Only)
            # 'comments',
            'password',
            'password_repeat',
            'state',

            # # Misc (Write Only)
            'extra_comment',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX

            # Emergency Contact
            'emergency_contact_name',
            'emergency_contact_relationship',
            'emergency_contact_telephone',
            'emergency_contact_alternative_telephone')
        extra_kwargs = {
            "is_ok_to_email": {
                "error_messages": {
                    "invalid": _("Please pick either 'Yes' or 'No' choice.")
                }
            },
            "is_ok_to_text": {
                "error_messages": {
                    "invalid": _("Please pick either 'Yes' or 'No' choice.")
                }
            },
            "hourly_salary_desired": {
                "error_messages": {
                    "min_value":
                    _("Ensure this value is greater than or equal to 0."),
                    "invalid":
                    _("Please enter a value with no $, such as 20")
                }
            }
        }

    def validate_telephone(self, value):
        """
        Include validation on no-blanks
        """
        if value is None:
            raise serializers.ValidationError("This field may not be blank.")
        return value

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            'tags',
            'skill_sets',
            'vehicle_types'
            'comments',
            'insurance_requirements',
        )
        return queryset

    @transaction.atomic
    def create(self, validated_data):
        """
        Override the `create` function to add extra functinality:

        - Create a `User` object in the public database.

        - Create a `SharedUser` object in the public database.

        - Create a `Associate` object in the tenant database.

        - If user has entered text in the 'extra_comment' field then we will
          a `Comment` object and attach it to the `Associate` object.

        - We will attach the staff user whom created this `Associate` object.
        """
        # Format our telephone(s)
        fax_number = validated_data.get('fax_number', None)
        if fax_number:
            fax_number = phonenumbers.parse(fax_number, "CA")
        telephone = validated_data.get('telephone', None)
        if telephone:
            telephone = phonenumbers.parse(telephone, "CA")
        other_telephone = validated_data.get('other_telephone', None)
        if other_telephone:
            other_telephone = phonenumbers.parse(other_telephone, "CA")

        validated_data['fax_number'] = fax_number
        validated_data['telephone'] = telephone
        validated_data['other_telephone'] = other_telephone

        #-------------------
        # Create our user.
        #-------------------
        email = validated_data.get('email', None)  # Extract our "email" field.
        owner = SharedUser.objects.create(
            first_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            email=email,
            franchise=self.context['franchise'],
            was_email_activated=True,
            is_active=validated_data['is_active'],
        )

        # Attach the user to the `Associate` group.
        owner.groups.add(ASSOCIATE_GROUP_ID)

        # Update the password.
        password = validated_data.get('password', None)
        owner.set_password(password)
        owner.save()
        logger.info("Created shared user.")

        #---------------------------------------------------
        # Create our `Associate` object in our tenant schema.
        #---------------------------------------------------
        # Create an "Associate".
        associate = Associate.objects.create(
            owner=owner,
            created_by=self.context['created_by'],
            last_modified_by=self.context['created_by'],
            description=validated_data['description'],

            # Profile
            given_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            middle_name=validated_data['middle_name'],
            birthdate=validated_data.get('birthdate', None),
            join_date=validated_data.get('join_date', None),
            gender=validated_data.get('gender', None),
            tax_id=validated_data.get('tax_id', None),

            # Misc
            is_ok_to_email=validated_data.get('is_ok_to_email', None),
            is_ok_to_text=validated_data.get('is_ok_to_text', None),
            hourly_salary_desired=validated_data.get('hourly_salary_desired',
                                                     0.00),
            limit_special=validated_data.get('limit_special', None),
            dues_date=validated_data.get('dues_date', None),
            commercial_insurance_expiry_date=validated_data.get(
                'commercial_insurance_expiry_date', None),
            auto_insurance_expiry_date=validated_data.get(
                'auto_insurance_expiry_date', None),
            wsib_number=validated_data.get('wsib_number', None),
            wsib_insurance_date=validated_data.get('wsib_insurance_date',
                                                   None),
            police_check=validated_data.get('police_check', None),
            drivers_license_class=validated_data.get('drivers_license_class',
                                                     None),
            how_hear=validated_data.get('how_hear', None),
            how_hear_other=validated_data.get('how_hear_other', None),
            created_from=self.context['created_from'],
            created_from_is_public=self.context['created_from_is_public'],
            # 'organizations', #TODO: IMPLEMENT.

            # Contact Point
            area_served=validated_data.get('area_served', None),
            available_language=validated_data.get('available_language', None),
            contact_type=validated_data.get('contact_type', None),
            email=email,
            fax_number=fax_number,
            # 'hours_available', #TODO: IMPLEMENT.
            telephone=telephone,
            telephone_extension=validated_data.get('telephone_extension',
                                                   None),
            telephone_type_of=validated_data.get('telephone_type_of', None),
            other_telephone=other_telephone,
            other_telephone_extension=validated_data.get(
                'other_telephone_extension', None),
            other_telephone_type_of=validated_data.get(
                'other_telephone_type_of', None),

            # Postal Address
            address_country=validated_data.get('address_country', None),
            address_locality=validated_data.get('address_locality', None),
            address_region=validated_data.get('address_region', None),
            post_office_box_number=validated_data.get('post_office_box_number',
                                                      None),
            postal_code=validated_data.get('postal_code', None),
            street_address=validated_data.get('street_address', None),
            street_address_extra=validated_data.get('street_address_extra',
                                                    None),

            # Geo-coordinate
            elevation=validated_data.get('elevation', None),
            latitude=validated_data.get('latitude', None),
            longitude=validated_data.get('longitude', None),
            # 'location' #TODO: IMPLEMENT.

            # Emergency contact
            emergency_contact_name=validated_data.get('emergency_contact_name',
                                                      None),
            emergency_contact_relationship=validated_data.get(
                'emergency_contact_relationship', None),
            emergency_contact_telephone=validated_data.get(
                'emergency_contact_telephone', None),
            emergency_contact_alternative_telephone=validated_data.get(
                'emergency_contact_alternative_telephone', None),
        )
        logger.info("Created associate.")

        #-----------------------------
        # Set our `SkillSet` objects.
        #-----------------------------
        skill_sets = validated_data.get('skill_sets', None)
        if skill_sets is not None:
            if len(skill_sets) > 0:
                associate.skill_sets.set(skill_sets)
                logger.info("Set associate skill sets.")

        #-------------------------------
        # Set our `VehicleType` objects.
        #-------------------------------
        vehicle_types = validated_data.get('vehicle_types', None)
        if vehicle_types is not None:
            if len(vehicle_types) > 0:
                associate.vehicle_types.set(vehicle_types)
                logger.info("Set associate vehicle types.")

        #------------------------
        # Set our `Tag` objects.
        #------------------------
        tags = validated_data.get('tags', None)
        if tags is not None:
            if len(tags) > 0:
                associate.tags.set(tags)
                logger.info("Set associate tags.")

        #-----------------------------
        # Create our `Comment` object.
        #-----------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['created_by'],
                last_modified_by=self.context['created_by'],
                text=extra_comment,
                created_from=self.context['created_from'],
                created_from_is_public=self.context['created_from_is_public'])
            AssociateComment.objects.create(
                about=associate,
                comment=comment,
            )
            logger.info("Set associate comments.")

        #----------------------------------------
        # Set our `InsuranceRequirement` objects.
        #----------------------------------------
        insurance_requirements = validated_data.get('insurance_requirements',
                                                    None)
        if insurance_requirements is not None:
            if len(insurance_requirements) > 0:
                associate.insurance_requirements.set(insurance_requirements)
                logger.info("Set associate insurance requirements.")

        # Update validation data.
        # validated_data['comments'] = AssociateComment.objects.filter(associate=associate)
        validated_data['created_by'] = self.context['created_by']
        validated_data['last_modified_by'] = self.context['created_by']
        validated_data['extra_comment'] = None
        validated_data['id'] = associate.id
        # validated_data['assigned_skill_sets'] = associate.skill_sets.all()

        # Return our validated data.
        return validated_data
Esempio n. 7
0
class CustomerRetrieveUpdateDestroySerializer(serializers.ModelSerializer):
    # owner = serializers.PrimaryKeyRelatedField(many=False, read_only=True)
    given_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    last_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_region = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_locality = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    postal_code = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    street_address = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=Customer.objects.all()),

        ],
        required=False
    )

    # All comments are created by our `create` function and not by
    # `django-rest-framework`.
    # comments = CustomerCommentSerializer(many=True, read_only=True)

    # This is a field used in the `create` function if the user enters a
    # comment. This field is *ONLY* to be used during the POST creation and
    # will be blank during GET.
    extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(allow_null=True, required=False)
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=63,
        style={'input_type': 'password'},
        validators = [
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")
            ),
            EnhancedPasswordStrengthFieldValidator()
        ]
    )
    password_repeat = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=63,
        style={'input_type': 'password'}
    )

    # Attach with our foreign keys.
    how_hear = serializers.PrimaryKeyRelatedField(
        many=False,
        required=True,
        allow_null=False,
        queryset=HowHearAboutUsItem.objects.all()
    )

    # Generate the full name of the associate.
    full_name = serializers.SerializerMethodField()
    address = serializers.SerializerMethodField()
    address_url = serializers.SerializerMethodField()
    full_address = serializers.SerializerMethodField()
    e164_telephone = serializers.SerializerMethodField()
    created_by = serializers.SerializerMethodField()
    last_modified_by = serializers.SerializerMethodField()
    how_hear_pretty = serializers.SerializerMethodField()

    #
    # Fields used for mapping to organizations.
    #

    organization_name = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=False,
        allow_null=False,
        max_length=63,
        validators=[

        #     UniqueValidator(
        #         queryset=Organization.objects.all(),
        #     )
        ],
    )
    organization_type_of = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=True,
        max_length=63,
        validators=[]
    )
    organization_address_country = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_address_locality = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_address_region = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_post_office_box_number = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )
    organization_postal_code = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_street_address = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )
    organization_street_address_extra = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )

    class Meta:
        model = Customer
        fields = (
            # Thing
            'id',
            'created',
            'created_by',
            'last_modified',
            'last_modified_by',
            # 'owner',
            'description',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',

            # Misc (Read/Write)
            'is_ok_to_email',
            'is_ok_to_text',
            'is_senior',
            'is_support',
            'job_info_read',
            'type_of',
            'tags',
            'how_hear',
            'how_hear_other',

            # Misc (Read Only)
            'extra_comment',
            'full_name',
            'address',
            'address_url',
            'full_address',
            'e164_telephone',
            'how_hear_pretty',

            # Misc (Write Only)
            'password',
            'password_repeat',

            # Organization
            'organization_name',
            'organization_type_of',
            'organization_address_country',
            'organization_address_locality',
            'organization_address_region',
            'organization_post_office_box_number',
            'organization_postal_code',
            'organization_street_address',
            'organization_street_address_extra',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX
        )

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            'tags',
            'comments',
            'organization'
        )
        return queryset

    def validate(self, data):
        """
        Override the validator to provide additional custom validation based
        on our custom logic.

        1. If 'type_of' == Commercial then make sure 'email' was inputted.
        """
        # CASE 1 - Other reason
        if data.get('type_of', None) == COMMERCIAL_CUSTOMER_TYPE_OF_ID:
            email = data.get('email', None)
            if email is None:
                raise serializers.ValidationError(_("Please provide an email if client is commercial."))

        # Return our data.
        return data

    def get_full_name(self, obj):
        try:
            return str(obj)
        except Exception as e:
            return None

    def get_address(self, obj):
        try:
            return obj.get_postal_address_without_postal_code()
        except Exception as e:
            return None

    def get_address_url(self, obj):
        try:
            return obj.get_google_maps_url()
        except Exception as e:
            return None

    def get_full_address(self, obj):
        try:
            return obj.get_postal_address()
        except Exception as e:
            return None

    def get_created_by(self, obj):
        try:
            return str(obj.created_by)
        except Exception as e:
            return None

    def get_last_modified_by(self, obj):
        try:
            return str(obj.last_modified_by)
        except Exception as e:
            return None

    def get_e164_telephone(self, obj):
        """
        Converts the "PhoneNumber" object into a "E164" format.
        See: https://github.com/daviddrysdale/python-phonenumbers
        """
        try:
            if obj.telephone:
                return phonenumbers.format_number(obj.telephone, phonenumbers.PhoneNumberFormat.E164)
            else:
                return "-"
        except Exception as e:
            return None

    def get_how_hear_pretty(self, obj):
        try:
            return str(obj.how_hear)
        except Exception as e:
            return None

    def update(self, instance, validated_data):
        """
        Override this function to include extra functionality.
        """
        # Get our inputs.
        email = validated_data.get('email', instance.email)
        type_of_customer = validated_data.get('type_of', UNASSIGNED_CUSTOMER_TYPE_OF_ID)

        #-----------------------------------------------------------
        # Bugfix: Created `SharedUser` object if not created before.
        #-----------------------------------------------------------
        if instance.owner is None and email:
            owner = SharedUser.objects.filter(email=email).first()
            if owner:
                instance.owner = owner
                instance.save()
                logger.info("BUGFIX: Attached existing shared user to staff.")
            else:
                instance.owner = SharedUser.objects.create(
                    first_name=validated_data['given_name'],
                    last_name=validated_data['last_name'],
                    email=email,
                    is_active=True,
                    franchise=self.context['franchise'],
                    was_email_activated=True
                )
                instance.save()
                logger.info("BUGFIX: Created shared user and attached to staff.")

        #---------------------------
        # Update `SharedUser` object.
        #---------------------------
        if instance.owner:
            # Update details.
            instance.owner.first_name = validated_data.get('given_name', instance.owner.first_name)
            instance.owner.last_name = validated_data.get('last_name', instance.owner.last_name)

            if email:
                instance.owner.email = email
                instance.owner.username = get_unique_username_from_email(email)

            # Update the password.
            password = validated_data.get('password', None)
            instance.owner.set_password(password)

            # Save the model to the database.
            instance.owner.save()
            logger.info("Updated shared user.")

        #---------------------------
        # Update `Customer` object.
        #---------------------------
        # Update email instance.
        instance.description = validated_data.get('description', instance.description)
        if email:
            instance.email = email

        # Profile
        instance.given_name = validated_data.get('given_name', instance.given_name)
        instance.middle_name = validated_data.get('middle_name', instance.middle_name)
        instance.last_name = validated_data.get('last_name', instance.last_name)
        instance.last_modified_by = self.context['last_modified_by']
        instance.birthdate = validated_data.get('birthdate', instance.birthdate)
        instance.join_date = validated_data.get('join_date', instance.join_date)
        instance.gender = validated_data.get('gender', instance.gender)

        # Misc (Read/Write)
        instance.is_ok_to_email = validated_data.get('is_ok_to_email', instance.is_ok_to_email)
        instance.is_ok_to_text = validated_data.get('is_ok_to_text', instance.is_ok_to_text)
        instance.is_senior = validated_data.get('is_ok_to_text', instance.is_ok_to_text)
        instance.is_senior = validated_data.get('is_senior', instance.is_senior)
        instance.is_support = validated_data.get('is_support', instance.is_support)
        instance.job_info_read = validated_data.get('job_info_read', instance.job_info_read)
        instance.how_hear = validated_data.get('how_hear', instance.how_hear)
        instance.how_hear_other = validated_data.get('how_hear_other', instance.how_hear_other)
        instance.type_of=validated_data.get('type_of', instance.type_of)

        # # Misc (Read Only)
        instance.last_modified_by = self.context['last_modified_by']
        instance.last_modified_from = self.context['last_modified_from']
        instance.last_modified_from_is_public = self.context['last_modified_from_is_public']
        # 'organizations', #TODO: FIX

        # Contact Point
        instance.area_served = validated_data.get('area_served', instance.area_served)
        instance.available_language = validated_data.get('available_language', instance.available_language)
        instance.contact_type = validated_data.get('contact_type', instance.contact_type)
        instance.email = validated_data.get('email', instance.contact_type)
        instance.fax_number = validated_data.get('fax_number', instance.fax_number)
        # 'hours_available', #TODO: FIX
        instance.telephone=validated_data.get('telephone', None)
        instance.telephone_extension=validated_data.get('telephone_extension', None)
        instance.telephone_type_of=validated_data.get('telephone_type_of', None)
        instance.other_telephone=validated_data.get('other_telephone', None)
        instance.other_telephone_extension=validated_data.get('other_telephone_extension', None)
        instance.other_telephone_type_of=validated_data.get('other_telephone_type_of', None)

        # Postal Address
        instance.address_country = validated_data.get('address_country', instance.address_country)
        instance.address_locality = validated_data.get('address_locality', instance.address_locality)
        instance.address_region = validated_data.get('address_region', instance.address_region)
        instance.post_office_box_number = validated_data.get('post_office_box_number', instance.post_office_box_number)
        instance.postal_code = validated_data.get('postal_code', instance.postal_code)
        instance.street_address = validated_data.get('street_address', instance.street_address)
        instance.street_address_extra = validated_data.get('street_address_extra', instance.street_address_extra)

        # Geo-coordinate
        instance.elevation = validated_data.get('elevation', instance.elevation)
        instance.latitude = validated_data.get('latitude', instance.latitude)
        instance.longitude = validated_data.get('longitude', instance.longitude)
        # 'location' #TODO: FIX

        # Save
        instance.save()
        logger.info("Updated the customer.")

        #------------------------
        # Set our `Tag` objects.
        #------------------------
        tags = validated_data.get('tags', instance.tags)
        if tags is not None:
            if len(tags) > 0:
                instance.tags.set(tags)

        #---------------------------
        # Attach our comment.
        #---------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['last_modified_by'],
                last_modified_by=self.context['last_modified_by'],
                text=extra_comment,
                created_from = self.context['last_modified_from'],
                created_from_is_public = self.context['last_modified_from_is_public']
            )
            CustomerComment.objects.create(
                about=instance,
                comment=comment,
            )

        #----------------------------------------
        # Update or create `Organization` object.
        #----------------------------------------
        if type_of_customer == COMMERCIAL_CUSTOMER_TYPE_OF_ID:
            logger.info("Detected commercial customer...")

            organization_name = validated_data.get('organization_name', None)
            organization_type_of = validated_data.get('organization_type_of', None)
            organization_address_country = validated_data.get('organization_address_country', None)
            organization_address_locality = validated_data.get('organization_address_locality', None)
            organization_address_region = validated_data.get('organization_address_region', None)
            organization_post_office_box_number = validated_data.get('organization_post_office_box_number', None)
            organization_postal_code = validated_data.get('organization_postal_code', None)
            organization_street_address = validated_data.get('organization_street_address', None)
            organization_street_address_extra = validated_data.get('organization_street_address_extra', None)

            if organization_name and organization_type_of:
                organization, created = Organization.objects.update_or_create(
                    name=organization_name,
                    type_of=organization_type_of,
                    defaults={
                        'type_of': organization_type_of,
                        'name': organization_name,
                        'address_country': organization_address_country,
                        'address_locality': organization_address_locality,
                        'address_region': organization_address_region,
                        'post_office_box_number': organization_post_office_box_number,
                        'postal_code': organization_postal_code,
                        'street_address': organization_street_address,
                        'street_address_extra': organization_street_address_extra,
                    }
                )
                logger.info("Created organization.")
                if created:
                    logger.info("Created organization.")
                    organization.owner = instance.owner
                    organization.save()

                instance.organization = organization
                instance.save()
                logger.info("Attached created organization to customer.")

        #---------------------------
        # Update validation data.
        #---------------------------
        # validated_data['comments'] = CustomerComment.objects.filter(customer=instance)
        validated_data['last_modified_by'] = self.context['last_modified_by']
        validated_data['extra_comment'] = None

        # Return our validated data.
        return validated_data
Esempio n. 8
0
class CustomerListCreateSerializer(serializers.ModelSerializer):
    # OVERRIDE THE MODEL FIELDS AND ENFORCE THE FOLLOWING CUSTOM VALIDATION RULES.
    given_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    last_name = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    gender = serializers.CharField(
        required=True,
        allow_blank=False,
        allow_null=False,
    )
    address_country = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_region = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    address_locality = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    postal_code = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )
    street_address = serializers.CharField(
        required=True,
        allow_blank=False,
        validators=[]
    )

    # We are overriding the `email` field to include unique email validation.
    email = serializers.EmailField(
        validators=[
            UniqueValidator(queryset=SharedUser.objects.all()),

        ],
        required=False,
    )

    # All comments are created by our `create` function and not by
    # `django-rest-framework`.
    # comments = CustomerCommentSerializer(many=True, read_only=True, allow_null=True)

    # This is a field used in the `create` function if the user enters a
    # comment. This field is *ONLY* to be used during the POST creation and
    # will be blank during GET.
    extra_comment = serializers.CharField(write_only=True, allow_null=True)

    # Custom formatting of our telephone fields.
    fax_number = PhoneNumberField(allow_null=True, required=False)
    telephone = PhoneNumberField(allow_null=False, required=True,)
    other_telephone = PhoneNumberField(allow_null=True, required=False)

    # Attach with our foreign keys.
    how_hear = serializers.PrimaryKeyRelatedField(
        many=False,
        required=True,
        allow_null=False,
        queryset=HowHearAboutUsItem.objects.all()
    )

    # Add password adding.
    password = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'},
        validators = [
            MatchingDuelFieldsValidator(
                another_field='password_repeat',
                message=_("Inputted passwords fields do not match.")
            ),
            EnhancedPasswordStrengthFieldValidator()
        ]
    )
    password_repeat = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=False,
        max_length=63,
        style={'input_type': 'password'}
    )

    #
    # Fields used for mapping to organizations.
    #

    organization_name = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=False,
        allow_null=False,
        max_length=63,
        validators=[

        #     UniqueValidator(
        #         queryset=Organization.objects.all(),
        #     )
        ],
    )
    organization_type_of = serializers.CharField(
        write_only=True,
        required=True,
        allow_blank=True,
        max_length=63,
        validators=[]
    )
    organization_address_country = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_address_locality = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_address_region = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_post_office_box_number = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )
    organization_postal_code = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=127,
        validators=[]
    )
    organization_street_address = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )
    organization_street_address_extra = serializers.CharField(
        write_only=True,
        required=False,
        allow_blank=True,
        max_length=255,
        validators=[]
    )

    # Generate the full name of the associate.
    full_name = serializers.SerializerMethodField()
    address = serializers.SerializerMethodField()
    address_url = serializers.SerializerMethodField()
    full_address = serializers.SerializerMethodField()
    e164_telephone = serializers.SerializerMethodField()

    # Meta Information.
    class Meta:
        model = Customer
        fields = (
            # Thing
            'id',
            'created',
            'last_modified',
            # 'owner',
            'description',

            # Person
            'given_name',
            'middle_name',
            'last_name',
            'birthdate',
            'join_date',
            'gender',
            'nationality',

            # Misc (Read/Write)
            'is_ok_to_email',
            'is_ok_to_text',
            'is_senior',
            'is_support',
            'job_info_read',
            'type_of',
            'tags',
            'how_hear',
            'how_hear_other',

            # Misc (Read Only)
            # 'comments',
            'password',
            'password_repeat',
            'state',
            'full_name',
            'address',
            'address_url',
            'full_address',
            'e164_telephone',

            # Organization
            'organization_name',
            'organization_type_of',
            'organization_address_country',
            'organization_address_locality',
            'organization_address_region',
            'organization_post_office_box_number',
            'organization_postal_code',
            'organization_street_address',
            'organization_street_address_extra',

            # Misc (Write Only)
            'extra_comment',

            # Contact Point
            'area_served',
            'available_language',
            'contact_type',
            'email',
            'fax_number',
            # 'hours_available', #TODO: FIX
            'telephone',
            'telephone_extension',
            'telephone_type_of',
            'other_telephone',
            'other_telephone_extension',
            'other_telephone_type_of',

            # Postal Address
            'address_country',
            'address_locality',
            'address_region',
            'post_office_box_number',
            'postal_code',
            'street_address',
            'street_address_extra',

            # Geo-coordinate
            'elevation',
            'latitude',
            'longitude',
            # 'location' #TODO: FIX
        )
        extra_kwargs = {
            "is_ok_to_email": {
                "error_messages": {
                    "invalid": "Please pick either 'Yes' or 'No' choice."
                }
            },
            "is_ok_to_text": {
                "error_messages": {
                    "invalid": "Please pick either 'Yes' or 'No' choice."
                }
            }
        }

    def validate_telephone(self, value):
        """
        Include validation on no-blanks
        """
        if value is None:
            raise serializers.ValidationError("This field may not be blank.")
        return value

    def setup_eager_loading(cls, queryset):
        """ Perform necessary eager loading of data. """
        queryset = queryset.prefetch_related(
            'owner',
            'created_by',
            'last_modified_by',
            'tags',
            'comments'
        )
        return queryset

    def get_full_name(self, obj):
        try:
            return str(obj)
        except Exception as e:
            return None

    def get_address(self, obj):
        try:
            return obj.get_postal_address_without_postal_code()
        except Exception as e:
            return None

    def get_address_url(self, obj):
        try:
            return obj.get_google_maps_url()
        except Exception as e:
            return None

    def get_full_address(self, obj):
        try:
            return obj.get_postal_address()
        except Exception as e:
            return None

    def get_e164_telephone(self, obj):
        """
        Converts the "PhoneNumber" object into a "NATIONAL" format.
        See: https://github.com/daviddrysdale/python-phonenumbers
        """
        try:
            if obj.telephone:
                return phonenumbers.format_number(obj.telephone, phonenumbers.PhoneNumberFormat.E164)
            else:
                return "-"
        except Exception as e:
            return None

    def create(self, validated_data):
        """
        Override the `create` function to add extra functinality.
        """
        type_of_customer = validated_data.get('type_of', UNASSIGNED_CUSTOMER_TYPE_OF_ID)

        # Format our telephone(s)
        fax_number = validated_data.get('fax_number', None)
        if fax_number:
            fax_number = phonenumbers.parse(fax_number, "CA")
        telephone = validated_data.get('telephone', None)
        if telephone:
            telephone = phonenumbers.parse(telephone, "CA")
        other_telephone = validated_data.get('other_telephone', None)
        if other_telephone:
            other_telephone = phonenumbers.parse(other_telephone, "CA")

        #-------------------
        # Create our user.
        #-------------------
        # Extract our "email" field.
        email = validated_data.get('email', None)

        # If an email exists then
        owner = None
        if email:
            owner = SharedUser.objects.create(
                first_name=validated_data['given_name'],
                last_name=validated_data['last_name'],
                email=email,
                is_active=True,
                franchise=self.context['franchise'],
                was_email_activated=True
            )

            # Attach the user to the `Customer` group.
            owner.groups.add(CUSTOMER_GROUP_ID)

            # Update the password.
            password = validated_data.get('password', None)
            owner.set_password(password)
            owner.save()
            logger.info("Created shared user.")

        #---------------------------------------------------
        # Create our `Customer` object in our tenant schema.
        #---------------------------------------------------
        customer = Customer.objects.create(
            owner=owner,
            created_by=self.context['created_by'],
            last_modified_by=self.context['created_by'],
            description=validated_data.get('description', None),

            # Profile
            given_name=validated_data['given_name'],
            last_name=validated_data['last_name'],
            middle_name=validated_data['middle_name'],
            birthdate=validated_data.get('birthdate', None),
            join_date=validated_data.get('join_date', None),
            gender=validated_data.get('gender', None),

            # Misc
            is_senior=validated_data.get('is_senior', False),
            is_support=validated_data.get('is_support', False),
            job_info_read=validated_data.get('job_info_read', False),
            how_hear=validated_data.get('how_hear', 1),
            how_hear_other=validated_data.get('how_hear_other', "Not answered"),
            type_of=type_of_customer,
            created_from = self.context['created_from'],
            created_from_is_public = self.context['created_from_is_public'],

            # Contact Point
            email=email,
            area_served=validated_data.get('area_served', None),
            available_language=validated_data.get('available_language', None),
            contact_type=validated_data.get('contact_type', None),
            fax_number=fax_number,
            # 'hours_available', #TODO: IMPLEMENT.
            telephone=telephone,
            telephone_extension=validated_data.get('telephone_extension', None),
            telephone_type_of=validated_data.get('telephone_type_of', None),
            other_telephone=other_telephone,
            other_telephone_extension=validated_data.get('other_telephone_extension', None),
            other_telephone_type_of=validated_data.get('other_telephone_type_of', None),

            # Postal Address
            address_country=validated_data.get('address_country', None),
            address_locality=validated_data.get('address_locality', None),
            address_region=validated_data.get('address_region', None),
            post_office_box_number=validated_data.get('post_office_box_number', None),
            postal_code=validated_data.get('postal_code', None),
            street_address=validated_data.get('street_address', None),
            street_address_extra=validated_data.get('street_address_extra', None),

            # Geo-coordinate
            elevation=validated_data.get('elevation', None),
            latitude=validated_data.get('latitude', None),
            longitude=validated_data.get('longitude', None),
            # 'location' #TODO: IMPLEMENT.
        )
        logger.info("Created customer.")

        #-----------------------------------
        # Create or update our Organization.
        #-----------------------------------
        type_of_customer = validated_data.get('type_of', UNASSIGNED_CUSTOMER_TYPE_OF_ID)
        if type_of_customer == COMMERCIAL_CUSTOMER_TYPE_OF_ID:
            logger.info("Detected commercial customer...")
            organization_name = validated_data.get('organization_name', None)
            organization_type_of = validated_data.get('organization_type_of', None)
            organization_address_country = validated_data.get('organization_address_country', None)
            organization_address_locality = validated_data.get('organization_address_locality', None)
            organization_address_region = validated_data.get('organization_address_region', None)
            organization_post_office_box_number = validated_data.get('organization_post_office_box_number', None)
            organization_postal_code = validated_data.get('organization_postal_code', None)
            organization_street_address = validated_data.get('organization_street_address', None)
            organization_street_address_extra = validated_data.get('organization_street_address_extra', None)

            if organization_name and organization_type_of:
                organization, created = Organization.objects.update_or_create(
                    name=organization_name,
                    type_of=organization_type_of,
                    defaults={
                        'type_of': organization_type_of,
                        'name': organization_name,
                        'address_country': organization_address_country,
                        'address_locality': organization_address_locality,
                        'address_region': organization_address_region,
                        'post_office_box_number': organization_post_office_box_number,
                        'postal_code': organization_postal_code,
                        'street_address': organization_street_address,
                        'street_address_extra': organization_street_address_extra,
                    }
                )
                logger.info("Created organization.")
                if created:
                    logger.info("Created organization.")
                    organization.owner = owner
                    organization.save()

                customer.organization = organization # DEPRECATED
                customer.organization_name = validated_data.get('organization_name', None)
                customer.organization_type_of = validated_data.get('organization_type_of', None)
                customer.save()
                logger.info("Attached created organization to customer.")

        #------------------------
        # Set our `Tag` objects.
        #------------------------
        tags = validated_data.get('tags', None)
        if tags is not None:
            if len(tags) > 0:
                customer.tags.set(tags)

        #-----------------------------
        # Create our `Comment` object.
        #-----------------------------
        extra_comment = validated_data.get('extra_comment', None)
        if extra_comment is not None:
            comment = Comment.objects.create(
                created_by=self.context['created_by'],
                last_modified_by=self.context['created_by'],
                text=extra_comment,
                created_from = self.context['created_from'],
                created_from_is_public = self.context['created_from_is_public']
            )
            CustomerComment.objects.create(
                about=customer,
                comment=comment,
            )

        # Update validation data.
        # validated_data['comments'] = CustomerComment.objects.filter(customer=customer)
        validated_data['created_by'] = self.context['created_by']
        validated_data['last_modified_by'] = self.context['created_by']
        validated_data['extra_comment'] = None
        validated_data['telephone'] = telephone
        validated_data['fax_number'] = fax_number
        validated_data['other_telephone'] = other_telephone
        validated_data['id'] = customer.id

        # Return our validated data.
        return validated_data