def adyen_return_handler(request, methodid): method = get_object_or_404(InvoicePaymentMethod, pk=methodid, active=True) pm = method.get_implementation() sig = pm.calculate_signature(request.GET) if sig != request.GET['merchantSig']: return render(request, 'adyen/sigerror.html') # We're going to need the invoice for pretty much everything, # so attempt to find it. if request.GET['merchantReturnData'] != request.GET[ 'merchantReference'] or not request.GET[ 'merchantReturnData'].startswith( pm.config('merchantref_prefix')): AdyenLog(pspReference='', message='Return handler received invalid reference %s/%s' % (request.GET['merchantReturnData'], request.GET['merchantReference']), error=True, paymentmethod=method).save() return render( request, 'adyen/invalidreference.html', { 'reference': "%s//%s" % (request.GET['merchantReturnData'], request.GET['merchantReference']), }) invoiceid = int(request.GET['merchantReturnData'] [len(pm.config('merchantref_prefix')):]) try: invoice = Invoice.objects.get(pk=invoiceid) except Invoice.DoesNotExist: AdyenLog( pspReference='', message='Return handler could not find invoice for reference %s' % request.GET['merchantReturnData'], error=True, paymentmethod=method).save() return render(request, 'adyen/invalidreference.html', { 'reference': request.GET['merchantReturnData'], }) manager = InvoiceManager() if invoice.processor: processor = manager.get_invoice_processor(invoice) returnurl = processor.get_return_url(invoice) else: if invoice.recipient_user: returnurl = "%s/invoices/%s/" % (settings.SITEBASE, invoice.pk) else: returnurl = "%s/invoices/%s/%s/" % (settings.SITEBASE, invoice.pk, invoice.recipient_secret) AdyenLog(pspReference='', message='Return handler received %s result for %s' % (request.GET['authResult'], request.GET['merchantReturnData']), error=False, paymentmethod=method).save() if request.GET['authResult'] == 'REFUSED': return render(request, 'adyen/refused.html', { 'url': returnurl, }) elif request.GET['authResult'] == 'CANCELLED': return HttpResponseRedirect(returnurl) elif request.GET['authResult'] == 'ERROR': return render(request, 'adyen/transerror.html', { 'url': returnurl, }) elif request.GET['authResult'] == 'PENDING': return render(request, 'adyen/pending.html', { 'url': returnurl, }) elif request.GET['authResult'] == 'AUTHORISED': # NOTE! Adyen strongly recommends not reacting on # authorized values, but deal with them from the # notifications instead. So we'll do that. # However, if we reach this point and it's actually # already dealt with by the notification arriving # asynchronously, redirect the user properly. if invoice.paidat: # Yup, it's paid, so send the user off to the page # that they came from. return HttpResponseRedirect(returnurl) # Show the user a pending message. The refresh time is dependent # on how many times we've seen this one before. status, created = ReturnAuthorizationStatus.objects.get_or_create( pspReference=request.GET['pspReference']) status.seencount += 1 status.save() return render(request, 'adyen/authorized.html', { 'refresh': 3**status.seencount, 'url': returnurl, }) else: return render(request, 'adyen/invalidresult.html', { 'result': request.GET['authResult'], })
def payment_post(request): nonce = request.POST['payment_method_nonce'] invoice = get_object_or_404(Invoice, pk=get_int_or_error(request.POST, 'invoice'), deleted=False, finalized=True) method = get_object_or_404(InvoicePaymentMethod, pk=get_int_or_error(request.POST, 'method'), active=True) pm = method.get_implementation() if invoice.processor: manager = InvoiceManager() processor = manager.get_invoice_processor(invoice) returnurl = processor.get_return_url(invoice) else: if invoice.recipient_user: returnurl = "%s/invoices/%s/" % (settings.SITEBASE, invoice.pk) else: returnurl = "%s/invoices/%s/%s/" % (settings.SITEBASE, invoice.pk, invoice.recipient_secret) # Generate the transaction result = pm.braintree_sale({ 'amount': '{0}'.format(invoice.total_amount), 'order_id': '#{0}'.format(invoice.pk), 'payment_method_nonce': nonce, 'merchant_account_id': pm.config('merchantacctid'), 'options': { 'submit_for_settlement': True, } }) trans = result.transaction if result.is_success: # Successful transaction. Store it for later processing. At authorization, we proceed to # flag the payment as done. BraintreeLog(transid=trans.id, message='Received successful result for {0}'.format(trans.id), paymentmethod=method).save() if trans.currency_iso_code != settings.CURRENCY_ISO: BraintreeLog(transid=trans.id, error=True, message='Invalid currency {0}, should be {1}'.format(trans.currency_iso_code, settings.CURRENCY_ISO), paymentmethod=method).save() send_simple_mail(settings.INVOICE_SENDER_EMAIL, pm.config('notification_receiver'), 'Invalid currency received in Braintree payment', 'Transaction {0} paid in {1}, should be {2}.'.format(trans.id, trans.currency_iso_code, settings.CURRENCY_ISO)) # We'll just throw the "processing error" page, and have # the operator deal with the complaints as this is a # should-never-happen scenario. return render(request, 'braintreepayment/processing_error.html') with transaction.atomic(): # Flag the invoice as paid manager = InvoiceManager() try: def invoice_logger(msg): raise BraintreeProcessingException('Invoice processing failed: %s'.format(msg)) manager.process_incoming_payment_for_invoice(invoice, trans.amount, 'Braintree id {0}'.format(trans.id), 0, pm.config('accounting_authorized'), 0, [], invoice_logger, method, ) except BraintreeProcessingException as ex: send_simple_mail(settings.INVOICE_SENDER_EMAIL, pm.config('notification_receiver'), 'Exception occurred processing Braintree result', "An exception occured processing the payment result for {0}:\n\n{1}\n".format(trans.id, ex)) return render(request, 'braintreepayment/processing_error.html') # Create a braintree transaction - so we can update it later when the transaction settles bt = BraintreeTransaction(transid=trans.id, authorizedat=timezone.now(), amount=trans.amount, method=trans.credit_card['card_type'], paymentmethod=method) if invoice.accounting_object: bt.accounting_object = invoice.accounting_object bt.save() send_simple_mail(settings.INVOICE_SENDER_EMAIL, pm.config('notification_receiver'), 'Braintree payment authorized', "A payment of %s%s with reference %s was authorized on the Braintree platform for %s.\nInvoice: %s\nRecipient name: %s\nRecipient user: %s\nBraintree reference: %s\n" % ( settings.CURRENCY_ABBREV, trans.amount, trans.id, method.internaldescription, invoice.title, invoice.recipient_name, invoice.recipient_email, trans.id)) return HttpResponseRedirect(returnurl) else: if not trans: reason = "Internal error" elif trans.status == 'processor_declined': reason = "Processor declined: {0}/{1}".format(trans.processor_response_code, trans.processor_response_text) elif trans.status == 'gateway_rejected': reason = "Gateway rejected: {0}".format(trans.gateway_rejection_reason) else: reason = "unknown" BraintreeLog(transid=trans and trans.id or "UNKNOWN", message='Received FAILED result for {0}'.format(trans and trans.id or "UNKNOWN"), error=True, paymentmethod=method).save() return render(request, 'braintreepayment/payment_failed.html', { 'invoice': invoice, 'reason': reason, 'url': returnurl, })