diff --git a/eboutic/models.py b/eboutic/models.py index 63c2969e..3a61da9d 100644 --- a/eboutic/models.py +++ b/eboutic/models.py @@ -27,9 +27,9 @@ from django.utils.translation import ugettext_lazy as _ from django.conf import settings from accounting.models import CurrencyField -from counter.models import Counter, Product, Customer, Selling, Refilling +from counter.models import Counter, Product, Selling, Refilling from core.models import User -from subscription.models import Subscription + class Basket(models.Model): """ @@ -38,16 +38,16 @@ class Basket(models.Model): user = models.ForeignKey(User, related_name='baskets', verbose_name=_('user'), blank=False) date = models.DateTimeField(_('date'), auto_now=True) - def add_product(self, p, q = 1): + def add_product(self, p, q=1): item = self.items.filter(product_id=p.id).first() if item is None: BasketItem(basket=self, product_id=p.id, product_name=p.name, type_id=p.product_type.id, - quantity=q, product_unit_price=p.selling_price).save() + quantity=q, product_unit_price=p.selling_price).save() else: item.quantity += q item.save() - def del_product(self, p, q = 1): + def del_product(self, p, q=1): item = self.items.filter(product_id=p.id).first() if item is not None: item.quantity -= q @@ -64,6 +64,7 @@ class Basket(models.Model): def __str__(self): return "%s's basket (%d items)" % (self.user, self.items.all().count()) + class Invoice(models.Model): """ Invoices are generated once the payment has been validated @@ -92,34 +93,35 @@ class Invoice(models.Model): for i in self.items.all(): if i.type_id == settings.SITH_COUNTER_PRODUCTTYPE_REFILLING: new = Refilling( - counter=eboutic, - customer=self.user.customer, - operator=self.user, - amount=i.product_unit_price * i.quantity, - payment_method="CARD", - bank="OTHER", - date=self.date, - ) + counter=eboutic, + customer=self.user.customer, + operator=self.user, + amount=i.product_unit_price * i.quantity, + payment_method="CARD", + bank="OTHER", + date=self.date, + ) new.save() else: product = Product.objects.filter(id=i.product_id).first() new = Selling( - label=i.product_name, - counter=eboutic, - club=product.club, - product=product, - seller=self.user, - customer=self.user.customer, - unit_price=i.product_unit_price, - quantity=i.quantity, - payment_method="CARD", - is_validated=True, - date=self.date, - ) + label=i.product_name, + counter=eboutic, + club=product.club, + product=product, + seller=self.user, + customer=self.user.customer, + unit_price=i.product_unit_price, + quantity=i.quantity, + payment_method="CARD", + is_validated=True, + date=self.date, + ) new.save() self.validated = True self.save() + class AbstractBaseItem(models.Model): product_id = models.IntegerField(_('product id')) product_name = models.CharField(_('product name'), max_length=255) @@ -133,8 +135,10 @@ class AbstractBaseItem(models.Model): def __str__(self): return "Item: %s (%s) x%d" % (self.product_name, self.product_unit_price, self.quantity) + class BasketItem(AbstractBaseItem): basket = models.ForeignKey(Basket, related_name='items', verbose_name=_('basket')) + class InvoiceItem(AbstractBaseItem): invoice = models.ForeignKey(Invoice, related_name='items', verbose_name=_('invoice')) diff --git a/eboutic/tests.py b/eboutic/tests.py index c33d4a1b..a2dc4875 100644 --- a/eboutic/tests.py +++ b/eboutic/tests.py @@ -34,7 +34,8 @@ from django.core.management import call_command from django.conf import settings from core.models import User -from counter.models import Customer, ProductType, Product, Counter, Refilling +from counter.models import Product, Counter, Refilling + class EbouticTest(TestCase): def setUp(self): @@ -74,25 +75,24 @@ class EbouticTest(TestCase): "action": "add_product", "product_id": self.barbar.id}) self.assertTrue("\\n" - " \\n" - "\\n Barbar: 1.70 \\xe2\\x82\\xac" in str(response.content)) + " \\n" + "\\n Barbar: 1.70 \\xe2\\x82\\xac" in str(response.content)) response = self.client.post(reverse("eboutic:command")) self.assertTrue("\\n Barbar\\n 1\\n" - " 1.70 \\xe2\\x82\\xac\\n " in str(response.content)) + " 1.70 \\xe2\\x82\\xac\\n " in str(response.content)) response = self.client.post(reverse("eboutic:pay_with_sith"), { "action": "pay_with_sith_account" - }) + }) self.assertTrue("Le paiement a \\xc3\\xa9t\\xc3\\xa9 effectu\\xc3\\xa9\\n" in str(response.content)) response = self.client.get(reverse("core:user_account_detail", kwargs={ "user_id": self.subscriber.id, "year": datetime.now().year, "month": datetime.now().month, - })) + })) self.assertTrue("class=\"selected_tab\">Compte (8.30 \\xe2\\x82\\xac)" in str(response.content)) self.assertTrue("Eboutic\\n Subscribed User\\n" - " Barbar\\n 1\\n 1.70 \\xe2\\x82\\xac\\n" - " Compte utilisateur" in str(response.content)) - + " Barbar\\n 1\\n 1.70 \\xe2\\x82\\xac\\n" + " Compte utilisateur" in str(response.content)) def test_buy_simple_product_with_credit_card(self): self.client.login(username='subscriber', password='plop') @@ -100,11 +100,11 @@ class EbouticTest(TestCase): "action": "add_product", "product_id": self.barbar.id}) self.assertTrue("\\n" - " \\n" - "\\n Barbar: 1.70 \\xe2\\x82\\xac" in str(response.content)) + " \\n" + "\\n Barbar: 1.70 \\xe2\\x82\\xac" in str(response.content)) response = self.client.post(reverse("eboutic:command")) self.assertTrue("\\n Barbar\\n 1\\n" - " 1.70 \\xe2\\x82\\xac\\n " in str(response.content)) + " 1.70 \\xe2\\x82\\xac\\n " in str(response.content)) response = self.generate_bank_valid_answer_from_page_content(response.content) @@ -112,11 +112,11 @@ class EbouticTest(TestCase): "user_id": self.subscriber.id, "year": datetime.now().year, "month": datetime.now().month, - })) + })) self.assertTrue("class=\"selected_tab\">Compte (0.00 \\xe2\\x82\\xac)" in str(response.content)) self.assertTrue("Eboutic\\n Subscribed User\\n" - " Barbar\\n 1\\n 1.70 \\xe2\\x82\\xac\\n" - " Carte bancaire" in str(response.content)) + " Barbar\\n 1\\n 1.70 \\xe2\\x82\\xac\\n" + " Carte bancaire" in str(response.content)) def test_buy_refill_product_with_credit_card(self): self.client.login(username='subscriber', password='plop') @@ -124,11 +124,11 @@ class EbouticTest(TestCase): "action": "add_product", "product_id": self.refill.id}) self.assertTrue("\\n" - " \\n" - "\\n Rechargement 15 \\xe2\\x82\\xac: 15.00 \\xe2\\x82\\xac" in str(response.content)) + " \\n" + "\\n Rechargement 15 \\xe2\\x82\\xac: 15.00 \\xe2\\x82\\xac" in str(response.content)) response = self.client.post(reverse("eboutic:command")) self.assertTrue("\\n Rechargement 15 \\xe2\\x82\\xac\\n 1\\n" - " 15.00 \\xe2\\x82\\xac\\n " in str(response.content)) + " 15.00 \\xe2\\x82\\xac\\n " in str(response.content)) response = self.generate_bank_valid_answer_from_page_content(response.content) @@ -136,12 +136,12 @@ class EbouticTest(TestCase): "user_id": self.subscriber.id, "year": datetime.now().year, "month": datetime.now().month, - })) + })) self.assertTrue("class=\"selected_tab\">Compte (15.00 \\xe2\\x82\\xac)" in str(response.content)) self.assertTrue("\\n \\n \\n" - " 15.00 \\xe2\\x82\\xac" in str(response.content)) + "
  • 1 x Rechargement 15 \\xe2\\x82\\xac - 15.00 \\xe2\\x82\\xac
  • \\n" + " \\n \\n \\n" + " 15.00 \\xe2\\x82\\xac" in str(response.content)) def test_buy_subscribe_product_with_credit_card(self): self.client.login(username='old_subscriber', password='plop') @@ -151,11 +151,11 @@ class EbouticTest(TestCase): "action": "add_product", "product_id": self.cotis.id}) self.assertTrue("\\n" - " \\n" - "\\n Cotis 1 semestre: 15.00 \\xe2\\x82\\xac" in str(response.content)) + " \\n" + "\\n Cotis 1 semestre: 15.00 \\xe2\\x82\\xac" in str(response.content)) response = self.client.post(reverse("eboutic:command")) self.assertTrue("\\n Cotis 1 semestre\\n 1\\n" - " 15.00 \\xe2\\x82\\xac\\n " in str(response.content)) + " 15.00 \\xe2\\x82\\xac\\n " in str(response.content)) response = self.generate_bank_valid_answer_from_page_content(response.content) @@ -163,14 +163,11 @@ class EbouticTest(TestCase): "user_id": self.old_subscriber.id, "year": datetime.now().year, "month": datetime.now().month, - })) + })) self.assertTrue("class=\"selected_tab\">Compte (0.00 \\xe2\\x82\\xac)" in str(response.content)) self.assertTrue("\\n \\n \\n" - " 15.00 \\xe2\\x82\\xac" in str(response.content)) + "
  • 1 x Cotis 1 semestre - 15.00 \\xe2\\x82\\xac
  • \\n" + " \\n \\n \\n" + " 15.00 \\xe2\\x82\\xac" in str(response.content)) response = self.client.get(reverse("core:user_profile", kwargs={"user_id": self.old_subscriber.id})) self.assertTrue("Cotisant jusqu\\'au" in str(response.content)) - - - diff --git a/eboutic/urls.py b/eboutic/urls.py index bb964d1e..d4ddb486 100644 --- a/eboutic/urls.py +++ b/eboutic/urls.py @@ -22,7 +22,7 @@ # # -from django.conf.urls import url, include +from django.conf.urls import url from eboutic.views import * @@ -33,6 +33,3 @@ urlpatterns = [ url(r'^pay$', EbouticPayWithSith.as_view(), name='pay_with_sith'), url(r'^et_autoanswer$', EtransactionAutoAnswer.as_view(), name='etransation_autoanswer'), ] - - - diff --git a/eboutic/views.py b/eboutic/views.py index 58e518cb..7d841d26 100644 --- a/eboutic/views.py +++ b/eboutic/views.py @@ -24,29 +24,27 @@ from collections import OrderedDict from datetime import datetime -import pytz import hmac import base64 from OpenSSL import crypto -from django.shortcuts import render from django.core.urlresolvers import reverse_lazy from django.views.generic import TemplateView, View from django.http import HttpResponse, HttpResponseRedirect from django.core.exceptions import SuspiciousOperation -from django.shortcuts import render from django.db import transaction, DataError from django.utils.translation import ugettext as _ from django.conf import settings from counter.models import Customer, Counter, ProductType, Selling -from eboutic.models import Basket, Invoice, BasketItem, InvoiceItem +from eboutic.models import Basket, Invoice, InvoiceItem + class EbouticMain(TemplateView): template_name = 'eboutic/eboutic_main.jinja' def make_basket(self, request): - if 'basket_id' not in request.session.keys(): # Init the basket session entry + if 'basket_id' not in request.session.keys(): # Init the basket session entry self.basket = Basket(user=request.user) self.basket.save() else: @@ -60,7 +58,7 @@ class EbouticMain(TemplateView): def get(self, request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect(reverse_lazy('core:login', args=self.args, kwargs=kwargs) + "?next=" + - request.path) + request.path) self.object = Counter.objects.filter(type="EBOUTIC").first() self.make_basket(request) return super(EbouticMain, self).get(request, *args, **kwargs) @@ -68,7 +66,7 @@ class EbouticMain(TemplateView): def post(self, request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect(reverse_lazy('core:login', args=self.args, kwargs=kwargs) + "?next=" + - request.path) + request.path) self.object = Counter.objects.filter(type="EBOUTIC").first() self.make_basket(request) if 'add_product' in request.POST['action']: @@ -77,7 +75,6 @@ class EbouticMain(TemplateView): self.del_product(request) return self.render_to_response(self.get_context_data(**kwargs)) - def add_product(self, request): """ Add a product to the basket """ try: @@ -108,19 +105,20 @@ class EbouticMain(TemplateView): kwargs['categories'] = kwargs['categories'].exclude(id=settings.SITH_PRODUCTTYPE_SUBSCRIPTION) return kwargs + class EbouticCommand(TemplateView): template_name = 'eboutic/eboutic_makecommand.jinja' def get(self, request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect(reverse_lazy('core:login', args=self.args, kwargs=kwargs) + "?next=" + - request.path) + request.path) return HttpResponseRedirect(reverse_lazy('eboutic:main', args=self.args, kwargs=kwargs)) def post(self, request, *args, **kwargs): if not request.user.is_authenticated(): return HttpResponseRedirect(reverse_lazy('core:login', args=self.args, kwargs=kwargs) + "?next=" + - request.path) + request.path) if 'basket_id' not in request.session.keys(): return HttpResponseRedirect(reverse_lazy('eboutic:main', args=self.args, kwargs=kwargs)) self.basket = Basket.objects.filter(id=request.session['basket_id']).first() @@ -136,8 +134,8 @@ class EbouticCommand(TemplateView): kwargs['et_request']['PBX_SITE'] = settings.SITH_EBOUTIC_PBX_SITE kwargs['et_request']['PBX_RANG'] = settings.SITH_EBOUTIC_PBX_RANG kwargs['et_request']['PBX_IDENTIFIANT'] = settings.SITH_EBOUTIC_PBX_IDENTIFIANT - kwargs['et_request']['PBX_TOTAL'] = int(self.basket.get_total()*100) - kwargs['et_request']['PBX_DEVISE'] = 978 # This is Euro. ET support only this value anyway + kwargs['et_request']['PBX_TOTAL'] = int(self.basket.get_total() * 100) + kwargs['et_request']['PBX_DEVISE'] = 978 # This is Euro. ET support only this value anyway kwargs['et_request']['PBX_CMD'] = self.basket.id kwargs['et_request']['PBX_PORTEUR'] = self.basket.user.email kwargs['et_request']['PBX_RETOUR'] = "Amount:M;BasketID:R;Auto:A;Error:E;Sig:K" @@ -146,10 +144,11 @@ class EbouticCommand(TemplateView): kwargs['et_request']['PBX_TYPECARTE'] = "CB" kwargs['et_request']['PBX_TIME'] = str(datetime.now().replace(microsecond=0).isoformat('T')) kwargs['et_request']['PBX_HMAC'] = hmac.new(settings.SITH_EBOUTIC_HMAC_KEY, - bytes("&".join(["%s=%s"%(k,v) for k,v in kwargs['et_request'].items()]), 'utf-8'), - "sha512").hexdigest().upper() + bytes("&".join(["%s=%s" % (k, v) for k, v in kwargs['et_request'].items()]), 'utf-8'), + "sha512").hexdigest().upper() return kwargs + class EbouticPayWithSith(TemplateView): template_name = 'eboutic/eboutic_payment_result.jinja' @@ -172,30 +171,31 @@ class EbouticPayWithSith(TemplateView): for it in b.items.all(): product = eboutic.products.filter(id=it.product_id).first() Selling( - label=it.product_name, - counter=eboutic, - club=product.club, - product=product, - seller=c.user, - customer=c, - unit_price=it.product_unit_price, - quantity=it.quantity, - payment_method="SITH_ACCOUNT", - ).save() + label=it.product_name, + counter=eboutic, + club=product.club, + product=product, + seller=c.user, + customer=c, + unit_price=it.product_unit_price, + quantity=it.quantity, + payment_method="SITH_ACCOUNT", + ).save() b.delete() kwargs['not_enough'] = False request.session.pop('basket_id', None) except DataError as e: - kwargs['not_enough'] = True + kwargs['not_enough'] = True return self.render_to_response(self.get_context_data(**kwargs)) + class EtransactionAutoAnswer(View): def get(self, request, *args, **kwargs): if (not 'Amount' in request.GET.keys() or not 'BasketID' in request.GET.keys() or not 'Auto' in request.GET.keys() or not 'Error' in request.GET.keys() or - not 'Sig' in request.GET.keys()): + not 'Sig' in request.GET.keys()): return HttpResponse("Bad arguments", status=400) key = crypto.load_publickey(crypto.FILETYPE_PEM, settings.SITH_EBOUTIC_PUB_KEY) cert = crypto.X509() @@ -217,12 +217,11 @@ class EtransactionAutoAnswer(View): i.save() for it in b.items.all(): InvoiceItem(invoice=i, product_id=it.product_id, product_name=it.product_name, type_id=it.type_id, - product_unit_price=it.product_unit_price, quantity=it.quantity).save() + product_unit_price=it.product_unit_price, quantity=it.quantity).save() i.validate() b.delete() except Exception as e: - return HttpResponse("Payment failed with error: "+repr(e), status=400) + return HttpResponse("Payment failed with error: " + repr(e), status=400) return HttpResponse() else: - return HttpResponse("Payment failed with error: "+request.GET['Error'], status=400) - + return HttpResponse("Payment failed with error: " + request.GET['Error'], status=400)