from functools import lru_cache from django.db.models import F from django.utils.translation import gettext_lazy as _ from rest_framework import serializers from account.serializers.common import UserShortSerializer from establishment import models from establishment import serializers as model_serializers from establishment.models import ContactPhone, EstablishmentEmployee from gallery.models import Image from location.models import Address from location.serializers import AddressDetailSerializer, TranslatedField from main.models import Currency from main.serializers import AwardSerializer from utils.decorators import with_base_attributes from utils.serializers import TimeZoneChoiceField, ImageBaseSerializer def phones_handler(phones_list, establishment): """ create or update phones for establishment """ ContactPhone.objects.filter(establishment=establishment).delete() for new_phone in phones_list: ContactPhone.objects.create(establishment=establishment, phone=new_phone) class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSerializer): """Establishment create serializer""" type_id = serializers.PrimaryKeyRelatedField( source='establishment_type', queryset=models.EstablishmentType.objects.all(), write_only=True ) address_id = serializers.PrimaryKeyRelatedField( source='address', queryset=models.Address.objects.all(), write_only=True ) emails = model_serializers.ContactEmailsSerializer(read_only=True, many=True, ) socials = model_serializers.SocialNetworkRelatedSerializers(read_only=True, many=True, ) type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True) address_id = serializers.PrimaryKeyRelatedField(write_only=True, source='address', queryset=Address.objects.all()) tz = TimeZoneChoiceField() phones = serializers.ListField( source='contact_phones', allow_null=True, allow_empty=True, child=serializers.CharField(max_length=128), required=False, ) class Meta: model = models.Establishment fields = [ 'id', 'name', 'transliterated_name', 'index_name', 'website', 'phones', 'emails', 'price_level', 'toque_number', 'type_id', 'type', 'socials', 'image_url', 'slug', # TODO: check in admin filters 'is_publish', 'guestonline_id', 'lastable_id', 'tags', 'tz', 'address_id', ] def create(self, validated_data): phones_list = [] if 'contact_phones' in validated_data: phones_list = validated_data.pop('contact_phones') instance = super().create(validated_data) phones_handler(phones_list, instance) return instance class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer): """Establishment create serializer""" type_id = serializers.PrimaryKeyRelatedField( source='establishment_type', queryset=models.EstablishmentType.objects.all(), write_only=True ) address = AddressDetailSerializer() emails = model_serializers.ContactEmailsSerializer(read_only=False, many=True, ) socials = model_serializers.SocialNetworkRelatedSerializers(read_only=False, many=True, ) type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type') phones = serializers.ListField( source='contact_phones', allow_null=True, allow_empty=True, child=serializers.CharField(max_length=128), required=False, ) class Meta: model = models.Establishment fields = [ 'id', 'slug', 'name', 'website', 'phones', 'emails', 'price_level', 'toque_number', 'type_id', 'type', 'socials', 'image_url', # TODO: check in admin filters 'is_publish', 'address', 'tags', ] def update(self, instance, validated_data): phones_list = [] if 'contact_phones' in validated_data: phones_list = validated_data.pop('contact_phones') instance = super().update(instance, validated_data) phones_handler(phones_list, instance) return instance class SocialChoiceSerializers(serializers.ModelSerializer): """SocialChoice serializers.""" class Meta: model = models.SocialChoice fields = '__all__' class SocialNetworkSerializers(serializers.ModelSerializer): """Social network serializers.""" class Meta: model = models.SocialNetwork fields = [ 'id', 'establishment', 'network', 'url', ] class PlatesSerializers(model_serializers.PlateSerializer): """Plates serializers.""" currency_id = serializers.PrimaryKeyRelatedField( source='currency', queryset=Currency.objects.all(), write_only=True ) class Meta: """Meta class.""" model = models.Plate fields = model_serializers.PlateSerializer.Meta.fields + [ 'name', 'currency_id', 'menu' ] class ContactPhoneBackSerializers(model_serializers.PlateSerializer): """ContactPhone serializers.""" class Meta: model = models.ContactPhone fields = [ 'id', 'establishment', 'phone' ] class ContactEmailBackSerializers(model_serializers.PlateSerializer): """ContactEmail serializers.""" class Meta: model = models.ContactEmail fields = [ 'id', 'establishment', 'email' ] class PositionBackSerializer(serializers.ModelSerializer): """Position Back serializer.""" name_translated = TranslatedField() class Meta: model = models.Position fields = [ 'id', 'name_translated', 'priority', 'index_name', ] # TODO: test decorator @with_base_attributes class EmployeeBackSerializers(serializers.ModelSerializer): """Employee serializers.""" public_mark = serializers.SerializerMethodField() positions = serializers.SerializerMethodField() establishment = serializers.SerializerMethodField() awards = AwardSerializer(many=True, read_only=True) toque_number = serializers.SerializerMethodField() photo = ImageBaseSerializer(source='crop_image', read_only=True) @staticmethod @lru_cache(maxsize=32) def get_qs(obj): return obj.establishmentemployee_set.actual().annotate( public_mark=F('establishment__public_mark'), est_id=F('establishment__id'), est_slug=F('establishment__slug'), toque_number=F('establishment__toque_number'), ).order_by('-from_date').first() def get_public_mark(self, obj): """Get last list actual public_mark""" if hasattr(obj, 'prefetched_establishment_employee'): return obj.prefetched_establishment_employee[0].establishment.public_mark if len( obj.prefetched_establishment_employee) else None qs = self.get_qs(obj) if qs: return qs.public_mark return None def get_toque_number(self, obj): if hasattr(obj, 'prefetched_establishment_employee'): return obj.prefetched_establishment_employee[0].establishment.toque_number if len( obj.prefetched_establishment_employee) else None qs = self.get_qs(obj) if qs: return qs.toque_number return None def get_positions(self, obj): """Get last list actual positions""" if hasattr(obj, 'prefetched_establishment_employee'): if not len(obj.prefetched_establishment_employee): return [] return [PositionBackSerializer(ee.position).data for ee in obj.prefetched_establishment_employee] est_id = self.get_qs(obj) if not est_id: return None qs = obj.establishmentemployee_set.actual() \ .filter(establishment_id=est_id.establishment_id) \ .prefetch_related('position').values('position') positions = models.Position.objects.filter(id__in=[q['position'] for q in qs]) return [PositionBackSerializer(p).data for p in positions] def get_establishment(self, obj): """Get last actual establishment""" if hasattr(obj, 'prefetched_establishment_employee'): return { 'id': obj.prefetched_establishment_employee[0].establishment.pk, 'slug': obj.prefetched_establishment_employee[0].establishment.slug, } if len(obj.prefetched_establishment_employee) else None est = self.get_qs(obj) if not est: return None return { "id": est.est_id, "slug": est.est_slug } class Meta: model = models.Employee fields = [ 'id', 'name', 'last_name', 'user', 'public_mark', 'positions', 'awards', 'establishment', 'sex', 'birth_date', 'email', 'phone', 'toque_number', 'available_for_events', 'photo', ] class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer): """Establishment Employee serializer.""" employee = EmployeeBackSerializers() position = PositionBackSerializer() class Meta: model = models.EstablishmentEmployee fields = [ 'id', 'employee', 'from_date', 'to_date', 'position', 'status', ] class EstEmployeeBackSerializer(EmployeeBackSerializers): @property def request_kwargs(self): """Get url kwargs from request.""" return self.context.get('request').parser_context.get('kwargs') def get_positions(self, obj): establishment_id = self.request_kwargs.get('establishment_id') es_emp = EstablishmentEmployee.objects.filter( employee=obj, establishment_id=establishment_id, ).distinct().order_by('position_id') result = [] for item in es_emp: result.append({ 'id': item.id, 'from_date': item.from_date, 'to_date': item.to_date, 'status': item.status, 'position_id': item.position_id, 'position_priority': item.position.priority, 'position_index_name': item.position.index_name, 'position_name_translated': item.position.name_translated, }) return result class Meta: model = models.Employee fields = [ 'id', 'name', 'last_name', 'user', 'public_mark', 'positions', 'awards', 'sex', 'birth_date', 'email', 'phone', 'toque_number', 'available_for_events', 'photo', ] class EstablishmentBackOfficeGallerySerializer(serializers.ModelSerializer): """Serializer class for model EstablishmentGallery.""" class Meta: """Meta class""" model = models.EstablishmentGallery fields = [ 'id', 'is_main', ] @property def request_kwargs(self): """Get url kwargs from request.""" return self.context.get('request').parser_context.get('kwargs') def validate(self, attrs): """Override validate method.""" establishment_pk = self.request_kwargs.get('pk') establishment_slug = self.request_kwargs.get('slug') search_kwargs = {'pk': establishment_pk} if establishment_pk else {'slug': establishment_slug} image_id = self.request_kwargs.get('image_id') establishment_qs = models.Establishment.objects.filter(**search_kwargs) image_qs = Image.objects.filter(id=image_id) if not establishment_qs.exists(): raise serializers.ValidationError({'detail': _('Establishment not found')}) if not image_qs.exists(): raise serializers.ValidationError({'detail': _('Image not found')}) establishment = establishment_qs.first() image = image_qs.first() if image in establishment.gallery.all(): raise serializers.ValidationError({'detail': _('Image is already added.')}) attrs['establishment'] = establishment attrs['image'] = image return attrs class EstablishmentCompanyListCreateSerializer(model_serializers.CompanyBaseSerializer): """Serializer for linking page w/ advertisement.""" class Meta(model_serializers.CompanyBaseSerializer.Meta): """Meta class.""" model_serializers.CompanyBaseSerializer.Meta.extra_kwargs.update({ 'establishment': {'required': False} }) def create(self, validated_data): """Overridden create method.""" validated_data['establishment'] = self.context.get('view').get_object() return super().create(validated_data) class EstablishmentNoteBaseSerializer(serializers.ModelSerializer): """Serializer for model EstablishmentNote.""" user_detail = UserShortSerializer(read_only=True, source='user') class Meta: """Meta class.""" model = models.EstablishmentNote fields = [ 'id', 'created', 'modified', 'text', 'user', 'user_detail', 'establishment', ] extra_kwargs = { 'created': {'read_only': True}, 'modified': {'read_only': True}, 'establishment': {'required': False, 'write_only': True}, 'user': {'required': False, 'write_only': True}, } @property def serializer_view(self): """Return view instance.""" return self.context.get('view') class EstablishmentNoteListCreateSerializer(EstablishmentNoteBaseSerializer): """Serializer for List|Create action for model EstablishmentNote.""" def create(self, validated_data): """Overridden create method.""" validated_data['user'] = self.user validated_data['establishment'] = self.establishment return super().create(validated_data) @property def user(self): """Return user instance from view.""" if self.serializer_view: return self.serializer_view.request.user @property def establishment(self): """Return establishment instance from view.""" if self.serializer_view: return self.serializer_view.get_object() class EstablishmentAdminListSerializer(UserShortSerializer): """Establishment admin serializer.""" class Meta: model = UserShortSerializer.Meta.model fields = [ 'id', 'username', 'email' ]