diff --git a/core/utils.py b/core/utils.py index 7dd2b4af..1ae82b4c 100644 --- a/core/utils.py +++ b/core/utils.py @@ -83,13 +83,13 @@ def queryset_to_workbook(queryset, columns, report_date = None): 'pattern: pattern solid, fore_color gray_ega;', ) odd_style = xlwt.Style.easyxf( - 'font: name Calibri, height 300, bold False;' + 'font: name Calibri, height 240, bold False;' 'borders: left thin, right thin, top thin, bottom thin;' 'alignment: horizontal center, vertical center, wrap True;' 'pattern: pattern solid, fore_color white;', ) even_style = xlwt.Style.easyxf( - 'font: name Calibri, height 300, bold False;' + 'font: name Calibri, height 240, bold False;' 'borders: left thin, right thin, top thin, bottom thin;' 'alignment: horizontal center, vertical center, wrap True;' 'pattern: pattern solid, fore_color silver_ega;', diff --git a/core/views.py b/core/views.py index d762dc01..08ecb20c 100644 --- a/core/views.py +++ b/core/views.py @@ -266,13 +266,18 @@ def download_workbook(request): lang = get_language() data = request.GET if data: - qs = [] - for i,obj in enumerate(data): - if data.get('data[%i][name]' % i) == 'expo': - qs.append(Exposition.objects.language(lang).get(id=data['data[%i][value]'%i])) - elif data.get('data[%i][name]' % i) == 'conf': - qs.append(Conference.objects.language(lang).get(id=data['data[%i][value]'%i])) - + if data.get('filter') == u'future': + qs = request.user.calendar.get_events() + qs = [event for event in qs if event.data_begin > datetime.date.today()] + else: + qs = [] + for i,obj in enumerate(data): + if data.get('data[%i][name]' % i) == 'expo': + qs.append(Exposition.objects.language(lang).get(id=data['data[%i][value]'%i])) + elif data.get('data[%i][name]' % i) == 'conf': + qs.append(Conference.objects.language(lang).get(id=data['data[%i][value]'%i])) + if not qs: + return HttpResponseRedirect("/profile/calendar/?message=empty") earliest_event = qs[0].data_begin for i, obj in enumerate(qs, start=1): if obj.data_begin < earliest_event: @@ -305,4 +310,4 @@ def download_workbook(request): workbook.save(response) return response else: - return HttpResponseRedirect(request.META.get('HTTP_REFERER'), "/profile/calendar/") + return HttpResponseRedirect("/profile/calendar/") diff --git a/emencia/django/newsletter/admin_urls.py b/emencia/django/newsletter/admin_urls.py index eeaa6f2b..4007fc9b 100644 --- a/emencia/django/newsletter/admin_urls.py +++ b/emencia/django/newsletter/admin_urls.py @@ -2,16 +2,18 @@ from django.conf.urls import url from django.conf.urls import patterns from emencia.django.newsletter.views.admin_views import ContactList, UpdateContact, MailingListView, UpdateMailingList,\ CreateMailingList, NewsletterListView, NewsletterCreate, ExportContacts, DeleteContact, NewsletterUpdate, \ - DeleteMailingList, ImportContacts + DeleteMailingList, ImportContacts, NewsletterHistory, NewsletterStatistics urlpatterns = patterns('', url(r'^newsletters/all/$', NewsletterListView.as_view(), name='newsletters_newsletters_list'), - url(r'^newsletters/(?P\d+)/edit/', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'), - url(r'^newsletters/(?P\d+)/test/', + url(r'^newsletters/(?P\d+)/edit/$', NewsletterUpdate.as_view(), name='newsletters_newsletters_update'), + url(r'^newsletters/(?P\d+)/history/', NewsletterHistory.as_view(), name='newsletters_newsletters_history'), + url(r'^newsletters/(?P\d+)/statistics/', NewsletterStatistics.as_view(), name='newsletters_newsletters_stat'), + url(r'^newsletters/(?P\d+)/test/$', 'emencia.django.newsletter.views.admin_views.send_test_newsletter', name='newsletters_newsletters_send_test'), - url(r'^newsletters/', NewsletterCreate.as_view(), name='newsletters_newsletters_create'), + url(r'^newsletters/$', NewsletterCreate.as_view(), name='newsletters_newsletters_create'), url(r'^mailinglist/all/$', MailingListView.as_view(), name='newsletters_mailinglist'), diff --git a/emencia/django/newsletter/models.py b/emencia/django/newsletter/models.py index 46298791..fbebc686 100644 --- a/emencia/django/newsletter/models.py +++ b/emencia/django/newsletter/models.py @@ -471,6 +471,16 @@ class ContactMailingStatus(models.Model): creation_date = models.DateTimeField(_('creation date'), auto_now_add=True) + def get_verbose_status(self): + verbose = '' + for s in self.STATUS_CHOICES: + if s[0] == self.status: + verbose = unicode(s[1]) + break + if self.status == ContactMailingStatus.LINK_OPENED: + verbose +=": %s"% (self.link.url, self.link.url) + return verbose + def __unicode__(self): return '%s : %s : %s' % (self.newsletter.__unicode__(), self.contact.__unicode__(), diff --git a/emencia/django/newsletter/views/admin_views.py b/emencia/django/newsletter/views/admin_views.py index cd62387e..1a7f4f2f 100644 --- a/emencia/django/newsletter/views/admin_views.py +++ b/emencia/django/newsletter/views/admin_views.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -from django.views.generic import CreateView, ListView, UpdateView, DeleteView, FormView +from django.views.generic import CreateView, ListView, UpdateView, DeleteView, FormView, DetailView from django.conf import settings from django.utils import translation from django.utils.translation import ugettext_lazy as _ @@ -8,7 +8,7 @@ from django.http import HttpResponseRedirect, HttpResponse from django.shortcuts import get_object_or_404 from django.core.urlresolvers import reverse_lazy from HTMLParser import HTMLParseError -from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter, Attachment +from emencia.django.newsletter.models import Contact, ContactSettings, MailingList, Newsletter, Attachment, ContactMailingStatus from emencia.django.newsletter.admin_forms import ContactSettingsForm, MailingListForm, NewsletterForm, AttachmentForm from emencia.django.newsletter.mailer import Mailer from ..forms import ContactFilterForm, ContactImportForm @@ -222,6 +222,51 @@ def send_test_newsletter(request, pk): return HttpResponseRedirect(redirect) +class NewsletterHistory(ListView): + model = ContactMailingStatus + template_name = 'admin/newsletters/newsletter_history.html' + paginate_by = 50 + + def get_queryset(self): + self.newsletter = get_object_or_404(Newsletter, pk=self.kwargs['pk']) + qs = self.newsletter.contactmailingstatus_set.select_related('contact', 'link').all() + if self.request.GET.get('filter'): + qs = qs.filter(status=self.request.GET['filter']) + return qs + + def get_context_data(self, **kwargs): + context = super(NewsletterHistory, self).get_context_data(**kwargs) + context['newsletter'] = self.newsletter + context['choices'] = ContactMailingStatus.STATUS_CHOICES + return context + +class NewsletterStatistics(DetailView): + model = Newsletter + template_name = 'admin/newsletters/newsletter_stat.html' + + def get_context_data(self, **kwargs): + context = super(NewsletterStatistics, self).get_context_data(**kwargs) + sent = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.SENT).count() + errors = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.ERROR).count() + opened = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.OPENED).count() + unsubscribed = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.UNSUBSCRIPTION).count() + no_data = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.ANNOUNCE_NO_DATA).count() + links = self.object.contactmailingstatus_set.filter(status=ContactMailingStatus.LINK_OPENED).count() + CMS = ContactMailingStatus + opened_percent = 0 if opened or sent == 0 else (float(opened)/sent)*100 + unsub_percent = 0 if unsubscribed or sent == 0 else (float(unsubscribed)/sent)*100 + stat = { + 'sent':{'data':sent, 'filter':""}, + 'errors':{ 'data':errors, 'filter':CMS.ERROR}, + 'opened':{'data': opened, 'filter': CMS.OPENED, 'percent': opened_percent}, + 'unsub':{'data': unsubscribed, 'filter': CMS.UNSUBSCRIPTION, 'percent': unsub_percent}, + 'no_data':{'data': no_data, 'filter': CMS.ANNOUNCE_NO_DATA}, + 'links':{'data': links, 'filter': CMS.LINK_OPENED}} + context.update({'stat': stat}) + return context + + + class ExportContacts(FormView): form_class = ContactFilterForm diff --git a/functions/forms.py b/functions/forms.py index e011dda3..cb19d3f5 100644 --- a/functions/forms.py +++ b/functions/forms.py @@ -97,10 +97,10 @@ class TranslatableModelForm(forms.ModelForm): if field.name not in veto_fields} for code, name in settings.LANGUAGES: - # todo: fix requirements - where field is required default language must be required to) for tr_field in self.translatable_fields: field = fkwargs[tr_field].formfield() - field.required = False + if code != get_language(): + field.required = False self.fields[tr_field+"_"+code] = field def clean(self): @@ -126,14 +126,13 @@ class TranslatableModelForm(forms.ModelForm): translations = {obj.language_code: obj for obj in list(inst.translations.all())} for lang in self.data_by_lang: if lang is not init_lang: - try: - tr = translations[lang] - except KeyError: - # there are no available translation in db - tr = inst.translate(lang) + translation = translations.get(lang) + # there are no available translation in db + if not translation: + translation = inst.translate(lang) for key, value in self.data_by_lang[lang].iteritems(): - setattr(tr, key, value) - tr.save() + setattr(translation, key, value) + translation.save() self.instance = inst.lazy_translation_getter(init_lang) return self.instance diff --git a/static/img/announce-letter.png b/static/img/announce-letter.png new file mode 100644 index 00000000..df548884 Binary files /dev/null and b/static/img/announce-letter.png differ diff --git a/templates/admin/newsletters/newsletter_history.html b/templates/admin/newsletters/newsletter_history.html new file mode 100644 index 00000000..f9a64245 --- /dev/null +++ b/templates/admin/newsletters/newsletter_history.html @@ -0,0 +1,58 @@ +{% extends 'admin/base.html' %} +{% load staticfiles %} +{% block body %} + +
+
+

История для {{ newsletter.title }}

+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + {% for item in object_list %} + + + + + + {% endfor %} + +
ДатаКонтактСтатус
{{ item.creation_date|date:"Y-m-d H:i:s" }}{{ item.contact.email }}{{ item.get_verbose_status|safe }}
+ +
+ {# pagination #} + {% include 'admin/includes/admin_pagination.html' with page_obj=object_list %} +
+ +{% endblock %} + diff --git a/templates/admin/newsletters/newsletter_list.html b/templates/admin/newsletters/newsletter_list.html index 6f7d712a..7cb4bef7 100644 --- a/templates/admin/newsletters/newsletter_list.html +++ b/templates/admin/newsletters/newsletter_list.html @@ -31,8 +31,8 @@ {{ item.sending_date|date:"Y-m-d H:i" }} тест Изменить - История - {% if item.status == item.SENT or item.status == item.CANCELED %}Статистика{% endif %} + История + {% if item.status == item.SENT or item.status == item.CANCELED %}Статистика{% endif %} {% endfor %} diff --git a/templates/admin/newsletters/newsletter_stat.html b/templates/admin/newsletters/newsletter_stat.html new file mode 100644 index 00000000..2f8bd0c6 --- /dev/null +++ b/templates/admin/newsletters/newsletter_stat.html @@ -0,0 +1,62 @@ +{% extends 'admin/base.html' %} +{% load staticfiles %} +{% block body %} + +
+
+

Статистика для {{ newsletter.title }}

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
НазваниеКоличество писем 
Отправлено{{ stat.sent.data }}Подробно
Ошибок{{ stat.errors.data }}Подробно
Открыто{{ stat.opened.data }} {% if stat.opened.percent %} ({{ stat.opened.percent|floatformat:"0" }}%) {% endif %}Подробно
Отписалось{{ stat.unsub.data }} {% if stat.unsub.percent %} ({{ stat.unsub.percent|floatformat:"0" }}%) {% endif %}Подробно
Нет данных{{ stat.no_data.data }}Подробно
Переходов по ссылкам{{ stat.links.data }}Подробно
+ +
+
+{% endblock %} + diff --git a/templates/client/accounts/calendar.html b/templates/client/accounts/calendar.html index 6a1f8502..36e0eb31 100644 --- a/templates/client/accounts/calendar.html +++ b/templates/client/accounts/calendar.html @@ -20,14 +20,18 @@ {% block content_list %}
{% with days=days events=events current_day=current_day %} - {% include 'includes/accounts/calendar_table.html' %} + {% include 'client/includes/accounts/calendar_table.html' %} {% endwith %}
{% if events|length > 0 %}
-
{{ days.15|date:"F"}}’{{ days.15|date:"y"}}
+
{{ days.15|date:"F"}}’{{ days.15|date:"y"}} +
+ +
+
{% include 'client/includes/accounts/calendar_list.html' with events=events %}
@@ -35,8 +39,8 @@
{% trans 'Все / выделенные:' %}