class ActivitySheetItemListCreateSerializer(serializers.ModelSerializer): # text = serializers.CharField( # required=True, # allow_blank=False, # allow_null=False, # validators=[] # ) associate_full_name = serializers.SerializerMethodField() associate_telephone = PhoneNumberField(read_only=True, source="associate.telephone") associate_e164_telephone = serializers.SerializerMethodField() associate_email = serializers.EmailField(read_only=True, source="associate.email") pretty_state = serializers.CharField(read_only=True, source="get_pretty_state") class Meta: model = ActivitySheetItem fields = ( 'id', 'job', 'ongoing_job', 'associate', 'associate_full_name', 'associate_telephone', 'associate_e164_telephone', 'associate_email', 'comment', 'state', 'pretty_state', 'created_at', 'created_by', ) def get_associate_full_name(self, obj): try: if obj.associate: return str(obj.associate) except Exception as e: pass return None def get_associate_e164_telephone(self, obj): """ Converts the "PhoneNumber" object into a "NATIONAL" format. See: https://github.com/daviddrysdale/python-phonenumbers """ try: if obj.associate.telephone: return phonenumbers.format_number( obj.associate.telephone, phonenumbers.PhoneNumberFormat.E164) else: return "-" except Exception as e: print(e) return None
class AssociateRetrieveUpdateDestroySerializer(serializers.ModelSerializer): 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=Associate.objects.all()), ], required=True, allow_blank=False, ) # All comments are created by our `create` function and not by # `django-rest-framework`. # comments = AssociateCommentSerializer(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) # 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) insurance_requirements = serializers.PrimaryKeyRelatedField( many=True, queryset=InsuranceRequirement.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() 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) is_active = serializers.BooleanField( write_only=True, required=True, ) join_date = serializers.DateField(required=True, ) # Attach with our foreign keys. how_hear = serializers.PrimaryKeyRelatedField( many=False, required=True, allow_null=False, queryset=HowHearAboutUsItem.objects.all()) class Meta: model = Associate fields = ( # Thing 'id', 'created', 'last_modified', 'description', # 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', # 'assigned_skill_sets', # 'organizations', #TODO: FIX # # 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 setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related('owner', 'created_by', 'last_modified_by', 'skill_sets', 'tags', 'vehicle_types' 'comments', 'insurance_requirements') return queryset @transaction.atomic def update(self, instance, validated_data): """ Override this function to include extra functionality. """ # For debugging purposes only. # logger.info(validated_data) # Get our inputs. email = validated_data.get('email', instance.email) skill_sets = validated_data.get('skill_sets', None) vehicle_types = validated_data.get('vehicle_types', None) insurance_requirements = validated_data.get('insurance_requirements', None) # Update telephone numbers. fax_number = validated_data.get('fax_number', instance.fax_number) if fax_number is not None: validated_data['fax_number'] = phonenumbers.parse(fax_number, "CA") telephone = validated_data.get('telephone', instance.telephone) if telephone is not None: validated_data['telephone'] = phonenumbers.parse(telephone, "CA") other_telephone = validated_data.get('other_telephone', instance.other_telephone) if other_telephone is not None: validated_data['other_telephone'] = phonenumbers.parse( other_telephone, "CA") #--------------------------- # Update `SharedUser` object. #--------------------------- instance.owner, created = SharedUser.objects.update_or_create( email=email, defaults={ 'email': email, 'first_name': validated_data.get('given_name', instance.given_name), 'last_name': validated_data.get('last_name', instance.last_name), 'is_active': validated_data.get('is_active', False) }) logger.info("Updated shared user.") # Update the password. password = validated_data.get('password', None) if password: instance.owner.set_password(password) # Save the model. instance.owner.save() logger.info("Password was updated.") #--------------------------- # Update `Associate` object. #--------------------------- instance.email = email # Profile instance.given_name = validated_data.get('given_name', instance.given_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.middle_name = validated_data.get('middle_name', instance.middle_name) 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) instance.description = validated_data.get('description', instance.description) instance.tax_id = validated_data.get('tax_id', instance.tax_id) # Misc 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.hourly_salary_desired = validated_data.get( 'hourly_salary_desired', instance.hourly_salary_desired) instance.limit_special = validated_data.get('limit_special', instance.limit_special) instance.dues_date = validated_data.get('dues_date', instance.dues_date) instance.commercial_insurance_expiry_date = validated_data.get( 'commercial_insurance_expiry_date', instance.commercial_insurance_expiry_date) instance.auto_insurance_expiry_date = validated_data.get( 'auto_insurance_expiry_date', instance.auto_insurance_expiry_date) instance.wsib_insurance_date = validated_data.get( 'wsib_insurance_date', instance.wsib_insurance_date) instance.wsib_number = validated_data.get('wsib_number', instance.wsib_number) instance.police_check = validated_data.get('police_check', instance.police_check) instance.drivers_license_class = validated_data.get( 'drivers_license_class', instance.drivers_license_class) 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.last_modified_from = self.context['last_modified_from'] instance.last_modified_from_is_public = self.context[ 'last_modified_from_is_public'] instance.last_modified_by = self.context['last_modified_by'] # 'organizations', #TODO: IMPLEMENT. # 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.fax_number = validated_data.get('fax_number', instance.fax_number) # 'hours_available', #TODO: IMPLEMENT. instance.telephone = validated_data.get('telephone', instance.telephone) instance.telephone_extension = validated_data.get( 'telephone_extension', instance.telephone_extension) instance.telephone_type_of = validated_data.get( 'telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) instance.other_telephone = validated_data.get('other_telephone', instance.other_telephone) instance.other_telephone_extension = validated_data.get( 'other_telephone_extension', instance.other_telephone_extension) instance.other_telephone_type_of = validated_data.get( 'other_telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) # 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: IMPLEMENT. # Emergency contact. instance.emergency_contact_name = validated_data.get( 'emergency_contact_name', instance.emergency_contact_name) instance.emergency_contact_relationship = validated_data.get( 'emergency_contact_relationship', instance.emergency_contact_relationship) instance.emergency_contact_telephone = validated_data.get( 'emergency_contact_telephone', instance.emergency_contact_telephone) instance.emergency_contact_alternative_telephone = validated_data.get( 'emergency_contact_alternative_telephone', instance.emergency_contact_alternative_telephone) # Save our instance. instance.save() logger.info("Updated the associate.") #----------------------------- # Set our `SkillSet` objects. #----------------------------- if skill_sets is not None: if len(skill_sets) > 0: instance.skill_sets.set(skill_sets) logger.info("Set associate skill sets.") #------------------------------- # Set our `VehicleType` objects. #------------------------------- if vehicle_types is not None: if len(vehicle_types) > 0: instance.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: instance.tags.set(tags) logger.info("Set associate 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']) AssociateComment.objects.create( about=instance, comment=comment, ) logger.info("Set associate comments.") #---------------------------------------- # Set our `InsuranceRequirement` objects. #---------------------------------------- if insurance_requirements is not None: if len(insurance_requirements) > 0: instance.insurance_requirements.set(insurance_requirements) logger.info("Set associate insurance requirements.") #--------------------------- # Update validation data. #--------------------------- # validated_data['comments'] = AssociateComment.objects.filter(associate=instance) validated_data['last_modified_by'] = self.context['last_modified_by'] # validated_data['extra_comment'] = None # validated_data['assigned_skill_sets'] = instance.skill_sets.all() # Return our validated data. return validated_data
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
class CustomerContactUpdateSerializer(serializers.ModelSerializer): organization_name = serializers.CharField( required=False, allow_blank=True, validators=[ UniqueValidator(queryset=Customer.objects.all()), ], ) organization_type_of = serializers.IntegerField(required=False, ) given_name = serializers.CharField(required=True, allow_blank=False, validators=[]) last_name = 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, allow_null=True, allow_blank=True, ) # Custom formatting of our telephone fields. primary_phone = PhoneNumberField(allow_null=False, required=True, source="telephone") primary_phone_type_of = serializers.IntegerField( required=True, validators=[], source="telephone_type_of") secondary_phone = PhoneNumberField(allow_null=True, required=False, source="other_telephone") secondary_phone_type_of = serializers.IntegerField( required=False, validators=[], source="other_telephone_type_of") class Meta: model = Customer fields = ( 'organization_name', 'organization_type_of', 'given_name', 'last_name', 'email', 'primary_phone', 'primary_phone_type_of', 'secondary_phone', 'secondary_phone_type_of', 'is_ok_to_email', 'is_ok_to_text', ) 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 get_organization_name(self, data): if data.get('type_of', None) == COMMERCIAL_CUSTOMER_TYPE_OF_ID: organization_name = data.get('organization_name', None) if organization_name is None: raise serializers.ValidationError( _("Please provide the organization name.")) return data def get_organization_type_of(self, data): if data.get('type_of', None) == COMMERCIAL_CUSTOMER_TYPE_OF_ID: organization_type_of = data.get('organization_type_of', None) if organization_type_of is None: raise serializers.ValidationError( _("Please provide the organization type of.")) return data 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 update(self, instance, validated_data): """ Override this function to include extra functionality. """ # Get our inputs. email = validated_data.get('email', instance.email) #----------------------------------------------------------- # 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. #--------------------------- 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.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.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'] instance.organization_name = validated_data.get( 'organization_name', instance.organization_name) instance.organization_type_of = validated_data.get( 'organization_type_of', instance.organization_type_of) instance.email = validated_data.get('email', instance.contact_type) 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) instance.save() logger.info("Updated the customer.") return instance
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
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
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
class StaffContactUpdateSerializer(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=[]) # We are overriding the `email` field to include unique email validation. work_email = serializers.EmailField(validators=[ UniqueValidator(queryset=Staff.objects.all()), ], required=False, source="email") personal_email = serializers.EmailField(validators=[ UniqueValidator(queryset=Staff.objects.all()), ], required=False) # Custom formatting of our telephone fields. primary_phone = PhoneNumberField(allow_null=False, required=True, source="telephone") primary_phone_type_of = serializers.IntegerField( required=True, validators=[], source="telephone_type_of") secondary_phone = PhoneNumberField(allow_null=True, required=False, source="other_telephone") secondary_phone_type_of = serializers.IntegerField( required=False, validators=[], source="other_telephone_type_of") # Meta Information. class Meta: model = Staff fields = ( 'given_name', 'last_name', 'primary_phone', 'primary_phone_type_of', 'secondary_phone', 'secondary_phone_type_of', 'work_email', 'personal_email', ) 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_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 def update(self, instance, validated_data): """ Override this function to include extra functionality. """ # # For debugging purposes only. # print(validated_data) # Get our inputs. work_email = validated_data.get('work_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=work_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=work_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. #--------------------------- # Update the account. if work_email: instance.owner.email = work_email instance.owner.username = get_unique_username_from_email( work_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.save() logger.info("Updated the shared user.") #--------------------------- # Update `Staff` object. #--------------------------- # Person 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) # Misc 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'] # 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 = work_email instance.personal_email = personal_email # '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', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) # Save our instance. instance.save() logger.info("Updated the staff member.") # Return our validated data. return instance
class OngoingWorkOrderRetrieveSerializer(serializers.ModelSerializer): customer = serializers.PrimaryKeyRelatedField(many=False, read_only=True) associate = serializers.PrimaryKeyRelatedField(many=False, read_only=True) associate_full_name = serializers.SerializerMethodField() associate_telephone = PhoneNumberField(read_only=True, source="associate.telephone") associate_telephone_type_of = serializers.IntegerField(read_only=True, source="associate.telephone_type_of") associate_pretty_telephone_type_of = serializers.CharField(read_only=True, source="associate.get_pretty_telephone_type_of") associate_other_telephone = PhoneNumberField(read_only=True, source="associate.other_telephone") associate_other_telephone_type_of = serializers.IntegerField(read_only=True, source="associate.other_telephone_type_of") associate_pretty_other_telephone_type_of = serializers.CharField(read_only=True, source="associate.get_pretty_other_telephone_type_of") customer_full_name = serializers.SerializerMethodField() customer_telephone = PhoneNumberField(read_only=True, source="customer.telephone") customer_telephone_type_of = serializers.IntegerField(read_only=True, source="customer.telephone_type_of") customer_pretty_telephone_type_of = serializers.CharField(read_only=True, source="customer.get_pretty_telephone_type_of") customer_other_telephone = PhoneNumberField(read_only=True, source="customer.other_telephone") customer_other_telephone_type_of = serializers.IntegerField(read_only=True, source="customer.other_telephone_type_of") customer_pretty_other_telephone_type_of = serializers.CharField(read_only=True, source="customer.get_pretty_other_telephone_type_of") pretty_status = serializers.CharField(read_only=True, source="get_pretty_status") pretty_type_of = serializers.CharField(read_only=True, source="get_pretty_type_of") class Meta: model = OngoingWorkOrder fields = ( # Read only fields. 'id', # Read Only fields. 'associate_full_name', 'associate_telephone', 'associate_telephone_type_of', 'associate_pretty_telephone_type_of', 'associate_other_telephone', 'associate_other_telephone_type_of', 'associate_pretty_other_telephone_type_of', 'customer_full_name', 'customer_telephone', 'customer_telephone_type_of', 'customer_pretty_telephone_type_of', 'customer_other_telephone', 'customer_other_telephone_type_of', 'customer_pretty_other_telephone_type_of', 'pretty_status', 'pretty_type_of', 'associate', 'customer', # Read / write fields. 'state' ) def get_associate_full_name(self, obj): try: if obj.associate: return str(obj.associate) except Exception as e: pass return None def get_customer_full_name(self, obj): try: if obj.customer: return str(obj.customer) except Exception as e: pass return None # def get_pretty_skill_sets(self, obj): # try: # s = SkillSetListCreateSerializer(obj.skill_sets.all(), many=True) # return s.data # 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
class WorkOrderRetrieveUpdateDestroySerializer(serializers.ModelSerializer): assigned_skill_sets = SkillSetListCreateSerializer(many=True, read_only=True) associate_first_name = serializers.ReadOnlyField(source='associate.owner.first_name') associate_last_name = serializers.ReadOnlyField(source='associate.owner.last_name') customer_first_name = serializers.ReadOnlyField(source='customer.owner.first_name') customer_last_name = serializers.ReadOnlyField(source='customer.owner.last_name') # created_by = serializers.ReadOnlyField() # last_modified_by = serializers.ReadOnlyField() tags = serializers.PrimaryKeyRelatedField(many=True, queryset=Tag.objects.all(), 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) invoice_ids = serializers.CharField(required=False, allow_null=True) assignment_date = serializers.DateField(required=False, allow_null=True) completion_date = serializers.DateField(required=False, allow_null=True) start_date = serializers.DateField(required=False, allow_null=True) invoice_service_fee_payment_date = serializers.DateField(required=False, allow_null=True) invoice_date = serializers.DateField(required=False, allow_null=True) associate_full_name = serializers.SerializerMethodField() associate_telephone = PhoneNumberField(read_only=True, source="associate.telephone") associate_telephone_type_of = serializers.IntegerField(read_only=True, source="associate.telephone_type_of") associate_pretty_telephone_type_of = serializers.CharField(read_only=True, source="associate.get_pretty_telephone_type_of") associate_other_telephone = PhoneNumberField(read_only=True, source="associate.other_telephone") associate_other_telephone_type_of = serializers.IntegerField(read_only=True, source="associate.other_telephone_type_of") associate_pretty_other_telephone_type_of = serializers.CharField(read_only=True, source="associate.get_pretty_other_telephone_type_of") associate_tax_id = serializers.ReadOnlyField(source='associate.tax_id') associate_service_fee = serializers.IntegerField(source='associate.service_fee.id', read_only=True,) associate_service_fee_label = serializers.CharField(source='associate.service_fee.title', read_only=True,) customer_address = serializers.SerializerMethodField() customer_email = serializers.EmailField(read_only=True, source="associate.email") customer_full_name = serializers.SerializerMethodField() customer_telephone = PhoneNumberField(read_only=True, source="customer.telephone") customer_telephone_type_of = serializers.IntegerField(read_only=True, source="customer.telephone_type_of") customer_pretty_telephone_type_of = serializers.CharField(read_only=True, source="customer.get_pretty_telephone_type_of") customer_other_telephone = PhoneNumberField(read_only=True, source="customer.other_telephone") customer_other_telephone_type_of = serializers.IntegerField(read_only=True, source="customer.other_telephone_type_of") customer_pretty_other_telephone_type_of = serializers.CharField(read_only=True, source="customer.get_pretty_other_telephone_type_of") pretty_status = serializers.CharField(read_only=True, source="get_pretty_status") pretty_type_of = serializers.CharField(read_only=True, source="get_pretty_type_of") pretty_skill_sets = serializers.SerializerMethodField() pretty_tags = serializers.SerializerMethodField() pretty_invoice_service_fee = serializers.SerializerMethodField() latest_pending_task = serializers.ReadOnlyField(source="latest_pending_task.id") latest_pending_task_type_of = serializers.SerializerMethodField() # ReadOnlyField(source="latest_pending_task.type_of") pretty_latest_pending_task = serializers.SerializerMethodField() created_at = serializers.DateTimeField(read_only=True, source="created") created_by = serializers.SerializerMethodField() last_modified_at = serializers.DateTimeField(read_only=True, source="last_modified") last_modified_by = serializers.SerializerMethodField() was_survey_conducted = serializers.BooleanField(read_only=True) no_survey_conducted_reason = serializers.IntegerField(read_only=True) no_survey_conducted_reason_other =serializers.CharField(read_only=True) score = serializers.FloatField(read_only=True) was_job_satisfactory = serializers.BooleanField(read_only=True) was_job_finished_on_time_and_on_budget = serializers.BooleanField(read_only=True) was_associate_punctual = serializers.BooleanField(read_only=True) was_associate_professional = serializers.BooleanField(read_only=True) would_customer_refer_our_organization = serializers.BooleanField(read_only=True) cloned_from = serializers.IntegerField(read_only=True, allow_null=False, source="cloned_from.id") invoice_id = serializers.IntegerField(read_only=True, allow_null=False, source="invoice.order.id") invoice_paid_to = serializers.IntegerField(read_only=True,) invoice_deposit_amount = serializers.CharField(read_only=True, source="invoice_deposit_amount.amount") invoice_sub_total_amount = serializers.CharField(read_only=True, source="invoice_sub_total_amount.amount") closing_reason = serializers.IntegerField(read_only=True,) closing_reason_other = serializers.CharField(read_only=True, allow_blank=False, allow_null=False,) closing_reason_comment = serializers.CharField(read_only=True, allow_blank=False, allow_null=False,) class Meta: model = WorkOrder fields = ( # Read only field. 'id', # 'comments', 'closing_reason', 'closing_reason_comment', 'closing_reason_other', 'assigned_skill_sets', 'associate_first_name', 'associate_last_name', 'customer_first_name', 'customer_last_name', 'tags', # Write only fields. 'extra_comment', # Read or write fields. 'assignment_date', 'associate', 'completion_date', 'customer', 'hours', 'is_home_support_service', # 'created_by', # 'last_modified_by', 'skill_sets', 'description', 'start_date', 'invoice_service_fee', 'invoice_ids', 'invoice_service_fee_payment_date', 'invoice_date', 'invoice_quote_amount', 'invoice_labour_amount', 'invoice_material_amount', 'invoice_other_costs_amount', 'invoice_quoted_labour_amount', 'invoice_quoted_material_amount', 'invoice_quoted_other_costs_amount', 'invoice_total_quote_amount', 'invoice_sub_total_amount', 'invoice_tax_amount', 'invoice_deposit_amount', 'invoice_total_amount', 'invoice_amount_due', 'invoice_service_fee_amount', 'invoice_actual_service_fee_amount_paid', 'state', 'invoice_balance_owing_amount', 'visits', 'cloned_from', 'invoice_id', # Read Only fields. 'associate_full_name', 'associate_telephone', 'associate_telephone_type_of', 'associate_pretty_telephone_type_of', 'associate_other_telephone', 'associate_other_telephone_type_of', 'associate_pretty_other_telephone_type_of', 'associate_tax_id', 'associate_service_fee_label', 'customer_address', 'associate_service_fee', 'customer_email', 'customer_full_name', 'customer_telephone', 'customer_telephone_type_of', 'customer_pretty_telephone_type_of', 'customer_other_telephone', 'customer_other_telephone_type_of', 'customer_pretty_other_telephone_type_of', 'pretty_status', 'pretty_type_of', 'pretty_skill_sets', 'pretty_tags', 'pretty_invoice_service_fee', 'pretty_latest_pending_task', 'latest_pending_task', 'latest_pending_task_type_of', 'created_at', 'created_by', 'last_modified_at', 'last_modified_by', 'was_survey_conducted', 'no_survey_conducted_reason', 'no_survey_conducted_reason_other', 'score', 'was_job_satisfactory', 'was_job_finished_on_time_and_on_budget', 'was_associate_punctual', 'was_associate_professional', 'would_customer_refer_our_organization', 'invoice_paid_to', ) def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related( 'associate', 'tags', 'created_by', 'customer', 'comments', 'last_modified_by', 'skill_sets', 'invoice_service_fee' ) return queryset def get_associate_full_name(self, obj): try: if obj.associate: return obj.associate.get_pretty_name() except Exception as e: pass return None def get_customer_full_name(self, obj): try: if obj.customer: return obj.customer.get_pretty_name() except Exception as e: pass return None def get_customer_address(self, obj): try: return obj.customer.get_postal_address() except Exception as e: return None def get_pretty_skill_sets(self, obj): try: s = SkillSetListCreateSerializer(obj.skill_sets.all(), many=True) return s.data 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_latest_pending_task_type_of(self, obj): try: if obj.latest_pending_task.type_of == FOLLOW_UP_CUSTOMER_SURVEY_TASK_ITEM_TYPE_OF_ID: return FOLLOW_UP_DID_CUSTOMER_REVIEW_ASSOCIATE_AFTER_JOB_TASK_ITEM_TYPE_OF_ID return obj.latest_pending_task.type_of except Exception as e: return None def get_pretty_latest_pending_task(self, obj): try: return str(obj.latest_pending_task) except Exception as e: return None def validate_invoice_service_fee_payment_date(self, value): """ Include validation on no-blanks if the state is set to be changed to ``completed_and_paid`` state of the work order. """ state = self.context['state'] if state: if state == WORK_ORDER_STATE.COMPLETED_AND_PAID: if value is None: raise serializers.ValidationError("This field may not be blank when submitting a payment status.") return value def validate_invoice_date(self, value): """ Include validation on no-blanks """ if value is None: raise serializers.ValidationError("This field may not be blank.") return value def get_pretty_tags(self, obj): try: s = TagListCreateSerializer(obj.tags.all(), many=True) return s.data except Exception as e: return None def get_pretty_invoice_service_fee(self, obj): try: return obj.invoice_service_fee.title except Exception as e: return None @transaction.atomic def update(self, instance, validated_data): """ Override this function to include extra functionality. """ instance.assignment_date = validated_data.get('assignment_date', instance.assignment_date) instance.associate = validated_data.get('associate', instance.associate) instance.completion_date = validated_data.get('completion_date', instance.completion_date) instance.customer = validated_data.get('customer', instance.customer) instance.hours = validated_data.get('hours', instance.hours) instance.is_home_support_service = validated_data.get('is_home_support_service', instance.is_home_support_service) 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'] instance.description = validated_data.get('description', instance.description) instance.start_date = validated_data.get('start_date', instance.start_date) instance.state = validated_data.get('state', instance.state) # Financial information. instance.visits = validated_data.get('visits', instance.visits) instance.invoice_service_fee = validated_data.get('invoice_service_fee', instance.invoice_service_fee) instance.invoice_service_fee_payment_date = validated_data.get('invoice_service_fee_payment_date', instance.invoice_service_fee_payment_date) instance.invoice_ids = validated_data.get('invoice_ids', instance.invoice_ids) instance.invoice_date = validated_data.get('invoice_date', instance.invoice_date) instance.invoice_quote_amount = validated_data.get('invoice_quote_amount', instance.invoice_quote_amount) instance.invoice_labour_amount = validated_data.get('invoice_labour_amount', instance.invoice_labour_amount) instance.invoice_material_amount = validated_data.get('invoice_material_amount', instance.invoice_material_amount) instance.invoice_other_costs_amount = validated_data.get('invoice_other_costs_amount', instance.invoice_other_costs_amount) instance.invoice_quoted_material_amount = validated_data.get('invoice_quoted_material_amount', instance.invoice_quoted_material_amount) instance.invoice_quoted_labour_amount = validated_data.get('invoice_quoted_labour_amount', instance.invoice_quoted_labour_amount) instance.invoice_quoted_other_costs_amount = validated_data.get('invoice_quoted_other_costs_amount', instance.invoice_quoted_other_costs_amount) instance.invoice_total_quote_amount = validated_data.get('invoice_total_quote_amount', instance.invoice_total_quote_amount) instance.invoice_tax_amount = validated_data.get('invoice_tax_amount', instance.invoice_tax_amount) instance.invoice_total_amount = validated_data.get('invoice_total_amount', instance.invoice_total_amount) instance.invoice_amount_due = validated_data.get('invoice_amount_due', instance.invoice_amount_due) instance.invoice_service_fee_amount = validated_data.get('invoice_service_fee_amount', instance.invoice_service_fee_amount) instance.invoice_actual_service_fee_amount_paid = validated_data.get('invoice_actual_service_fee_amount_paid', instance.invoice_actual_service_fee_amount_paid) instance.invoice_balance_owing_amount = instance.invoice_service_fee_amount.amount - instance.invoice_actual_service_fee_amount_paid.amount # Update the job type based off of the customers type. This is done in # in case the new customer is either commercial or residential but # the job type was marked the opposite. if instance.customer: instance.job_type_of = UNASSIGNED_JOB_TYPE_OF_ID if instance.customer.type_of == RESIDENTIAL_CUSTOMER_TYPE_OF_ID: instance.job_type_of = RESIDENTIAL_JOB_TYPE_OF_ID if instance.customer.type_of == COMMERCIAL_CUSTOMER_TYPE_OF_ID: instance.job_type_of = COMMERCIAL_JOB_TYPE_OF_ID # Save the model. instance.save() logger.info("Updated order object.") #TODO: IMPLEMENT ASSOCIATE GLOBAL BALANCE OWING AMOUNT. #----------------------------- # Set our `Tags` objects. #----------------------------- tags = validated_data.get('tags', None) if tags is not None: if len(tags) > 0: instance.tags.set(tags) logger.info("Set tags with order.") #----------------------------- # Set our `SkillSet` objects. #----------------------------- skill_sets = validated_data.get('skill_sets', instance.skill_sets) if skill_sets is not None: if len(skill_sets) > 0: instance.skill_sets.set(skill_sets) logger.info("Set skill set with order.") #----------------------------- # 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['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'] ) WorkOrderComment.objects.create( about=instance, comment=comment, ) logger.info("Created and set comment with order.") # Update validation data. # validated_data['comments'] = WorkOrderComment.objects.filter(order=instance) validated_data['created'] = instance.created validated_data['created_by'] = instance.created_by validated_data['last_modified_by'] = self.context['last_modified_by'] validated_data['extra_comment'] = None validated_data['assigned_skill_sets'] = instance.skill_sets.all() #--------------------------------------------------------------------- # Update the `Associate` object for the `balance_owing_amount` field. #--------------------------------------------------------------------- if instance.associate: import django_rq from shared_etl.tasks import update_balance_owing_amount_for_associate_func django_rq.enqueue(update_balance_owing_amount_for_associate_func, { 'franchise_schema_name': self.context['franchise'].schema_name, 'associate_id': instance.associate.id }) #---------------------------------------- # Clear our cache for specific functions. #---------------------------------------- if instance.associate: instance.associate.invalidate("latest_completed_and_paid_order") # Return our validated data. return validated_data
class StaffAccountUpdateSerializer(serializers.ModelSerializer): 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=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 = ( 'description', 'account_type', 'tags', 'is_active', 'police_check', # 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 update(self, instance, validated_data): """ Override this function to include extra functionality. """ # For debugging purposes only. # print(validated_data) #------------------------------------- # Bugfix: Created `SharedUser` object. #------------------------------------- if instance.owner is None: owner = SharedUser.objects.filter(email=instance.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=instance.given_name, last_name=instance.last_name, email=instance.mail, 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. #--------------------------- # Update the account. if instance.email: instance.owner.email = instance.email instance.owner.username = get_unique_username_from_email( instance.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.police_check = validated_data.get('police_check', instance.police_check) 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" and account_type != None: account_type = int(account_type) instance.owner.groups.set([account_type]) logger.info("Updated the group membership.") #--------------------------- # Update `Staff` object. #--------------------------- # Misc 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'] # Emergency contact. instance.description = validated_data.get('description', None) 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) # Return our validated data. return instance
class AssociateProfileSerializer(serializers.ModelSerializer): organization_name = serializers.CharField( required=False, allow_blank=True, allow_null=True, max_length=63, validators=[ UniqueValidator( queryset=Associate.objects.all(), ) ], ) organization_type_of = serializers.IntegerField( required=False, validators=[] ) organization_type_of_label = serializers.ReadOnlyField(source="get_organization_type_of_label") type_of = serializers.IntegerField( required=False, allow_null=True, validators=[] ) 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=Associate.objects.all()), ], required=True, allow_blank=False, ) # All comments are created by our `create` function and not by # `django-rest-framework`. # comments = AssociateCommentSerializer(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) # 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) insurance_requirements = serializers.PrimaryKeyRelatedField(many=True, queryset=InsuranceRequirement.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() 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) is_active = serializers.BooleanField( write_only=True, required=True, ) join_date = serializers.DateField( required=True, ) # 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() pretty_skill_sets = serializers.SerializerMethodField() pretty_tags = serializers.SerializerMethodField() pretty_insurance_requirements = serializers.SerializerMethodField() pretty_vehicle_types = serializers.SerializerMethodField() latest_completed_and_paid_order = serializers.SerializerMethodField() balance_owing_amount = serializers.SerializerMethodField() created_by = serializers.SerializerMethodField() last_modified_by = serializers.SerializerMethodField() score = serializers.FloatField(read_only=True) avatar_url = serializers.SerializerMethodField() associate_id = serializers.PrimaryKeyRelatedField(many=False, queryset=Associate.objects.all(), source="id") # SharedUser id = serializers.PrimaryKeyRelatedField(many=False, queryset=SharedUser.objects.all(), source="owner.id") first_name = serializers.CharField(read_only=True, allow_blank=False, source="owner.first_name") last_name = serializers.CharField(read_only=True, allow_blank=False, source="owner.last_name") group_id = serializers.SerializerMethodField() date_joined = serializers.DateTimeField(read_only=True, source="owner.date_joined") franchise = serializers.PrimaryKeyRelatedField(many=False, queryset=SharedFranchise.objects.all(), source="owner.franchise") class Meta: model = Associate fields = ( # SharedUser 'id', 'first_name', 'last_name', 'group_id', 'date_joined', 'franchise', # Thing 'associate_id', 'created', 'created_by', 'last_modified', 'last_modified_by', 'description', # Person 'organization_name', 'organization_type_of', 'organization_type_of_label', 'given_name', 'middle_name', 'last_name', 'birthdate', 'join_date', 'gender', 'description', 'tax_id', # Misc (Read/Write) 'type_of', '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', # 'assigned_skill_sets', # 'organizations', #TODO: FIX 'full_name', 'address', 'address_url', 'full_address', 'e164_telephone', 'pretty_skill_sets', 'pretty_tags', 'pretty_insurance_requirements', 'pretty_vehicle_types', 'latest_completed_and_paid_order', 'balance_owing_amount', 'score', 'avatar_url', # # 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 setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related( 'owner', 'created_by', 'last_modified_by', 'skill_sets', 'tags', 'vehicle_types' 'comments', 'insurance_requirements' ) return queryset def get_group_id(self, obj): try: return obj.owner.groups.first().id except Exception as e: print("AssociateProfileSerializer | get_group_id |", e) return None 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 get_pretty_skill_sets(self, obj): try: s = SkillSetListCreateSerializer(obj.skill_sets.all(), many=True) return s.data except Exception as e: return None def get_pretty_tags(self, obj): try: s = TagListCreateSerializer(obj.tags.all(), many=True) return s.data except Exception as e: return None def get_pretty_insurance_requirements(self, obj): try: s = InsuranceRequirementListCreateSerializer(obj.insurance_requirements.all(), many=True) return s.data except Exception as e: return None def get_pretty_vehicle_types(self, obj): try: s = VehicleTypeListCreateSerializer(obj.vehicle_types.all(), many=True) return s.data except Exception as e: return None def get_latest_completed_and_paid_order(self, obj): try: task_item = obj.latest_completed_and_paid_order return { 'id': task_item.id, 'paid_at': str(task_item.invoice_service_fee_payment_date) } except Exception as e: return { 'id': None, 'paid_at': None } def get_balance_owing_amount(self, obj): try: return str(obj.balance_owing_amount).replace("C", "") 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_avatar_url(self, obj): try: return obj.avatar_image.image_file.url except Exception as e: return None
class AssociateRetrieveUpdateDestroySerializer(serializers.ModelSerializer): organization_name = serializers.CharField( required=False, allow_blank=True, allow_null=True, max_length=63, validators=[UniqueValidator(queryset=Associate.objects.all(), )], ) organization_type_of = serializers.IntegerField(required=False, validators=[]) organization_type_of_label = serializers.ReadOnlyField( source="get_organization_type_of_label") type_of = serializers.IntegerField(required=False, allow_null=True, validators=[]) 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=Associate.objects.all()), ], required=True, allow_blank=False, ) # All comments are created by our `create` function and not by # `django-rest-framework`. # comments = AssociateCommentSerializer(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) # 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) insurance_requirements = serializers.PrimaryKeyRelatedField( many=True, queryset=InsuranceRequirement.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() 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) is_active = serializers.BooleanField( write_only=True, required=True, ) join_date = serializers.DateField(required=True, ) # 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() pretty_skill_sets = serializers.SerializerMethodField() pretty_tags = serializers.SerializerMethodField() pretty_insurance_requirements = serializers.SerializerMethodField() pretty_vehicle_types = serializers.SerializerMethodField() latest_completed_and_paid_order = serializers.SerializerMethodField() balance_owing_amount = serializers.SerializerMethodField() created_by = serializers.SerializerMethodField() last_modified_by = serializers.SerializerMethodField() score = serializers.FloatField(read_only=True) avatar_url = serializers.SerializerMethodField() state = serializers.IntegerField(read_only=True, source="owner.is_active") # Attach with our foreign keys. service_fee = serializers.PrimaryKeyRelatedField( many=False, required=True, allow_null=False, queryset=WorkOrderServiceFee.objects.all()) service_fee_label = serializers.CharField( read_only=True, source="service_fee.title", allow_null=True, allow_blank=True, ) away_log = AwayLogRetrieveUpdateDestroySerializer( many=False, allow_null=True, ) class Meta: model = Associate fields = ( # Thing 'id', 'created', 'created_by', 'last_modified', 'last_modified_by', 'description', # Person 'organization_name', 'organization_type_of', 'organization_type_of_label', 'given_name', 'middle_name', 'last_name', 'birthdate', 'join_date', 'gender', 'description', 'tax_id', # Misc (Read/Write) 'type_of', '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 'service_fee', 'service_fee_label', # Misc (Read Only) # 'comments', # 'assigned_skill_sets', # 'organizations', #TODO: FIX 'full_name', 'address', 'address_url', 'full_address', 'e164_telephone', 'pretty_skill_sets', 'pretty_tags', 'pretty_insurance_requirements', 'pretty_vehicle_types', 'latest_completed_and_paid_order', 'balance_owing_amount', 'score', 'avatar_url', 'state', 'away_log', # # 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 setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related('owner', 'created_by', 'last_modified_by', 'skill_sets', 'tags', 'vehicle_types' 'comments', 'insurance_requirements') 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 get_pretty_skill_sets(self, obj): try: s = SkillSetListCreateSerializer(obj.skill_sets.all(), many=True) return s.data except Exception as e: return None def get_pretty_tags(self, obj): try: s = TagListCreateSerializer(obj.tags.all(), many=True) return s.data except Exception as e: return None def get_pretty_insurance_requirements(self, obj): try: s = InsuranceRequirementListCreateSerializer( obj.insurance_requirements.all(), many=True) return s.data except Exception as e: return None def get_pretty_vehicle_types(self, obj): try: s = VehicleTypeListCreateSerializer(obj.vehicle_types.all(), many=True) return s.data except Exception as e: return None def get_latest_completed_and_paid_order(self, obj): try: task_item = obj.latest_completed_and_paid_order return { 'id': task_item.id, 'paid_at': str(task_item.invoice_service_fee_payment_date) } except Exception as e: return {'id': None, 'paid_at': None} def get_balance_owing_amount(self, obj): try: return str(obj.balance_owing_amount).replace("C", "") 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_avatar_url(self, obj): try: return obj.avatar_image.image_file.url except Exception as e: return None @transaction.atomic def update(self, instance, validated_data): """ Override this function to include extra functionality. """ # For debugging purposes only. # logger.info(validated_data) # Get our inputs. email = validated_data.get('email', instance.email) skill_sets = validated_data.get('skill_sets', None) vehicle_types = validated_data.get('vehicle_types', None) insurance_requirements = validated_data.get('insurance_requirements', None) # Update telephone numbers. fax_number = validated_data.get('fax_number', instance.fax_number) if fax_number is not None: validated_data['fax_number'] = phonenumbers.parse(fax_number, "CA") telephone = validated_data.get('telephone', instance.telephone) if telephone is not None: validated_data['telephone'] = phonenumbers.parse(telephone, "CA") other_telephone = validated_data.get('other_telephone', instance.other_telephone) if other_telephone is not None: validated_data['other_telephone'] = phonenumbers.parse( other_telephone, "CA") #--------------------------- # Update `SharedUser` object. #--------------------------- instance.owner, created = SharedUser.objects.update_or_create( email=email, defaults={ 'email': email, 'first_name': validated_data.get('given_name', instance.given_name), 'last_name': validated_data.get('last_name', instance.last_name), 'is_active': validated_data.get('is_active', False) }) logger.info("Updated shared user.") # Update the password. password = validated_data.get('password', None) if password: instance.owner.set_password(password) # Save the model. instance.owner.save() logger.info("Password was updated.") #--------------------------- # Update `Associate` object. #--------------------------- instance.email = email # Profile instance.given_name = validated_data.get('given_name', instance.given_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.middle_name = validated_data.get('middle_name', instance.middle_name) 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) instance.description = validated_data.get('description', instance.description) instance.tax_id = validated_data.get('tax_id', instance.tax_id) # Misc instance.organization_name = validated_data.get( "organization_name", None) instance.organization_type_of = validated_data.get( "organization_type_of", UNKNOWN_ORGANIZATION_TYPE_OF_ID) instance.type_of = validated_data.get("type_of", UNASSIGNED_ASSOCIATE_TYPE_OF_ID) 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.hourly_salary_desired = validated_data.get( 'hourly_salary_desired', instance.hourly_salary_desired) instance.limit_special = validated_data.get('limit_special', instance.limit_special) instance.dues_date = validated_data.get('dues_date', instance.dues_date) instance.commercial_insurance_expiry_date = validated_data.get( 'commercial_insurance_expiry_date', instance.commercial_insurance_expiry_date) instance.auto_insurance_expiry_date = validated_data.get( 'auto_insurance_expiry_date', instance.auto_insurance_expiry_date) instance.wsib_insurance_date = validated_data.get( 'wsib_insurance_date', instance.wsib_insurance_date) instance.wsib_number = validated_data.get('wsib_number', instance.wsib_number) instance.police_check = validated_data.get('police_check', instance.police_check) instance.drivers_license_class = validated_data.get( 'drivers_license_class', instance.drivers_license_class) 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.last_modified_from = self.context['last_modified_from'] instance.last_modified_from_is_public = self.context[ 'last_modified_from_is_public'] instance.last_modified_by = self.context['last_modified_by'] instance.service_fee = validated_data.get('service_fee', instance.service_fee) # 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.fax_number = validated_data.get('fax_number', instance.fax_number) # 'hours_available', #TODO: IMPLEMENT. instance.telephone = validated_data.get('telephone', instance.telephone) instance.telephone_extension = validated_data.get( 'telephone_extension', instance.telephone_extension) instance.telephone_type_of = validated_data.get( 'telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) instance.other_telephone = validated_data.get('other_telephone', instance.other_telephone) instance.other_telephone_extension = validated_data.get( 'other_telephone_extension', instance.other_telephone_extension) instance.other_telephone_type_of = validated_data.get( 'other_telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) # 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: IMPLEMENT. # Emergency contact. instance.emergency_contact_name = validated_data.get( 'emergency_contact_name', instance.emergency_contact_name) instance.emergency_contact_relationship = validated_data.get( 'emergency_contact_relationship', instance.emergency_contact_relationship) instance.emergency_contact_telephone = validated_data.get( 'emergency_contact_telephone', instance.emergency_contact_telephone) instance.emergency_contact_alternative_telephone = validated_data.get( 'emergency_contact_alternative_telephone', instance.emergency_contact_alternative_telephone) # Save our instance. instance.save() logger.info("Updated the associate.") #----------------------------- # Set our `SkillSet` objects. #----------------------------- if skill_sets is not None: if len(skill_sets) > 0: instance.skill_sets.set(skill_sets) logger.info("Set associate skill sets.") #------------------------------- # Set our `VehicleType` objects. #------------------------------- if vehicle_types is not None: if len(vehicle_types) > 0: instance.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: instance.tags.set(tags) logger.info("Set associate 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']) AssociateComment.objects.create( about=instance, comment=comment, ) logger.info("Set associate comments.") #---------------------------------------- # Set our `InsuranceRequirement` objects. #---------------------------------------- if insurance_requirements is not None: if len(insurance_requirements) > 0: instance.insurance_requirements.set(insurance_requirements) logger.info("Set associate insurance requirements.") #--------------------------- # Update validation data. #--------------------------- # validated_data['comments'] = AssociateComment.objects.filter(associate=instance) validated_data['last_modified_by'] = self.context['last_modified_by'] # validated_data['extra_comment'] = None # validated_data['assigned_skill_sets'] = instance.skill_sets.all() # This is for debugging purposes only. # raise serializers.ValidationError("This is a temporary stop point set by the programmer.") # Return our validated data. return validated_data
class AssociateAccountUpdateSerializer(serializers.ModelSerializer): skill_sets = serializers.PrimaryKeyRelatedField(many=True, queryset=SkillSet.objects.all(), allow_null=True) insurance_requirements = serializers.PrimaryKeyRelatedField(many=True, queryset=InsuranceRequirement.objects.all(), allow_null=True) emergency_contact_telephone = PhoneNumberField(allow_null=True, required=False) emergency_contact_alternative_telephone = PhoneNumberField(allow_null=True, required=False) service_fee = serializers.PrimaryKeyRelatedField(many=False, required=True, allow_null=False, queryset=WorkOrderServiceFee.objects.all()) class Meta: model = Associate fields = ( 'tax_id', '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 'skill_sets', # many-to-many 'insurance_requirements', # many-to-many 'service_fee', # Emergency Contact 'emergency_contact_name', 'emergency_contact_relationship', 'emergency_contact_telephone', 'emergency_contact_alternative_telephone' ) extra_kwargs = { "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 update(self, instance, validated_data): """ Override this function to include extra functionality. """ # For debugging purposes only. # logger.info(validated_data) # Get our inputs. skill_sets = validated_data.get('skill_sets', None) vehicle_types = validated_data.get('vehicle_types', None) insurance_requirements = validated_data.get('insurance_requirements', None) #--------------------------- # Update `Associate` object. #--------------------------- instance.tax_id = validated_data.get('tax_id', instance.tax_id) instance.hourly_salary_desired=validated_data.get('hourly_salary_desired', instance.hourly_salary_desired) instance.limit_special=validated_data.get('limit_special', instance.limit_special) instance.dues_date=validated_data.get('dues_date', instance.dues_date) instance.commercial_insurance_expiry_date=validated_data.get('commercial_insurance_expiry_date', instance.commercial_insurance_expiry_date) instance.auto_insurance_expiry_date = validated_data.get('auto_insurance_expiry_date', instance.auto_insurance_expiry_date) instance.wsib_insurance_date = validated_data.get('wsib_insurance_date', instance.wsib_insurance_date) instance.wsib_number = validated_data.get('wsib_number', instance.wsib_number) instance.police_check=validated_data.get('police_check', instance.police_check) instance.drivers_license_class=validated_data.get('drivers_license_class', instance.drivers_license_class) instance.last_modified_from = self.context['last_modified_from'] instance.last_modified_from_is_public = self.context['last_modified_from_is_public'] instance.last_modified_by = self.context['last_modified_by'] instance.emergency_contact_name=validated_data.get('emergency_contact_name', instance.emergency_contact_name) instance.emergency_contact_relationship=validated_data.get('emergency_contact_relationship', instance.emergency_contact_relationship) instance.emergency_contact_telephone=validated_data.get('emergency_contact_telephone', instance.emergency_contact_telephone) instance.emergency_contact_alternative_telephone=validated_data.get('emergency_contact_alternative_telephone', instance.emergency_contact_alternative_telephone) instance.service_fee = validated_data.get('service_fee', instance.service_fee) instance.save() logger.info("Updated the associate.") #----------------------------- # Set our `SkillSet` objects. #----------------------------- if skill_sets is not None: if len(skill_sets) > 0: instance.skill_sets.set(skill_sets) logger.info("Set associate skill sets.") #------------------------------- # Set our `VehicleType` objects. #------------------------------- if vehicle_types is not None: if len(vehicle_types) > 0: instance.vehicle_types.set(vehicle_types) logger.info("Set associate vehicle types.") #---------------------------------------- # Set our `InsuranceRequirement` objects. #---------------------------------------- if insurance_requirements is not None: if len(insurance_requirements) > 0: instance.insurance_requirements.set(insurance_requirements) logger.info("Set associate insurance requirements.") return instance
class OngoingWorkOrderRetrieveUpdateDestroySerializer( serializers.ModelSerializer): associate_full_name = serializers.SerializerMethodField() associate_telephone = PhoneNumberField(read_only=True, source="associate.telephone") associate_telephone_type_of = serializers.IntegerField( read_only=True, source="associate.telephone_type_of") associate_pretty_telephone_type_of = serializers.CharField( read_only=True, source="associate.get_pretty_telephone_type_of") associate_other_telephone = PhoneNumberField( read_only=True, source="associate.other_telephone") associate_other_telephone_type_of = serializers.IntegerField( read_only=True, source="associate.other_telephone_type_of") associate_pretty_other_telephone_type_of = serializers.CharField( read_only=True, source="associate.get_pretty_other_telephone_type_of") customer_full_name = serializers.SerializerMethodField() customer_telephone = PhoneNumberField(read_only=True, source="customer.telephone") customer_telephone_type_of = serializers.IntegerField( read_only=True, source="customer.telephone_type_of") customer_pretty_telephone_type_of = serializers.CharField( read_only=True, source="customer.get_pretty_telephone_type_of") customer_other_telephone = PhoneNumberField( read_only=True, source="customer.other_telephone") customer_other_telephone_type_of = serializers.IntegerField( read_only=True, source="customer.other_telephone_type_of") customer_pretty_other_telephone_type_of = serializers.CharField( read_only=True, source="customer.get_pretty_other_telephone_type_of") pretty_status = serializers.CharField(read_only=True, source="get_pretty_status") pretty_type_of = serializers.CharField(read_only=True, source="get_pretty_type_of") class Meta: model = OngoingWorkOrder fields = ( # Read only fields. 'id', # Read Only fields. 'associate_full_name', 'associate_telephone', 'associate_telephone_type_of', 'associate_pretty_telephone_type_of', 'associate_other_telephone', 'associate_other_telephone_type_of', 'associate_pretty_other_telephone_type_of', 'customer_full_name', 'customer_telephone', 'customer_telephone_type_of', 'customer_pretty_telephone_type_of', 'customer_other_telephone', 'customer_other_telephone_type_of', 'customer_pretty_other_telephone_type_of', 'pretty_status', 'pretty_type_of', # Read / write fields. 'associate', 'customer', 'state') def setup_eager_loading(cls, queryset): """ Perform necessary eager loading of data. """ queryset = queryset.prefetch_related('associate', 'customer', 'comments', 'last_modified_by', 'created_by', 'work_orders') return queryset def get_associate_full_name(self, obj): try: if obj.associate: return str(obj.associate) except Exception as e: pass return None def get_customer_full_name(self, obj): try: if obj.customer: return str(obj.customer) except Exception as e: pass return None # def get_pretty_skill_sets(self, obj): # try: # s = SkillSetListCreateSerializer(obj.skill_sets.all(), many=True) # return s.data # 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 validate_invoice_service_fee_payment_date(self, value): # """ # Include validation on no-blanks if the state is set to be changed # to ``completed_and_paid`` state of the work order. # """ # state = self.context['state'] # if state: # if state == WORK_ORDER_STATE.COMPLETED_AND_PAID: # if value is None: # raise serializers.ValidationError("This field may not be blank when submitting a payment status.") # return value # def validate_invoice_date(self, value): # """ # Include validation on no-blanks # """ # if value is None: # raise serializers.ValidationError("This field may not be blank.") # return value # # def get_pretty_tags(self, obj): # try: # s = TagListCreateSerializer(obj.tags.all(), many=True) # return s.data # except Exception as e: # return None @transaction.atomic def update(self, instance, validated_data): """ Override this function to include extra functionality. """ # (a) Object details. instance.customer = validated_data.get('customer', instance.customer) instance.associate = validated_data.get('associate', instance.associate) instance.state = validated_data.get('state', instance.state) # (b) System details. instance.last_modified_from = self.context['last_modified_from'] instance.last_modified_from_is_public = self.context[ 'last_modified_from_is_public'] instance.last_modified_by = self.context['last_modified_by'] instance.save() # Return our validated data. return validated_data
class PartnerContactUpdateSerializer(serializers.ModelSerializer): organization_name = serializers.CharField(required=True, allow_blank=False, validators=[]) given_name = serializers.CharField(required=True, allow_blank=False, validators=[]) last_name = 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=Partner.objects.all())], required=True, ) # Custom formatting of our telephone fields. primary_phone = PhoneNumberField(allow_null=False, required=True, source="telephone") primary_phone_type_of = serializers.IntegerField( required=True, validators=[], source="telephone_type_of") secondary_phone = PhoneNumberField(allow_null=True, required=False, source="other_telephone") secondary_phone_type_of = serializers.IntegerField( required=False, validators=[], source="other_telephone_type_of") class Meta: model = Partner fields = ( 'organization_name', 'given_name', 'last_name', 'primary_phone', 'primary_phone_type_of', 'secondary_phone', 'secondary_phone_type_of', 'email', 'is_ok_to_email', 'is_ok_to_text', ) 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 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) # Update telephone numbers. telephone = validated_data.get('telephone', instance.telephone) if telephone is not None: validated_data['telephone'] = phonenumbers.parse(telephone, "CA") other_telephone = validated_data.get('other_telephone', instance.other_telephone) if other_telephone is not None: validated_data['other_telephone'] = phonenumbers.parse( other_telephone, "CA") #--------------------------- # Update `SharedUser` object. #--------------------------- instance.owner, created = SharedUser.objects.update_or_create( email=email, defaults={ 'email': email, 'first_name': validated_data.get('given_name', instance.given_name), 'last_name': validated_data.get('last_name', instance.last_name), 'is_active': True }) logger.info("Updated shared user.") #--------------------------- # Update `Partner` object. #--------------------------- instance.email = email instance.organization_name = validated_data.get( 'organization_name', None) instance.organization_type_of = validated_data.get( 'organization_type_of', UNKNOWN_ORGANIZATION_TYPE_OF_ID) instance.given_name = validated_data.get('given_name', instance.given_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.middle_name = validated_data.get('middle_name', instance.middle_name) instance.is_ok_to_email = validated_data.get('is_ok_to_email', None) instance.is_ok_to_text = validated_data.get('is_ok_to_text', 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'] 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', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) 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', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) instance.save() logger.info("Updated the partner.") return instance
class TaskItemAvailableAssociateListCreateSerializer( serializers.ModelSerializer): full_name = serializers.SerializerMethodField() telephone = PhoneNumberField() e164_telephone = serializers.SerializerMethodField() pretty_tags = serializers.SerializerMethodField() # Meta Information. class Meta: model = Associate fields = ( 'id', 'type_of', 'full_name', 'past_30_days_activity_sheet_count', 'telephone', 'e164_telephone', 'email', 'wsib_number', 'hourly_salary_desired', 'score', 'tags', 'pretty_tags', ) 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 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 def get_full_name(self, obj): try: return str(obj) 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 get_pretty_tags(self, obj): try: s = TagListCreateSerializer(obj.tags.all(), many=True) return s.data except Exception as e: return None @transaction.atomic def create(self, validated_data): """ Override the `create` function to add extra functinality: """ return validated_data
class StaffRetrieveSerializer(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) # Attach with our foreign keys. how_hear = serializers.PrimaryKeyRelatedField( many=False, required=False, allow_null=True, queryset=HowHearAboutUsItem.objects.all()) # 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) 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() pretty_tags = serializers.SerializerMethodField() group_id = serializers.ReadOnlyField(allow_null=True) group_description = serializers.ReadOnlyField(allow_null=True) state = serializers.IntegerField(read_only=True, source="owner.is_active") is_archived = serializers.BooleanField(read_only=True) avatar_url = serializers.SerializerMethodField() # Meta Information. class Meta: model = Staff fields = ( # Thing 'id', 'created', 'last_modified', # 'owner', 'description', # Person 'given_name', 'middle_name', 'last_name', 'birthdate', 'join_date', 'gender', # Misc (Read/Write) 'tags', # # 'is_senior', # # 'is_support', # # 'job_info_read', 'how_hear', 'how_hear_other', # Misc (Read Only) 'is_archived', 'avatar_url', # # Misc (Write Only) # 'extra_comment', 'full_name', 'address', 'address_url', 'full_address', 'created_by', 'last_modified_by', 'e164_telephone', 'how_hear_pretty', 'pretty_tags', 'group_id', 'group_description', 'state', # 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', # Misc 'police_check', ) 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 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_how_hear_pretty(self, obj): try: return str(obj.how_hear) except Exception as e: return None def get_pretty_tags(self, obj): try: s = TagListCreateSerializer(obj.tags.all(), many=True) return s.data 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 get_avatar_url(self, obj): try: return obj.avatar_image.image_file.url except Exception as e: return None
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
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
class PartnerRetrieveUpdateDestroySerializer(serializers.ModelSerializer): # owner = serializers.PrimaryKeyRelatedField(many=False, read_only=True) # We are overriding the `email` field to include unique email validation. email = serializers.EmailField( validators=[UniqueValidator(queryset=Partner.objects.all())], required=True, allow_blank=False, ) gender = serializers.CharField( required=True, allow_blank=False, allow_null=False, ) # All comments are created by our `create` function and not by # `django-rest-framework`. # comments = PartnerCommentSerializer(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() other_telephone = PhoneNumberField(allow_null=True, required=False) is_active = serializers.BooleanField( write_only=True, required=True, ) # Attach with our foreign keys. how_hear = serializers.PrimaryKeyRelatedField( many=False, required=True, allow_null=False, queryset=HowHearAboutUsItem.objects.all()) class Meta: model = Partner fields = ( # Thing 'id', 'created', 'last_modified', # 'owner', 'description', # Profile 'given_name', 'middle_name', 'last_name', 'birthdate', 'join_date', # Misc (Read/Write) 'is_active', 'is_ok_to_email', 'is_ok_to_text', # 'is_senior', # 'is_support', # 'job_info_read', 'gender', 'how_hear', # Misc (Read Only) # 'comments', # 'organizations', #TODO: FIX # 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 ) 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 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) # Update telephone numbers. fax_number = validated_data.get('fax_number', instance.fax_number) if fax_number is not None: validated_data['fax_number'] = phonenumbers.parse(fax_number, "CA") telephone = validated_data.get('telephone', instance.telephone) if telephone is not None: validated_data['telephone'] = phonenumbers.parse(telephone, "CA") other_telephone = validated_data.get('other_telephone', instance.other_telephone) if other_telephone is not None: validated_data['other_telephone'] = phonenumbers.parse( other_telephone, "CA") #--------------------------- # Update `SharedUser` object. #--------------------------- instance.owner, created = SharedUser.objects.update_or_create( email=email, defaults={ 'email': email, 'first_name': validated_data.get('given_name', instance.given_name), 'last_name': validated_data.get('last_name', instance.last_name), 'is_active': validated_data.get('is_active', False) }) logger.info("Updated shared user.") # Update the password. password = validated_data.get('password', None) if password: instance.owner.set_password(password) # Save the model. instance.owner.save() #--------------------------- # Update `Partner` object. #--------------------------- instance.email = email # Profile instance.given_name = validated_data.get('given_name', instance.given_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.middle_name = validated_data.get('middle_name', instance.middle_name) 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) instance.description = validated_data.get('description', instance.description) # Misc instance.is_ok_to_email = validated_data.get('is_ok_to_email', None) instance.is_ok_to_text = validated_data.get('is_ok_to_text', None) 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.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', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) 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', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) # 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. # Save our instance. instance.save() logger.info("Updated the partner.") # #--------------------------- # # 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 # ) # partner_comment = PartnerComment.objects.create( # partner=instance, # comment=comment, # created_from = self.context['last_modified_from'], # created_from_is_public = self.context['last_modified_from_is_public'] # ) #--------------------------- # Update validation data. #--------------------------- # validated_data['comments'] = PartnerComment.objects.filter(partner=instance) validated_data['last_modified_by'] = self.context['last_modified_by'] # validated_data['extra_comment'] = None # Return our validated data. return validated_data
class AssociateContactUpdateSerializer(serializers.ModelSerializer): # OVERRIDE THE MODEL FIELDS AND ENFORCE THE FOLLOWING CUSTOM VALIDATION RULES. organization_name = serializers.CharField( required=False, validators=[], allow_null=True, allow_blank=True, ) organization_type_of = serializers.IntegerField(required=False, validators=[]) given_name = serializers.CharField(required=True, allow_blank=False, validators=[]) last_name = 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=Associate.objects.all())], required=True, ) # Custom formatting of our telephone fields. primary_phone = PhoneNumberField(allow_null=False, required=True, source="telephone") primary_phone_type_of = serializers.IntegerField( required=True, validators=[], source="telephone_type_of") secondary_phone = PhoneNumberField(allow_null=True, required=False, source="other_telephone") secondary_phone_type_of = serializers.IntegerField( required=False, validators=[], source="other_telephone_type_of") # Meta Information. class Meta: model = Associate fields = ( 'organization_name', 'organization_type_of', 'given_name', 'last_name', 'primary_phone', 'primary_phone_type_of', 'secondary_phone', 'secondary_phone_type_of', 'email', 'is_ok_to_email', 'is_ok_to_text', ) 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_name(self, value): """ Include validation on no-blanks """ associate = self.context['associate'] if associate.type_of == COMMERCIAL_ASSOCIATE_TYPE_OF_ID or associate.type_of == UNASSIGNED_ASSOCIATE_TYPE_OF_ID: if value is None: raise serializers.ValidationError( "This field may not be blank.") return value def validate_organization_type_of(self, value): associate = self.context['associate'] if associate.type_of == COMMERCIAL_ASSOCIATE_TYPE_OF_ID or associate.type_of == UNASSIGNED_ASSOCIATE_TYPE_OF_ID: if value is None or value == 1: 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. # logger.info(validated_data) # Get our inputs. email = validated_data.get('email', instance.email) telephone = validated_data.get('telephone', instance.telephone) if telephone is not None: validated_data['telephone'] = phonenumbers.parse(telephone, "CA") other_telephone = validated_data.get('other_telephone', instance.other_telephone) if other_telephone is not None: validated_data['other_telephone'] = phonenumbers.parse( other_telephone, "CA") #--------------------------- # Update `SharedUser` object. #--------------------------- instance.owner, created = SharedUser.objects.update_or_create( email=email, defaults={ 'email': email, 'first_name': validated_data.get('given_name', instance.given_name), 'last_name': validated_data.get('last_name', instance.last_name), 'is_active': True }) logger.info("Updated shared user.") #--------------------------- # Update `Associate` object. #--------------------------- instance.email = email # Profile instance.organization_name = validated_data.get( 'organization_name', instance.organization_name) instance.organization_type_of = validated_data.get( 'organization_type_of', instance.organization_type_of) instance.given_name = validated_data.get('given_name', instance.given_name) instance.last_name = validated_data.get('last_name', instance.last_name) instance.middle_name = validated_data.get('middle_name', instance.middle_name) 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) instance.description = validated_data.get('description', instance.description) instance.tax_id = validated_data.get('tax_id', instance.tax_id) # Misc 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.last_modified_from = self.context['last_modified_from'] instance.last_modified_from_is_public = self.context[ 'last_modified_from_is_public'] instance.last_modified_by = self.context['last_modified_by'] instance.telephone = validated_data.get('telephone', instance.telephone) instance.telephone_extension = validated_data.get( 'telephone_extension', instance.telephone_extension) instance.telephone_type_of = validated_data.get( 'telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) instance.other_telephone = validated_data.get('other_telephone', instance.other_telephone) instance.other_telephone_extension = validated_data.get( 'other_telephone_extension', instance.other_telephone_extension) instance.other_telephone_type_of = validated_data.get( 'other_telephone_type_of', TELEPHONE_CONTACT_POINT_TYPE_OF_ID) # Save our instance. instance.save() logger.info("Updated the associate.") # Return our validated data. return instance