2025-10-27 08:36:12 +03:30
|
|
|
import typing
|
|
|
|
|
|
|
|
|
|
from django.contrib.auth.hashers import make_password
|
2025-10-27 11:21:29 +03:30
|
|
|
from django.db.models import Q
|
2025-05-06 16:22:35 +03:30
|
|
|
from rest_framework import serializers
|
2025-10-27 08:36:12 +03:30
|
|
|
|
2025-10-29 10:33:14 +03:30
|
|
|
from apps.authentication.exceptions import UserExistException, OrganizationNationalUniqueIDException, \
|
|
|
|
|
OrganizationTypeRepeatableException
|
2025-05-24 15:01:55 +03:30
|
|
|
from apps.authentication.models import (
|
|
|
|
|
User,
|
|
|
|
|
City,
|
|
|
|
|
Province,
|
|
|
|
|
Organization,
|
|
|
|
|
OrganizationType,
|
2025-07-16 12:21:29 +03:30
|
|
|
OrganizationStats,
|
2025-05-24 15:01:55 +03:30
|
|
|
BankAccountInformation
|
|
|
|
|
)
|
|
|
|
|
from apps.authorization import models as authorize_models
|
2025-10-27 08:36:12 +03:30
|
|
|
from apps.authorization.api.v1.serializers import (
|
|
|
|
|
UserRelationSerializer
|
|
|
|
|
)
|
2025-05-24 15:01:55 +03:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class CitySerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize city data """
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = City
|
|
|
|
|
fields = [
|
|
|
|
|
'id',
|
2025-06-10 14:53:01 +03:30
|
|
|
'name',
|
|
|
|
|
'province'
|
2025-05-24 15:01:55 +03:30
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class ProvinceSerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize province data """
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = Province
|
|
|
|
|
fields = [
|
|
|
|
|
'id',
|
2025-06-10 14:53:01 +03:30
|
|
|
'name',
|
2025-05-24 15:01:55 +03:30
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BankAccountSerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize bank account data """
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = BankAccountInformation
|
2025-08-17 09:57:14 +03:30
|
|
|
fields = '__all__'
|
2025-05-24 15:01:55 +03:30
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
|
""" update user bank account information """
|
|
|
|
|
instance.name = validated_data.get('name', instance.name)
|
|
|
|
|
instance.account = validated_data.get('account', instance.account)
|
2025-08-06 16:08:07 +03:30
|
|
|
instance.organization = validated_data.get('organization', instance.organization)
|
|
|
|
|
instance.account_type = validated_data.get('account_type', instance.account_type)
|
2025-05-24 15:01:55 +03:30
|
|
|
instance.card = validated_data.get('card', instance.card)
|
|
|
|
|
instance.sheba = validated_data.get('sheba', instance.sheba)
|
|
|
|
|
instance.save()
|
|
|
|
|
return instance
|
2025-05-06 16:22:35 +03:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class UserSerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize user data """
|
|
|
|
|
|
2025-05-06 16:22:35 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = User
|
|
|
|
|
fields = [
|
2025-05-24 15:01:55 +03:30
|
|
|
'id',
|
2025-05-06 16:22:35 +03:30
|
|
|
'username',
|
2025-05-24 15:01:55 +03:30
|
|
|
'password',
|
|
|
|
|
'first_name',
|
|
|
|
|
'last_name',
|
|
|
|
|
'is_active',
|
|
|
|
|
'mobile',
|
|
|
|
|
'phone',
|
|
|
|
|
'national_code',
|
|
|
|
|
'birthdate',
|
|
|
|
|
'nationality',
|
|
|
|
|
'ownership',
|
|
|
|
|
'address',
|
2025-10-27 08:36:12 +03:30
|
|
|
'unit_name',
|
|
|
|
|
'unit_national_id',
|
2025-05-24 15:01:55 +03:30
|
|
|
'photo',
|
|
|
|
|
'province',
|
|
|
|
|
'city',
|
|
|
|
|
'otp_status',
|
2025-06-15 10:56:41 +03:30
|
|
|
'is_herd_owner',
|
2025-05-24 15:01:55 +03:30
|
|
|
]
|
2025-06-15 12:19:21 +03:30
|
|
|
extra_kwargs = {
|
|
|
|
|
'password': {
|
|
|
|
|
'required': False
|
2025-06-15 13:01:21 +03:30
|
|
|
},
|
|
|
|
|
'username': {
|
|
|
|
|
'required': False
|
|
|
|
|
},
|
|
|
|
|
"national_code": {
|
|
|
|
|
'required': False
|
2025-10-27 11:40:15 +03:30
|
|
|
},
|
|
|
|
|
"unit_name": {
|
|
|
|
|
'required': False
|
|
|
|
|
},
|
|
|
|
|
"unit_national_id": {
|
|
|
|
|
'required': False
|
2025-06-15 12:19:21 +03:30
|
|
|
}
|
|
|
|
|
}
|
2025-05-24 15:01:55 +03:30
|
|
|
|
2025-10-27 11:21:29 +03:30
|
|
|
def validate(self, attrs):
|
|
|
|
|
mobile = attrs['mobile']
|
|
|
|
|
|
2025-10-27 11:32:41 +03:30
|
|
|
if not self.instance:
|
2025-10-27 17:06:06 +03:30
|
|
|
if self.Meta.model.objects.filter(
|
2025-10-29 16:59:28 +03:30
|
|
|
Q(mobile=mobile) | Q(username=attrs['username']),
|
|
|
|
|
trash=False
|
2025-10-27 17:06:06 +03:30
|
|
|
).exists():
|
2025-10-27 11:32:41 +03:30
|
|
|
raise UserExistException()
|
2025-10-27 17:06:06 +03:30
|
|
|
|
2025-10-27 11:32:41 +03:30
|
|
|
elif self.instance:
|
|
|
|
|
if self.instance.mobile != mobile:
|
2025-10-29 16:59:28 +03:30
|
|
|
if self.Meta.model.objects.filter(trash=False, mobile=mobile).exists():
|
2025-10-27 11:32:41 +03:30
|
|
|
raise UserExistException()
|
2025-10-27 17:06:06 +03:30
|
|
|
|
|
|
|
|
if 'username' in attrs.keys():
|
|
|
|
|
if self.instance.username != attrs['username']:
|
2025-10-29 16:59:28 +03:30
|
|
|
if self.Meta.model.objects.filter(trash=False, username=attrs['username']).exists():
|
2025-10-27 17:06:06 +03:30
|
|
|
raise UserExistException()
|
2025-10-27 14:46:48 +03:30
|
|
|
|
2025-10-27 11:43:10 +03:30
|
|
|
return attrs
|
2025-10-27 11:21:29 +03:30
|
|
|
|
2025-06-08 16:09:46 +03:30
|
|
|
def to_representation(self, instance):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Custom output """
|
|
|
|
|
|
2025-06-08 16:09:46 +03:30
|
|
|
representation = super().to_representation(instance)
|
2025-06-15 13:01:21 +03:30
|
|
|
if isinstance(instance, User):
|
|
|
|
|
if instance.bank_information.filter().exists():
|
|
|
|
|
representation['bank_account'] = BankAccountSerializer(
|
|
|
|
|
instance.bank_information.all(), many=True
|
|
|
|
|
).data
|
|
|
|
|
|
|
|
|
|
if instance.city:
|
|
|
|
|
representation['city_name'] = instance.city.name
|
|
|
|
|
if instance.province:
|
|
|
|
|
representation['province_name'] = instance.province.name
|
2025-06-15 11:19:39 +03:30
|
|
|
|
2025-06-08 16:09:46 +03:30
|
|
|
return representation
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
def update(self, instance, validated_data):
|
|
|
|
|
""" update user instance """
|
|
|
|
|
instance.username = validated_data.get('username', instance.username)
|
2025-08-07 10:54:00 +03:30
|
|
|
|
|
|
|
|
# control password
|
2025-08-07 10:13:46 +03:30
|
|
|
if validated_data.get('password'):
|
2025-08-07 10:54:00 +03:30
|
|
|
instance.password = make_password(validated_data.get('password', instance.password))
|
2025-05-24 15:01:55 +03:30
|
|
|
instance.first_name = validated_data.get('first_name')
|
|
|
|
|
instance.last_name = validated_data.get('last_name')
|
|
|
|
|
instance.is_active = validated_data.get('is_active')
|
|
|
|
|
instance.mobile = validated_data.get('mobile')
|
|
|
|
|
instance.phone = validated_data.get('phone')
|
|
|
|
|
instance.national_code = validated_data.get('national_code')
|
|
|
|
|
instance.birthdate = validated_data.get('birthdate')
|
|
|
|
|
instance.nationality = validated_data.get('nationality')
|
|
|
|
|
instance.ownership = validated_data.get('ownership')
|
|
|
|
|
instance.address = validated_data.get('address')
|
2025-10-27 14:46:48 +03:30
|
|
|
instance.unit_name = validated_data.get('unit_name')
|
|
|
|
|
instance.unit_national_id = validated_data.get('unit_national_id')
|
2025-05-24 15:01:55 +03:30
|
|
|
instance.photo = validated_data.get('photo')
|
2025-07-02 15:42:51 +03:30
|
|
|
instance.province = validated_data.get('province', instance.province)
|
2025-08-03 17:59:20 +03:30
|
|
|
instance.city = validated_data.get('city', instance.city)
|
2025-05-24 15:01:55 +03:30
|
|
|
instance.otp_status = validated_data.get('otp_status')
|
|
|
|
|
instance.save()
|
|
|
|
|
|
|
|
|
|
return instance
|
|
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
|
def update_relations(user: object, relation_data: dict, bank_data: dict) -> typing.Any:
|
|
|
|
|
"""
|
|
|
|
|
update user relations & bank account for user
|
|
|
|
|
"""
|
|
|
|
|
user_relation = UserRelationSerializer(data=relation_data) # Create user relation
|
|
|
|
|
if user_relation.is_valid(raise_exception=True):
|
|
|
|
|
user_relation_obj = user_relation.update(
|
|
|
|
|
authorize_models.UserRelations.objects.get(user=user),
|
|
|
|
|
validated_data=relation_data
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
bank_info = BankAccountSerializer(data=bank_data) # Create user bank information
|
|
|
|
|
if bank_info.is_valid(raise_exception=True):
|
|
|
|
|
bank_obj = bank_info.update(
|
|
|
|
|
BankAccountInformation.objects.get(id=bank_data['id']),
|
|
|
|
|
validated_data=bank_data
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
return user_relation_obj, bank_obj # noqa
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class OrganizationTypeSerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize organization type data """
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = OrganizationType
|
|
|
|
|
fields = [
|
|
|
|
|
'id',
|
|
|
|
|
'key',
|
|
|
|
|
'name',
|
2025-10-28 16:48:19 +03:30
|
|
|
'org_type_field',
|
2025-10-29 09:31:56 +03:30
|
|
|
'is_repeatable'
|
2025-05-06 16:22:35 +03:30
|
|
|
]
|
2025-05-24 15:01:55 +03:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class OrganizationSerializer(serializers.ModelSerializer):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Serialize organization data """
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
class Meta:
|
|
|
|
|
model = Organization
|
|
|
|
|
fields = [
|
|
|
|
|
'id',
|
|
|
|
|
'name',
|
|
|
|
|
'type',
|
|
|
|
|
'province',
|
|
|
|
|
'city',
|
|
|
|
|
'parent_organization',
|
2025-06-16 08:29:17 +03:30
|
|
|
'national_unique_id',
|
2025-06-16 09:26:55 +03:30
|
|
|
'company_code',
|
|
|
|
|
'field_of_activity'
|
2025-05-24 15:01:55 +03:30
|
|
|
]
|
|
|
|
|
extra_kwargs = {}
|
|
|
|
|
|
2025-10-28 14:37:59 +03:30
|
|
|
def validate(self, attrs):
|
2025-10-28 16:48:19 +03:30
|
|
|
"""
|
|
|
|
|
@ validate national_unique_code to be unique
|
|
|
|
|
@ validate to organization type field
|
|
|
|
|
"""
|
2025-10-29 10:33:14 +03:30
|
|
|
|
|
|
|
|
# check national_unique_id
|
2025-10-29 09:51:55 +03:30
|
|
|
national_unique_id = attrs['national_unique_id']
|
2025-10-28 14:37:59 +03:30
|
|
|
|
|
|
|
|
if not self.instance:
|
|
|
|
|
if self.Meta.model.objects.filter(national_unique_id=national_unique_id).exists():
|
|
|
|
|
raise OrganizationNationalUniqueIDException()
|
|
|
|
|
if self.instance:
|
|
|
|
|
if self.instance.national_unique_id != national_unique_id:
|
|
|
|
|
if self.Meta.model.objects.filter(national_unique_id=national_unique_id).exists():
|
|
|
|
|
raise OrganizationNationalUniqueIDException()
|
|
|
|
|
|
2025-10-29 10:33:14 +03:30
|
|
|
# check organization type field
|
|
|
|
|
# if is repeatable of type, organization will not be recreating
|
|
|
|
|
org_type = attrs['type']
|
2025-10-29 16:39:13 +03:30
|
|
|
if not self.instance:
|
|
|
|
|
if not org_type.is_repeatable:
|
|
|
|
|
if org_type.org_type_field == 'PR' and self.Meta.model.objects.filter(
|
|
|
|
|
type=org_type,
|
|
|
|
|
province=attrs['province']
|
|
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
|
|
|
|
|
|
|
|
|
if org_type.org_type_field == 'CI' and self.Meta.model.objects.filter(
|
|
|
|
|
type=org_type,
|
|
|
|
|
city=attrs['city']
|
|
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
|
|
|
|
|
|
|
|
|
if org_type.org_type_field == 'CO' and self.Meta.model.objects.filter(
|
|
|
|
|
type=org_type,
|
|
|
|
|
province=attrs['province'],
|
|
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
|
|
|
|
|
|
|
|
|
# check organization type field when updating
|
|
|
|
|
elif self.instance:
|
|
|
|
|
if not org_type.is_repeatable:
|
|
|
|
|
if org_type.org_type_field == 'PR' and self.instance.province != attrs[
|
|
|
|
|
'province'] and self.Meta.model.objects.filter(
|
2025-10-29 16:59:28 +03:30
|
|
|
type=org_type,
|
|
|
|
|
province=attrs['province'],
|
2025-10-29 16:39:13 +03:30
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
|
|
|
|
|
|
|
|
|
if org_type.org_type_field == 'CI' and self.instance.city != attrs[
|
|
|
|
|
'city'] and self.Meta.model.objects.filter(
|
2025-10-29 16:59:28 +03:30
|
|
|
type=org_type,
|
|
|
|
|
city=attrs['city'],
|
2025-10-29 16:39:13 +03:30
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
|
|
|
|
|
|
|
|
|
if org_type.org_type_field == 'CO' and self.instance.province != attrs[
|
|
|
|
|
'province'] and self.Meta.model.objects.filter(
|
2025-10-29 16:59:28 +03:30
|
|
|
type=org_type,
|
|
|
|
|
province=attrs['province'],
|
2025-10-29 16:39:13 +03:30
|
|
|
).exists():
|
|
|
|
|
raise OrganizationTypeRepeatableException()
|
2025-10-29 10:33:14 +03:30
|
|
|
|
|
|
|
|
return attrs
|
|
|
|
|
|
2025-05-24 15:01:55 +03:30
|
|
|
def to_representation(self, instance):
|
2025-06-09 16:09:50 +03:30
|
|
|
""" Custom output """
|
2025-05-24 15:01:55 +03:30
|
|
|
representation = super().to_representation(instance)
|
|
|
|
|
if isinstance(instance, Organization):
|
|
|
|
|
representation['province'] = ProvinceSerializer(instance.province).data
|
|
|
|
|
representation['city'] = CitySerializer(instance.city).data
|
|
|
|
|
representation['type'] = OrganizationTypeSerializer(instance.type).data
|
|
|
|
|
if instance.parent_organization:
|
2025-06-09 16:09:50 +03:30
|
|
|
representation['parent_organization'] = OrganizationSerializer(
|
|
|
|
|
instance.parent_organization
|
|
|
|
|
).data
|
2025-08-07 10:12:33 +03:30
|
|
|
|
2025-08-07 10:37:07 +03:30
|
|
|
if instance.bank_information.exists():
|
|
|
|
|
representation['bank_account'] = BankAccountSerializer(
|
|
|
|
|
instance.bank_information.all(), many=True
|
|
|
|
|
).data
|
2025-05-24 15:01:55 +03:30
|
|
|
return representation
|
|
|
|
|
|
|
|
|
|
def update(self, instance, validated_data):
|
|
|
|
|
""" update user organization information """ # noqa
|
|
|
|
|
instance.name = validated_data.get('name', instance.name)
|
2025-07-02 15:42:51 +03:30
|
|
|
instance.type = validated_data.get('type', instance.type)
|
|
|
|
|
instance.province = validated_data.get('province', instance.province)
|
|
|
|
|
instance.city = validated_data.get('city', instance.city)
|
|
|
|
|
instance.parent_organization = validated_data.get('parent_organization', instance.parent_organization)
|
2025-05-24 15:01:55 +03:30
|
|
|
instance.national_unique_id = validated_data.get('national_unique_id', instance.national_unique_id)
|
|
|
|
|
instance.save()
|
|
|
|
|
return instance
|
2025-07-16 12:21:29 +03:30
|
|
|
|
|
|
|
|
|
|
|
|
|
class OrganizationStatsSerializer(serializers.ModelSerializer):
|
|
|
|
|
class Meta:
|
|
|
|
|
model = OrganizationStats
|
|
|
|
|
fields = '__all__'
|