From: Radek Czajka Date: Thu, 31 Oct 2013 10:32:43 +0000 (+0100) Subject: Working book shop. X-Git-Url: https://git.mdrn.pl/prawokultury.git/commitdiff_plain/c66b8465f48325fe5fdc0fcf600f97dcc7bb7a26?hp=-c Working book shop. --- c66b8465f48325fe5fdc0fcf600f97dcc7bb7a26 diff --git a/prawokultury/locale/pl/LC_MESSAGES/django.mo b/prawokultury/locale/pl/LC_MESSAGES/django.mo index 5859207..41f6877 100644 Binary files a/prawokultury/locale/pl/LC_MESSAGES/django.mo and b/prawokultury/locale/pl/LC_MESSAGES/django.mo differ diff --git a/prawokultury/locale/pl/LC_MESSAGES/django.po b/prawokultury/locale/pl/LC_MESSAGES/django.po index 261bf54..ff1d3f9 100644 --- a/prawokultury/locale/pl/LC_MESSAGES/django.po +++ b/prawokultury/locale/pl/LC_MESSAGES/django.po @@ -7,16 +7,16 @@ msgid "" msgstr "" "Project-Id-Version: prawokultury\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2013-05-17 10:41+0200\n" -"PO-Revision-Date: 2013-01-14 16:09+0100\n" +"POT-Creation-Date: 2013-10-31 11:29+0100\n" +"PO-Revision-Date: 2013-10-31 11:30+0100\n" "Last-Translator: Radek Czajka \n" "Language-Team: FNP \n" -"Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " -"|| n%100>=20) ? 1 : 2)\n" +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.5.4\n" #: menu_items.py:15 msgid "Publications" @@ -38,10 +38,14 @@ msgstr "Pierwsza pomoc" msgid "Guide" msgstr "Przewodnik" -#: urls.py:42 +#: urls.py:47 msgid "events" msgstr "wydarzenia" +#: urls.py:50 +msgid "shop" +msgstr "sklep" + #: settings.d/60-custom.py:5 msgid "news" msgstr "newsy" @@ -62,44 +66,44 @@ msgstr "Strona nie znaleziona" msgid "The page you were looking for doesn't exist." msgstr "Strona, której szukasz, nie istnieje." -#: templates/base.html:8 templates/base.html.py:14 templates/base.html:15 -#: templates/base.html.py:27 templates/base.html:79 +#: templates/base.html:9 templates/base.html.py:15 templates/base.html:16 +#: templates/base.html.py:28 templates/base.html:80 msgid "Right to Culture" msgstr "Prawo kultury" -#: templates/base.html:32 +#: templates/base.html:33 msgid "Organizer" msgstr "Organizator" -#: templates/base.html:35 +#: templates/base.html:36 msgid "Modern Poland Foundation" msgstr "Fundacja Nowoczesna Polska" -#: templates/base.html:37 +#: templates/base.html:38 msgid "Sponsor" msgstr "Wspierane przez" -#: templates/base.html:40 +#: templates/base.html:41 msgid "Trust for Civil Society in Central and Eastern Europe" msgstr "" -#: templates/base.html:49 +#: templates/base.html:50 msgid "Search" msgstr "Szukaj" -#: templates/base.html:65 +#: templates/base.html:66 msgid "Upcoming events" msgstr "Nadchodzące wydarzenia" -#: templates/base.html:69 +#: templates/base.html:70 msgid "Ask a lawyer" msgstr "Zapytaj prawnika" -#: templates/base.html:83 +#: templates/base.html:84 msgid "Latest comments" msgstr "Ostatnie komentarze" -#: templates/base.html:112 +#: templates/base.html:113 msgid "" "If not explicitly stated otherwise, all texts are licensed under the Creative Commons " @@ -109,6 +113,14 @@ msgstr "" "href='http://creativecommons.org/licenses/by-sa/3.0/deed.pl'>Creative " "Commons Uznanie autorstwa – Na tych samych warunkach." +#: templates/migdal/entry/publications/entry_detail.html:10 +msgid "This entry hasn't been published yet." +msgstr "Ten wpis nie został jeszcze opublikowany." + +#: templates/migdal/entry/publications/entry_detail.html:28 +msgid "Price" +msgstr "Cena" + #~ msgid "First aid in copyright" #~ msgstr "Pierwsza pomoc w prawie autorskim" diff --git a/prawokultury/middleware.py b/prawokultury/middleware.py new file mode 100755 index 0000000..0911a69 --- /dev/null +++ b/prawokultury/middleware.py @@ -0,0 +1,12 @@ +from honeypot.middleware import HoneypotViewMiddleware + +def honeypot_exempt(view): + view.honeypot_exempt = True + return view + +class ExemptableHoneypotViewMiddleware(HoneypotViewMiddleware): + def process_view(self, request, callback, callback_args, callback_kwargs): + if hasattr(callback, 'honeypot_exempt'): + return None + return super(ExemptableHoneypotViewMiddleware, self).process_view( + request, callback, callback_args, callback_kwargs) diff --git a/prawokultury/settings.d/30-apps.py b/prawokultury/settings.d/30-apps.py index 578e9dd..1e87f11 100644 --- a/prawokultury/settings.d/30-apps.py +++ b/prawokultury/settings.d/30-apps.py @@ -22,6 +22,9 @@ INSTALLED_APPS = ( 'taggit_autosuggest', 'getpaid', 'getpaid.backends.payu', + 'djcelery', + 'djkombu', + 'django.contrib.auth', 'django.contrib.contenttypes', diff --git a/prawokultury/settings.d/40-middleware.py b/prawokultury/settings.d/40-middleware.py index c8a63b6..f0229cd 100644 --- a/prawokultury/settings.d/40-middleware.py +++ b/prawokultury/settings.d/40-middleware.py @@ -5,7 +5,8 @@ MIDDLEWARE_CLASSES = ( 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', - 'honeypot.middleware.HoneypotMiddleware', + 'prawokultury.middleware.ExemptableHoneypotViewMiddleware', + 'honeypot.middleware.HoneypotResponseMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', ) diff --git a/prawokultury/settings.d/50-contrib.py b/prawokultury/settings.d/50-contrib.py index 4423184..4625e79 100644 --- a/prawokultury/settings.d/50-contrib.py +++ b/prawokultury/settings.d/50-contrib.py @@ -19,3 +19,21 @@ CAS_VERSION = '1' HONEYPOT_FIELD_NAME='miut' TAGGIT_AUTOSUGGEST_MODEL = ('questions', 'Tag') + +GETPAID_BACKENDS = ( + 'getpaid.backends.payu', +) + + +import djcelery +djcelery.setup_loader() + +BROKER_BACKEND = "djkombu.transport.DatabaseTransport" +BROKER_HOST = "localhost" +BROKER_PORT = 5672 +BROKER_USER = "guest" +BROKER_PASSWORD = "guest" +BROKER_VHOST = "/" + +CELERY_EAGER_PROPAGATES_EXCEPTIONS = True +CELERY_SEND_TASK_ERROR_EMAILS = True diff --git a/prawokultury/settings.d/50-static.py b/prawokultury/settings.d/50-static.py index 8f514da..f43274b 100644 --- a/prawokultury/settings.d/50-static.py +++ b/prawokultury/settings.d/50-static.py @@ -42,6 +42,7 @@ PIPELINE_JS = { 'base': { 'source_filenames': ( 'js/promobox.js', + 'shop/shop.js', ), 'output_filename': 'compressed/base.js', diff --git a/prawokultury/static/css/forms.css b/prawokultury/static/css/forms.css index 4acb30f..70930a0 100644 --- a/prawokultury/static/css/forms.css +++ b/prawokultury/static/css/forms.css @@ -1,10 +1,13 @@ +.entry-wrapped .submit-form { + font-size: .9em; } + .form-info { font-size: 1.2em; } .submit-form { margin-top: 3em; } .submit-form table { - border-spacing: 0 .5em; } + border-spacing: 0 0.5em; } .submit-form tr { background-color: #fdfdfd; } .submit-form label { @@ -14,7 +17,7 @@ color: #e41b13; font-size: 1.2em; padding: 0 0 0 1.3em; - margin: 0 0 .5em 0; + margin: 0 0 0.5em 0; list-style: url("/static/img/read-more.png"); } .submit-form input, .submit-form textarea, .submit-form select { font-size: 1.2em; @@ -23,7 +26,7 @@ color: #363A3B; width: 100%; margin-bottom: .5em; - border: 1px solid #EDECE7; } + border: 1px solid #edece7; } .submit-form th, .submit-form td { text-align: left; font-weight: normal; diff --git a/prawokultury/static/css/forms.scss b/prawokultury/static/css/forms.scss index 9539415..1f3488a 100644 --- a/prawokultury/static/css/forms.scss +++ b/prawokultury/static/css/forms.scss @@ -1,3 +1,7 @@ +.entry-wrapped .submit-form { + font-size: .9em; +} + .form-info { font-size: 1.2em; } diff --git a/prawokultury/templates/migdal/entry/publications/entry_detail.html b/prawokultury/templates/migdal/entry/publications/entry_detail.html index 0cae1fa..b231954 100755 --- a/prawokultury/templates/migdal/entry/publications/entry_detail.html +++ b/prawokultury/templates/migdal/entry/publications/entry_detail.html @@ -1,6 +1,7 @@ {% extends "base.html" %} {% load comments i18n %} {% load fnp_common migdal_tags fnp_share shop_tags %} +{% load url from future %} {% block "body" %} @@ -14,18 +15,27 @@ {% entry_begin entry 1 %}
-{{ entry.body }} + +{% if entry.offer %} +
+Regulamin sklepu +
+{% endif %} +{% if entry.offer %} +

