Merge branch 'develop' into feature/collect

This commit is contained in:
Виктор Гладких 2019-11-01 14:31:30 +03:00
commit 1df89b6c48
18 changed files with 273 additions and 38 deletions

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.4 on 2019-10-25 16:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('booking', '0002_auto_20191003_1601'),
]
operations = [
migrations.AddField(
model_name='booking',
name='amount',
field=models.CharField(default=None, max_length=30, null=True, verbose_name='prepayment price'),
),
migrations.AddField(
model_name='booking',
name='stripe_key',
field=models.TextField(default=None, null=True, verbose_name='stripe service payment key'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-10-25 16:50
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('booking', '0003_auto_20191025_1613'),
]
operations = [
migrations.AddField(
model_name='booking',
name='stripe_token',
field=models.TextField(default=None, null=True, verbose_name='stripe service pre-payed booking token'),
),
]

View File

@ -24,6 +24,9 @@ class Booking(ProjectBaseMixin):
pending_booking_id = models.TextField(verbose_name=_('external service pending booking'), default=None)
booking_id = models.TextField(verbose_name=_('external service booking id'), default=None, null=True,
db_index=True, )
stripe_key = models.TextField(null=True, default=None, verbose_name=_('stripe service payment key'))
stripe_token = models.TextField(null=True, default=None, verbose_name=_('stripe service pre-payed booking token'))
amount = models.CharField(null=True, default=None, verbose_name=_('prepayment price'), max_length=30)
user = models.ForeignKey(
'account.User', verbose_name=_('booking owner'), null=True,
related_name='bookings',

View File

@ -1,10 +1,13 @@
from abc import ABC, abstractmethod
import json
from abc import ABC, abstractmethod
import requests
from django.conf import settings
from rest_framework import status
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers, status
from rest_framework.response import Response
import booking.models.models as models
from rest_framework import serializers
class AbstractBookingService(ABC):
@ -24,8 +27,12 @@ class AbstractBookingService(ABC):
self.url = settings.LASTABLE_SERVICE
@staticmethod
def get_certain_keys(d: dict, keys_to_preserve: set) -> dict:
def get_certain_keys(d: dict, keys_to_preserve: set, required=True) -> dict:
""" Helper """
if required:
diff = keys_to_preserve - d.keys()
if diff:
raise serializers.ValidationError({field: _(f'This field is required') for field in diff})
return {key: d[key] for key in d.keys() & keys_to_preserve}
@abstractmethod
@ -66,22 +73,22 @@ class GuestonlineService(AbstractBookingService):
def get_common_headers(self):
return {'X-Token': self.token, 'Content-type': 'application/json', 'Accept': 'application/json'}
def check_whether_booking_available(self, restaurant_id, date: str):
super().check_whether_booking_available(restaurant_id, date)
url = f'{self.url}v1/runtime_services'
params = {'restaurant_id': restaurant_id, 'date': date, 'expands[]': 'table_availabilities'}
def check_whether_booking_available(self, restaurant_id, *args, **kwargs):
url = f'{self.url}v1/periods'
params = {'restaurant_id': restaurant_id, **kwargs}
r = requests.get(url, headers=self.get_common_headers(), params=params)
if not status.is_success(r.status_code):
return False
response = json.loads(r.content)['runtime_services']
keys_to_preserve = {'left_seats', 'table_availabilities', 'closed', 'start_time', 'end_time', 'last_booking'}
response = map(lambda x: self.get_certain_keys(x, keys_to_preserve), response)
self.response = response
self.response = r.json()
return True
def commit_booking(self, payload):
def commit_booking(self, payload, stripe_token = None):
url = f'{self.url}v1/pending_bookings/{payload}/commit'
r = requests.put(url, headers=self.get_common_headers())
if stripe_token:
r = requests.put(url, headers=self.get_common_headers(),
data=json.dumps({'stripe_token': stripe_token}))
else:
r = requests.put(url, headers=self.get_common_headers())
self.response = json.loads(r.content)
if status.is_success(r.status_code) and self.response is None:
raise serializers.ValidationError(detail='Booking already committed.')
@ -93,8 +100,13 @@ class GuestonlineService(AbstractBookingService):
payload['lastname'] = payload.pop('last_name')
payload['firstname'] = payload.pop('first_name')
payload['mobile_phone'] = payload.pop('phone')
payload['user_locale'] = payload.pop('country_code')
headers = self.get_common_headers()
r = requests.put(url, headers=headers, data=json.dumps({'contact_info': payload}))
response = r.json()
self.response = response.get('prepayment')
if not status.is_success(r.status_code):
return Response(status=r.status_code, data=response)
return status.is_success(r.status_code)
def create_booking(self, payload):
@ -103,7 +115,10 @@ class GuestonlineService(AbstractBookingService):
payload['persons'] = payload.pop('booked_persons_number')
payload['date'] = payload.pop('booking_date')
r = requests.post(url, headers=self.get_common_headers(), data=json.dumps(payload))
return json.loads(r.content)['id'] if status.is_success(r.status_code) else False
if status.is_success(r.status_code):
return json.loads(r.content)['id']
else:
return Response(status=r.status_code, data=r.json())
def cancel_booking(self, payload):
url = f'{self.url}v1/pending_bookings/{payload}'

View File

@ -42,13 +42,29 @@ class PendingBookingSerializer(serializers.ModelSerializer):
'user',
)
class CommitBookingSerializer(serializers.ModelSerializer):
class Meta:
model = models.Booking
fields = (
'stripe_token',
)
def update(self, instance, validated_data):
"""Override update method"""
# Update user password from instance
service = instance.get_service_by_type(instance.type)
service.commit_booking(instance.pending_booking_id, validated_data.get('stripe_token'))
instance.stripe_token = validated_data.get('stripe_token')
instance.save()
return instance
class UpdateBookingSerializer(serializers.ModelSerializer):
id = serializers.ReadOnlyField()
class Meta:
model = models.Booking
fields = ('booking_id', 'id')
fields = ('booking_id', 'id', 'stripe_key', 'amount')
class GetBookingSerializer(serializers.ModelSerializer):

View File

@ -8,6 +8,7 @@ urlpatterns = [
path('<int:establishment_id>/check/', views.CheckWhetherBookingAvailable.as_view(), name='booking-check'),
path('<int:establishment_id>/create/', views.CreatePendingBooking.as_view(), name='create-pending-booking'),
path('<int:pk>/', views.UpdatePendingBooking.as_view(), name='update-pending-booking'),
path('<int:pk>/commit/', views.CommitPendingBooking.as_view(), name='update-pending-booking'),
path('<int:pk>/cancel/', views.CancelBooking.as_view(), name='cancel-existing-booking'),
path('last/', views.LastBooking.as_view(), name='last_booking-for-authorizer-user'),
path('retrieve/<int:pk>/', views.GetBookingById.as_view(), name='retrieves-booking-by-id'),

View File

@ -1,11 +1,13 @@
from rest_framework import generics, permissions, status, serializers
from django.shortcuts import get_object_or_404
from establishment.models import Establishment
from booking.models.models import Booking, GuestonlineService, LastableService
from rest_framework import generics, permissions, status, serializers
from rest_framework.response import Response
from booking.serializers.web import (PendingBookingSerializer,
UpdateBookingSerializer, GetBookingSerializer, CheckBookingSerializer)
from booking.models.models import Booking, GuestonlineService, LastableService
from booking.serializers.web import (PendingBookingSerializer, UpdateBookingSerializer, GetBookingSerializer,
CheckBookingSerializer, CommitBookingSerializer)
from establishment.models import Establishment
from notification.models import Subscriber
from utils.methods import get_user_ip
class CheckWhetherBookingAvailable(generics.GenericAPIView):
@ -28,7 +30,9 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
service = l_service
service.service_id = establishment.lastable_id
elif (not establishment.guestonline_id is None) and g_service \
.check_whether_booking_available(establishment.guestonline_id, date):
.check_whether_booking_available(establishment.guestonline_id,
**g_service.get_certain_keys(request.query_params,
{'date', 'persons'})):
is_booking_available = True
service = g_service
service.service_id = establishment.guestonline_id
@ -61,7 +65,9 @@ class CreatePendingBooking(generics.CreateAPIView):
}
data['pending_booking_id'] = service.create_booking(
service.get_certain_keys(data.copy(), service_to_keys[data.get('type')]))
if not data['pending_booking_id']:
if isinstance(data['pending_booking_id'], Response):
return data['pending_booking_id']
elif not data['pending_booking_id']:
return Response(status=status.HTTP_403_FORBIDDEN, data='Unable to create booking')
data['booking_id'] = data['pending_booking_id'] if data.get('type') == Booking.LASTABLE else None
serializer = self.get_serializer(data=data)
@ -70,6 +76,13 @@ class CreatePendingBooking(generics.CreateAPIView):
return Response(status=status.HTTP_201_CREATED, data=serializer.data)
class CommitPendingBooking(generics.UpdateAPIView):
""" Commit pending booking """
queryset = Booking.objects.all()
permission_classes = (permissions.AllowAny,)
serializer_class = CommitBookingSerializer
class UpdatePendingBooking(generics.UpdateAPIView):
""" Update pending booking with contacts """
queryset = Booking.objects.all()
@ -81,9 +94,29 @@ class UpdatePendingBooking(generics.UpdateAPIView):
data = request.data.copy()
service = Booking.get_service_by_type(instance.type)
data['pending_booking_id'] = instance.pending_booking_id
service.update_booking(service.get_certain_keys(data, {
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id',
r = service.update_booking(service.get_certain_keys(data, {
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id', 'note',
}))
if isinstance(r, Response):
return r
if data.get('newsletter'):
Subscriber.objects.make_subscriber(email=data['email'], country_code=data['country_code'],
locale=request.locale, ip_address=get_user_ip(request),
user=request.user)
if service.response:
# если есть предоплата, возвращаем фронту страйп-ключ для совершения оплаты и цену
amount = service.response.get('amount')
stripe_key = service.response.get('stripe_key')
data = {
'id': instance.pk,
'amount': amount,
'stripe_key': stripe_key,
'type': instance.type,
}
serializer = self.get_serializer(data=data)
serializer.is_valid(raise_exception=True)
serializer.update(instance, data)
return Response(status=status.HTTP_200_OK, data=data)
service.commit_booking(data['pending_booking_id'])
data = {
'booking_id': service.response.get('id'),

View File

@ -26,6 +26,5 @@ class Command(BaseCommand):
establishment.description = description
establishment.save()
count += 1
break
self.stdout.write(self.style.WARNING(f'Updated {count} objects.'))

View File

@ -0,0 +1,56 @@
from django.core.management.base import BaseCommand
from establishment.models import Establishment, SocialNetwork
from transfer.models import EstablishmentInfos
class Command(BaseCommand):
help = 'Add social links values from old db to new db'
def handle(self, *args, **kwargs):
count = 0
queryset = EstablishmentInfos.objects.exclude(
establishment_id__isnull=True
).values_list('id', 'establishment_id', 'facebook', 'twitter', 'instagram')
for id, es_id, facebook, twitter, instagram in queryset:
try:
establishment = Establishment.objects.get(old_id=es_id)
except Establishment.DoesNotExist:
continue
except Establishment.MultipleObjectsReturned:
establishment = Establishment.objects.filter(old_id=es_id).first()
else:
if facebook:
if 'facebook.com/' not in facebook:
facebook = 'https://www.facebook.com/' + facebook
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='facebook',
url=facebook,
)
count += 1
if twitter:
if 'twitter.com/' not in twitter:
twitter = 'https://www.twitter.com/' + twitter
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='twitter',
url=twitter,
)
count += 1
if instagram:
if 'instagram.com/' not in instagram:
instagram = 'https://www.instagram.com/' + instagram
obj, _ = SocialNetwork.objects.get_or_create(
old_id=id,
establishment=establishment,
title='instagram',
url=instagram,
)
count += 1
self.stdout.write(self.style.WARNING(f'Created/updated {count} objects.'))

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-01 07:25
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0049_auto_20191031_1616'),
]
operations = [
migrations.AddField(
model_name='socialnetwork',
name='old_id',
field=models.PositiveIntegerField(blank=True, default=None, null=True, verbose_name='old id'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-01 07:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0050_socialnetwork_old_id'),
]
operations = [
migrations.AlterField(
model_name='socialnetwork',
name='url',
field=models.URLField(max_length=255, verbose_name='URL'),
),
]

View File

@ -309,6 +309,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
public_mark = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('public mark'),)
# todo: set default 0
toque_number = models.PositiveIntegerField(blank=True, null=True,
default=None,
verbose_name=_('toque number'),)
@ -383,7 +384,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
# todo: recalculate toque_number
def recalculate_toque_number(self):
toque_number = None
toque_number = 0
if self.address and self.public_mark:
toque_number = RatingStrategy.objects. \
get_toque_number(country=self.address.city.country,
@ -661,11 +662,12 @@ class Menu(TranslatedFieldsMixin, BaseAttributes):
class SocialNetwork(models.Model):
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
establishment = models.ForeignKey(
'Establishment', verbose_name=_('establishment'),
related_name='socials', on_delete=models.CASCADE)
title = models.CharField(_('title'), max_length=255)
url = models.URLField(_('URL'))
url = models.URLField(_('URL'), max_length=255)
class Meta:
verbose_name = _('social network')
@ -686,7 +688,7 @@ class RatingStrategyManager(models.Manager):
obj = qs.for_public_mark(public_mark).first()
if obj:
return obj.toque_number
return None
return 0
class RatingStrategyQuerySet(models.QuerySet):

View File

@ -7,7 +7,8 @@ from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _
from translation.models import Language
from utils.models import ProjectBaseMixin, SVGImageMixin, TranslatedFieldsMixin, TJSONField
from utils.models import (ProjectBaseMixin, SVGImageMixin, TJSONField,
TranslatedFieldsMixin, get_current_locale)
class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
@ -15,6 +16,13 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
STR_FIELD_NAME = 'name'
TWELVE_HOURS_FORMAT_COUNTRIES = [
'ca', # Canada
'au', # Australia
'us', # USA
'nz', # New Zealand
]
name = TJSONField(null=True, blank=True, default=None,
verbose_name=_('Name'), help_text='{"en-GB":"some text"}')
code = models.CharField(max_length=255, unique=True, verbose_name=_('Code'))
@ -23,6 +31,12 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
languages = models.ManyToManyField(Language, verbose_name=_('Languages'))
old_id = models.IntegerField(null=True, blank=True, default=None)
@property
def time_format(self):
if self.code.lower() not in self.TWELVE_HOURS_FORMAT_COUNTRIES:
return 'hh:mm'
return 'hh:mmA'
@property
def country_id(self):
return self.id
@ -33,6 +47,14 @@ class Country(TranslatedFieldsMixin, SVGImageMixin, ProjectBaseMixin):
verbose_name_plural = _('Countries')
verbose_name = _('Country')
def __str__(self):
str_name = self.code
if isinstance(self.name, dict):
translated_name = self.name.get(get_current_locale())
if translated_name:
str_name = translated_name
return str_name
class Region(models.Model):
"""Region model."""

View File

@ -1,11 +1,11 @@
from django.db.models import Q, QuerySet
from transfer.serializers.location import CountrySerializer, RegionSerializer, \
CitySerializer, AddressSerializer, \
Country
from transfer.models import Cities, Locations
from pprint import pprint
from requests import get
def transfer_countries():
queryset = Cities.objects.raw("""
@ -135,10 +135,14 @@ def transfer_addresses():
def update_flags():
queryset = Country.objects.only("id", "code", "svg_image").filter(old_id__isnull=False)
link_to_request = "https://s3.eu-central-1.amazonaws.com/gm-test.com/media"
for query in queryset:
query.svg_image = f"/image/image/10-31-2019/{query.code}.svg"
query.save()
svg_link = f"/svg/country/10-31-2019/{query.code}.svg"
resp = get(f"{link_to_request}{svg_link}")
if resp.status_code == 200:
query.svg_image = svg_link
query.save()
data_types = {

View File

@ -64,6 +64,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
country_code = serializers.CharField(source='subdomain', read_only=True)
country_name = serializers.CharField(source='country.name_translated', read_only=True)
time_format = serializers.CharField(source='country.time_format', read_only=True)
class Meta:
"""Meta class."""
@ -71,6 +72,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
model = models.SiteSettings
fields = (
'country_code',
'time_format',
'subdomain',
'pinterest_page_url',
'twitter_page_url',
@ -81,7 +83,7 @@ class SiteSettingsSerializer(serializers.ModelSerializer):
'ad_config',
'published_features',
'currency',
'country_name'
'country_name',
)

View File

@ -553,6 +553,7 @@ class EstablishmentInfos(MigrateMixin):
website = models.CharField(max_length=255, blank=True, null=True)
facebook = models.CharField(max_length=255, blank=True, null=True)
twitter = models.CharField(max_length=255, blank=True, null=True)
instagram = models.TextField(blank=True, null=True)
lafourchette = models.CharField(max_length=255, blank=True, null=True)
pub = models.IntegerField(blank=True, null=True)
created_at = models.DateTimeField()

View File

@ -64,7 +64,7 @@ def image_path(instance, filename):
def svg_image_path(instance, filename):
"""Determine SVG path method."""
filename = '%s.svg' % generate_code()
return 'image/svg/%s/%s/%s' % (
return 'svg/%s/%s/%s' % (
instance._meta.model_name,
datetime.now().strftime(settings.REST_DATE_FORMAT),
filename)

View File

@ -60,4 +60,8 @@ DATABASES = {
'USER': os.environ.get('MYSQL_USER'),
'PASSWORD': os.environ.get('MYSQL_PASSWORD')
}
}
}
BROKER_URL = 'redis://localhost:6379/1'
CELERY_RESULT_BACKEND = BROKER_URL
CELERY_BROKER_URL = BROKER_URL