diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 8ad1663c..88fbdbd1 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -125,7 +125,8 @@ class EstablishmentQuerySet(models.QuerySet): def with_extended_address_related(self): """Return qs with deeply related address models.""" - return self.select_related('address__city', 'address__city__region', 'address__city__region__country', + return self.select_related('address__city', 'address__city__region', + 'address__city__region__country', 'address__city__country') def with_extended_related(self): @@ -140,7 +141,8 @@ class EstablishmentQuerySet(models.QuerySet): def with_es_related(self): """Return qs with related for ES indexing objects.""" - return self.select_related('address', 'establishment_type', 'address__city', 'address__city__country'). \ + return self.select_related('address', 'establishment_type', 'address__city', + 'address__city__country'). \ prefetch_related('tags', 'schedule') def search(self, value, locale=None): @@ -237,11 +239,12 @@ class EstablishmentQuerySet(models.QuerySet): 'address__city__country': establishment.address.city.country } if establishment.establishment_subtypes.exists(): - filters.update({'establishment_subtypes__in': establishment.establishment_subtypes.all()}) + filters.update( + {'establishment_subtypes__in': establishment.establishment_subtypes.all()}) return self.exclude(id=establishment.id) \ - .filter(**filters) \ - .annotate_distance(point=establishment.location) + .filter(**filters) \ + .annotate_distance(point=establishment.location) def similar_base_subquery(self, establishment, filters: dict) -> Subquery: """ @@ -274,10 +277,10 @@ class EstablishmentQuerySet(models.QuerySet): ) # todo: fix this - replace ids_by_subquery.queryset on ids_by_subquery return self.filter(id__in=ids_by_subquery.queryset) \ - .annotate_intermediate_public_mark() \ - .annotate_mark_similarity(mark=restaurant.public_mark) \ - .order_by('mark_similarity') \ - .distinct('mark_similarity', 'id') + .annotate_intermediate_public_mark() \ + .annotate_mark_similarity(mark=restaurant.public_mark) \ + .order_by('mark_similarity') \ + .distinct('mark_similarity', 'id') def same_subtype(self, establishment): """Annotate flag same subtype.""" @@ -296,11 +299,11 @@ class EstablishmentQuerySet(models.QuerySet): :param establishment: Establishment instance """ return self.similar_base(establishment) \ - .same_subtype(establishment) \ - .has_published_reviews() \ - .order_by(F('same_subtype').desc(), - F('distance').asc()) \ - .distinct('same_subtype', 'distance', 'id') + .same_subtype(establishment) \ + .has_published_reviews() \ + .order_by(F('same_subtype').desc(), + F('distance').asc()) \ + .distinct('same_subtype', 'distance', 'id') def by_wine_region(self, wine_region): """ @@ -322,13 +325,13 @@ class EstablishmentQuerySet(models.QuerySet): :param winery: Establishment instance """ return self.similar_base(winery) \ - .order_by(F('wine_origins__wine_region').asc(), - F('wine_origins__wine_sub_region').asc(), - F('distance').asc()) \ - .distinct('wine_origins__wine_region', - 'wine_origins__wine_sub_region', - 'distance', - 'id') + .order_by(F('wine_origins__wine_region').asc(), + F('wine_origins__wine_sub_region').asc(), + F('distance').asc()) \ + .distinct('wine_origins__wine_region', + 'wine_origins__wine_sub_region', + 'distance', + 'id') def last_reviewed(self, point: Point): """ @@ -486,10 +489,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, schedule = models.ManyToManyField(to='timetable.Timetable', blank=True, verbose_name=_('Establishment schedule'), related_name='schedule') - # holidays_from = models.DateTimeField(verbose_name=_('Holidays from'), - # help_text=_('Holidays closing date from')) - # holidays_to = models.DateTimeField(verbose_name=_('Holidays to'), - # help_text=_('Holidays closing date to')) transportation = models.TextField(blank=True, null=True, default=None, verbose_name=_('Transportation')) collections = models.ManyToManyField(to='collection.Collection', @@ -546,7 +545,7 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, .exclude(category__index_name__in=['guide', 'collection', 'purchased_item', 'business_tag', 'business_tags_de']) \ .exclude(value__in=['rss', 'rss_selection']) - # todo: recalculate toque_number + # todo: recalculate toque_number @property def visible_tags_detail(self): @@ -572,13 +571,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin, country = self.address.city.country return country.low_price, country.high_price - # todo: make via prefetch - # @property - # def subtypes(self): - # return EstablishmentSubType.objects.filter( - # subtype_establishment=self, - # establishment_type=self.establishment_type, - # establishment_type__use_subtypes=True) def set_establishment_type(self, establishment_type): self.establishment_type = establishment_type @@ -844,6 +836,12 @@ class EmployeeQuerySet(models.QuerySet): """Search by name or last_name.""" return self._generic_search(value, ['name', 'last_name']) + def actual_establishment(self): + e = EstablishmentEmployee.objects.actual().filter(employee=self) + return self.prefetch_related(models.Prefetch('establishmentemployee_set', + queryset=EstablishmentEmployee.objects.actual() + )).all().distinct() + class Employee(BaseAttributes): """Employee model.""" @@ -852,7 +850,8 @@ class Employee(BaseAttributes): null=True, blank=True, default=None, verbose_name=_('User')) name = models.CharField(max_length=255, verbose_name=_('Name')) - last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, default=None) + last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, + default=None) # SEX CHOICES MALE = 0 @@ -862,11 +861,14 @@ class Employee(BaseAttributes): (MALE, _('Male')), (FEMALE, _('Female')) ) - sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, default=None) - birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, default=None) + sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, + default=None) + birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, + default=None) email = models.EmailField(blank=True, null=True, default=None, verbose_name=_('Email')) phone = PhoneNumberField(null=True, default=None) - toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, default=None) + toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, + default=None) establishments = models.ManyToManyField(Establishment, related_name='employees', through=EstablishmentEmployee, ) @@ -917,25 +919,6 @@ class ContactEmail(models.Model): return f'{self.email}' -# -# class Wine(TranslatedFieldsMixin, models.Model): -# """Wine model.""" -# establishment = models.ForeignKey( -# 'establishment.Establishment', verbose_name=_('establishment'), -# on_delete=models.CASCADE) -# bottles = models.IntegerField(_('bottles')) -# price_min = models.DecimalField( -# _('price min'), max_digits=14, decimal_places=2) -# price_max = models.DecimalField( -# _('price max'), max_digits=14, decimal_places=2) -# by_glass = models.BooleanField(_('by glass')) -# price_glass_min = models.DecimalField( -# _('price min'), max_digits=14, decimal_places=2) -# price_glass_max = models.DecimalField( -# _('price max'), max_digits=14, decimal_places=2) -# - - class Plate(TranslatedFieldsMixin, models.Model): """Plate model.""" STR_FIELD_NAME = 'name' diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index fbdd7a10..54a33c5a 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -157,28 +157,6 @@ class ContactEmailBackSerializers(model_serializers.PlateSerializer): ] -# TODO: test decorator -@with_base_attributes -class EmployeeBackSerializers(serializers.ModelSerializer): - """Employee serializers.""" - - awards = AwardSerializer(many=True, read_only=True) - - class Meta: - model = models.Employee - fields = [ - 'id', - 'user', - 'name', - 'last_name', - 'sex', - 'birth_date', - 'email', - 'phone', - 'toque_number', - 'awards', - ] - class PositionBackSerializer(serializers.ModelSerializer): """Position Back serializer.""" @@ -194,6 +172,64 @@ class PositionBackSerializer(serializers.ModelSerializer): '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) + + + def get_public_mark(self, obj): + """Get last list actual public_mark""" + qs = obj.establishmentemployee_set.actual().order_by('-from_date')\ + .values('establishment__public_mark').first() + return qs['establishment__public_mark'] + + + def get_positions(self, obj): + """Get last list actual positions""" + est_id = obj.establishmentemployee_set.actual().\ + order_by('-from_date').first().establishment_id + + qs = obj.establishmentemployee_set.actual()\ + .filter(establishment_id=est_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""" + est = obj.establishmentemployee_set.actual().order_by('-from_date')\ + .first().establishment + + return { + "id": est.id, + "slug": 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' + ] + class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer): """Establishment Employee serializer."""