{% trans "Price" %}: {{ entry.offer.price|floatformat:"-2" }} PLN

-{% if entry.offer_set.all.exists %} -{% order_form_for entry.offer_set.all.0 form %} +{% order_form_for entry.offer form %} {% endif %} +{{ entry.body }} + + {% for inline_html in entry.inline_html %} diff --git a/shop/admin.py b/shop/admin.py index 6c84a94..58fd842 100644 --- a/shop/admin.py +++ b/shop/admin.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from django.utils.translation import ugettext_lazy as _ @@ -10,7 +10,6 @@ from .models import Offer, Order class OfferAdmin(admin.ModelAdmin): model = Offer list_display = ['entry', 'price'] - #~ search_fields = ['entry__title_pl'] class PayedFilter(admin.SimpleListFilter): diff --git a/shop/forms.py b/shop/forms.py index ce8a48f..fedd152 100644 --- a/shop/forms.py +++ b/shop/forms.py @@ -1,32 +1,50 @@ # -*- coding: utf-8 -*- -# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later. +# This file is part of PrawoKultury, licensed under GNU Affero GPLv3 or later. # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from django import forms from django.utils import formats from django.utils.translation import ugettext_lazy as _, ugettext, get_language -from .models import Order from . import app_settings +from .models import Order +from .widgets import NumberInput class OrderForm(forms.Form): required_css_class = 'required' backend = 'getpaid.backends.payu' - + items = forms.IntegerField(label=_("Items"), min_value=1, initial=1, + widget=NumberInput(attrs={'min': '1', 'step': '1', 'class': 'cost-items'})) name = forms.CharField(label=_("Name")) email = forms.EmailField(label=_("Contact e-mail")) address = forms.CharField(label=_("Address"), widget=forms.Textarea) - consent = forms.CharField(label=_("Consent"), widget=forms.Textarea, - help_text=_('I hereby consent')) + + accept = forms.BooleanField(label=_("Accept terms"), + help_text='''Akceptuję regulamin sklepu.''') + + consent = forms.BooleanField(label=_("Consent to the processing of data"), + help_text='''Wyrażam zgodę na przetwarzanie moich danych osobowych w celu realizacji +zamówienia. Administratorem danych osobowych jest Fundacja Nowoczesna +Polska, ul. Marszałkowska 84/92, lok. 125, 00-514 Warszawa. +Zapoznałem/zapoznałam się +z polityką prywatności Fundacji. +Jestem świadom/świadoma, iż moja zgoda może być odwołana w każdym czasie, co skutkować będzie +usunięciem mojego adresu e-mail z bazy danych.''') def __init__(self, offer, *args, **kwargs): - print 'o:', offer self.offer = offer super(OrderForm, self).__init__(*args, **kwargs) + self.fields['items'].widget.attrs.update({ + 'data-cost-price': self.offer.price, + 'data-cost-per-item': self.offer.cost_per_item, + 'data-cost-const': self.offer.cost_const, + 'data-decimal-separator': formats.get_format("DECIMAL_SEPARATOR"), + }) def save(self): order = Order.objects.create( offer=self.offer, + items=self.cleaned_data['items'], name=self.cleaned_data['name'], email=self.cleaned_data['email'], address=self.cleaned_data['address'], diff --git a/shop/locale/pl/LC_MESSAGES/django.mo b/shop/locale/pl/LC_MESSAGES/django.mo new file mode 100644 index 0000000..24fe2e9 Binary files /dev/null and b/shop/locale/pl/LC_MESSAGES/django.mo differ diff --git a/shop/locale/pl/LC_MESSAGES/django.po b/shop/locale/pl/LC_MESSAGES/django.po new file mode 100644 index 0000000..b523584 --- /dev/null +++ b/shop/locale/pl/LC_MESSAGES/django.po @@ -0,0 +1,143 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-10-31 11:13+0100\n" +"PO-Revision-Date: 2013-10-31 11:25+0100\n" +"Last-Translator: Radek Czajka \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " +"|| n%100>=20) ? 1 : 2);\n" +"X-Generator: Poedit 1.5.4\n" + +#: admin.py:16 +msgid "payment complete" +msgstr "płatność wykonana" + +#: admin.py:20 +msgid "Yes" +msgstr "Tak" + +#: admin.py:21 +msgid "No" +msgstr "Nie" + +#: forms.py:16 +msgid "Items" +msgstr "Liczba egzemplarzy" + +#: forms.py:18 +msgid "Name" +msgstr "Imię i nazwisko" + +#: forms.py:19 +msgid "Contact e-mail" +msgstr "E-mail kontaktowy" + +#: forms.py:20 +msgid "Address" +msgstr "Adres" + +#: forms.py:22 +msgid "Accept terms" +msgstr "Akceptacja regulaminu" + +#: forms.py:25 +msgid "Consent to the processing of data" +msgstr "Zgoda na przetwarzanie danych" + +#: models.py:20 +msgid "price" +msgstr "cena" + +#: models.py:25 models.py:45 +msgid "offer" +msgstr "oferta" + +#: models.py:26 +msgid "offers" +msgstr "oferty" + +#: models.py:46 +msgid "items" +msgstr "liczba egzemplarzy" + +#: models.py:47 +msgid "name" +msgstr "nazwisko" + +#: models.py:48 +msgid "email" +msgstr "e-mail" + +#: models.py:49 +msgid "address" +msgstr "adres" + +#: models.py:50 +msgid "payed at" +msgstr "zapłacono" + +#: models.py:54 +msgid "order" +msgstr "zamówienie" + +#: models.py:55 +msgid "orders" +msgstr "zamówienie" + +#: models.py:113 +msgid "Your payment has been completed." +msgstr "Twoja płatność została wykonana." + +#: models.py:117 +msgid "New order has been placed." +msgstr "Zostało złożone nowe zamówienie." + +#: templates/shop/no_thanks.html:5 templates/shop/no_thanks.html.py:9 +msgid "Payment failed" +msgstr "Płatność zakończona niepowodzeniem" + +#: templates/shop/no_thanks.html:13 +msgid "You're support has not been processed successfully." +msgstr "Twoja płatność nie została zakończona powodzeniem." + +#: templates/shop/no_thanks.html:15 templates/shop/thanks.html:15 +msgid "Go back to:" +msgstr "Wróć do:" + +#: templates/shop/thanks.html:5 templates/shop/thanks.html.py:9 +msgid "Payment successful" +msgstr "Płatność wykonana." + +#: templates/shop/thanks.html:13 templates/shop/email/payed.txt:6 +msgid "Your payment has been successfully completed." +msgstr "Twoja płatność została wykonana." + +#: templates/shop/email/base.txt:1 +msgid "Hi" +msgstr "Cześć" + +#: templates/shop/email/base.txt:4 +msgid "" +"Cheers,\n" +"Right to Culture team" +msgstr "" +"Pozdrowienia,\n" +"Zespół Prawa Kultury" + +#: templates/shop/email/payed.txt:8 +msgid "Your order is now being processed: " +msgstr "Twoje zamówienie jest przetwarzane:" + +#: templates/shop/snippets/order_form.html:18 +msgid "Donate!" +msgstr "Wesprzyj!" diff --git a/shop/migrations/0001_initial.py b/shop/migrations/0001_initial.py index 0bc1dc2..471a911 100644 --- a/shop/migrations/0001_initial.py +++ b/shop/migrations/0001_initial.py @@ -11,8 +11,10 @@ class Migration(SchemaMigration): # Adding model 'Offer' db.create_table('shop_offer', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('entry', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['migdal.Entry'])), + ('entry', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['migdal.Entry'], unique=True)), ('price', self.gf('django.db.models.fields.DecimalField')(max_digits=6, decimal_places=2)), + ('cost_const', self.gf('django.db.models.fields.DecimalField')(max_digits=6, decimal_places=2)), + ('cost_per_item', self.gf('django.db.models.fields.DecimalField')(default=0, max_digits=6, decimal_places=2)), )) db.send_create_signal('shop', ['Offer']) @@ -20,6 +22,7 @@ class Migration(SchemaMigration): db.create_table('shop_order', ( ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), ('offer', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['shop.Offer'])), + ('items', self.gf('django.db.models.fields.IntegerField')(default=1)), ('name', self.gf('django.db.models.fields.CharField')(max_length=127, blank=True)), ('email', self.gf('django.db.models.fields.EmailField')(max_length=75, db_index=True)), ('address', self.gf('django.db.models.fields.TextField')(db_index=True)), @@ -83,8 +86,10 @@ class Migration(SchemaMigration): 'type': ('django.db.models.fields.CharField', [], {'max_length': '16', 'db_index': 'True'}) }, 'shop.offer': { - 'Meta': {'ordering': "['entry__title']", 'object_name': 'Offer'}, - 'entry': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['migdal.Entry']"}), + 'Meta': {'ordering': "['entry']", 'object_name': 'Offer'}, + 'cost_const': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}), + 'cost_per_item': ('django.db.models.fields.DecimalField', [], {'default': '0', 'max_digits': '6', 'decimal_places': '2'}), + 'entry': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['migdal.Entry']", 'unique': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'price': ('django.db.models.fields.DecimalField', [], {'max_digits': '6', 'decimal_places': '2'}) }, @@ -93,6 +98,7 @@ class Migration(SchemaMigration): 'address': ('django.db.models.fields.TextField', [], {'db_index': 'True'}), 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'db_index': 'True'}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'items': ('django.db.models.fields.IntegerField', [], {'default': '1'}), 'language_code': ('django.db.models.fields.CharField', [], {'max_length': '2', 'null': 'True', 'blank': 'True'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '127', 'blank': 'True'}), 'offer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['shop.Offer']"}), diff --git a/shop/models.py b/shop/models.py index 72d599c..349cf43 100644 --- a/shop/models.py +++ b/shop/models.py @@ -3,7 +3,7 @@ # Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information. # from datetime import datetime -from django.core.mail import send_mail +from django.core.mail import send_mail, mail_managers from django.conf import settings from django.contrib.sites.models import Site from django.db import models @@ -16,8 +16,10 @@ from . import app_settings class Offer(models.Model): """ A fundraiser for a particular book. """ - entry = models.ForeignKey(Entry) # filter publications! + entry = models.OneToOneField(Entry) # filter publications! price = models.DecimalField(_('price'), decimal_places=2, max_digits=6) + cost_const = models.DecimalField(decimal_places=2, max_digits=6) + cost_per_item = models.DecimalField(decimal_places=2, max_digits=6, default=0) class Meta: verbose_name = _('offer') @@ -30,9 +32,11 @@ class Offer(models.Model): def get_absolute_url(self): return self.entry.get_absolute_url() - def sum(self): - """ The money gathered. """ - return self.order_payed().aggregate(s=models.Sum('amount'))['s'] or 0 + def total_per_item(self): + return self.price + self.cost_per_item + + def price_per_items(self, items): + return self.cost_const + items * self.total_per_item() class Order(models.Model): @@ -42,6 +46,7 @@ class Order(models.Model): """ offer = models.ForeignKey(Offer, verbose_name=_('offer')) + items = models.IntegerField(verbose_name=_('items'), default=1) name = models.CharField(_('name'), max_length=127, blank=True) email = models.EmailField(_('email'), db_index=True) address = models.TextField(_('address'), db_index=True) @@ -54,11 +59,14 @@ class Order(models.Model): ordering = ['-payed_at'] def __unicode__(self): - return unicode(self.offer) + return "%s (%d egz.)" % (unicode(self.offer), self.items) def get_absolute_url(self): return self.offer.get_absolute_url() + def amount(self): + return self.offer.price_per_items(self.items) + def notify(self, subject, template_name, extra_context=None): context = { 'order': self, @@ -74,13 +82,23 @@ class Order(models.Model): fail_silently=False ) + def notify_managers(self, subject, template_name, extra_context=None): + context = { + 'order': self, + 'site': Site.objects.get_current(), + } + if extra_context: + context.update(extra_context) + with override(app_settings.DEFAULT_LANGUAGE): + mail_managers(subject, render_to_string(template_name, context)) + # Register the Order model with django-getpaid for payments. getpaid.register_to_payment(Order, unique=False, related_name='payment') def new_payment_query_listener(sender, order=None, payment=None, **kwargs): """ Set payment details for getpaid. """ - payment.amount = order.offer.price + payment.amount = order.amount() payment.currency = 'PLN' getpaid.signals.new_payment_query.connect(new_payment_query_listener) @@ -99,4 +117,8 @@ def payment_status_changed_listener(sender, instance, old_status, new_status, ** _('Your payment has been completed.'), 'shop/email/payed.txt' ) + instance.order.notify_managers( + _('New order has been placed.'), + 'shop/email/payed_managers.txt' + ) getpaid.signals.payment_status_changed.connect(payment_status_changed_listener) diff --git a/shop/static/shop/shop.js b/shop/static/shop/shop.js new file mode 100755 index 0000000..96b9f9d --- /dev/null +++ b/shop/static/shop/shop.js @@ -0,0 +1,31 @@ +$(function() { + + $('.cost-items').each(function() { + + var $items = $(this); + var price = parseFloat($items.attr('data-cost-price')) * 100; + var cost_const = parseFloat($items.attr('data-cost-const')) * 100; + var cost_per_item = parseFloat($items.attr('data-cost-per-item')) * 100; + + var decimal_separator = $items.attr('data-decimal-separator'); + + var money = function(amount) { + return amount.toFixed(2).replace(".", decimal_separator); + } + + var update_costs = function() { + var items = $items.val(); + if (items < 1) + items = 1; + var total_costs = cost_per_item * items + cost_const; + var final = price * items + total_costs; + $("#cost-costs").text(money(total_costs / 100) + " zł"); + $("#cost-final").text(money(final / 100) + " zł"); + } + + $items.change(update_costs); + update_costs(); + + }); + +}); diff --git a/shop/templates/shop/email/base.txt b/shop/templates/shop/email/base.txt index 5cf1b9a..a0fd074 100755 --- a/shop/templates/shop/email/base.txt +++ b/shop/templates/shop/email/base.txt @@ -1,5 +1,5 @@ -{% autoescape off %}{% load i18n %}{% trans 'Hi' %}{{ order.name }}{% endif %}, +{% autoescape off %}{% load i18n %}{% trans 'Hi' %} {{ order.name }}, {% block body %} {% endblock %} {% blocktrans %}Cheers, -Right to Culture team{% endblocktrans %} +Right to Culture team{% endblocktrans %}{% endautoescape %} diff --git a/shop/templates/shop/email/payed.txt b/shop/templates/shop/email/payed.txt index 4697ea9..387b6ba 100644 --- a/shop/templates/shop/email/payed.txt +++ b/shop/templates/shop/email/payed.txt @@ -4,4 +4,11 @@ {% block body %} {% blocktrans %}Your payment has been successfully completed.{% endblocktrans %} + +{% blocktrans %}Your order is now being processed: {% endblocktrans %} + +{{ order }} +{{ order.name }} +{{ order.address }} + {% endblock %} diff --git a/shop/templates/shop/email/payed_managers.txt b/shop/templates/shop/email/payed_managers.txt new file mode 100755 index 0000000..748d4d9 --- /dev/null +++ b/shop/templates/shop/email/payed_managers.txt @@ -0,0 +1,18 @@ +{% extends "shop/email/base.txt" %} +{% load i18n %} +{% load url from future %} + + +{% block body %} +Następujące zamówienie zostało złożone i opłacone: + +{{ order }} + +{{ order.email }} +{{ order.name }} + +{{ order.address }} + +http://{{ site.domain }}{% url 'admin:shop_order_change' order.pk %} + +{% endblock %} diff --git a/shop/templates/shop/no_thanks.html b/shop/templates/shop/no_thanks.html index 007c28d..ad2d65e 100644 --- a/shop/templates/shop/no_thanks.html +++ b/shop/templates/shop/no_thanks.html @@ -8,8 +8,11 @@

