Merge remote-tracking branch 'origin/develop' into develop
This commit is contained in:
commit
e0cbf1115b
23
apps/establishment/migrations/0099_auto_20200207_1136.py
Normal file
23
apps/establishment/migrations/0099_auto_20200207_1136.py
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
# Generated by Django 2.2.7 on 2020-02-07 11:36
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('establishment', '0098_auto_20200204_1205'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='establishment',
|
||||||
|
name='last_update_by_gm',
|
||||||
|
field=models.DateTimeField(null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='establishment',
|
||||||
|
name='last_update_by_manager',
|
||||||
|
field=models.DateTimeField(null=True),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
@ -33,7 +33,7 @@ from utils.models import (
|
||||||
BaseAttributes, FavoritesMixin, FileMixin, GalleryMixin, HasTagsMixin,
|
BaseAttributes, FavoritesMixin, FileMixin, GalleryMixin, HasTagsMixin,
|
||||||
IntermediateGalleryModelMixin, ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
|
IntermediateGalleryModelMixin, ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
|
||||||
TypeDefaultImageMixin, URLImageMixin, default_menu_bool_array, PhoneModelMixin,
|
TypeDefaultImageMixin, URLImageMixin, default_menu_bool_array, PhoneModelMixin,
|
||||||
AwardsModelMixin)
|
AwardsModelMixin, CarouselMixin, UpdateByMixin)
|
||||||
|
|
||||||
|
|
||||||
# todo: establishment type&subtypes check
|
# todo: establishment type&subtypes check
|
||||||
|
|
@ -137,6 +137,14 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
"""Return qs with related reviews."""
|
"""Return qs with related reviews."""
|
||||||
return self.prefetch_related('reviews')
|
return self.prefetch_related('reviews')
|
||||||
|
|
||||||
|
def with_reviews_sorted(self):
|
||||||
|
return self.prefetch_related(
|
||||||
|
Prefetch(
|
||||||
|
'reviews',
|
||||||
|
queryset=Review.objects.published().order_by('-published_at'),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def with_currency_related(self):
|
def with_currency_related(self):
|
||||||
"""Return qs with related """
|
"""Return qs with related """
|
||||||
return self.prefetch_related('currency')
|
return self.prefetch_related('currency')
|
||||||
|
|
@ -547,8 +555,15 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
return self.prefetch_related('menu_set', 'menu_set__plates', 'back_office_wine')
|
return self.prefetch_related('menu_set', 'menu_set__plates', 'back_office_wine')
|
||||||
|
|
||||||
|
|
||||||
class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
|
class Establishment(GalleryMixin,
|
||||||
TranslatedFieldsMixin, HasTagsMixin, FavoritesMixin, AwardsModelMixin):
|
ProjectBaseMixin,
|
||||||
|
URLImageMixin,
|
||||||
|
TranslatedFieldsMixin,
|
||||||
|
HasTagsMixin,
|
||||||
|
FavoritesMixin,
|
||||||
|
AwardsModelMixin,
|
||||||
|
CarouselMixin,
|
||||||
|
UpdateByMixin):
|
||||||
"""Establishment model."""
|
"""Establishment model."""
|
||||||
|
|
||||||
ABANDONED = 0
|
ABANDONED = 0
|
||||||
|
|
@ -717,9 +732,13 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
|
||||||
raise ValidationError('Establishment type of subtype does not match')
|
raise ValidationError('Establishment type of subtype does not match')
|
||||||
self.establishment_subtypes.add(establishment_subtype)
|
self.establishment_subtypes.add(establishment_subtype)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def last_review(self):
|
||||||
|
return self.reviews.by_status(Review.READY).last()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def vintage_year(self):
|
def vintage_year(self):
|
||||||
last_review = self.reviews.by_status(Review.READY).last()
|
last_review = self.last_review
|
||||||
if last_review:
|
if last_review:
|
||||||
return last_review.vintage
|
return last_review.vintage
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from datetime import datetime
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
|
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
|
@ -9,17 +10,20 @@ from rest_framework import serializers
|
||||||
from slugify import slugify
|
from slugify import slugify
|
||||||
|
|
||||||
from account import models as account_models
|
from account import models as account_models
|
||||||
|
from account.models import Role
|
||||||
from account.serializers.common import UserShortSerializer
|
from account.serializers.common import UserShortSerializer
|
||||||
from collection.models import Guide
|
from collection.models import Guide
|
||||||
from establishment import models, serializers as model_serializers
|
from establishment import models, serializers as model_serializers
|
||||||
from establishment.models import ContactEmail, ContactPhone, EstablishmentEmployee
|
from establishment.models import ContactEmail, ContactPhone, EstablishmentEmployee
|
||||||
from establishment.serializers.common import ContactPhonesSerializer
|
from establishment.serializers.common import ContactPhonesSerializer
|
||||||
|
from review.serializers.common import ReviewBaseSerializer
|
||||||
from gallery.models import Image
|
from gallery.models import Image
|
||||||
from location.serializers import AddressDetailSerializer, TranslatedField, AddressBaseSerializer, \
|
from location.serializers import AddressDetailSerializer, TranslatedField, AddressBaseSerializer, \
|
||||||
AddressEstablishmentSerializer
|
AddressEstablishmentSerializer
|
||||||
from main import models as main_models
|
from main import models as main_models
|
||||||
from main.models import Currency
|
from main.models import Currency
|
||||||
from main.serializers import AwardSerializer
|
from main.serializers import AwardSerializer
|
||||||
|
from review.serializers import ReviewBaseSerializer, User
|
||||||
from tag.serializers import TagBaseSerializer
|
from tag.serializers import TagBaseSerializer
|
||||||
from utils.decorators import with_base_attributes
|
from utils.decorators import with_base_attributes
|
||||||
from utils.methods import string_random
|
from utils.methods import string_random
|
||||||
|
|
@ -92,7 +96,7 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
||||||
)
|
)
|
||||||
subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes',
|
subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes',
|
||||||
read_only=True, many=True)
|
read_only=True, many=True)
|
||||||
|
reviews = ReviewBaseSerializer(allow_null=True, read_only=True, many=True)
|
||||||
restaurant_category = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
restaurant_category = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
||||||
restaurant_cuisine = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
restaurant_cuisine = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
||||||
artisan_category = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
artisan_category = TagBaseSerializer(read_only=True, many=True, allow_null=True)
|
||||||
|
|
@ -137,6 +141,7 @@ class EstablishmentListCreateSerializer(model_serializers.EstablishmentBaseSeria
|
||||||
'artisan_category',
|
'artisan_category',
|
||||||
'distillery_type',
|
'distillery_type',
|
||||||
'food_producer',
|
'food_producer',
|
||||||
|
'reviews',
|
||||||
]
|
]
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
|
|
@ -211,6 +216,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||||
subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes',
|
subtypes = model_serializers.EstablishmentSubTypeBaseSerializer(source='establishment_subtypes',
|
||||||
read_only=True, many=True)
|
read_only=True, many=True)
|
||||||
type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
|
type = model_serializers.EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
|
||||||
|
|
||||||
phones = serializers.ListField(
|
phones = serializers.ListField(
|
||||||
source='contact_phones',
|
source='contact_phones',
|
||||||
allow_null=True,
|
allow_null=True,
|
||||||
|
|
@ -219,8 +225,11 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||||
required=False,
|
required=False,
|
||||||
write_only=True,
|
write_only=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
contact_phones = ContactPhonesSerializer(source='phones', read_only=True, many=True)
|
contact_phones = ContactPhonesSerializer(source='phones', read_only=True, many=True)
|
||||||
|
|
||||||
|
last_review = ReviewBaseSerializer(read_only=True)
|
||||||
|
|
||||||
class Meta(model_serializers.EstablishmentBaseSerializer.Meta):
|
class Meta(model_serializers.EstablishmentBaseSerializer.Meta):
|
||||||
fields = [
|
fields = [
|
||||||
'id',
|
'id',
|
||||||
|
|
@ -249,6 +258,10 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||||
'tags',
|
'tags',
|
||||||
'status',
|
'status',
|
||||||
'status_display',
|
'status_display',
|
||||||
|
'last_review',
|
||||||
|
'must_of_the_week',
|
||||||
|
'last_update_by_gm',
|
||||||
|
'last_update_by_manager',
|
||||||
]
|
]
|
||||||
|
|
||||||
def to_representation(self, instance):
|
def to_representation(self, instance):
|
||||||
|
|
@ -256,7 +269,7 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||||
data['phones'] = data.pop('contact_phones', None)
|
data['phones'] = data.pop('contact_phones', None)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def update(self, instance, validated_data):
|
def update(self, instance: models.Establishment, validated_data):
|
||||||
phones_list = []
|
phones_list = []
|
||||||
if 'contact_phones' in validated_data:
|
if 'contact_phones' in validated_data:
|
||||||
phones_list = validated_data.pop('contact_phones')
|
phones_list = validated_data.pop('contact_phones')
|
||||||
|
|
@ -265,9 +278,30 @@ class EstablishmentRUDSerializer(model_serializers.EstablishmentBaseSerializer):
|
||||||
if 'contact_emails' in validated_data:
|
if 'contact_emails' in validated_data:
|
||||||
emails_list = validated_data.pop('contact_emails')
|
emails_list = validated_data.pop('contact_emails')
|
||||||
|
|
||||||
|
request = self.context.get('request')
|
||||||
|
if request and hasattr(request, 'user'):
|
||||||
|
user = request.user
|
||||||
|
|
||||||
|
if isinstance(user, User):
|
||||||
|
is_by_manager = user.userrole_set.filter(
|
||||||
|
pk=user.pk,
|
||||||
|
role__in=(
|
||||||
|
Role.ESTABLISHMENT_MANAGER,
|
||||||
|
Role.ESTABLISHMENT_ADMINISTRATOR,
|
||||||
|
Role.COUNTRY_ADMIN
|
||||||
|
)
|
||||||
|
).exists()
|
||||||
|
|
||||||
|
if is_by_manager:
|
||||||
|
instance.last_update_by_manager = datetime.now()
|
||||||
|
else:
|
||||||
|
''' by gm. '''
|
||||||
|
instance.last_update_by_gm = datetime.now()
|
||||||
|
|
||||||
instance = super().update(instance, validated_data)
|
instance = super().update(instance, validated_data)
|
||||||
phones_handler(phones_list, instance)
|
phones_handler(phones_list, instance)
|
||||||
emails_handler(emails_list, instance)
|
emails_handler(emails_list, instance)
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,8 @@ class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAP
|
||||||
.with_certain_tag_category_related('cuisine', 'restaurant_cuisine') \
|
.with_certain_tag_category_related('cuisine', 'restaurant_cuisine') \
|
||||||
.with_certain_tag_category_related('shop_category', 'artisan_category') \
|
.with_certain_tag_category_related('shop_category', 'artisan_category') \
|
||||||
.with_certain_tag_category_related('distillery_type', 'distillery_type') \
|
.with_certain_tag_category_related('distillery_type', 'distillery_type') \
|
||||||
.with_certain_tag_category_related('producer_type', 'food_producer')
|
.with_certain_tag_category_related('producer_type', 'food_producer') \
|
||||||
|
.with_reviews_sorted()
|
||||||
|
|
||||||
|
|
||||||
class EmployeeEstablishmentPositionsView(generics.ListAPIView):
|
class EmployeeEstablishmentPositionsView(generics.ListAPIView):
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ from utils.models import (
|
||||||
BaseAttributes, FavoritesMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin,
|
BaseAttributes, FavoritesMixin, GalleryMixin, HasTagsMixin, IntermediateGalleryModelMixin,
|
||||||
ProjectBaseMixin,
|
ProjectBaseMixin,
|
||||||
TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin,
|
TJSONField, TranslatedFieldsMixin, TypeDefaultImageMixin,
|
||||||
)
|
CarouselMixin)
|
||||||
from utils.querysets import TranslationQuerysetMixin
|
from utils.querysets import TranslationQuerysetMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -257,8 +257,12 @@ class NewsQuerySet(TranslationQuerysetMixin):
|
||||||
return self.filter(site__country__code=country_code) if not user.is_superuser else self
|
return self.filter(site__country__code=country_code) if not user.is_superuser else self
|
||||||
|
|
||||||
|
|
||||||
class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
|
class News(GalleryMixin,
|
||||||
FavoritesMixin):
|
BaseAttributes,
|
||||||
|
TranslatedFieldsMixin,
|
||||||
|
HasTagsMixin,
|
||||||
|
FavoritesMixin,
|
||||||
|
CarouselMixin):
|
||||||
"""News model."""
|
"""News model."""
|
||||||
|
|
||||||
STR_FIELD_NAME = 'title'
|
STR_FIELD_NAME = 'title'
|
||||||
|
|
@ -366,16 +370,6 @@ class News(GalleryMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixin,
|
||||||
self.duplication_date = timezone.now()
|
self.duplication_date = timezone.now()
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
@property
|
|
||||||
def must_of_the_week(self) -> bool:
|
|
||||||
"""Detects whether current item in carousel"""
|
|
||||||
kwargs = {
|
|
||||||
'content_type': ContentType.objects.get_for_model(self),
|
|
||||||
'object_id': self.pk,
|
|
||||||
'country': self.country,
|
|
||||||
}
|
|
||||||
return Carousel.objects.filter(**kwargs).exists()
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def publication_datetime(self):
|
def publication_datetime(self):
|
||||||
"""Represents datetime object combined from `publication_date` & `publication_time` fields"""
|
"""Represents datetime object combined from `publication_date` & `publication_time` fields"""
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ from os.path import exists
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
from django.contrib.auth.tokens import PasswordResetTokenGenerator
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.contrib.gis.db import models
|
from django.contrib.gis.db import models
|
||||||
from django.contrib.postgres.aggregates import ArrayAgg
|
from django.contrib.postgres.aggregates import ArrayAgg
|
||||||
from django.contrib.postgres.fields import JSONField
|
from django.contrib.postgres.fields import JSONField
|
||||||
|
|
@ -517,6 +518,7 @@ def default_menu_bool_array():
|
||||||
|
|
||||||
class PhoneModelMixin:
|
class PhoneModelMixin:
|
||||||
"""Mixin for PhoneNumberField."""
|
"""Mixin for PhoneNumberField."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def country_calling_code(self):
|
def country_calling_code(self):
|
||||||
"""Return phone code from PhonеNumberField."""
|
"""Return phone code from PhonеNumberField."""
|
||||||
|
|
@ -537,3 +539,32 @@ class AwardsModelMixin:
|
||||||
|
|
||||||
if hasattr(self, 'awards'):
|
if hasattr(self, 'awards'):
|
||||||
self.awards.remove(award)
|
self.awards.remove(award)
|
||||||
|
|
||||||
|
|
||||||
|
class CarouselMixin:
|
||||||
|
@property
|
||||||
|
def must_of_the_week(self) -> bool:
|
||||||
|
"""Detects whether current item in carousel"""
|
||||||
|
from main.models import Carousel
|
||||||
|
|
||||||
|
if hasattr(self, 'pk') and (hasattr(self, 'country') or hasattr(self, 'country_id')):
|
||||||
|
kwargs = {
|
||||||
|
'content_type': ContentType.objects.get_for_model(self),
|
||||||
|
'object_id': self.pk,
|
||||||
|
'country': getattr(self, 'country', getattr(self, 'country_id', None)),
|
||||||
|
}
|
||||||
|
|
||||||
|
return Carousel.objects.filter(**kwargs).exists()
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateByMixin(models.Model):
|
||||||
|
"""Modify by mixin"""
|
||||||
|
last_update_by_manager = models.DateTimeField(null=True)
|
||||||
|
|
||||||
|
last_update_by_gm = models.DateTimeField(null=True)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""Meta class."""
|
||||||
|
abstract = True
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user