# -*- coding: utf-8 -*- import copy import datetime from dateutil.relativedelta import relativedelta from bitfield import BitField from django.conf import settings from django.contrib.contenttypes import generic from django.core.urlresolvers import reverse_lazy from django.db import models from django.db.models import Q from django.db.models.signals import post_save, pre_save from django.utils import translation from django.utils.translation import ugettext as _ from functions.custom_fields import EnumField from functions.db import db_table_exists from functions.model_mixin import EventMixin, ExpoMixin from functions.models_methods import ExpoManager, hvad_to_dict from functions.signal_handlers import post_save_handler, pre_save_handler from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from import_xls.model_utils import ExpoImportManager from manager import ClientManager from organiser.models import Organiser from service.models import Service from events.common import MEMBERS, VISITORS, PRICE, PRICE_EUR AUDIENCE1 = ((None,_(u'Не выбрано')), ('experts', _(u'Специалисты')), ('experts and consumers', _(u'Специалисты и потребители')), ('general public', _(u'Широкая публика')) ) AUDIENCE = (None,'experts', 'experts and consumers', 'general public') BIT_AUDIENCE = settings.BIT_AUDIENCE CURRENCY = settings.CURRENCY # check if table exist and create flags if true #flags = [item.url for item in Service.objects.all()] if db_table_exists('service_service') else [] flags = ['catalog', 'translator', 'participation', 'remote', 'tickets', 'visit', 'buildstand'] class Exposition(TranslatableModel, EventMixin, ExpoMixin): """ Create Exposition model Uses hvad.TranslatableModel which is child of django.db.models class """ catalog = '/expo/' catalog_name = _(u'Выставки:') search_name = None # type of event event_type = 'expo' url = models.SlugField(unique=True, max_length=255) bad_url = models.BooleanField(verbose_name=_(u'Подозрение на неправильный урл'), default=False) old_url = models.SlugField(unique=True, max_length=255) data_begin = models.DateField(verbose_name=_(u'Дата начала'), db_index=True) data_end = models.DateField(verbose_name=_(u'Дата окончания')) services = BitField(flags=flags) # relations creator = models.ForeignKey('accounts.User', verbose_name=_(u'Создатель'), on_delete=models.SET_NULL, related_name='exposition_creator', blank=True, null=True) country = models.ForeignKey('country.Country', verbose_name=_(u'Страна'), on_delete=models.PROTECT, related_name='exposition_country') city = models.ForeignKey('city.City', verbose_name=_(u'Город'), on_delete=models.PROTECT, related_name='exposition_city') place = models.ForeignKey('place_exposition.PlaceExposition', verbose_name=_(u'Место проведения'), blank=True, null=True, on_delete=models.PROTECT, related_name='exposition_place') theme = models.ManyToManyField('theme.Theme', verbose_name=_(u'Тематики'), related_name='exposition_themes') tag = models.ManyToManyField('theme.Tag', verbose_name=_(u'Теги'), blank=True, null=True, related_name='exposition_tags') organiser = models.ManyToManyField('organiser.Organiser', verbose_name=_(u'Организатор'), blank=True, null=True, related_name='exposition_organisers') org = models.CharField(max_length=255, blank=True, null=True) place_alt = models.CharField(max_length=255, blank=True, null=True) company = models.ManyToManyField('company.Company', verbose_name=_(u'Компании'), blank=True, null=True, related_name='exposition_companies') users = models.ManyToManyField('accounts.User', verbose_name=_(u'Посетители выставки'), blank=True, null=True, related_name='exposition_users') photogallery = models.ForeignKey('photologue.Gallery', blank=True, null=True, on_delete=models.SET_NULL) logo = models.ImageField(verbose_name='Logo', upload_to='exposition/logo/', blank=True) rating = models.IntegerField(default=0) # добавить индекс в базе quality_label = BitField(flags=['ufi', 'rsva', 'exporating']) visitors = models.PositiveIntegerField(verbose_name=_(u'Посетители'), blank=True, null=True) members = models.PositiveIntegerField(verbose_name=_(u'Участники'), blank=True, null=True) discount = models.PositiveIntegerField(verbose_name=_(u'Скидка'), blank=True, null=True) expohit = models.BooleanField(verbose_name=_(u'Expohit'), default=0) # administrator can cancel exposition canceled_by_administrator = models.BooleanField(default=0) #can publish not immediately is_published = models.BooleanField(default=0, db_index=True) canceled = models.BooleanField(default=0) moved = models.BooleanField(default=0) # field saves information about creating and changing model created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) main_page = models.PositiveIntegerField(default=0, db_index=True) views = models.PositiveIntegerField(default=0) translations = TranslatedFields( name = models.CharField(verbose_name=_(u'Название'), max_length=255), main_title = models.TextField(verbose_name=_(u'Краткое описание'), blank=True), description = models.TextField(verbose_name=_(u'Описание'), blank=True), products = models.TextField(verbose_name=_(u'Экспонируемые продукты'), blank=True), discount_description = models.TextField(verbose_name=_(u'Описание скидки'), blank=True), time = models.TextField(verbose_name=_(u'Время работы'), blank=True), # visit and particaption data price_day = models.CharField(verbose_name=_(u'Стоимость билета 1 день'), max_length=255, blank=True), price_all = models.CharField(verbose_name=_(u'Стоимость билета все дни'), max_length=255, blank=True), price_day_bar = models.CharField(verbose_name=_(u'Стоимость на стойке 1 день'), max_length=255, blank=True), price_all_bar = models.CharField(verbose_name=_(u'Стоимость на стойке все дни'), max_length=255, blank=True), stat_countries = models.TextField(verbose_name=_(u'Участвующие страны'), blank=True), pre_condition = models.CharField(verbose_name=_(u'Условия предварительной регистрации'), max_length=255, blank=True), stand_condition = models.CharField(verbose_name=_(u'Условия регистрации на стойке'), max_length=255, blank=True), visit_note = models.CharField(verbose_name=_(u'Примечание по посещению'), max_length=255, blank=True), participation_note = models.TextField(verbose_name=_(u'Примечание по участии'), blank=True), #-----meta data title = models.CharField(max_length=250), descriptions = models.CharField(max_length=250), keywords = models.CharField(max_length=250), ) files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') note = generic.GenericRelation('note.Note', content_type_field='content_type', object_id_field='object_id') #about periodic = models.FloatField(verbose_name=_(u'Переодичность'), blank=True, null=True) audience = BitField(flags=[k for k, v in BIT_AUDIENCE]) web_page = models.CharField(verbose_name=_(u'Вебсайт'), max_length=255, blank=True) foundation_year = models.PositiveIntegerField(verbose_name=_(u'Год основания'), blank=True, null=True) area = models.PositiveIntegerField(verbose_name=_(u'Площадь'), blank=True, null=True) # conditions of Participation registration_link = models.URLField(verbose_name=_(u'Ссылка на регистрацию'), max_length=255, blank=True) min_area = models.PositiveIntegerField(verbose_name=_(u'Минимальная площадь'), blank=True, null=True) currency = EnumField(values=CURRENCY, default='USD') application_deadline = models.DateField(verbose_name=_(u'Срок подачи заявки'), null=True) min_stand_size = models.PositiveIntegerField(verbose_name=_(u'Минимальный размер стэнда'), blank=True, null=True) price_catalog = models.PositiveIntegerField(verbose_name=_(u'Стоимость каталога'), blank=True, null=True) tax = models.BooleanField(verbose_name=_(u'Налог'), default=1) min_closed_area = models.PositiveIntegerField(verbose_name=_(u'Минимальная цена закрытой НЕ оборудованной площади'), blank=True, null=True) max_closed_area = models.PositiveIntegerField(verbose_name=_(u'Максимальная цена закрытой НЕ оборудованной площади'), blank=True, null=True) min_closed_equipped_area = models.PositiveIntegerField(verbose_name=_(u'Минимальная цена закрытой оборудованной площади'), blank=True, null=True) max_closed_equipped_area = models.PositiveIntegerField(verbose_name=_(u'Максимальная цена закрытой оборудованной площади'), blank=True, null=True) min_open_area = models.PositiveIntegerField(verbose_name=_(u'Минимальная цена открытой площади'), blank=True, null=True) max_open_area = models.PositiveIntegerField(verbose_name=_(u'Максимальная цена открытой площади'), blank=True, null=True) registration_payment = models.PositiveIntegerField(verbose_name=_(u'Регистрационный взнос'), blank=True, null=True) paid_new = models.ForeignKey('expobanner.Paid', blank=True, null=True, on_delete=models.SET_NULL) top = models.ForeignKey('expobanner.Top', blank=True, null=True, on_delete=models.SET_NULL) main = models.ForeignKey('expobanner.MainPage', blank=True, null=True, on_delete=models.SET_NULL) # fields for filter easy members_choice = models.PositiveSmallIntegerField( _(u'Участники'), choices=MEMBERS, blank=True, null=True, db_index=True) visitors_choice = models.PositiveSmallIntegerField( _(u'Посетители'), choices=VISITORS, blank=True, null=True, db_index=True) price_choice = models.PositiveSmallIntegerField( _(u'Минимальная цена'), choices=PRICE, blank=True, null=True, db_index=True) price_rub = models.PositiveIntegerField(verbose_name=_(u'Рублевая цена'), blank=True, null=True) price_choice_eur = models.PositiveSmallIntegerField( _(u'Минимальная цена'), choices=PRICE_EUR, blank=True, null=True, db_index=True) price_eur = models.PositiveIntegerField(verbose_name=_(u'Цена в евро'), blank=True, null=True) #set manager of this model(fisrt manager is default) objects = ExpoManager() enable = ClientManager() imports = ExpoImportManager() def __unicode__(self): return self.lazy_translation_getter('name', unicode(self.pk)) @property def get_price(self): return self.price_day or self.price_all def get_services(self): return self.get_services_detail() # country_ids = [item for item, bool in self.country.services if bool==True] # ids = [item for item, bool in self.services if bool==True] # qs = Service.objects.language().filter(Q(Q(url__in=country_ids) & Q(type=Service.type.expo)) | Q(url__in=ids)) # return list(qs) def get_services_detail(self): excluded = ['visit'] return super(Exposition, self).get_services_detail(excluded, Service.type.expo) def get_parent(self): return {} def get_absolute_url(self): return self.get_permanent_url() def get_news_url(self): return reverse_lazy('news_expo', kwargs={'slug': self.url}) def get_index_text(self): translation.activate('ru') translations = self.translations.all() names = ' '.join([tr.name for tr in translations]) titles = ' '.join([tr.main_title for tr in translations]) themes = ' '.join([' '.join(theme.get_all_names()) for theme in self.theme.all()]) tags = ' '.join([' '.join(tag.get_all_names()) for tag in self.tag.all()]) return names + ' ' + titles + ' ' + themes + ' ' + tags def get_note_by_user(self, user_id): note = self.note.filter(user__id=user_id) try: return note.get().text except: return '' def upload_photo_url(self): return '/admin/exposition/upload-photo/%s/' % self.id def tags(self): return self.tag.language().all() def themes(self): return self.theme.language().all() def statistic_exists(self): return Statistic.objects.filter(exposition=self).exists() def get_audience(self): checked = [item for item, bool in self.audience if bool==True] audience = [] for k, v in BIT_AUDIENCE: for item in checked: if item == k: audience.append(unicode(v)) return ', '.join(audience) def get_periodic(self): periodic = {0: '', 1.0: _(u'Ежегодно'), 2.0: _(u'2 раза в год'), 3.0: _(u'3 раза в год'), 4.0: _(u'4 раза в год'), 5.0: _(u'5 раз в год'), 0.5: _(u'Раз в 2 года'), 0.33: _(u'Раз в 3 года'), 0.25: _(u'Раз в 4 года'), 0.2: _(u'Раз в 5 лет')} return periodic.get(self.periodic) def get_catalog_url(self): return self.catalog def get_event_type(self): return _(u'Выставки') def get_calendar_url(self): return '/exposition-add-calendar/%s/'%self.id def get_visit_url(self): return '/exposition-visit/%s/'%self.id def get_note_url(self): return '/expo/add-note/%s/'%self.url def get_timetables_days(self): tables = list(self.business_program.all()) days = [] for t in tables: d = t.begin.replace(hour = 0, minute = 0, second = 0, microsecond = 0) if not d in days: days.append(d) return days def theme_ids(self): return [item['id'] for item in self.theme.all().values('id')] def clicks(self): return self.paid_new.tickets.clicks() + self.paid_new.participation.clicks() + self.paid_new.official.clicks() def get_paid_change_url(self): return reverse_lazy('expobanner-update_paid', kwargs={'pk': self.paid_new_id}) def get_objectstat_views(self): return sum(self.objectstats_set.all().values_list('value', flat=True)) class Statistic(TranslatableModel): exposition = models.ForeignKey(Exposition, related_name='statistic') year = models.PositiveIntegerField(verbose_name=_(u'Год')) members = models.PositiveIntegerField(verbose_name=_(u'Посетители'), blank=True, null=True) visitors = models.PositiveIntegerField(verbose_name=_(u'Участники'), blank=True, null=True) area = models.PositiveIntegerField(verbose_name=_(u'Площадь'), blank=True, null=True) countries_number = models.PositiveIntegerField(verbose_name=_(u'Количество стран'), blank=True, null=True) translations = TranslatedFields( countries = models.TextField(blank=True) ) def to_dict(self): return hvad_to_dict(self) class TimeTable(TranslatableModel): """ TimeTable for business program """ exposition = models.ForeignKey(Exposition, related_name='business_program') begin = models.DateTimeField(verbose_name=_(u'Начало')) end = models.DateTimeField(verbose_name=_(u'Конец')) timetable_organiser = models.ForeignKey(Organiser, null=True, blank=True) # created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) #translated fields translations = TranslatedFields( name = models.CharField(verbose_name=_(u'Название программы'), max_length=255, blank=True), programe = models.TextField(verbose_name=_(u'Программа'), blank=True), speaker = models.CharField(verbose_name=_(u'Организатор'), max_length=255, blank=True), place = models.CharField(verbose_name=_(u'Место проведения'), max_length=255, blank=True) ) def to_dict(self): #obj = serializers.serialize('json', [self,]) return hvad_to_dict(self) class TmpTimeTable(TranslatableModel): exposition = models.ForeignKey(Exposition, null=True, blank=True) begin = models.DateTimeField(verbose_name=_(u'Начало')) end = models.DateTimeField(verbose_name=_(u'Конец')) timetable_organiser = models.ForeignKey(Organiser, null=True, blank=True) # key uses for checking keys from new objects. key = models.CharField(max_length=255, blank=True) # created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) #translated fields translations = TranslatedFields( name = models.CharField(verbose_name=_(u'Название программы'), max_length=255, blank=True), programe = models.TextField(verbose_name=_(u'Программа')), speaker = models.CharField(verbose_name=_(u'Спикеры'), max_length=255, blank=True), place = models.CharField(verbose_name=_(u'Место проведения'), max_length=255, blank=True) ) def logo_name(instance, filename): url = instance.expo.url return '/'.join(['exposition', url, url+'_org_logo.jpg']) pre_save.connect(pre_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=Exposition) post_save.connect(post_save_handler, sender=TimeTable) post_save.connect(post_save_handler, sender=TmpTimeTable) post_save.connect(post_save_handler, sender=Statistic)