Merge remote-tracking branch 'origin/feature/guides' into feature/guides

# Conflicts:
#	apps/utils/export.py
This commit is contained in:
Dmitriy Kuzmenko 2019-12-27 17:59:20 +03:00
commit ccd9f717df
11 changed files with 101 additions and 32 deletions

View File

@ -965,3 +965,8 @@ class GuideElement(ProjectBaseMixin, MPTTModel):
def __str__(self): def __str__(self):
"""Overridden dunder method.""" """Overridden dunder method."""
return self.guide_element_type.name if self.guide_element_type else self.id return self.guide_element_type.name if self.guide_element_type else self.id
@property
def advertorial_page(self):
if self.advertorial:
return self.advertorial.right_pages

View File

@ -220,7 +220,7 @@ class GuideElementExportSerializer(GuideElementBaseSerializer):
# establishment = EstablishmentGuideElementSerializer(read_only=True,) # establishment = EstablishmentGuideElementSerializer(read_only=True,)
name = serializers.CharField(source='establishment.name', default=None) name = serializers.CharField(source='establishment.name', default=None)
public_mark = serializers.CharField(source='establishment.public_mark_display', default=None) public_mark = serializers.CharField(source='establishment.public_mark_display', default=None)
toque_number = serializers.CharField(source='establishment.toque_number', default=None) toque_number = serializers.IntegerField(source='establishment.toque_number', default=None)
schedule = serializers.DictField(source='establishment.schedule_display', schedule = serializers.DictField(source='establishment.schedule_display',
default=None) default=None)
address = serializers.CharField(source='establishment.address.full_address', address = serializers.CharField(source='establishment.address.full_address',
@ -235,13 +235,15 @@ class GuideElementExportSerializer(GuideElementBaseSerializer):
default=None) default=None)
price_level = serializers.CharField(source='establishment.price_level_display', price_level = serializers.CharField(source='establishment.price_level_display',
default=None) default=None)
# metadata = serializers.ListField(source='establishment.metadata', metadata = serializers.ListField(source='establishment.metadata',
# default=None) default=None)
advertorial_page = serializers.IntegerField(default=None)
class Meta: class Meta:
model = models.GuideElement model = models.GuideElement
fields = [ fields = [
'id', 'id',
'guide',
'node_name', 'node_name',
# 'establishment', # 'establishment',
# 'review', # 'review',
@ -263,5 +265,6 @@ class GuideElementExportSerializer(GuideElementBaseSerializer):
'establishment_subtypes', 'establishment_subtypes',
'review', 'review',
'price_level', 'price_level',
# 'metadata', 'metadata',
'advertorial_page',
] ]

View File

@ -205,6 +205,7 @@ class GuideElementExportDOCView(generics.ListAPIView):
"""Overridden get_queryset method.""" """Overridden get_queryset method."""
guide = get_object_or_404( guide = get_object_or_404(
models.Guide.objects.all(), pk=self.kwargs.get('pk')) models.Guide.objects.all(), pk=self.kwargs.get('pk'))
# todo: put in GuideElement model
tasks.export_guide(guide_id=guide.id, user_id=request.user.id, file_type='doc') tasks.export_guide(guide_id=guide.id, user_id=request.user.id, file_type='doc')
return Response({"success": _('The file will be sent to your email.')}, return Response({"success": _('The file will be sent to your email.')},
status=status.HTTP_200_OK) status=status.HTTP_200_OK)

View File