{% trans "Payment failed" %}

-

{% trans "You're support has not been processed successfully." %}

+
+

{% trans "You're support has not been processed successfully." %}

+

{% trans "Go back to:" %} {{ object.order.offer }}.

+
{% endblock %} diff --git a/shop/templates/shop/snippets/order_form.html b/shop/templates/shop/snippets/order_form.html index c513025..a1f00e9 100755 --- a/shop/templates/shop/snippets/order_form.html +++ b/shop/templates/shop/snippets/order_form.html @@ -1,13 +1,22 @@ -{% load i18n %} +{% load i18n staticfiles %} {% load url from future %} -
+ - {{ form.as_table }} - + +
- + {{ form.as_table }} + +
{% trans "Payment and shipping costs" %}: + {{ form.offer.cost_const|floatformat:"-2" }} zł + + {{ form.offer.cost_per_item|floatformat:"-2" }} zł {% trans "for each copy" %} +
{% trans "Final cost" %}: + {{ form.offer.total_per_item|floatformat:"-2" }} zł {% trans "for each copy" %} + + {{ form.offer.cost_const|floatformat:"-2" }} zł +
+
diff --git a/shop/templates/shop/thanks.html b/shop/templates/shop/thanks.html index fe21d98..c08447c 100644 --- a/shop/templates/shop/thanks.html +++ b/shop/templates/shop/thanks.html @@ -8,6 +8,12 @@

