diff options
| author | Magnus Hagander | 2018-12-14 11:43:50 +0000 |
|---|---|---|
| committer | Magnus Hagander | 2018-12-14 11:43:50 +0000 |
| commit | 5e8a4a7ab78a9939b21d11094234231bda59567a (patch) | |
| tree | 9d32974ce783aeecbae020d6391baef4fa376a95 /postgresqleu/trustlypayment | |
| parent | 5e500d7d55ef048adc1dcf009db42d10c7ad53fc (diff) | |
Replace tabs with spaces
In an effort to close up with PEP8, we should use spaces for indent
rather than tabs... Time to update your editor config!
Diffstat (limited to 'postgresqleu/trustlypayment')
9 files changed, 544 insertions, 544 deletions
diff --git a/postgresqleu/trustlypayment/admin.py b/postgresqleu/trustlypayment/admin.py index 770c9f87..336c2645 100644 --- a/postgresqleu/trustlypayment/admin.py +++ b/postgresqleu/trustlypayment/admin.py @@ -5,39 +5,39 @@ from django.urls import reverse from models import TrustlyTransaction, TrustlyRawNotification, TrustlyNotification, TrustlyLog class TrustlyTransactionAdmin(admin.ModelAdmin): - list_display=('orderid', 'invoiceid', 'amount', 'createdat', 'pendingat', 'completedat',) + list_display=('orderid', 'invoiceid', 'amount', 'createdat', 'pendingat', 'completedat',) class TrustlyRawNotificationAdmin(admin.ModelAdmin): - list_display = ('dat', 'confirmed') - readonly_fields = ('notification_link',) + list_display = ('dat', 'confirmed') + readonly_fields = ('notification_link',) - def notification_link(self, obj): - if obj.trustlynotification_set.exists(): - n = obj.trustlynotification_set.all()[0] - url = reverse('admin:trustlypayment_trustlynotification_change', args=(n.id,)) - return mark_safe('<a href="{0}">{1}</a>'.format(url, n)) - notification_link.short_description = 'Notification' + def notification_link(self, obj): + if obj.trustlynotification_set.exists(): + n = obj.trustlynotification_set.all()[0] + url = reverse('admin:trustlypayment_trustlynotification_change', args=(n.id,)) + return mark_safe('<a href="{0}">{1}</a>'.format(url, n)) + notification_link.short_description = 'Notification' class TrustlyNotificationAdmin(admin.ModelAdmin): - list_display = ('receivedat', 'notificationid', 'orderid', 'method', 'amount', 'confirmed') - readonly_fields = ('rawnotification_link',) - exclude = ('rawnotification',) + list_display = ('receivedat', 'notificationid', 'orderid', 'method', 'amount', 'confirmed') + readonly_fields = ('rawnotification_link',) + exclude = ('rawnotification',) - def rawnotification_link(self, obj): - url = reverse('admin:trustlypayment_trustlyrawnotification_change', args=(obj.rawnotification.id, )) - return mark_safe('<a href="{0}">{1}</a>'.format(url, obj)) - rawnotification_link.short_description='Rawnotification' + def rawnotification_link(self, obj): + url = reverse('admin:trustlypayment_trustlyrawnotification_change', args=(obj.rawnotification.id, )) + return mark_safe('<a href="{0}">{1}</a>'.format(url, obj)) + rawnotification_link.short_description='Rawnotification' class TrustlyLogAdmin(admin.ModelAdmin): - list_display = ('timestamp', 'success', 'sentstr', 'message', ) + list_display = ('timestamp', 'success', 'sentstr', 'message', ) - def success(self, obj): - return not obj.error - success.boolean = True + def success(self, obj): + return not obj.error + success.boolean = True - def sentstr(self, obj): - return obj.sent and 'Yes' or 'No' - sentstr.short_description='Log sent' + def sentstr(self, obj): + return obj.sent and 'Yes' or 'No' + sentstr.short_description='Log sent' admin.site.register(TrustlyTransaction, TrustlyTransactionAdmin) admin.site.register(TrustlyRawNotification, TrustlyRawNotificationAdmin) diff --git a/postgresqleu/trustlypayment/api.py b/postgresqleu/trustlypayment/api.py index 9a1bfef0..b2acad39 100644 --- a/postgresqleu/trustlypayment/api.py +++ b/postgresqleu/trustlypayment/api.py @@ -9,157 +9,157 @@ import base64 import urllib2 class TrustlyException(Exception): - pass + pass class TrustlyWrapper(object): - def __init__(self, apibase, username, password, privatekey, publickey, notificationurl, currency='EUR', hold_notifications=False): - self.apibase = apibase - self.username = username - self.password = password - self.signer = PKCS1_v1_5.new(RSA.importKey(privatekey)) - self.verifier = PKCS1_v1_5.new(RSA.importKey(publickey)) - self.notificationurl = notificationurl - self.currency = currency - self.hold_notifications = hold_notifications + def __init__(self, apibase, username, password, privatekey, publickey, notificationurl, currency='EUR', hold_notifications=False): + self.apibase = apibase + self.username = username + self.password = password + self.signer = PKCS1_v1_5.new(RSA.importKey(privatekey)) + self.verifier = PKCS1_v1_5.new(RSA.importKey(publickey)) + self.notificationurl = notificationurl + self.currency = currency + self.hold_notifications = hold_notifications - def new_uuid(self): - return str(uuid4()) + def new_uuid(self): + return str(uuid4()) - def deposit(self, enduserid, invoiceid, amount, shopperstatement, successurl, failurl, firstname=None, lastname=None, email=None, ip=None): - d = { - 'NotificationURL': self.notificationurl, - 'EndUserID': enduserid, - 'MessageID': "{0}-{1}".format(invoiceid, time()), - 'Attributes': { - 'Currency': self.currency, - 'Firstname': firstname, - 'Lastname': lastname, - 'Email': email, - 'IP': ip, - 'SuccessURL': successurl, - 'FailURL': failurl, - 'ShopperStatement': shopperstatement, - 'Amount': '{0:.2f}'.format(amount), - }, - } - if self.hold_notifications: - d['Attributes']['HoldNotifications'] = '1' - return self.apicall('Deposit', d) + def deposit(self, enduserid, invoiceid, amount, shopperstatement, successurl, failurl, firstname=None, lastname=None, email=None, ip=None): + d = { + 'NotificationURL': self.notificationurl, + 'EndUserID': enduserid, + 'MessageID': "{0}-{1}".format(invoiceid, time()), + 'Attributes': { + 'Currency': self.currency, + 'Firstname': firstname, + 'Lastname': lastname, + 'Email': email, + 'IP': ip, + 'SuccessURL': successurl, + 'FailURL': failurl, + 'ShopperStatement': shopperstatement, + 'Amount': '{0:.2f}'.format(amount), + }, + } + if self.hold_notifications: + d['Attributes']['HoldNotifications'] = '1' + return self.apicall('Deposit', d) - def refund(self, orderid, amount): - r = self.apicall('Refund', { - 'OrderID': str(orderid), - 'Amount': '{0:.2f}'.format(amount), - 'Currency': self.currency, - }) - if r['data']['result'] == '1': - # Yay! Successful. But what about the orderid? - if r['data']['orderid'] != str(orderid): - raise TrustlyException('Refunded orderid {0} does not match requested orderid {1}'.format( - r['data']['orderid'], orderid)) - return True - else: - raise TrustlyException('Failed to refund orderid {0}'.format(orderid)) + def refund(self, orderid, amount): + r = self.apicall('Refund', { + 'OrderID': str(orderid), + 'Amount': '{0:.2f}'.format(amount), + 'Currency': self.currency, + }) + if r['data']['result'] == '1': + # Yay! Successful. But what about the orderid? + if r['data']['orderid'] != str(orderid): + raise TrustlyException('Refunded orderid {0} does not match requested orderid {1}'.format( + r['data']['orderid'], orderid)) + return True + else: + raise TrustlyException('Failed to refund orderid {0}'.format(orderid)) - def get_balance(self): - r = self.apicall('Balance', {}) - balance = None - for b in r['data']: - # We can get multiple balances. If we see a non-zero balance for a non-standard - # currency, bail. - if b['currency'] == self.currency: - balance = Decimal(b['balance']) - else: - # Different currency, so ensure it's zero - if Decimal(b['balance']) != 0: - raise TrustlyException('Found non-zero balance {0} for non-standard currency {1}'.format(b['balance'],b['currency'])) - if balance is None: - raise TrustlyException('Found no balance for {0}'.format(self.currency)) - return balance + def get_balance(self): + r = self.apicall('Balance', {}) + balance = None + for b in r['data']: + # We can get multiple balances. If we see a non-zero balance for a non-standard + # currency, bail. + if b['currency'] == self.currency: + balance = Decimal(b['balance']) + else: + # Different currency, so ensure it's zero + if Decimal(b['balance']) != 0: + raise TrustlyException('Found non-zero balance {0} for non-standard currency {1}'.format(b['balance'],b['currency'])) + if balance is None: + raise TrustlyException('Found no balance for {0}'.format(self.currency)) + return balance - def getwithdrawal(self, orderid): - r = self.apicall('GetWithdrawals', {'OrderID': orderid}) - w = r['data'] - if len(w) != 1: - raise TrustlyException('Received more than one withdrawal for order {0}'.format(orderid)) - return w[0] + def getwithdrawal(self, orderid): + r = self.apicall('GetWithdrawals', {'OrderID': orderid}) + w = r['data'] + if len(w) != 1: + raise TrustlyException('Received more than one withdrawal for order {0}'.format(orderid)) + return w[0] - def apicall(self, method, data): - params = { - 'UUID': self.new_uuid(), - 'Data': data, - } - params['Data']['Username'] = self.username - params['Data']['Password'] = self.password - tosign = unicode((method+params['UUID']+self._serializestruct(params['Data'])).decode('utf8')) - sha1hash = SHA.new(tosign.encode('utf-8')) - signature = self.signer.sign(sha1hash) - params['Signature'] = base64.b64encode(signature) - p = { - 'method': method, - 'params': params, - 'version': '1.1', - } - apijson = json.dumps(p) + def apicall(self, method, data): + params = { + 'UUID': self.new_uuid(), + 'Data': data, + } + params['Data']['Username'] = self.username + params['Data']['Password'] = self.password + tosign = unicode((method+params['UUID']+self._serializestruct(params['Data'])).decode('utf8')) + sha1hash = SHA.new(tosign.encode('utf-8')) + signature = self.signer.sign(sha1hash) + params['Signature'] = base64.b64encode(signature) + p = { + 'method': method, + 'params': params, + 'version': '1.1', + } + apijson = json.dumps(p) - req = urllib2.Request(self.apibase) - req.add_header('Content-type', 'application/json') - u = urllib2.urlopen(req, apijson) - resp = u.read() - if u.getcode () != 200: - raise TrustlyException("bad http response code {0}".format(u.getcode())) - u.close() - r = json.loads(resp) - if r.has_key('error'): - # XXX log and raise generic exception! - raise TrustlyException(r['error']['message']) - if r['result']['method'] != method: - raise TrustlyException("bad method in response") + req = urllib2.Request(self.apibase) + req.add_header('Content-type', 'application/json') + u = urllib2.urlopen(req, apijson) + resp = u.read() + if u.getcode () != 200: + raise TrustlyException("bad http response code {0}".format(u.getcode())) + u.close() + r = json.loads(resp) + if r.has_key('error'): + # XXX log and raise generic exception! + raise TrustlyException(r['error']['message']) + if r['result']['method'] != method: + raise TrustlyException("bad method in response") - # XXX: verify signature? But we made a https call... - return r['result'] + # XXX: verify signature? But we made a https call... + return r['result'] - def parse_notification(self, notstr): - struct = json.loads(notstr) - tosign = unicode(struct['method']+struct['params']['uuid']+self._serializestruct(struct['params']['data'])) - sha1hash = SHA.new(tosign.encode('utf-8')) + def parse_notification(self, notstr): + struct = json.loads(notstr) + tosign = unicode(struct['method']+struct['params']['uuid']+self._serializestruct(struct['params']['data'])) + sha1hash = SHA.new(tosign.encode('utf-8')) - if self.verifier.verify(sha1hash, base64.b64decode(struct['params']['signature'])): - return (struct['params']['uuid'], struct['method'], struct['params']['data']) - else: - # Indicate that signature failed - return (struct['params']['uuid'], struct['method'], None) + if self.verifier.verify(sha1hash, base64.b64decode(struct['params']['signature'])): + return (struct['params']['uuid'], struct['method'], struct['params']['data']) + else: + # Indicate that signature failed + return (struct['params']['uuid'], struct['method'], None) - def create_notification_response(self, uuid, method, status): - struct = { - 'result': { - 'uuid': uuid, - 'method': method, - 'data': { - 'status': status, - } - }, - 'version': '1.1', - } - tosign = unicode(method+uuid+self._serializestruct(struct['result']['data'])) - sha1hash = SHA.new(tosign.encode('utf-8')) - signature = self.signer.sign(sha1hash) - struct['result']['signature'] = base64.b64encode(signature) - return json.dumps(struct) + def create_notification_response(self, uuid, method, status): + struct = { + 'result': { + 'uuid': uuid, + 'method': method, + 'data': { + 'status': status, + } + }, + 'version': '1.1', + } + tosign = unicode(method+uuid+self._serializestruct(struct['result']['data'])) + sha1hash = SHA.new(tosign.encode('utf-8')) + signature = self.signer.sign(sha1hash) + struct['result']['signature'] = base64.b64encode(signature) + return json.dumps(struct) - def _serializestruct(self, struct): - if (type(struct) == dict): - serialized = '' - for k in sorted(struct.keys()): - if struct[k]: - serialized += k - serialized += self._serializestruct(struct[k]) - else: - serialized += k - return serialized - # XXX: Handle regular arrays? - elif (type(struct) == unicode): - return struct.encode('utf-8') - else: - return str(struct) + def _serializestruct(self, struct): + if (type(struct) == dict): + serialized = '' + for k in sorted(struct.keys()): + if struct[k]: + serialized += k + serialized += self._serializestruct(struct[k]) + else: + serialized += k + return serialized + # XXX: Handle regular arrays? + elif (type(struct) == unicode): + return struct.encode('utf-8') + else: + return str(struct) diff --git a/postgresqleu/trustlypayment/management/commands/reprocess_trustly_notification.py b/postgresqleu/trustlypayment/management/commands/reprocess_trustly_notification.py index 2857557e..8340c5b5 100644 --- a/postgresqleu/trustlypayment/management/commands/reprocess_trustly_notification.py +++ b/postgresqleu/trustlypayment/management/commands/reprocess_trustly_notification.py @@ -6,23 +6,23 @@ from postgresqleu.trustlypayment.util import Trustly class Command(BaseCommand): - help = 'Reprocess a notification that for some reason failed' + help = 'Reprocess a notification that for some reason failed' - def add_arguments(self, parser): - parser.add_argument('id') + def add_arguments(self, parser): + parser.add_argument('id') - def handle(self, *args, **options): - with transaction.atomic(): - try: - notification = TrustlyNotification.objects.get(id=options['id']) - except TrustlyNotification.DoesNotExist: - raise CommandError("Notification {0} does not exist.".format(options['id'])) + def handle(self, *args, **options): + with transaction.atomic(): + try: + notification = TrustlyNotification.objects.get(id=options['id']) + except TrustlyNotification.DoesNotExist: + raise CommandError("Notification {0} does not exist.".format(options['id'])) - TrustlyLog(message="Reprocessing notification {0}".format(notification.id)).save() + TrustlyLog(message="Reprocessing notification {0}".format(notification.id)).save() - t = Trustly() - result = t.process_notification(notification) - if not result: - raise CommandError("Reprocessing failed, see log!") + t = Trustly() + result = t.process_notification(notification) + if not result: + raise CommandError("Reprocessing failed, see log!") - self.stdout.write("Completed reprocessing notification {0}.".format(notification.id)) + self.stdout.write("Completed reprocessing notification {0}.".format(notification.id)) diff --git a/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py b/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py index 6ff3803d..4af5ac6e 100755 --- a/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py +++ b/postgresqleu/trustlypayment/management/commands/send_trustly_logreport.py @@ -15,59 +15,59 @@ from postgresqleu.trustlypayment.models import TrustlyLog, TrustlyNotification, from postgresqleu.mailqueue.util import send_simple_mail class Command(BaseCommand): - help = 'Send log information about Trustly events' + help = 'Send log information about Trustly events' - def handle(self, *args, **options): - self.report_loglines() - self.report_unconfirmed_notifications() - self.report_unfinished_transactions() + def handle(self, *args, **options): + self.report_loglines() + self.report_unconfirmed_notifications() + self.report_unfinished_transactions() - @transaction.atomic - def report_loglines(self): - lines = list(TrustlyLog.objects.filter(error=True,sent=False).order_by('timestamp')) - if len(lines): - sio = StringIO() - sio.write("The following error events have been logged by the Trustly integration:\n\n") - for l in lines: - sio.write("%s: %s\n" % (l.timestamp, l.message)) - l.sent = True - l.save() - sio.write("\n\n\nAll these events have now been tagged as sent, and will no longer be\nprocessed by the system in any way.\n") + @transaction.atomic + def report_loglines(self): + lines = list(TrustlyLog.objects.filter(error=True,sent=False).order_by('timestamp')) + if len(lines): + sio = StringIO() + sio.write("The following error events have been logged by the Trustly integration:\n\n") + for l in lines: + sio.write("%s: %s\n" % (l.timestamp, l.message)) + l.sent = True + l.save() + sio.write("\n\n\nAll these events have now been tagged as sent, and will no longer be\nprocessed by the system in any way.\n") - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - 'Trustly integration error report', - sio.getvalue()) + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + 'Trustly integration error report', + sio.getvalue()) - def report_unconfirmed_notifications(self): - lines = list(TrustlyNotification.objects.filter(confirmed=False, receivedat__lt=datetime.now()-timedelta(days=1)).order_by('receivedat')) - if len(lines): - sio = StringIO() - sio.write("The following notifications have not been confirmed in the Trustly integration.\nThese need to be manually processed and then flagged as confirmed!\n\nThis list only contains unconfirmed events older than 24 hours.\n\n\n") - for l in lines: - sio.write("%s: %s (%s%s)\n" % (l.receivedat, l.method, settings.SITEBASE, reverse('admin:trustlypayment_trustlynotification_change', args=(l.id,)))) + def report_unconfirmed_notifications(self): + lines = list(TrustlyNotification.objects.filter(confirmed=False, receivedat__lt=datetime.now()-timedelta(days=1)).order_by('receivedat')) + if len(lines): + sio = StringIO() + sio.write("The following notifications have not been confirmed in the Trustly integration.\nThese need to be manually processed and then flagged as confirmed!\n\nThis list only contains unconfirmed events older than 24 hours.\n\n\n") + for l in lines: + sio.write("%s: %s (%s%s)\n" % (l.receivedat, l.method, settings.SITEBASE, reverse('admin:trustlypayment_trustlynotification_change', args=(l.id,)))) - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - 'Trustly integration unconfirmed notifications', - sio.getvalue()) + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + 'Trustly integration unconfirmed notifications', + sio.getvalue()) - def report_unfinished_transactions(self): - # Number of days until we start reporting unfinished transactions - # Note: we only care about transactions that have actually started, where the user - # got the first step of confirmation. The ones that were never started are uninteresting. - UNFINISHED_THRESHOLD=3 + def report_unfinished_transactions(self): + # Number of days until we start reporting unfinished transactions + # Note: we only care about transactions that have actually started, where the user + # got the first step of confirmation. The ones that were never started are uninteresting. + UNFINISHED_THRESHOLD=3 - lines = list(TrustlyTransaction.objects.filter(completedat__isnull=True, pendingat__isnull=False, pendingat__lt=datetime.now()-timedelta(days=UNFINISHED_THRESHOLD)).order_by('pendingat')) - if len(lines): - sio = StringIO() - sio.write("The following payments have been authorized, but not finished for more than %s days.\nThese probably need to be verified manually.\n\n\n" % UNFINISHED_THRESHOLD) + lines = list(TrustlyTransaction.objects.filter(completedat__isnull=True, pendingat__isnull=False, pendingat__lt=datetime.now()-timedelta(days=UNFINISHED_THRESHOLD)).order_by('pendingat')) + if len(lines): + sio = StringIO() + sio.write("The following payments have been authorized, but not finished for more than %s days.\nThese probably need to be verified manually.\n\n\n" % UNFINISHED_THRESHOLD) - for l in lines: - sio.write("%s at %s: %s (%s%s)\n" % (l.orderid, l.pendingat, l.amount, settings.SITEBASE, reverse('admin:trustlypayment_trustlytransactionstatus_change', args=(l.id,)))) + for l in lines: + sio.write("%s at %s: %s (%s%s)\n" % (l.orderid, l.pendingat, l.amount, settings.SITEBASE, reverse('admin:trustlypayment_trustlytransactionstatus_change', args=(l.id,)))) - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - 'Trustly integration unconfirmed notifications', - sio.getvalue()) + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + 'Trustly integration unconfirmed notifications', + sio.getvalue()) diff --git a/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py b/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py index 20fa9003..b66d6336 100644 --- a/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py +++ b/postgresqleu/trustlypayment/management/commands/trustly_match_refunds.py @@ -19,43 +19,43 @@ from postgresqleu.invoices.util import InvoiceManager from decimal import Decimal class Command(BaseCommand): - help = 'Verify that a Trustly refund has completed, and flag it as such' - - @transaction.atomic - def handle(self, *args, **options): - trustly = Trustly() - manager = InvoiceManager() - method = InvoicePaymentMethod.objects.get(classname='postgresqleu.util.payment.trustly.TrustlyPayment') - - refunds = InvoiceRefund.objects.filter(completed__isnull=True, invoice__paidusing=method) - - for r in refunds: - # Find the matching Trustly transaction - trustlytransactionlist = list(TrustlyTransaction.objects.filter(invoiceid=r.invoice.pk)) - if len(trustlytransactionlist) == 0: - raise CommandError("Could not find trustly transaction for invoice {0}".format(r.invoice.pk)) - elif len(trustlytransactionlist) != 1: - raise CommandError("Found {0} trustly transactions for invoice {1}!".format(len(trustlytransactionlist), r.invoice.pk)) - trustlytrans = trustlytransactionlist[0] - w = trustly.getwithdrawal(trustlytrans.orderid) - if not w: - # No refund yet - continue - - if w['transferstate'] != 'CONFIRMED': - # Still pending - continue - - if Decimal(w['amount']) != r.fullamount: - raise CommandError("Mismatch in amount on Trustly refund for invoice {0}".format(r.invoice.pk)) - - # Ok, things look good! - TrustlyLog(message="Refund for order {0}, invoice {1}, completed".format(trustlytrans.orderid, r.invoice.pk), error=False).save() - manager.complete_refund( - r.id, - Decimal(w['amount']), - 0, - settings.ACCOUNTING_TRUSTLY_ACCOUNT, - 0, # We don't support fees on Trustly at this point - [], - method) + help = 'Verify that a Trustly refund has completed, and flag it as such' + + @transaction.atomic + def handle(self, *args, **options): + trustly = Trustly() + manager = InvoiceManager() + method = InvoicePaymentMethod.objects.get(classname='postgresqleu.util.payment.trustly.TrustlyPayment') + + refunds = InvoiceRefund.objects.filter(completed__isnull=True, invoice__paidusing=method) + + for r in refunds: + # Find the matching Trustly transaction + trustlytransactionlist = list(TrustlyTransaction.objects.filter(invoiceid=r.invoice.pk)) + if len(trustlytransactionlist) == 0: + raise CommandError("Could not find trustly transaction for invoice {0}".format(r.invoice.pk)) + elif len(trustlytransactionlist) != 1: + raise CommandError("Found {0} trustly transactions for invoice {1}!".format(len(trustlytransactionlist), r.invoice.pk)) + trustlytrans = trustlytransactionlist[0] + w = trustly.getwithdrawal(trustlytrans.orderid) + if not w: + # No refund yet + continue + + if w['transferstate'] != 'CONFIRMED': + # Still pending + continue + + if Decimal(w['amount']) != r.fullamount: + raise CommandError("Mismatch in amount on Trustly refund for invoice {0}".format(r.invoice.pk)) + + # Ok, things look good! + TrustlyLog(message="Refund for order {0}, invoice {1}, completed".format(trustlytrans.orderid, r.invoice.pk), error=False).save() + manager.complete_refund( + r.id, + Decimal(w['amount']), + 0, + settings.ACCOUNTING_TRUSTLY_ACCOUNT, + 0, # We don't support fees on Trustly at this point + [], + method) diff --git a/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py b/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py index ca577658..2c273484 100644 --- a/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py +++ b/postgresqleu/trustlypayment/management/commands/verify_trustly_balance.py @@ -16,21 +16,21 @@ from postgresqleu.accounting.util import get_latest_account_balance from postgresqleu.mailqueue.util import send_simple_mail class Command(BaseCommand): - help = 'Compare trustly balance to the accounting system' + help = 'Compare trustly balance to the accounting system' - @transaction.atomic - def handle(self, *args, **options): - trustly = Trustly() + @transaction.atomic + def handle(self, *args, **options): + trustly = Trustly() - trustly_balance = trustly.get_balance() + trustly_balance = trustly.get_balance() - accounting_balance = get_latest_account_balance(settings.ACCOUNTING_TRUSTLY_ACCOUNT) + accounting_balance = get_latest_account_balance(settings.ACCOUNTING_TRUSTLY_ACCOUNT) - if accounting_balance != trustly_balance: - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - 'Trustly balance mismatch!', - """Trustly balance ({0}) does not match the accounting system ({1})! + if accounting_balance != trustly_balance: + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + 'Trustly balance mismatch!', + """Trustly balance ({0}) does not match the accounting system ({1})! This could be because some entry has been missed in the accouting (automatic or manual), or because of an ongoing booking of something diff --git a/postgresqleu/trustlypayment/models.py b/postgresqleu/trustlypayment/models.py index 2de9061f..6473d809 100644 --- a/postgresqleu/trustlypayment/models.py +++ b/postgresqleu/trustlypayment/models.py @@ -1,45 +1,45 @@ from django.db import models class TrustlyTransaction(models.Model): - createdat = models.DateTimeField(null=False, blank=False) - pendingat = models.DateTimeField(null=True, blank=True) - completedat = models.DateTimeField(null=True, blank=True) - amount = models.DecimalField(decimal_places=2, max_digits=20, null=False) - invoiceid = models.IntegerField(null=False, blank=False) - redirecturl = models.CharField(max_length=2000, null=False, blank=False) - orderid = models.BigIntegerField(null=False, blank=False) + createdat = models.DateTimeField(null=False, blank=False) + pendingat = models.DateTimeField(null=True, blank=True) + completedat = models.DateTimeField(null=True, blank=True) + amount = models.DecimalField(decimal_places=2, max_digits=20, null=False) + invoiceid = models.IntegerField(null=False, blank=False) + redirecturl = models.CharField(max_length=2000, null=False, blank=False) + orderid = models.BigIntegerField(null=False, blank=False) - def __unicode__(self): - return "%s" % self.orderid + def __unicode__(self): + return "%s" % self.orderid class TrustlyRawNotification(models.Model): - dat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True) - contents = models.TextField(null=False, blank=False) - confirmed = models.BooleanField(null=False, default=False) + dat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True) + contents = models.TextField(null=False, blank=False) + confirmed = models.BooleanField(null=False, default=False) - def __unicode__(self): - return "%s" % self.dat + def __unicode__(self): + return "%s" % self.dat class TrustlyNotification(models.Model): - receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True) - rawnotification = models.ForeignKey(TrustlyRawNotification, null=True, blank=True, on_delete=models.CASCADE) - notificationid = models.BigIntegerField(null=False, blank=False) - orderid = models.BigIntegerField(null=False, blank=False) - method = models.CharField(max_length=80, null=False, blank=False) - amount = models.DecimalField(decimal_places=2, max_digits=20, null=True, blank=True) - messageid = models.CharField(max_length=80, null=False, blank=False) + receivedat = models.DateTimeField(null=False, blank=False, auto_now_add=True, unique=True) + rawnotification = models.ForeignKey(TrustlyRawNotification, null=True, blank=True, on_delete=models.CASCADE) + notificationid = models.BigIntegerField(null=False, blank=False) + orderid = models.BigIntegerField(null=False, blank=False) + method = models.CharField(max_length=80, null=False, blank=False) + amount = models.DecimalField(decimal_places=2, max_digits=20, null=True, blank=True) + messageid = models.CharField(max_length=80, null=False, blank=False) - confirmed = models.BooleanField(null=False, default=False) + confirmed = models.BooleanField(null=False, default=False) - def __unicode__(self): - return "%s" % self.receivedat + def __unicode__(self): + return "%s" % self.receivedat class TrustlyLog(models.Model): - timestamp = models.DateTimeField(null=False, blank=False, auto_now_add=True) - message = models.TextField(null=False, blank=False) - error = models.BooleanField(null=False, blank=False, default=False) - sent = models.BooleanField(null=False, blank=False, default=False) + timestamp = models.DateTimeField(null=False, blank=False, auto_now_add=True) + message = models.TextField(null=False, blank=False) + error = models.BooleanField(null=False, blank=False, default=False) + sent = models.BooleanField(null=False, blank=False, default=False) class ReturnAuthorizationStatus(models.Model): - orderid = models.BigIntegerField(null=False, blank=False, primary_key=True) - seencount = models.IntegerField(null=False, default=0) + orderid = models.BigIntegerField(null=False, blank=False, primary_key=True) + seencount = models.IntegerField(null=False, default=0) diff --git a/postgresqleu/trustlypayment/util.py b/postgresqleu/trustlypayment/util.py index 15a3f1e0..7a4b7a8f 100644 --- a/postgresqleu/trustlypayment/util.py +++ b/postgresqleu/trustlypayment/util.py @@ -15,158 +15,158 @@ from models import TrustlyNotification # Django intgrated wrapper for the trustly API class Trustly(TrustlyWrapper): - def __init__(self): - super(Trustly, self).__init__(settings.TRUSTLY_APIBASE, - settings.TRUSTLY_USER, - settings.TRUSTLY_PASSWORD, - settings.TRUSTLY_PRIVATE_KEY, - settings.TRUSTLY_PUBLIC_KEY, - '{0}/trustly_notification/'.format(settings.SITEBASE), - settings.CURRENCY_ABBREV, - getattr(settings, 'TRUSTLY_HOLD_NOTIFICATIONS', False), - ) - - def process_raw_trustly_notification(self, raw): - (uuid, method, data) = self.parse_notification(raw.contents) - if not data: - TrustlyLog(message="Failed to parse trustly raw notification {0}".format(raw.id), error=True).save() - return (False, uuid, method) - - n = None - with transaction.atomic(): - # Find if we have already seen this guy - try: - TrustlyNotification.objects.get(notificationid=data['notificationid']) - # If it's found, then we're happy, so keep on smiling. Flag this one as - # confirmed as well. - raw.confirmed = True - raw.save() - return (True, uuid, method) - except TrustlyNotification.DoesNotExist: - pass - - n = TrustlyNotification( - receivedat=datetime.now(), - rawnotification=raw, - method=method, - notificationid=data['notificationid'], - orderid=data['orderid'], - amount=data.has_key('amount') and Decimal(data['amount']) or None, - messageid=data['messageid'], - ) - n.save() - raw.confirmed=True - raw.save() - - # Raw is confirmed, but parsed one is still pending. So handle that one. - try: - self.process_notification(n) - except Exception, e: - self.log_and_email("Exception processing notification {0}: {1}".format(n.id, e)) - - # If we somehow failed to handle at this level, we still flag things as ok to - # Trustly, and deal with it ourselves. - # Notifications can always be re-parsed - return (True, uuid, method) - - def log_and_email(self, message): - TrustlyLog(message=message, error=True).save() - - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - "Trustly payment error", - u"A trustly payment failed with the error:\n\n{0}".format(message), - ) - - @transaction.atomic - def process_notification(self, notification): - if notification.method in ('pending', 'credit'): - # Find the appropriate transaction - try: - trans = TrustlyTransaction.objects.get(orderid=notification.orderid) - except TrustlyTransaction.DoesNotExist: - self.log_and_email("Transaction {0} for notification {1} not found!".format(notification.orderid, notification.id)) - return False - if trans.amount != notification.amount: - self.log_and_email("Notification {0} for transaction {1} has invalid amount ({2} should be {3})!".format(notification.id, notification.orderid, notification.amount, trans.amount)) - return False - - if notification.method == 'pending': - # Pending is just an incremental state, so we collect it but don't do anything with - # it. - if not trans.pendingat: - trans.pendingat = datetime.now() - trans.save() - notification.confirmed=True - notification.save() - - TrustlyLog(message="Pending payment for Trustly id {0} (order {1}) received".format(trans.id, trans.orderid)).save() - - return True - else: - # Credit! The payment is completed! - if not trans.pendingat: - # We set pending in case it never showed up - trans.pendingat = datetime.now() - if trans.completedat: - self.log_and_email("Duplicate completed notification ({0}) received for transaction {1}!".format(notification.id, notification.orderid)) - return False - - trans.completedat = datetime.now() - try: - self.process_completed_payment(trans) - except TrustlyException, e: - self.log_and_email(e) - return False - trans.save() - notification.confirmed=True - notification.save() - return True - elif notification.method == 'cancel': - try: - trans = TrustlyTransaction.objects.get(orderid=notification.orderid) - if trans.pendingat: - self.log_and_email("Transaction {0} canceled by notification {1} but already in progress. Ignoring cancel!".format(notification.orderid, notification.id)) - return False - TrustlyLog(message='Transaction {0} canceled from notification'.format(notification.orderid)).save() - trans.delete() - except TrustlyTransaction.DoesNotExist: - TrustlyLog("Abandoned transaction {0} canceled from notification".format(notification.orderid)) - notification.confirmed = True - notification.save() - return True - else: - self.log_and_email("Unknown notification type '{0}' in notification {1}".format(notification.method, notification.id)) - return False - - # Can't reach here - return False - - def process_completed_payment(self, trans): - manager = InvoiceManager() - try: - invoice = Invoice.objects.get(pk=trans.invoiceid) - except Invoice.DoesNotExist: - raise TrustlyException("Received Trustly notification for non-existing invoice id {0}".format(trans.invoiceid)) - - def invoice_logger(msg): - raise TrustlyException("Trustly invoice processing failed: {0}".format(msg)) - - method = InvoicePaymentMethod.objects.get(classname='postgresqleu.util.payment.trustly.TrustlyPayment') - manager.process_incoming_payment_for_invoice(invoice, - trans.amount, - 'Trustly id {0}'.format(trans.id), - 0, #XXX: we pay zero now, but should perhaps support fees? - settings.ACCOUNTING_TRUSTLY_ACCOUNT, - 0, #XXX: if supporting fees, support fee account - [], - invoice_logger, - method) - - TrustlyLog(message="Completed payment for Trustly id {0} (order {1}), {2}{3}, invoice {4}".format(trans.id, trans.orderid, settings.CURRENCY_ABBREV, trans.amount, invoice.id)).save() - - send_simple_mail(settings.INVOICE_SENDER_EMAIL, - settings.TRUSTLY_NOTIFICATION_RECEIVER, - "Trustly payment completed", - u"A Trustly payment of {0}{1} for invoice {2} was completed on the Trustly platform.\n\nInvoice: {3}\nRecipient name: {4}\nRecipient email: {5}\n".format(settings.CURRENCY_ABBREV, trans.amount, invoice.id, invoice.title, invoice.recipient_name, invoice.recipient_email), - ) + def __init__(self): + super(Trustly, self).__init__(settings.TRUSTLY_APIBASE, + settings.TRUSTLY_USER, + settings.TRUSTLY_PASSWORD, + settings.TRUSTLY_PRIVATE_KEY, + settings.TRUSTLY_PUBLIC_KEY, + '{0}/trustly_notification/'.format(settings.SITEBASE), + settings.CURRENCY_ABBREV, + getattr(settings, 'TRUSTLY_HOLD_NOTIFICATIONS', False), + ) + + def process_raw_trustly_notification(self, raw): + (uuid, method, data) = self.parse_notification(raw.contents) + if not data: + TrustlyLog(message="Failed to parse trustly raw notification {0}".format(raw.id), error=True).save() + return (False, uuid, method) + + n = None + with transaction.atomic(): + # Find if we have already seen this guy + try: + TrustlyNotification.objects.get(notificationid=data['notificationid']) + # If it's found, then we're happy, so keep on smiling. Flag this one as + # confirmed as well. + raw.confirmed = True + raw.save() + return (True, uuid, method) + except TrustlyNotification.DoesNotExist: + pass + + n = TrustlyNotification( + receivedat=datetime.now(), + rawnotification=raw, + method=method, + notificationid=data['notificationid'], + orderid=data['orderid'], + amount=data.has_key('amount') and Decimal(data['amount']) or None, + messageid=data['messageid'], + ) + n.save() + raw.confirmed=True + raw.save() + + # Raw is confirmed, but parsed one is still pending. So handle that one. + try: + self.process_notification(n) + except Exception, e: + self.log_and_email("Exception processing notification {0}: {1}".format(n.id, e)) + + # If we somehow failed to handle at this level, we still flag things as ok to + # Trustly, and deal with it ourselves. + # Notifications can always be re-parsed + return (True, uuid, method) + + def log_and_email(self, message): + TrustlyLog(message=message, error=True).save() + + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + "Trustly payment error", + u"A trustly payment failed with the error:\n\n{0}".format(message), + ) + + @transaction.atomic + def process_notification(self, notification): + if notification.method in ('pending', 'credit'): + # Find the appropriate transaction + try: + trans = TrustlyTransaction.objects.get(orderid=notification.orderid) + except TrustlyTransaction.DoesNotExist: + self.log_and_email("Transaction {0} for notification {1} not found!".format(notification.orderid, notification.id)) + return False + if trans.amount != notification.amount: + self.log_and_email("Notification {0} for transaction {1} has invalid amount ({2} should be {3})!".format(notification.id, notification.orderid, notification.amount, trans.amount)) + return False + + if notification.method == 'pending': + # Pending is just an incremental state, so we collect it but don't do anything with + # it. + if not trans.pendingat: + trans.pendingat = datetime.now() + trans.save() + notification.confirmed=True + notification.save() + + TrustlyLog(message="Pending payment for Trustly id {0} (order {1}) received".format(trans.id, trans.orderid)).save() + + return True + else: + # Credit! The payment is completed! + if not trans.pendingat: + # We set pending in case it never showed up + trans.pendingat = datetime.now() + if trans.completedat: + self.log_and_email("Duplicate completed notification ({0}) received for transaction {1}!".format(notification.id, notification.orderid)) + return False + + trans.completedat = datetime.now() + try: + self.process_completed_payment(trans) + except TrustlyException, e: + self.log_and_email(e) + return False + trans.save() + notification.confirmed=True + notification.save() + return True + elif notification.method == 'cancel': + try: + trans = TrustlyTransaction.objects.get(orderid=notification.orderid) + if trans.pendingat: + self.log_and_email("Transaction {0} canceled by notification {1} but already in progress. Ignoring cancel!".format(notification.orderid, notification.id)) + return False + TrustlyLog(message='Transaction {0} canceled from notification'.format(notification.orderid)).save() + trans.delete() + except TrustlyTransaction.DoesNotExist: + TrustlyLog("Abandoned transaction {0} canceled from notification".format(notification.orderid)) + notification.confirmed = True + notification.save() + return True + else: + self.log_and_email("Unknown notification type '{0}' in notification {1}".format(notification.method, notification.id)) + return False + + # Can't reach here + return False + + def process_completed_payment(self, trans): + manager = InvoiceManager() + try: + invoice = Invoice.objects.get(pk=trans.invoiceid) + except Invoice.DoesNotExist: + raise TrustlyException("Received Trustly notification for non-existing invoice id {0}".format(trans.invoiceid)) + + def invoice_logger(msg): + raise TrustlyException("Trustly invoice processing failed: {0}".format(msg)) + + method = InvoicePaymentMethod.objects.get(classname='postgresqleu.util.payment.trustly.TrustlyPayment') + manager.process_incoming_payment_for_invoice(invoice, + trans.amount, + 'Trustly id {0}'.format(trans.id), + 0, #XXX: we pay zero now, but should perhaps support fees? + settings.ACCOUNTING_TRUSTLY_ACCOUNT, + 0, #XXX: if supporting fees, support fee account + [], + invoice_logger, + method) + + TrustlyLog(message="Completed payment for Trustly id {0} (order {1}), {2}{3}, invoice {4}".format(trans.id, trans.orderid, settings.CURRENCY_ABBREV, trans.amount, invoice.id)).save() + + send_simple_mail(settings.INVOICE_SENDER_EMAIL, + settings.TRUSTLY_NOTIFICATION_RECEIVER, + "Trustly payment completed", + u"A Trustly payment of {0}{1} for invoice {2} was completed on the Trustly platform.\n\nInvoice: {3}\nRecipient name: {4}\nRecipient email: {5}\n".format(settings.CURRENCY_ABBREV, trans.amount, invoice.id, invoice.title, invoice.recipient_name, invoice.recipient_email), + ) diff --git a/postgresqleu/trustlypayment/views.py b/postgresqleu/trustlypayment/views.py index 8cc5d351..4c3d2877 100644 --- a/postgresqleu/trustlypayment/views.py +++ b/postgresqleu/trustlypayment/views.py @@ -14,98 +14,98 @@ from models import ReturnAuthorizationStatus @transaction.atomic def invoicepayment_secret(request, invoiceid, secret): - invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret) - - # 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)).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() - - 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 - 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=datetime.now(), - invoiceid=invoice.id, - amount=invoice.total_amount, - orderid=r['data']['orderid'], - redirecturl=r['data']['url'], - ).save() - - # With the transaction saved, redirect the user to Trustly - return HttpResponseRedirect(r['data']['url']) - except TrustlyException, e: - return HttpResponse("Error communicating with Trustly: {0}".format(e)) + invoice = get_object_or_404(Invoice, pk=invoiceid, deleted=False, finalized=True, recipient_secret=secret) + + # 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)).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() + + 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 + 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=datetime.now(), + invoiceid=invoice.id, + amount=invoice.total_amount, + orderid=r['data']['orderid'], + redirecturl=r['data']['url'], + ).save() + + # With the transaction saved, redirect the user to Trustly + return HttpResponseRedirect(r['data']['url']) + except TrustlyException, 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, - }) + # 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), - }) + return render(request, 'trustlypayment/error.html', { + 'url': '/invoices/{0}/{1}/'.format(invoiceid, secret), + }) @csrf_exempt def notification(request): - raw = TrustlyRawNotification(contents=request.body) - raw.save() + raw = TrustlyRawNotification(contents=request.body) + raw.save() - t = Trustly() + t = Trustly() - (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') + (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') |
