gault-millau/apps/establishment/serializers/back.py
2020-01-31 00:16:52 +03:00

769 lines
23 KiB
Python

from functools import lru_cache
from django.db.models import F
from django.shortcuts import get_object_or_404
from django.utils.translation import gettext_lazy as _
from rest_framework import serializers
from account.serializers.common import UserShortSerializer
from establishment import models, serializers as model_serializers
from establishment.models import ContactEmail, ContactPhone, EstablishmentEmployee
from gallery.models import Image
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 ImageBaseSerializer, ProjectModelSerializer, TimeZoneChoiceField
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)
def emails_handler(emails_list, establishment):
"""
create or update emails for establishment
"""
ContactEmail.objects.filter(establishment=establishment).delete()
for new_email in emails_list:
ContactEmail.objects.create(establishment=establishment, email=new_email)
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
)
socials = model_serializers.SocialNetworkRelatedSerializers(
read_only=True,
many=True,
)
type = model_serializers.EstablishmentTypeBaseSerializer(
source='establishment_type',
read_only=True,
)
tz = TimeZoneChoiceField()
phones = serializers.ListField(
source='contact_phones',
allow_null=True,
allow_empty=True,
child=serializers.CharField(max_length=128),
required=False,
)
emails = serializers.ListField(
source='contact_emails',
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',
'facebook',
'twitter',
'instagram',
# 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')
emails_list = []
if 'contact_emails' in validated_data:
emails_list = validated_data.pop('contact_emails')
instance = super().create(validated_data)
phones_handler(phones_list, instance)
emails_handler(emails_list, instance)
return instance
class EstablishmentPositionListSerializer(model_serializers.EstablishmentBaseSerializer):
"""Establishment position serializer"""
class Meta:
model = models.Establishment
fields = [
'id',
'name',
'transliterated_name',
'index_name',
]
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(read_only=True)
emails = serializers.ListField(
source='contact_emails',
allow_null=True,
allow_empty=True,
child=serializers.CharField(max_length=128),
required=False,
)
socials = model_serializers.SocialNetworkRelatedSerializers(read_only=True,
many=True, )
type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
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',
'transliterated_name',
'name',
'website',
'phones',
'emails',
'price_level',
'toque_number',
'type_id',
'type',
'socials',
'image_url',
'facebook',
'twitter',
'instagram',
# TODO: check in admin filters
'is_publish',
'address',
'transportation',
'tags',
]
def update(self, instance, validated_data):
phones_list = []
if 'contact_phones' in validated_data:
phones_list = validated_data.pop('contact_phones')
emails_list = []
if 'contact_emails' in validated_data:
emails_list = validated_data.pop('contact_emails')
instance = super().update(instance, validated_data)
phones_handler(phones_list, instance)
emails_handler(emails_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."""
country_calling_code = serializers.CharField(read_only=True, allow_null=True)
national_calling_number = serializers.CharField(read_only=True, allow_null=True)
class Meta:
model = models.ContactPhone
fields = [
'id',
'establishment',
'phone',
'country_calling_code',
'national_calling_number',
]
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)
photo_id = serializers.PrimaryKeyRelatedField(source='photo', write_only=True, required=False,
queryset=Image.objects.all(), allow_null=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',
'photo_id',
]
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'
]
class EstablishmentEmployeePositionsSerializer(serializers.ModelSerializer):
"""Establishments from employee serializer"""
restaurant_name = serializers.CharField(read_only=True, source='establishment.name')
position = PositionBackSerializer(read_only=True)
state = serializers.CharField(read_only=True, source='status')
start = serializers.DateTimeField(read_only=True, source='from_date')
end = serializers.DateTimeField(read_only=True, source='to_date')
class Meta:
model = models.EstablishmentEmployee
fields = [
'restaurant_name',
'position',
'state',
'start',
'end',
]
class _PlateSerializer(ProjectModelSerializer):
name_translated = TranslatedField()
class Meta:
model = models.Plate
fields = [
'name_translated',
'price',
]
class _MenuUploadsSerializer(serializers.Serializer):
id = serializers.IntegerField()
title = serializers.CharField()
original_url = serializers.URLField()
class MenuDishesSerializer(ProjectModelSerializer):
"""for dessert, main_course and starter category"""
plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True)
category_translated = serializers.CharField(read_only=True)
last_update = serializers.DateTimeField(source='created')
gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True)
class Meta:
model = models.Menu
fields = [
'id',
'category',
'category_translated',
'establishment',
'is_drinks_included',
'schedule',
'plates',
'last_update',
'gallery',
]
class MenuDishesRUDSerializers(ProjectModelSerializer):
"""for dessert, main_course and starter category"""
plates = _PlateSerializer(read_only=True, many=True, source='plate_set', allow_null=True)
gallery = ImageBaseSerializer(read_only=True, source='crop_gallery', many=True)
class Meta:
model = models.Menu
fields = [
'id',
'category',
'plates',
'establishment',
'is_drinks_included',
'schedule',
'gallery',
]
class MenuGallerySerializer(serializers.ModelSerializer):
"""Serializer class for model MenuGallery."""
class Meta:
"""Meta class"""
model = models.MenuGallery
fields = [
'id',
'is_main',
]
@property
def request_kwargs(self):
"""Get url kwargs from request."""
return self.context.get('request').parser_context.get('kwargs')
def create(self, validated_data):
menu_pk = self.request_kwargs.get('pk')
image_id = self.request_kwargs.get('image_id')
qs = models.MenuGallery.objects.filter(image_id=image_id, menu_id=menu_pk)
instance = qs.first()
if instance:
qs.update(**validated_data)
return instance
return super().create(validated_data)
def validate(self, attrs):
"""Override validate method."""
menu_pk = self.request_kwargs.get('pk')
image_id = self.request_kwargs.get('image_id')
menu_qs = models.Menu.objects.filter(pk=menu_pk)
image_qs = Image.objects.filter(id=image_id)
if not menu_qs.exists():
raise serializers.ValidationError({'detail': _('Menu not found')})
if not image_qs.exists():
raise serializers.ValidationError({'detail': _('Image not found')})
menu = menu_qs.first()
image = image_qs.first()
attrs['menu'] = menu
attrs['image'] = image
return attrs
class MenuFilesSerializers(ProjectModelSerializer):
class Meta:
model = models.MenuFiles
fields = [
'id',
'name',
'type',
'file',
]
def create(self, validated_data):
instance = models.MenuFiles.objects.create(**validated_data)
return instance
class MenuBackOfficeSerializer(serializers.ModelSerializer):
name = serializers.CharField(source='category_translated')
drinks_included = serializers.BooleanField(source='is_drinks_included')
establishment_id = serializers.IntegerField(source='establishment.id')
establishment_slug = serializers.CharField(source='establishment.slug', read_only=True)
uploads = MenuFilesSerializers(many=True)
class Meta:
model = models.Menu
fields = [
'id',
'name',
'establishment_id',
'establishment_slug',
'price',
'drinks_included',
'diner',
'lunch',
'last_update',
'uploads',
]
extra_kwargs = {
'last_update': {'read_only': True}
}
def validate(self, attrs):
attrs['category'] = {'en-GB': attrs.pop('category_translated')}
return attrs
def update(self, instance, validated_data):
uploaded_files_ids = validated_data.pop('uploads')
if len(uploaded_files_ids):
uploaded_files = list(models.MenuFiles.objects.filter(id__in=uploaded_files_ids))
establishment_kwargs = validated_data.pop('establishment')
establishment = get_object_or_404(models.Establishment, **establishment_kwargs)
validated_data['establishment'] = establishment
instance = super().update(instance, validated_data)
instance.uploads.set(uploaded_files)
return instance
def create(self, validated_data):
uploaded_files_ids = validated_data.pop('uploads')
if len(uploaded_files_ids):
uploaded_files = list(models.MenuFiles.objects.filter(id__in=uploaded_files_ids))
establishment_kwargs = validated_data.pop('establishment')
establishment = get_object_or_404(models.Establishment, **establishment_kwargs)
validated_data['establishment'] = establishment
instance = models.Menu.objects.create(**validated_data)
instance.uploads.set(uploaded_files)
return instance