@ -14,11 +14,13 @@ from review import models as review_models
@admin.register(models.EstablishmentType) @admin.register(models.EstablishmentType)
class EstablishmentTypeAdmin(BaseModelAdminMixin, admin.ModelAdmin): class EstablishmentTypeAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""EstablishmentType admin.""" """EstablishmentType admin."""
raw_id_fields = ('tag_categories', 'default_image', )
@admin.register(models.EstablishmentSubType) @admin.register(models.EstablishmentSubType)
class EstablishmentSubTypeAdmin(BaseModelAdminMixin, admin.ModelAdmin): class EstablishmentSubTypeAdmin(BaseModelAdminMixin, admin.ModelAdmin):
"""EstablishmentSubType admin.""" """EstablishmentSubType admin."""
raw_id_fields = ('tag_categories', 'default_image', )
class AwardInline(GenericTabularInline): class AwardInline(GenericTabularInline):

View File

@ -0,0 +1,23 @@
# Generated by Django 2.2.7 on 2019-12-27 14:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('establishment', '0069_auto_20191220_1007'),
]
operations = [
migrations.AlterField(
model_name='establishmentsubtype',
name='tag_categories',
field=models.ManyToManyField(blank=True, related_name='establishment_subtypes', to='tag.TagCategory', verbose_name='Tag categories'),
),
migrations.AlterField(
model_name='establishmenttype',
name='tag_categories',
field=models.ManyToManyField(blank=True, related_name='establishment_types', to='tag.TagCategory', verbose_name='Tag categories'),
),
]

View File

@ -50,8 +50,9 @@ class EstablishmentType(TypeDefaultImageMixin, TranslatedFieldsMixin, ProjectBas
verbose_name=_('Index name')) verbose_name=_('Index name'))
use_subtypes = models.BooleanField(_('Use subtypes'), default=True) use_subtypes = models.BooleanField(_('Use subtypes'), default=True)
tag_categories = models.ManyToManyField('tag.TagCategory', tag_categories = models.ManyToManyField('tag.TagCategory',
blank=True,
related_name='establishment_types', related_name='establishment_types',
verbose_name=_('Tag')) verbose_name=_('Tag categories'))
default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL, default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL,
related_name='establishment_types', related_name='establishment_types',
blank=True, null=True, default=None, blank=True, null=True, default=None,
@ -92,8 +93,9 @@ class EstablishmentSubType(TypeDefaultImageMixin, TranslatedFieldsMixin, Project
on_delete=models.CASCADE, on_delete=models.CASCADE,
verbose_name=_('Type')) verbose_name=_('Type'))
tag_categories = models.ManyToManyField('tag.TagCategory', tag_categories = models.ManyToManyField('tag.TagCategory',
blank=True,
related_name='establishment_subtypes', related_name='establishment_subtypes',
verbose_name=_('Tag')) verbose_name=_('Tag categories'))
default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL, default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL,
related_name='establishment_sub_types', related_name='establishment_sub_types',
blank=True, null=True, default=None, blank=True, null=True, default=None,
@ -746,7 +748,7 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
@property @property
def contact_phones(self): def contact_phones(self):
if self.phones: if self.phones:
return [phone.as_e164 for phone in self.phones.all()] return [phone.phone.as_e164 for phone in self.phones.all()]
@property @property
def establishment_subtype_labels(self): def establishment_subtype_labels(self):
@ -780,7 +782,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
@property @property
def public_mark_display(self): def public_mark_display(self):
return f'{self.public_mark}/20' if self.public_mark and self.public_mark > 1:
return f'{self.public_mark}/20'
@property @property
def metadata(self): def metadata(self):
@ -790,7 +793,8 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
self.establishment_type.tag_categories.exclude(index_name__in=[ self.establishment_type.tag_categories.exclude(index_name__in=[
'business_tag', 'purchased_item', 'accepted_payments_de', 'business_tag', 'purchased_item', 'accepted_payments_de',
'accepted_payments_hr', 'drinks', 'bottles_per_year', 'accepted_payments_hr', 'drinks', 'bottles_per_year',
'serial_number', 'surface', 'cooperative', 'tag']).values_list('index_name', flat=True) 'serial_number', 'surface', 'cooperative', 'tag',
'outside_sits', 'private_room']).values_list('index_name', flat=True)
) )
for category in tag_categories: for category in tag_categories:
tags = self.tags.filter(category__index_name=category).values_list('value', flat=True) tags = self.tags.filter(category__index_name=category).values_list('value', flat=True)

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.7 on 2019-12-27 14:43
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('product', '0024_merge_20191223_1405'),
]
operations = [
migrations.AlterField(
model_name='producttype',
name='tag_categories',
field=models.ManyToManyField(blank=True, related_name='product_types', to='tag.TagCategory', verbose_name='Tag categories'),
),
]

View File

@ -43,6 +43,7 @@ class ProductType(TypeDefaultImageMixin, TranslatedFieldsMixin, ProjectBaseMixin
verbose_name=_('Index name'), choices=INDEX_CHOICES) verbose_name=_('Index name'), choices=INDEX_CHOICES)
use_subtypes = models.BooleanField(_('Use subtypes'), default=True) use_subtypes = models.BooleanField(_('Use subtypes'), default=True)
tag_categories = models.ManyToManyField('tag.TagCategory', tag_categories = models.ManyToManyField('tag.TagCategory',
blank=True,
related_name='product_types', related_name='product_types',
verbose_name=_('Tag categories')) verbose_name=_('Tag categories'))
default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL, default_image = models.ForeignKey('gallery.Image', on_delete=models.SET_NULL,

View File

@ -9,6 +9,8 @@ import docx
import xlsxwriter import xlsxwriter
from django.conf import settings from django.conf import settings
from django.core.mail import EmailMultiAlternatives from django.core.mail import EmailMultiAlternatives
from docx.blkcntnr import BlockItemContainer
from timetable.models import Timetable
from docx.shared import RGBColor, Pt from docx.shared import RGBColor, Pt
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
@ -27,7 +29,6 @@ class DocTemplate:
def __init__(self): def __init__(self):
self.document = docx.Document() self.document = docx.Document()
style = self.document.styles['Normal'] style = self.document.styles['Normal']
style.paragraph_format.space_before = Pt(12)
style.font.size = self.DOCUMENT_FONT_SIZE style.font.size = self.DOCUMENT_FONT_SIZE
style.font.name = self.DOCUMENT_FONT_NAME style.font.name = self.DOCUMENT_FONT_NAME
style.font.color.rgb = self.DOCUMENT_FONT_COLOR style.font.color.rgb = self.DOCUMENT_FONT_COLOR
@ -37,7 +38,6 @@ class DocTemplate:
def add_empty_line(self): def add_empty_line(self):
self.document.add_paragraph() self.document.add_paragraph()
self.document.add_paragraph()
def add_horizontal_line(self): def add_horizontal_line(self):
return self.document.add_paragraph(f'{"_" * 50}') return self.document.add_paragraph(f'{"_" * 50}')
@ -48,7 +48,9 @@ class DocTemplate:
'size': Pt(10) 'size': Pt(10)
} }
for element in elements: for element in elements:
bullet = self.document.add_paragraph(style='List Bullet').add_run(element) bullet = self.document.add_paragraph(style='List Bullet')
bullet.paragraph_format.space_before = Pt(10)
bullet = bullet.add_run(element)
self.apply_font_style(bullet, params=styles) self.apply_font_style(bullet, params=styles)
def add_heading(self, name: str, level: int = 2, font_style: dict = None, def add_heading(self, name: str, level: int = 2, font_style: dict = None,
@ -59,7 +61,9 @@ class DocTemplate:
self.apply_font_color(heading, color_rgb) self.apply_font_color(heading, color_rgb)
def add_paragraph(self, name: str, font_style: dict = None, color_rgb: tuple = (0, 0, 0)): def add_paragraph(self, name: str, font_style: dict = None, color_rgb: tuple = (0, 0, 0)):
paragraph = self.document.add_paragraph().add_run(name) paragraph = self.document.add_paragraph()
paragraph.paragraph_format.space_before = Pt(10)
paragraph.add_run(name)
self.apply_font_style(paragraph, font_style) self.apply_font_style(paragraph, font_style)
if color_rgb: if color_rgb:
self.apply_font_color(paragraph, color_rgb) self.apply_font_color(paragraph, color_rgb)
@ -81,6 +85,7 @@ class DocTemplate:
for instance in data: for instance in data:
instance = dict(instance) instance = dict(instance)
element_id = instance.get('id')
index_name = section_name_into_index_name(instance.get('section_name')) index_name = section_name_into_index_name(instance.get('section_name'))
# ESTABLISHMENT HEADING (LEVEL 1) # ESTABLISHMENT HEADING (LEVEL 1)
@ -117,6 +122,7 @@ class DocTemplate:
# REVIEW TEXT PARAGRAPH # REVIEW TEXT PARAGRAPH
self.add_paragraph(name=text, self.add_paragraph(name=text,
font_style={'size': Pt(10), 'name': 'Arial'}) font_style={'size': Pt(10), 'name': 'Arial'})
self.add_empty_line()
# PHONE HEADING (LEVEL 2) # PHONE HEADING (LEVEL 2)
phones = instance.get('phones') phones = instance.get('phones')
@ -147,7 +153,9 @@ class DocTemplate:
level=2) level=2)
# TIMETABLE ITEMS PARAGRAPH # TIMETABLE ITEMS PARAGRAPH
for weekday, working_hours in schedule.items(): for weekday, working_hours in schedule.items():
bullet = self.document.add_paragraph(style='List Bullet').add_run(f'{weekday}: {working_hours}') bullet = self.document.add_paragraph(style='List Bullet')
bullet.paragraph_format.space_before = Pt(10)
bullet = bullet.add_run(f'{weekday}: {working_hours}')
self.apply_font_style(bullet, {'name': 'Arial', 'size': Pt(10)}) self.apply_font_style(bullet, {'name': 'Arial', 'size': Pt(10)})
self.add_empty_line() self.add_empty_line()
@ -160,6 +168,7 @@ class DocTemplate:
self.add_heading(name=public_mark, self.add_heading(name=public_mark,
font_style={'size': Pt(10), 'name': 'Arial'}, font_style={'size': Pt(10), 'name': 'Arial'},
level=2) level=2)
self.add_empty_line()
# TOQUE HEADING (LEVEL 2) # TOQUE HEADING (LEVEL 2)
toque = instance.get('toque_number') toque = instance.get('toque_number')
@ -170,6 +179,7 @@ class DocTemplate:
self.add_heading(name=toque, self.add_heading(name=toque,
font_style={'size': Pt(10), 'name': 'Arial'}, font_style={'size': Pt(10), 'name': 'Arial'},
level=2) level=2)
self.add_empty_line()
# TOQUE HEADING (LEVEL 2) # TOQUE HEADING (LEVEL 2)
price_level = instance.get('price_level') price_level = instance.get('price_level')
@ -180,6 +190,7 @@ class DocTemplate:
self.add_heading(name=price_level, self.add_heading(name=price_level,
font_style={'size': Pt(10), 'name': 'Arial'}, font_style={'size': Pt(10), 'name': 'Arial'},
level=2) level=2)
self.add_empty_line()
# SERVICES HEADING (LEVEL 2) # SERVICES HEADING (LEVEL 2)
services = instance.get('services') services = instance.get('services')
@ -196,6 +207,7 @@ class DocTemplate:
if metadata: if metadata:
for obj in metadata: for obj in metadata:
for section, tags in obj.items(): for section, tags in obj.items():
section = section.capitalize()
self.add_heading(name=section, self.add_heading(name=section,
font_style={'size': Pt(13), 'name': 'Arial', 'bold': True}, font_style={'size': Pt(13), 'name': 'Arial', 'bold': True},
level=2) level=2)
@ -390,8 +402,15 @@ class SendGuideExport(SendExportBase):
objects = [] objects = []
city_name = None city_name = None
section_name = None section_name = None
advertorial_page = None
for instance in init_data: for instance in init_data:
row_advertorial_page = instance.get('advertorial_page')
if row_advertorial_page:
advertorial_page = row_advertorial_page
else:
instance['advertorial_page'] = advertorial_page
row_city = instance.get('city_name') row_city = instance.get('city_name')
if row_city: if row_city:
city_name = row_city city_name = row_city

View File

@ -154,7 +154,7 @@ def transform_into_readable_str(raw_string: str, postfix: str = 'SectionNode'):
re_exp = r'[\w]+' re_exp = r'[\w]+'
result = re.findall(re_exp, raw_string) result = re.findall(re_exp, raw_string)
if result: if result:
return f"{''.join([i.capitalize() for i in result])}{postfix}" return f"{''.join([i.capitalize() for i in result])}"
def section_name_into_index_name(section_name: str): def section_name_into_index_name(section_name: str):

View File

@ -7,7 +7,7 @@ ALLOWED_HOSTS = ['*', ]
SEND_SMS = False SEND_SMS = False
SMS_CODE_SHOW = True SMS_CODE_SHOW = True
USE_CELERY = True USE_CELERY = False
SCHEMA_URI = 'http' SCHEMA_URI = 'http'
DEFAULT_SUBDOMAIN = 'www' DEFAULT_SUBDOMAIN = 'www'
@ -85,11 +85,11 @@ LOGGING = {
'py.warnings': { 'py.warnings': {
'handlers': ['console'], 'handlers': ['console'],
}, },
# 'django.db.backends': { 'django.db.backends': {
# 'handlers': ['console', ], 'handlers': ['console', ],
# 'level': 'DEBUG', 'level': 'DEBUG',
# 'propagate': False, 'propagate': False,
# }, },
} }
} }
@ -114,15 +114,8 @@ if TESTING:
ELASTICSEARCH_DSL_AUTOSYNC = False ELASTICSEARCH_DSL_AUTOSYNC = False
# Email settings # Email settings
SERVER_EMAIL = 'honyl@yandex.ru'
EMAIL_HOST = 'smtp.yandex.ru'
EMAIL_HOST_USER = 'honyl@yandex.ru'
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_PORT = '587'
EMAIL_USE_TLS = True EMAIL_USE_TLS = True
EMAIL_SUBJECT = 'Technical email from LunchBox' EMAIL_HOST = 'smtp.gmail.com'
EMAIL_FROM = 'honyl@yandex.ru' EMAIL_HOST_USER = 'anatolyfeteleu@gmail.com'
EMAIL_TO = [ EMAIL_HOST_PASSWORD = 'nggrlnbehzksgmbt'
'd.kuzmenko@spider.ru', EMAIL_PORT = 587
# 'g.baranova@spider.ru'
]