{% trans "Payment successful" %}

+
+

{% trans "Your payment has been successfully completed." %}

+

{% trans "Go back to:" %} {{ object.order.offer }}.

+ +
+ {% endblock %} diff --git a/shop/templatetags/shop_tags.py b/shop/templatetags/shop_tags.py index 10c53ae..9ecf196 100755 --- a/shop/templatetags/shop_tags.py +++ b/shop/templatetags/shop_tags.py @@ -10,6 +10,6 @@ register = template.Library() @register.inclusion_tag('shop/snippets/order_form.html', takes_context=True) def order_form_for(context, offer, form=None): - if form is None: + if not form: form = OrderForm(offer) return {'form': form} diff --git a/shop/urls.py b/shop/urls.py index ff1c847..debea33 100644 --- a/shop/urls.py +++ b/shop/urls.py @@ -4,13 +4,18 @@ # from django.conf.urls import patterns, url, include from django.utils.translation import ugettext_lazy as _ - +from django.views.decorators.csrf import csrf_exempt +from getpaid.backends.payu.views import OnlineView +from prawokultury.middleware import honeypot_exempt from .views import ThanksView, NoThanksView, OfferDetailView urlpatterns = patterns('', url(r'^kup/(?P[^/]+)/$', OfferDetailView.as_view(), name='shop_buy'), - url(r'^dziekujemy/$', ThanksView.as_view(), name='shop_thanks'), - url(r'^niepowodzenie/$', NoThanksView.as_view(), name='shop_nothanks'), + url(r'^dziekujemy/(?P\d+)/$', ThanksView.as_view(), name='shop_thanks'), + url(r'^niepowodzenie/(?P\d+)/$', NoThanksView.as_view(), name='shop_nothanks'), + url(r'^getpaid/getpaid.backends.payu/online/$', + honeypot_exempt(csrf_exempt(OnlineView.as_view())), + name='getpaid-payu-online'), url(r'^getpaid/', include('getpaid.urls')), ) diff --git a/shop/views.py b/shop/views.py index 16634e7..ef73d66 100644 --- a/shop/views.py +++ b/shop/views.py @@ -30,16 +30,16 @@ class OfferDetailView(FormView): self.object = get_object_or_404(Offer, **args) return super(OfferDetailView, self).dispatch(request, slug) + def get(self, *args, **kwargs): + return redirect(self.object.get_absolute_url()) + def get_context_data(self, *args, **kwargs): ctx = super(OfferDetailView, self).get_context_data(*args, **kwargs) ctx['entry'] = self.object.entry return ctx def get_form(self, form_class): - if self.request.method == 'POST': - return form_class(self.object, self.request.POST) - else: - return form_class(self.object) + return form_class(self.object, self.request.POST) def form_valid(self, form): order = form.save() @@ -50,9 +50,11 @@ class OfferDetailView(FormView): return redirect(gateway_url_tuple[0]) -class ThanksView(TemplateView): +class ThanksView(DetailView): + model = Payment template_name = "shop/thanks.html" -class NoThanksView(TemplateView): +class NoThanksView(DetailView): + model = Payment template_name = "shop/no_thanks.html" diff --git a/shop/widgets.py b/shop/widgets.py new file mode 100755 index 0000000..5690be3 --- /dev/null +++ b/shop/widgets.py @@ -0,0 +1,4 @@ +from django.forms.widgets import TextInput + +class NumberInput(TextInput): + input_type = 'number'