From fc4facbf83941108d47088cf2c0eb09e6ca35830 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Sun, 1 Sep 2019 12:35:09 +0300 Subject: [PATCH] add contacts for establishments --- apps/establishment/admin.py | 25 +++- .../migrations/0005_auto_20190901_0831.py | 77 +++++++++++ .../migrations/0006_merge_20190901_0846.py | 14 ++ apps/establishment/models.py | 122 ++++++++++++++++-- apps/establishment/serializers.py | 37 ++++++ .../migrations/0003_auto_20190821_1407.py | 2 +- .../migrations/0009_auto_20190901_0831.py | 19 +++ apps/location/models.py | 2 +- apps/main/models.py | 16 ++- apps/news/models.py | 6 +- apps/translation/models.py | 2 +- project/settings/base.py | 1 + requirements/base.txt | 1 + 13 files changed, 307 insertions(+), 17 deletions(-) create mode 100644 apps/establishment/migrations/0005_auto_20190901_0831.py create mode 100644 apps/establishment/migrations/0006_merge_20190901_0846.py create mode 100644 apps/location/migrations/0009_auto_20190901_0831.py diff --git a/apps/establishment/admin.py b/apps/establishment/admin.py index d40950b1..a5209c3d 100644 --- a/apps/establishment/admin.py +++ b/apps/establishment/admin.py @@ -25,10 +25,33 @@ class MetaDataContentInline(GenericTabularInline): extra = 0 +class ContactPhoneInline(admin.TabularInline): + """Contact phone inline admin.""" + model = models.ContactPhone + extra = 0 + + +class ContactEmailInline(admin.TabularInline): + """Contact email inline admin.""" + model = models.ContactEmail + extra = 0 + + +@admin.register(models.Contact) +class ContactAdmin(admin.ModelAdmin): + """Contact admin.""" + inlines = [ContactPhoneInline, ContactEmailInline, ] + + +class ContactsInline(admin.TabularInline): + model = models.Contact + extra = 0 + + @admin.register(models.Establishment) class EstablishmentAdmin(admin.ModelAdmin): """Establishment admin.""" - inlines = [AwardInline, MetaDataContentInline] + inlines = [AwardInline, MetaDataContentInline, ContactsInline, ] @admin.register(models.EstablishmentSchedule) diff --git a/apps/establishment/migrations/0005_auto_20190901_0831.py b/apps/establishment/migrations/0005_auto_20190901_0831.py new file mode 100644 index 00000000..ef99bf4d --- /dev/null +++ b/apps/establishment/migrations/0005_auto_20190901_0831.py @@ -0,0 +1,77 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:31 + +from django.db import migrations, models +import django.db.models.deletion +import phonenumber_field.modelfields +import utils.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0009_auto_20190901_0831'), + ('establishment', '0004_auto_20190828_1156'), + ] + + operations = [ + migrations.CreateModel( + name='Contact', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('address', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='location.Address')), + ], + options={ + 'verbose_name': 'contact', + 'verbose_name_plural': 'contacts', + }, + ), + migrations.AlterField( + model_name='establishment', + name='description', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='establishment', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Name'), + ), + migrations.AlterField( + model_name='establishmentsubtype', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.AlterField( + model_name='establishmenttype', + name='name', + field=utils.models.TJSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Description'), + ), + migrations.CreateModel( + name='ContactPhone', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('phone', phonenumber_field.modelfields.PhoneNumberField(max_length=128)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='phones', to='establishment.Contact')), + ], + options={ + 'verbose_name': 'contact phone', + 'verbose_name_plural': 'contact phones', + }, + ), + migrations.CreateModel( + name='ContactEmail', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('email', models.EmailField(max_length=254)), + ('contact', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='emails', to='establishment.Contact')), + ], + options={ + 'verbose_name': 'contact email', + 'verbose_name_plural': 'contact emails', + }, + ), + migrations.AddField( + model_name='contact', + name='establishment', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contacts', to='establishment.Establishment'), + ), + ] diff --git a/apps/establishment/migrations/0006_merge_20190901_0846.py b/apps/establishment/migrations/0006_merge_20190901_0846.py new file mode 100644 index 00000000..e629f2b9 --- /dev/null +++ b/apps/establishment/migrations/0006_merge_20190901_0846.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:46 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('establishment', '0005_auto_20190901_0831'), + ('establishment', '0005_establishmentschedule'), + ] + + operations = [ + ] diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 68b8872e..0c73b722 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -1,12 +1,15 @@ """Establishment models.""" -from functools import reduce +from django.contrib.contenttypes import fields as generic from django.core.exceptions import ValidationError from django.db import models from django.utils.translation import gettext_lazy as _ +from phonenumber_field.modelfields import PhoneNumberField + from location.models import Address -from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, - TraslatedFieldsMixin, BaseAttributes) -from django.contrib.contenttypes import fields as generic +from utils.models import ( + ProjectBaseMixin, ImageMixin, TJSONField, + TraslatedFieldsMixin, BaseAttributes +) # todo: establishment type&subtypes check @@ -14,7 +17,7 @@ class EstablishmentType(ProjectBaseMixin, TraslatedFieldsMixin): """Establishment type model.""" name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') use_subtypes = models.BooleanField(_('Use subtypes'), default=True) class Meta: @@ -38,7 +41,7 @@ class EstablishmentSubType(ProjectBaseMixin, TraslatedFieldsMixin): """Establishment type model.""" name = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') establishment_type = models.ForeignKey(EstablishmentType, on_delete=models.CASCADE, verbose_name=_('Type')) @@ -75,10 +78,10 @@ class Establishment(ProjectBaseMixin, ImageMixin, TraslatedFieldsMixin): """Establishment model.""" name = TJSONField(blank=True, null=True, default=None, - verbose_name=_('Name'), help_text='{"en":"some text"}') + verbose_name=_('Name'), help_text='{"en-GB":"some text"}') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('Description'), - help_text='{"en":"some text"}') + help_text='{"en-GB":"some text"}') public_mark = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Public mark'),) @@ -160,3 +163,106 @@ class EstablishmentSchedule(BaseAttributes): """Meta class""" verbose_name = _('Establishment schedule') verbose_name_plural = _('Establishment schedules') + + +class Contact(models.Model): + """Contact model.""" + establishment = models.ForeignKey( + Establishment, related_name='contacts', on_delete=models.CASCADE) + address = models.ForeignKey('location.Address', on_delete=models.CASCADE) + + class Meta: + verbose_name = _('contact') + verbose_name_plural = _('contacts') + + +class ContactPhone(models.Model): + """Contact phone model.""" + contact = models.ForeignKey( + Contact, related_name='phones', on_delete=models.CASCADE) + phone = PhoneNumberField() + + class Meta: + verbose_name = _('contact phone') + verbose_name_plural = _('contact phones') + + def __str__(self): + return f'{self.phone.as_e164}' + + +class ContactEmail(models.Model): + """Contact email model.""" + contact = models.ForeignKey( + Contact, related_name='emails', on_delete=models.CASCADE) + email = models.EmailField() + + class Meta: + verbose_name = _('contact email') + verbose_name_plural = _('contact emails') + + def __str__(self): + return f'{self.email}' + +# +# class Wine(TraslatedFieldsMixin, 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(TraslatedFieldsMixin, models.Model): +# """Plate model.""" +# +# STARTER = 0 +# MAIN = 1 +# COURSE = 2 +# DESSERT = 3 +# +# PLATE_TYPE_CHOICES = ( +# (STARTER, _('starter')), +# (MAIN, _('main')), +# (COURSE, _('course')), +# (DESSERT, _('dessert')), +# ) +# name = models.CharField(_('name'), max_length=255) +# plate_type = models.PositiveSmallIntegerField(_('plate_type'), choices=PLATE_TYPE_CHOICES) +# description = TJSONField( +# blank=True, null=True, default=None, verbose_name=_('description'), +# help_text='{"en-GB":"some text"}') +# price = models.DecimalField( +# _('price'), max_digits=14, decimal_places=2) +# is_signature_plate = models.BooleanField(_('is signature plate')) +# currency = models.ForeignKey( +# 'main.Currency', verbose_name=_('currency'), on_delete=models.CASCADE) +# +# menu = models.ManyToManyField(to='Plate', verbose_name=_(''), through='establishment.Menu') +# +# class Meta: +# verbose_name = _('plate') +# verbose_name_plural = _('plates') +# +# def __str__(self): +# return f'plate_id:{self.id}' +# +# +# class Menu(TraslatedFieldsMixin, BaseAttributes): +# """Menu model.""" +# establishment = models.ForeignKey( +# 'establishment.Establishment', verbose_name=_('establishment'), +# on_delete=models.CASCADE) +# plate = models.ForeignKey(Plate, verbose_name=_('menu'), on_delete=models.CASCADE) +# +# class Meta: +# verbose_name = _('menu') +# verbose_name_plural = _('menu') \ No newline at end of file diff --git a/apps/establishment/serializers.py b/apps/establishment/serializers.py index 49788db3..92c7bb1c 100644 --- a/apps/establishment/serializers.py +++ b/apps/establishment/serializers.py @@ -6,6 +6,39 @@ from main.serializers import MetaDataContentSerializer, AwardSerializer from timetable.models import Timetable +class ContactPhonesSerializer(serializers.ModelSerializer): + """Contact phone serializer""" + class Meta: + model = models.ContactPhone + fields = [ + 'phone' + ] + + +class ContactEmailsSerializer(serializers.ModelSerializer): + """Contact email serializer""" + class Meta: + model = models.ContactEmail + fields = [ + 'email' + ] + + +class ContactSerializer(serializers.ModelSerializer): + """Contact serializer.""" + address = AddressSerializer(read_only=True) + phones = ContactPhonesSerializer(read_only=True, many=True,) + emails = ContactEmailsSerializer(read_only=True, many=True,) + + class Meta: + model = models.Contact + fields = [ + 'address', + 'phones', + 'emails' + ] + + class EstablishmentTypeSerializer(serializers.ModelSerializer): """Serializer for EstablishmentType model.""" @@ -59,6 +92,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): schedule = EstablishmentScheduleSerializer(source='schedule.schedule', many=True, allow_null=True) + contacts = ContactSerializer(read_only=True, many=True, ) class Meta: """Meta class.""" @@ -79,4 +113,7 @@ class EstablishmentSerializer(serializers.ModelSerializer): 'tags', 'awards', 'schedule', + 'contacts' ) + + diff --git a/apps/location/migrations/0003_auto_20190821_1407.py b/apps/location/migrations/0003_auto_20190821_1407.py index 548e2a70..c82ec597 100644 --- a/apps/location/migrations/0003_auto_20190821_1407.py +++ b/apps/location/migrations/0003_auto_20190821_1407.py @@ -30,6 +30,6 @@ class Migration(migrations.Migration): migrations.AddField( model_name='country', name='name', - field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en":"some text"}', null=True, verbose_name='Text'), + field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Text'), ), ] diff --git a/apps/location/migrations/0009_auto_20190901_0831.py b/apps/location/migrations/0009_auto_20190901_0831.py new file mode 100644 index 00000000..c4e21715 --- /dev/null +++ b/apps/location/migrations/0009_auto_20190901_0831.py @@ -0,0 +1,19 @@ +# Generated by Django 2.2.4 on 2019-09-01 08:31 + +import django.contrib.postgres.fields.jsonb +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('location', '0008_auto_20190827_1302'), + ] + + operations = [ + migrations.AlterField( + model_name='country', + name='name', + field=django.contrib.postgres.fields.jsonb.JSONField(blank=True, default=None, help_text='{"en-GB":"some text"}', null=True, verbose_name='Name'), + ), + ] diff --git a/apps/location/models.py b/apps/location/models.py index 56bd89f3..613cc013 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -17,7 +17,7 @@ class Country(SVGImageMixin, ProjectBaseMixin): """Country model.""" name = JSONField(null=True, blank=True, default=None, - verbose_name=_('Name'), help_text='{"en":"some text"}') + verbose_name=_('Name'), help_text='{"en-GB":"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')) diff --git a/apps/main/models.py b/apps/main/models.py index cb406d98..b58dc402 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -190,7 +190,7 @@ class Award(TraslatedFieldsMixin, models.Model): award_type = models.ForeignKey('main.AwardType', on_delete=models.CASCADE) title = TJSONField( _('title'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') vintage_year = models.CharField(_('vintage year'), max_length=255, default='') content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) @@ -228,7 +228,7 @@ class MetaData(TraslatedFieldsMixin, models.Model): """MetaData model.""" label = TJSONField( _('label'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') category = models.ForeignKey( MetaDataCategory, verbose_name=_('category'), on_delete=models.CASCADE) @@ -250,3 +250,15 @@ class MetaDataContent(models.Model): object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey('content_type', 'object_id') metadata = models.ForeignKey(MetaData, on_delete=models.CASCADE) + + +class Currency(models.Model): + """Currency model.""" + name = models.CharField(_('name'), max_length=50) + + class Meta: + verbose_name = _('currency') + verbose_name_plural = _('currencies') + + def __str__(self): + return f'{self.name}' diff --git a/apps/news/models.py b/apps/news/models.py index e3eff57e..0abc7ab5 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -43,14 +43,14 @@ class News(BaseAttributes, TraslatedFieldsMixin): title = TJSONField( _('title'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') subtitle = TJSONField( _('subtitle'), null=True, blank=True, - default=None, help_text='{"en":"some text"}' + default=None, help_text='{"en-GB":"some text"}' ) description = TJSONField( _('description'), null=True, blank=True, - default=None, help_text='{"en":"some text"}' + default=None, help_text='{"en-GB":"some text"}' ) start = models.DateTimeField(_('start')) end = models.DateTimeField(_('end')) diff --git a/apps/translation/models.py b/apps/translation/models.py index f675b315..42530965 100644 --- a/apps/translation/models.py +++ b/apps/translation/models.py @@ -49,7 +49,7 @@ class SiteInterfaceDictionary(ProjectBaseMixin): verbose_name=_('Page')) keywords = models.CharField(max_length=255, verbose_name='Keywords') text = JSONField(_('Text'), null=True, blank=True, - default=None, help_text='{"en":"some text"}') + default=None, help_text='{"en-GB":"some text"}') objects = SiteInterfaceDictionaryManager() diff --git a/project/settings/base.py b/project/settings/base.py index 588011d1..6a4a5836 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -82,6 +82,7 @@ EXTERNAL_APPS = [ 'django_extensions', 'rest_framework_simplejwt.token_blacklist', 'solo', + 'phonenumber_field', ] diff --git a/requirements/base.txt b/requirements/base.txt index 20a87346..3d7987c0 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -17,6 +17,7 @@ djangorestframework-xml celery amqp>=2.4.0 geoip2==2.9.0 +django-phonenumber-field[phonenumbers]==2.1.0 # auth socials djangorestframework-oauth