1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
from django.http import HttpResponse, HttpResponseRedirect
from django.shortcuts import get_object_or_404, render
from django.db import transaction
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from django.utils import timezone
from postgresqleu.invoices.models import Invoice, InvoicePaymentMethod
from .util import Trustly, TrustlyException
from .models import TrustlyTransaction, TrustlyRawNotification, TrustlyLog
from .models import ReturnAuthorizationStatus
@transaction.atomic
def invoicepayment_secret(request, paymentmethod, invoiceid, secret):
method = get_object_or_404(InvoicePaymentMethod, pk=paymentmethod, active=True)
invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret)
pm = method.get_implementation()
# If this payment has already been initiated, redirect back to existing URL
try:
t = TrustlyTransaction.objects.get(invoiceid=invoice.id, amount=invoice.total_amount)
if t.pendingat:
# This transaction is already started, so we need to redirect back to our own return URL
return HttpResponseRedirect('{0}/trustly_success/{1}/{2}/'.format(settings.SITEBASE, invoice.id, invoice.recipient_secret))
# Else it's not started, so we're going to abandon this one and create a new one
TrustlyLog(message='Abandoning order {0} and starting over.'.format(t.orderid), paymentmethod=method).save()
t.delete()
except TrustlyTransaction.DoesNotExist:
# Not processed, so get a new one
pass
# Make a call to the Trustly API to set up a payment.
# XXX: should we have a verify step here? As in "hey, we're about to send you to Trustly"
# XXX: should we use an iframe? For now just send everything there because it's easier..
t = Trustly(pm)
try:
if request.user and not request.user.is_anonymous:
enduserid = request.user.username
first = request.user.first_name
last = request.user.last_name
email = request.user.email.lower()
else:
first = last = email = None
# For secret payments, use the invoice secret as the identifier
enduserid = secret
r = t.deposit(enduserid,
"{0}".format(invoice.id),
invoice.total_amount,
'{0}#{1}'.format(settings.ORG_SHORTNAME, invoice.id),
'{0}/trustly_success/{1}/{2}/'.format(settings.SITEBASE, invoice.id, invoice.recipient_secret),
'{0}/trustly_failure/{1}/{2}/'.format(settings.SITEBASE, invoice.id, invoice.recipient_secret),
first,
last,
email,
request.META['REMOTE_ADDR'])
# Trustly request was successful, so we have an url to send the user to. Let's set up
# the transaction on our end.
TrustlyTransaction(createdat=timezone.now(),
invoiceid=invoice.id,
amount=invoice.total_amount,
orderid=r['data']['orderid'],
redirecturl=r['data']['url'],
paymentmethod=method,
).save()
# With the transaction saved, redirect the user to Trustly
return HttpResponseRedirect(r['data']['url'])
except TrustlyException as e:
return HttpResponse("Error communicating with Trustly: {0}".format(e))
def success(request, invoiceid, secret):
# Get the invoice so we can be sure that we have the secret
get_object_or_404(Invoice, id=invoiceid, recipient_secret=secret)
trans = get_object_or_404(TrustlyTransaction, invoiceid=invoiceid)
if trans.completedat:
# Payment is completed, to redirect the user back to the invoice
return HttpResponseRedirect("/invoices/{0}/{1}/".format(invoiceid, secret))
# Else we need to loop on this page. To handle this we create
# a temporary object so we can increase the waiting time
status, created = ReturnAuthorizationStatus.objects.get_or_create(orderid=trans.orderid)
status.seencount += 1
status.save()
return render(request, 'trustlypayment/pending.html', {
'refresh': 3 * status.seencount,
'url': '/invoices/{0}/{1}/'.format(invoiceid, secret),
'createdat': trans.createdat,
'pendingat': trans.pendingat,
})
def failure(request, invoiceid, secret):
return render(request, 'trustlypayment/error.html', {
'url': '/invoices/{0}/{1}/'.format(invoiceid, secret),
})
@csrf_exempt
def notification(request, methodid):
method = get_object_or_404(InvoicePaymentMethod, active=True, pk=methodid)
raw = TrustlyRawNotification(contents=request.body.decode('utf8'), paymentmethod=method)
raw.save()
t = Trustly(method.get_implementation())
(ok, uuid, method) = t.process_raw_trustly_notification(raw)
return HttpResponse(t.create_notification_response(uuid, method, ok and "OK" or "FAILED"),
content_type='application/json')
|