From bb284420c43dac9c3d66f52613765720f2efa168 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 26 Aug 2019 18:07:01 +0300 Subject: [PATCH 01/10] initial app --- apps/{establishments => establishment}/__init__.py | 0 apps/{establishments => establishment}/admin.py | 0 apps/establishment/apps.py | 8 ++++++++ .../migrations/__init__.py | 0 apps/{establishments => establishment}/models.py | 0 apps/{establishments => establishment}/tests.py | 0 apps/establishments/apps.py | 5 ----- apps/establishments/serializers/__init__.py | 0 apps/establishments/serializers/common.py | 0 apps/establishments/serializers/web.py | 0 apps/establishments/urls/__init__.py | 0 apps/establishments/urls/common.py | 0 apps/establishments/urls/web.py | 0 apps/establishments/views/__init__.py | 0 apps/establishments/views/common.py | 0 apps/establishments/views/web.py | 0 project/settings/base.py | 5 +++-- 17 files changed, 11 insertions(+), 7 deletions(-) rename apps/{establishments => establishment}/__init__.py (100%) rename apps/{establishments => establishment}/admin.py (100%) create mode 100644 apps/establishment/apps.py rename apps/{establishments => establishment}/migrations/__init__.py (100%) rename apps/{establishments => establishment}/models.py (100%) rename apps/{establishments => establishment}/tests.py (100%) delete mode 100644 apps/establishments/apps.py delete mode 100644 apps/establishments/serializers/__init__.py delete mode 100644 apps/establishments/serializers/common.py delete mode 100644 apps/establishments/serializers/web.py delete mode 100644 apps/establishments/urls/__init__.py delete mode 100644 apps/establishments/urls/common.py delete mode 100644 apps/establishments/urls/web.py delete mode 100644 apps/establishments/views/__init__.py delete mode 100644 apps/establishments/views/common.py delete mode 100644 apps/establishments/views/web.py diff --git a/apps/establishments/__init__.py b/apps/establishment/__init__.py similarity index 100% rename from apps/establishments/__init__.py rename to apps/establishment/__init__.py diff --git a/apps/establishments/admin.py b/apps/establishment/admin.py similarity index 100% rename from apps/establishments/admin.py rename to apps/establishment/admin.py diff --git a/apps/establishment/apps.py b/apps/establishment/apps.py new file mode 100644 index 00000000..a78c0c7c --- /dev/null +++ b/apps/establishment/apps.py @@ -0,0 +1,8 @@ +from django.apps import AppConfig +from django.utils.translation import ugettext_lazy as _ + + +class EstablishmentsConfig(AppConfig): + + name = 'establishment' + verbose_name = _('Establishment') diff --git a/apps/establishments/migrations/__init__.py b/apps/establishment/migrations/__init__.py similarity index 100% rename from apps/establishments/migrations/__init__.py rename to apps/establishment/migrations/__init__.py diff --git a/apps/establishments/models.py b/apps/establishment/models.py similarity index 100% rename from apps/establishments/models.py rename to apps/establishment/models.py diff --git a/apps/establishments/tests.py b/apps/establishment/tests.py similarity index 100% rename from apps/establishments/tests.py rename to apps/establishment/tests.py diff --git a/apps/establishments/apps.py b/apps/establishments/apps.py deleted file mode 100644 index 341b1bdb..00000000 --- a/apps/establishments/apps.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.apps import AppConfig - - -class EstablishmentsConfig(AppConfig): - name = 'establishments' diff --git a/apps/establishments/serializers/__init__.py b/apps/establishments/serializers/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/serializers/common.py b/apps/establishments/serializers/common.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/serializers/web.py b/apps/establishments/serializers/web.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/urls/__init__.py b/apps/establishments/urls/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/urls/common.py b/apps/establishments/urls/common.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/urls/web.py b/apps/establishments/urls/web.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/views/__init__.py b/apps/establishments/views/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/views/common.py b/apps/establishments/views/common.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/establishments/views/web.py b/apps/establishments/views/web.py deleted file mode 100644 index e69de29b..00000000 diff --git a/project/settings/base.py b/project/settings/base.py index 75a54cb9..1615b30b 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -54,12 +54,13 @@ CONTRIB_APPS = [ PROJECT_APPS = [ 'account.apps.AccountConfig', 'authorization.apps.AuthorizationConfig', + 'collection.apps.CollectionConfig', + 'establishment.apps.EstablishmentConfig', 'location.apps.LocationConfig', 'main.apps.MainConfig', 'news.apps.NewsConfig', - 'translation.apps.TranslationConfig', - 'collection.apps.CollectionConfig', 'partner.apps.PartnerConfig' + 'translation.apps.TranslationConfig', ] EXTERNAL_APPS = [ From f33fa21c0c6f2c6a4874bf70598a28cbed83b269 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 26 Aug 2019 18:12:15 +0300 Subject: [PATCH 02/10] update site feautures --- apps/main/migrations/0007_sitefeature_main.py | 18 ++++++++ apps/main/models.py | 5 +++ apps/main/serializers.py | 42 ++++++++++++------- 3 files changed, 50 insertions(+), 15 deletions(-) create mode 100644 apps/main/migrations/0007_sitefeature_main.py diff --git a/apps/main/migrations/0007_sitefeature_main.py b/apps/main/migrations/0007_sitefeature_main.py new file mode 100644 index 00000000..a16b98cb --- /dev/null +++ b/apps/main/migrations/0007_sitefeature_main.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-08-26 14:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('main', '0006_auto_20190822_1118'), + ] + + operations = [ + migrations.AddField( + model_name='sitefeature', + name='main', + field=models.BooleanField(default=False, verbose_name='Main'), + ), + ] diff --git a/apps/main/models.py b/apps/main/models.py index 563dbd88..5b41d75b 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -133,6 +133,10 @@ class SiteSettings(ProjectBaseMixin): return self.feature_set.filter(sitefeature__site_settings=self, sitefeature__published=True) + @property + def published_sitefeatures(self): + return self.sitefeature_set.filter(published=True) + @property def site_url(self): return methods.site_url(schema=settings.SCHEMA_URI, @@ -168,6 +172,7 @@ class SiteFeature(ProjectBaseMixin): site_settings = models.ForeignKey(SiteSettings, on_delete=models.CASCADE) feature = models.ForeignKey(Feature, on_delete=models.PROTECT) published = models.BooleanField(default=False, verbose_name=_('Published')) + main = models.BooleanField(default=False, verbose_name=_('Main')) objects = SiteFeatureQuerySet.as_manager() diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 708bc33c..7b55f6ac 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -16,11 +16,23 @@ class FeatureSerializer(serializers.ModelSerializer): ) +class SiteFeatureSerializer(serializers.ModelSerializer): + + id = serializers.IntegerField(source='feature.id') + slug = serializers.CharField(source='feature.slug') + + class Meta: + """Meta class.""" + model = models.SiteFeature + fields = ('main', + 'id', + 'slug') + + class SiteSettingsSerializer(serializers.ModelSerializer): """Site settings serializer.""" - published_features = FeatureSerializer(many=True, allow_null=None) - + published_features = SiteFeatureSerializer(many=True, allow_null=True) #todo: remove this country_code = serializers.CharField(source='subdomain', read_only=True) @@ -42,16 +54,16 @@ class SiteSettingsSerializer(serializers.ModelSerializer): ) -class SiteFeatureSerializer(serializers.ModelSerializer): - """Site feature serializer.""" - - class Meta: - """Meta class.""" - - model = models.SiteFeature - fields = ( - 'id', - 'published', - 'site_settings', - 'feature', - ) +# class SiteFeatureSerializer(serializers.ModelSerializer): +# """Site feature serializer.""" +# +# class Meta: +# """Meta class.""" +# +# model = models.SiteFeature +# fields = ( +# 'id', +# 'published', +# 'site_settings', +# 'feature', +# ) From 5c5ae15836e1fce83674b3cc4fa3d7a18e88a03a Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 26 Aug 2019 18:24:47 +0300 Subject: [PATCH 03/10] update settings --- project/settings/base.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/settings/base.py b/project/settings/base.py index 1615b30b..95900e5f 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -59,7 +59,7 @@ PROJECT_APPS = [ 'location.apps.LocationConfig', 'main.apps.MainConfig', 'news.apps.NewsConfig', - 'partner.apps.PartnerConfig' + 'partner.apps.PartnerConfig', 'translation.apps.TranslationConfig', ] From 0135b256354b08641cd3333154b04f7149753c04 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 26 Aug 2019 18:25:16 +0300 Subject: [PATCH 04/10] update urls conf --- project/urls/__init__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/project/urls/__init__.py b/project/urls/__init__.py index 3f1ee7a2..2f936184 100644 --- a/project/urls/__init__.py +++ b/project/urls/__init__.py @@ -54,6 +54,8 @@ urlpatterns_auth = [ ] api_urlpatterns = [ + path('establishments/', include(('establishment.urls', 'establishment'), + namespace='establishment')), path('location/', include(('location.urls', 'location'), namespace='location')), path('main/', include(('main.urls', 'main'), From 245158c43142375d4411a529c241a13c7c593794 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Mon, 26 Aug 2019 18:29:02 +0300 Subject: [PATCH 05/10] update SiteSettings serializer --- apps/main/serializers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 7b55f6ac..372e1b68 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -32,7 +32,8 @@ class SiteFeatureSerializer(serializers.ModelSerializer): class SiteSettingsSerializer(serializers.ModelSerializer): """Site settings serializer.""" - published_features = SiteFeatureSerializer(many=True, allow_null=True) + published_features = SiteFeatureSerializer(source='published_sitefeatures', + many=True, allow_null=True) #todo: remove this country_code = serializers.CharField(source='subdomain', read_only=True) From f82784cd19f8a1ccbbd618a0118cdc0017d1b002 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 27 Aug 2019 12:33:16 +0300 Subject: [PATCH 06/10] update establishment-list endpoint --- apps/establishment/apps.py | 2 +- apps/establishment/migrations/0001_initial.py | 68 ++++++++++ apps/establishment/models.py | 117 +++++++++++++++++- apps/establishment/serializers.py | 46 +++++++ apps/establishment/urls/__init__.py | 0 apps/establishment/urls/common.py | 11 ++ apps/establishment/urls/web.py | 7 ++ apps/establishment/views.py | 34 +++++ project/urls/__init__.py | 2 - project/urls/web.py | 5 +- requirements/development.txt | 1 + 11 files changed, 282 insertions(+), 11 deletions(-) create mode 100644 apps/establishment/migrations/0001_initial.py create mode 100644 apps/establishment/serializers.py create mode 100644 apps/establishment/urls/__init__.py create mode 100644 apps/establishment/urls/common.py create mode 100644 apps/establishment/urls/web.py create mode 100644 apps/establishment/views.py diff --git a/apps/establishment/apps.py b/apps/establishment/apps.py index a78c0c7c..ee5512ad 100644 --- a/apps/establishment/apps.py +++ b/apps/establishment/apps.py @@ -2,7 +2,7 @@ from django.apps import AppConfig from django.utils.translation import ugettext_lazy as _ -class EstablishmentsConfig(AppConfig): +class EstablishmentConfig(AppConfig): name = 'establishment' verbose_name = _('Establishment') diff --git a/apps/establishment/migrations/0001_initial.py b/apps/establishment/migrations/0001_initial.py new file mode 100644 index 00000000..660aa80f --- /dev/null +++ b/apps/establishment/migrations/0001_initial.py @@ -0,0 +1,68 @@ +# Generated by Django 2.2.4 on 2019-08-27 09:29 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone +import easy_thumbnails.fields +import utils.methods + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('location', '0007_auto_20190826_1342'), + ] + + operations = [ + migrations.CreateModel( + name='EstablishmentType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('name', models.CharField(max_length=255, unique=True, verbose_name='Name')), + ('use_subtypes', models.BooleanField(default=True, verbose_name='Use subtypes')), + ], + options={ + 'verbose_name': 'Establishment type', + 'verbose_name_plural': 'Establishment types', + }, + ), + migrations.CreateModel( + name='EstablishmentSubType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('name', models.CharField(max_length=255, unique=True, verbose_name='Name')), + ('establishment_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='establishment.EstablishmentType', verbose_name='Type')), + ], + options={ + 'verbose_name': 'Establishment subtype', + 'verbose_name_plural': 'Establishment subtypes', + }, + ), + migrations.CreateModel( + name='Establishment', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('image', easy_thumbnails.fields.ThumbnailerImageField(blank=True, default=None, null=True, upload_to=utils.methods.image_path, verbose_name='Image')), + ('name', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Name')), + ('description', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Description')), + ('public_mark', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Public mark')), + ('toque_number', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Toque number')), + ('address', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='location.Address', verbose_name='Address')), + ('establishment_subtypes', models.ManyToManyField(related_name='subtype_establishment', to='establishment.EstablishmentSubType', verbose_name='Subtype')), + ('establishment_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='establishment', to='establishment.EstablishmentType', verbose_name='Type')), + ], + options={ + 'verbose_name': 'Establishment', + 'verbose_name_plural': 'Establishments', + }, + ), + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 4c84c7cc..989cf625 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,14 +1,119 @@ +"""Establishment models.""" from django.contrib.postgres.fields import JSONField +from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ - -from utils.models import ProjectBaseMixin, ImageMixin +from location.models import Address +from utils.models import ProjectBaseMixin, ImageMixin, LocaleManagerMixin -class Establishment(ProjectBaseMixin): +# todo: establishment type&subtypes check +class EstablishmentType(ProjectBaseMixin): + """Establishment type model.""" + + name = models.CharField(_('Name'), max_length=255, unique=True) + use_subtypes = models.BooleanField(_('Use subtypes'), default=True) + + class Meta: + """Meta class.""" + + verbose_name = _('Establishment type') + verbose_name_plural = _('Establishment types') + + def __str__(self): + """__str__ method.""" + return self.name + + +class EstablishmentSubTypeManager(models.Manager): + """Extended manager for establishment subtype.""" + + def make(self, name, establishment_type): + obj = self.model(name=name, establishment_type=establishment_type) + obj.full_clean() + obj.save() + return obj + + +class EstablishmentSubType(ProjectBaseMixin): + """Establishment type model.""" + + name = models.CharField(_('Name'), max_length=255, unique=True) + establishment_type = models.ForeignKey(EstablishmentType, + on_delete=models.CASCADE, + verbose_name=_('Type')) + + objects = EstablishmentSubTypeManager() + + class Meta: + """Meta class.""" + + verbose_name = _('Establishment subtype') + verbose_name_plural = _('Establishment subtypes') + + def __str__(self): + """__str__ method.""" + return self.name + + def clean_fields(self, exclude=None): + if not self.establishment_type.use_subtypes: + raise ValidationError(_('Establishment type is not use subtypes.')) + + +class EstablishmentManager(LocaleManagerMixin): + """Extended manager for establishment model.""" + + +class Establishment(ProjectBaseMixin, ImageMixin): """Establishment model.""" - name = models.CharField(max_length=100) - description = JSONField() - country = models.ForeignKey('location.Country', on_delete=models.CASCADE) + name = JSONField(blank=True, null=True, default=None, + verbose_name=_('Name'), help_text='{"en":"some text"}') + description = JSONField(blank=True, null=True, default=None, + verbose_name=_('Description'), + help_text='{"en":"some text"}') + public_mark = models.PositiveIntegerField(blank=True, null=True, + default=None, + verbose_name=_('Public mark'),) + toque_number = models.PositiveIntegerField(blank=True, null=True, + default=None, + verbose_name=_('Toque number'),) + establishment_type = models.ForeignKey(EstablishmentType, + related_name='establishment', + on_delete=models.PROTECT, + verbose_name=_('Type')) + establishment_subtypes = models.ManyToManyField(EstablishmentSubType, + related_name='subtype_establishment', + verbose_name=_('Subtype')) + address = models.ForeignKey(Address, blank=True, null=True, default=None, + on_delete=models.PROTECT, + verbose_name=_('Address')) + objects = EstablishmentManager() + + class Meta: + """Meta class.""" + + verbose_name = _('Establishment') + verbose_name_plural = _('Establishments') + + # todo: recalculate toque_number + def recalculate_toque_number(self): + self.toque_number = 4 + + @property + def subtypes(self): + return EstablishmentSubType.objects.filter( + establishments=self, + establishment_type=self.establishment_type, + establishment_type__use_subtypes=True) + + def set_establishment_type(self, establishment_type): + self.establishment_type = establishment_type + self.establishment_subtypes.exclude( + establishement_type=establishment_type).delete() + + def add_establishment_subtype(self, establishment_subtype): + if establishment_subtype.establishment_type != self.establishment_type: + raise ValidationError('Establishment type of subtype does not match') + self.establishment_subtypes.add(establishment_subtype) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py new file mode 100644 index 00000000..81b438cb --- /dev/null +++ b/apps/establishment/serializers.py @@ -0,0 +1,46 @@ +"""Establishment serializers.""" +from rest_framework import serializers +from establishment import models + + +class EstablishmentTypeSerializer(serializers.ModelSerializer): + """Serializer for EstablishmentType model.""" + + class Meta: + """Meta class.""" + + model = models.EstablishmentType + fields = ('id', 'name', 'use_subtypes') + + +class EstablishmentSubTypeSerializer(serializers.ModelSerializer): + """Serializer for EstablishmentSubType models.""" + + class Meta: + """Meta class.""" + + model = models.EstablishmentSubType + fields = ('id', 'name') + + +class EstablishmentSerializer(serializers.ModelSerializer): + """Serializer for Establishment model.""" + + name_trans = serializers.CharField() + description_trans = serializers.CharField() + type = EstablishmentTypeSerializer(source='establishment_type') + subtypes = EstablishmentSubTypeSerializer(many=True) + + class Meta: + """Meta class.""" + + model = models.Establishment + fields = ( + 'id', + 'name_trans', + 'description_trans', + 'public_mark', + 'type', + 'subtypes', + 'address', + ) diff --git a/apps/establishment/urls/__init__.py b/apps/establishment/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py new file mode 100644 index 00000000..6542eec9 --- /dev/null +++ b/apps/establishment/urls/common.py @@ -0,0 +1,11 @@ +"""Establishment url patterns.""" +from django.urls import include, path +from establishment import views + + +app_name = 'establishment' + + +urlpatterns = [ + path('', views.EstablishmentListView.as_view(), name='establishment-list'), +] \ No newline at end of file diff --git a/apps/establishment/urls/web.py b/apps/establishment/urls/web.py new file mode 100644 index 00000000..b732d171 --- /dev/null +++ b/apps/establishment/urls/web.py @@ -0,0 +1,7 @@ +"""Establishment app web urlconf.""" +from establishment.urls.common import urlpatterns as common_urlpatterns + + +urlpatterns = [] + +urlpatterns.extend(common_urlpatterns) \ No newline at end of file diff --git a/apps/establishment/views.py b/apps/establishment/views.py new file mode 100644 index 00000000..094fca56 --- /dev/null +++ b/apps/establishment/views.py @@ -0,0 +1,34 @@ +"""Establishment app views.""" +from rest_framework import generics, permissions +from establishment import models, serializers +from utils.views import JWTGenericViewMixin + + +class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): + """Resource for getting a list of establishments.""" + + pagination_class = None + permission_classes = (permissions.AllowAny,) + serializer_class = serializers.EstablishmentSerializer + + def get_queryset(self): + return models.Establishment.objects.annotate_localized_fields( + locale=self.request.locale) + + +class EstablishmentTypeListView(generics.ListAPIView): + """Resource for getting a list of establishment types.""" + + pagination_class = None + permission_classes = (permissions.AllowAny,) + queryset = models.EstablishmentType.objects.all() + serializer_class = serializers.EstablishmentTypeSerializer + + +class EstablishmentSubTypeListView(generics.ListAPIView): + """Resource for getting a list of establishment subtypes.""" + + pagination_class = None + permission_classes = (permissions.AllowAny,) + queryset = models.EstablishmentType.objects.all() + serializer_class = serializers.EstablishmentSubTypeSerializer diff --git a/project/urls/__init__.py b/project/urls/__init__.py index fd03905a..ef909dcf 100644 --- a/project/urls/__init__.py +++ b/project/urls/__init__.py @@ -54,8 +54,6 @@ urlpatterns_auth = [ ] api_urlpatterns = [ - path('establishments/', include(('establishment.urls', 'establishment'), - namespace='establishment')), path('location/', include(('location.urls', 'location'), namespace='location')), path('main/', include(('main.urls', 'main'), diff --git a/project/urls/web.py b/project/urls/web.py index 956d0c11..7f4a20c7 100644 --- a/project/urls/web.py +++ b/project/urls/web.py @@ -19,8 +19,9 @@ app_name = 'web' urlpatterns = [ path('account/', include('account.urls.web')), - path('news/', include('news.urls.web')), + path('advertisement/', include('advertisement.urls.web')), path('collection/', include('collection.urls.web')), + path('establishments/', include('establishment.urls.web')), + path('news/', include('news.urls.web')), path('partner/', include('partner.urls.web')), - path('advertisement/', include('advertisement.urls.web')) ] diff --git a/requirements/development.txt b/requirements/development.txt index 79801f49..21f7ead9 100644 --- a/requirements/development.txt +++ b/requirements/development.txt @@ -1,2 +1,3 @@ -r base.txt +ipdb ipython \ No newline at end of file From c942f00bd6b7edaab021426ef64dff468456bd4f Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 27 Aug 2019 12:36:48 +0300 Subject: [PATCH 07/10] remove unused views --- apps/establishment/views.py | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/establishment/views.py b/apps/establishment/views.py index 094fca56..c8029249 100644 --- a/apps/establishment/views.py +++ b/apps/establishment/views.py @@ -14,21 +14,3 @@ class EstablishmentListView(JWTGenericViewMixin, generics.ListAPIView): def get_queryset(self): return models.Establishment.objects.annotate_localized_fields( locale=self.request.locale) - - -class EstablishmentTypeListView(generics.ListAPIView): - """Resource for getting a list of establishment types.""" - - pagination_class = None - permission_classes = (permissions.AllowAny,) - queryset = models.EstablishmentType.objects.all() - serializer_class = serializers.EstablishmentTypeSerializer - - -class EstablishmentSubTypeListView(generics.ListAPIView): - """Resource for getting a list of establishment subtypes.""" - - pagination_class = None - permission_classes = (permissions.AllowAny,) - queryset = models.EstablishmentType.objects.all() - serializer_class = serializers.EstablishmentSubTypeSerializer From 910027d10f028031766b361c036b785592e0d6e5 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 27 Aug 2019 14:23:11 +0300 Subject: [PATCH 08/10] update establishment model, migrations --- apps/establishment/migrations/0001_initial.py | 3 ++- apps/establishment/models.py | 5 ++++- apps/establishment/serializers.py | 6 +++++- apps/location/models.py | 2 ++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/apps/establishment/migrations/0001_initial.py b/apps/establishment/migrations/0001_initial.py index 660aa80f..fb92225e 100644 --- a/apps/establishment/migrations/0001_initial.py +++ b/apps/establishment/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.2.4 on 2019-08-27 09:29 +# Generated by Django 2.2.4 on 2019-08-27 11:22 import django.contrib.postgres.fields.jsonb from django.db import migrations, models @@ -56,6 +56,7 @@ class Migration(migrations.Migration): ('description', django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Description')), ('public_mark', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Public mark')), ('toque_number', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Toque number')), + ('price_level', models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='Price level')), ('address', models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='location.Address', verbose_name='Address')), ('establishment_subtypes', models.ManyToManyField(related_name='subtype_establishment', to='establishment.EstablishmentSubType', verbose_name='Subtype')), ('establishment_type', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='establishment', to='establishment.EstablishmentType', verbose_name='Type')), diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 989cf625..9473a86e 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -88,6 +88,9 @@ class Establishment(ProjectBaseMixin, ImageMixin): address = models.ForeignKey(Address, blank=True, null=True, default=None, on_delete=models.PROTECT, verbose_name=_('Address')) + price_level = models.PositiveIntegerField(blank=True, null=True, + default=None, + verbose_name=_('Price level')) objects = EstablishmentManager() @@ -104,7 +107,7 @@ class Establishment(ProjectBaseMixin, ImageMixin): @property def subtypes(self): return EstablishmentSubType.objects.filter( - establishments=self, + subtype_establishment=self, establishment_type=self.establishment_type, establishment_type__use_subtypes=True) diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 81b438cb..94676027 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -1,6 +1,7 @@ """Establishment serializers.""" from rest_framework import serializers from establishment import models +from location.serializers import AddressSerializer class EstablishmentTypeSerializer(serializers.ModelSerializer): @@ -10,7 +11,7 @@ class EstablishmentTypeSerializer(serializers.ModelSerializer): """Meta class.""" model = models.EstablishmentType - fields = ('id', 'name', 'use_subtypes') + fields = ('id', 'name',) class EstablishmentSubTypeSerializer(serializers.ModelSerializer): @@ -30,6 +31,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): description_trans = serializers.CharField() type = EstablishmentTypeSerializer(source='establishment_type') subtypes = EstablishmentSubTypeSerializer(many=True) + address = AddressSerializer() class Meta: """Meta class.""" @@ -40,7 +42,9 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'name_trans', 'description_trans', 'public_mark', + 'price_level', 'type', 'subtypes', + 'image', 'address', ) diff --git a/apps/location/models.py b/apps/location/models.py index f69eeeb9..e7b9e9ac 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -88,6 +88,8 @@ class Address(models.Model): _('Coordinates'), blank=True, null=True, default=None) class Meta: + """Meta class.""" + verbose_name_plural = _('Address') verbose_name = _('Address') From 6667047537c8a78fd70ad437788787f583e62a46 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 27 Aug 2019 14:23:41 +0300 Subject: [PATCH 09/10] establishment admin conf --- apps/establishment/admin.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index 8c38f3f3..0562fb8e 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -1,3 +1,4 @@ +"""Establishment admin conf.""" from django.contrib import admin # Register your models here. From c04771ca58d71a4dd37fbf7b623c31d557522ad2 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Tue, 27 Aug 2019 16:53:05 +0300 Subject: [PATCH 10/10] recalculate price level preview version --- apps/establishment/models.py | 10 ++++++++ apps/establishment/tasks.py | 21 +++++++++++++++++ .../migrations/0008_auto_20190827_1302.py | 23 +++++++++++++++++++ apps/location/models.py | 19 ++++++++++++++- 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 apps/establishment/tasks.py create mode 100644 apps/location/migrations/0008_auto_20190827_1302.py diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 9473a86e..67a6b6ce 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -104,6 +104,16 @@ class Establishment(ProjectBaseMixin, ImageMixin): def recalculate_toque_number(self): self.toque_number = 4 + def recalculate_price_level(self, low_price=None, high_price=None): + if low_price is None or high_price is None: + low_price, high_price = self.get_price_level() + # todo: calculate price level + self.price_level = 3 + + def get_price_level(self): + country = self.address.city.country + return country.low_price, country.high_price + @property def subtypes(self): return EstablishmentSubType.objects.filter( diff --git a/apps/establishment/tasks.py b/apps/establishment/tasks.py new file mode 100644 index 00000000..cf23a7e6 --- /dev/null +++ b/apps/establishment/tasks.py @@ -0,0 +1,21 @@ +"""Establishment app tasks.""" +import logging +from celery import shared_task +from establishment import models +from location.models import Country + + +logger = logging.getLogger(__name__) + + +@shared_task +def recalculate_price_levels_by_country(country_id): + try: + country = Country.objects.get(pk=country_id) + except Country.DoesNotExist as ex: + logger.error(f'ESTABLISHMENT. Country does not exist. ID {country_id}') + else: + qs = models.Establishment.objects.filter(address__city__country=country) + for establishment in qs: + establishment.recalculate_price_level(low_price=country.low_price, + high_price=country.high_price) diff --git a/apps/location/migrations/0008_auto_20190827_1302.py b/apps/location/migrations/0008_auto_20190827_1302.py new file mode 100644 index 00000000..173e7b96 --- /dev/null +++ b/apps/location/migrations/0008_auto_20190827_1302.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.4 on 2019-08-27 13:02 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0007_auto_20190826_1342'), + ] + + operations = [ + migrations.AddField( + model_name='country', + name='high_price', + field=models.IntegerField(default=50, verbose_name='High price'), + ), + migrations.AddField( + model_name='country', + name='low_price', + field=models.IntegerField(default=25, verbose_name='Low price'), + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index e7b9e9ac..578d4939 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -1,8 +1,12 @@ """Location app models.""" +from django.conf import settings +from django.db.models.signals import post_save +from django.db.transaction import on_commit +from django.dispatch import receiver from django.contrib.gis.db import models from django.contrib.postgres.fields import JSONField from django.utils.translation import gettext_lazy as _ - +from establishment.tasks import recalculate_price_levels_by_country from utils.models import ProjectBaseMixin, LocaleManagerMixin, SVGImageMixin @@ -16,6 +20,8 @@ class Country(SVGImageMixin, ProjectBaseMixin): name = JSONField(null=True, blank=True, default=None, verbose_name=_('Name'), help_text='{"en":"some text"}') code = models.CharField(max_length=255, unique=True, verbose_name=_('Code')) + low_price = models.IntegerField(default=25, verbose_name=_('Low price')) + high_price = models.IntegerField(default=50, verbose_name=_('High price')) objects = CountryManager() @@ -106,3 +112,14 @@ class Address(models.Model): @property def longitude(self): return self.coordinates.x + + +# todo: Make recalculate price levels +@receiver(post_save, sender=Country) +def run_recalculate_price_levels(sender, instance, **kwargs): + if settings.USE_CELERY: + on_commit(lambda: recalculate_price_levels_by_country.delay( + country_id=instance.id)) + else: + on_commit(lambda: recalculate_price_levels_by_country( + country_id=instance.id))