Exemplo n.º 1
0
    def process_completed_payment(self, trans):
        manager = InvoiceManager()
        invoice = self.get_invoice_for_transaction(trans)

        def invoice_logger(msg):
            raise TrustlyException("Trustly invoice processing failed: {0}".format(msg))

        method = trans.paymentmethod
        pm = method.get_implementation()

        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?
                                                     pm.config('accounting_income'),
                                                     pm.config('accounting_fee'),
                                                     [],
                                                     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), paymentmethod=method).save()

        send_simple_mail(settings.INVOICE_SENDER_EMAIL,
                         pm.config('notification_receiver'),
                         "Trustly payment completed",
                         "A Trustly payment for {0} of {1}{2} for invoice {3} was completed on the Trustly platform.\n\nInvoice: {4}\nRecipient name: {5}\nRecipient email: {6}\n".format(
                             method.internaldescription,
                             settings.CURRENCY_ABBREV,
                             trans.amount,
                             invoice.id,
                             invoice.title,
                             invoice.recipient_name,
                             invoice.recipient_email),
                         )
Exemplo n.º 2
0
def process_stripe_checkout(co):
    if co.completedat:
        # Already completed, so don't do anything with it
        return

    with transaction.atomic():
        method = co.paymentmethod
        pm = method.get_implementation()
        api = StripeApi(pm)

        # Update the status from the API
        if api.update_checkout_status(co):
            # Went from unpaid to paid, so Do The Magic (TM)
            manager = InvoiceManager()
            invoice = Invoice.objects.get(pk=co.invoiceid)

            def invoice_logger(msg):
                raise StripeException(
                    "Stripe invoice processing failed: {0}".format(msg))

            manager.process_incoming_payment_for_invoice(
                invoice, co.amount, 'Stripe checkout id {0}'.format(co.id),
                co.fee, pm.config('accounting_income'),
                pm.config('accounting_fee'), [], invoice_logger, method)

            StripeLog(
                message=
                "Completed payment for Stripe id {0} ({1}{2}, invoice {3})".
                format(co.id, settings.CURRENCY_ABBREV, co.amount, invoice.id),
                paymentmethod=method).save()

            send_simple_mail(
                settings.INVOICE_SENDER_EMAIL,
                pm.config('notification_receiver'), "Stripe payment completed",
                "A Stripe payment for {0} of {1}{2} for invoice {3} was completed.\n\nInvoice: {4}\nRecipient name: {5}\nRecipient email: {6}\n"
                .format(
                    method.internaldescription,
                    settings.CURRENCY_ABBREV,
                    co.amount,
                    invoice.id,
                    invoice.title,
                    invoice.recipient_name,
                    invoice.recipient_email,
                ))
Exemplo n.º 3
0
def _flag_invoices(request, trans, invoices, pm, fee_account):
    manager = InvoiceManager()
    invoicelog = []

    transaction.set_autocommit(False)

    def invoicelogger(msg):
        invoicelog.append(msg)

    if len(invoices) == 1:
        fee = invoices[0].total_amount - trans.amount  # Calculated fee
    else:
        # There can be no fees when using multiple invoices, so ensure that
        if sum([i.total_amount for i in invoices]) != trans.amount:
            raise Exception("Fees not supported for multi-invoice flagging")
        fee = 0

    for invoice in invoices:
        (status, _invoice,
         _processor) = manager.process_incoming_payment_for_invoice(
             invoice, invoice.total_amount,
             "Bank transfer from {0} with id {1}, manually matched".format(
                 trans.method.internaldescription,
                 trans.methodidentifier), fee, pm.config('bankaccount'),
             fee_account and fee_account.num, [], invoicelogger, trans.method)

        if status != manager.RESULT_OK:
            messages.error(request, "Failed to run invoice processor:")
            for m in invoicelog:
                messages.warning(request, m)

            # Roll back any changes so far
            transaction.rollback()

            return False

        BankTransferFees(invoice=invoice, fee=fee).save()

        InvoiceLog(
            message=
            "Manually matched invoice {0} for {1} {2}, bank transaction {3} {2}, fees {4}"
            .format(
                invoice.id,
                invoice.total_amount,
                settings.CURRENCY_ABBREV,
                trans.amount,
                fee,
            )).save()

    # Remove the pending transaction
    trans.delete()

    transaction.commit()

    return True
Exemplo n.º 4
0
def process_authorization(notification):
    method = notification.rawnotification.paymentmethod
    pm = method.get_implementation()

    if notification.success:
        # This is a successful notification, so flag this invoice
        # as paid. We also create a TransactionStatus for it, so that
        # can validate that it goes from authorized->captured.
        trans = TransactionStatus(pspReference=notification.pspReference,
                                  notification=notification,
                                  authorizedat=datetime.now(),
                                  amount=notification.amount,
                                  method=notification.paymentMethod,
                                  notes=notification.merchantReference,
                                  capturedat=None,
                                  paymentmethod=method)
        trans.save()

        # Generate urls pointing back to this entry in the Adyen online
        # system, for inclusion in accounting records.
        urls = [
            "https://ca-live.adyen.com/ca/ca/accounts/showTx.shtml?pspReference=%s&txType=Payment&accountKey=MerchantAccount.%s"
            % (notification.pspReference, notification.merchantAccountCode),
        ]

        # We can receive authorizations on non-primary Adyen merchant
        # accounts. This happens for example with payments from POS
        # terminals. In those cases, just send an email, and don't
        # try to match it to any invoices.
        # We still store and track the transaction.
        if notification.merchantAccountCode != pm.config('merchantaccount'):
            send_simple_mail(
                settings.INVOICE_SENDER_EMAIL,
                pm.config('notification_receiver'),
                'Manual Adyen payment authorized',
                "An Adyen payment of %s%s was authorized on the Adyen platform for %s.\nThis payment was not from the automated system, it was manually authorized, probably from a POS terminal.\nReference: %s\nAdyen reference: %s\nMerchant account: %s\n"
                %
                (settings.CURRENCY_ABBREV, notification.amount,
                 method.internaldescription, notification.merchantReference,
                 notification.pspReference, notification.merchantAccountCode))
            notification.confirmed = True
            notification.save()

            # For manual payments, we can only create an open-ended entry
            # in the accounting

            accstr = "Manual Adyen payment: %s (%s)" % (
                notification.merchantReference, notification.pspReference)
            accrows = [
                (pm.config('accounting_authorized'), accstr, trans.amount,
                 None),
            ]

            create_accounting_entry(date.today(), accrows, True, urls)
            return

        # Process a payment on the primary account
        manager = InvoiceManager()
        try:
            # Figure out the invoiceid
            if not notification.merchantReference.startswith(
                    pm.config('merchantref_prefix')):
                raise AdyenProcessingException(
                    'Merchant reference does not start with %s' %
                    pm.config('merchantref_prefix'))
            invoiceid = int(
                notification.
                merchantReference[len(pm.config('merchantref_prefix')):])

            # Get the actual invoice
            try:
                invoice = Invoice.objects.get(pk=invoiceid)
            except Invoice.DoesNotExist:
                raise AdyenProcessingException(
                    'Invoice with id %s does not exist' % invoiceid)

            def invoice_logger(msg):
                invoice_logger.invoice_log += msg
                invoice_logger.invoice_log += "\n"

            invoice_logger.invoice_log = ""

            # Handle our special case where an IBAN notification comes in on the creditcard
            # processor (the primary one), but needs to be flagged as the other one.
            # If it can't be found, we just flag it on the other method, since the only
            # thing lost is some statistics.
            if trans.method == 'bankTransfer_IBAN':
                # Find our related method, if it exists
                mlist = list(
                    InvoicePaymentMethod.objects.filter(
                        classname=
                        'postgresqleu.util.payment.adyen.AdyenBanktransfer').
                    extra(
                        where=["config->>'merchantaccount' = %s"],
                        params=[pm.config('merchantaccount')],
                    ))
                if len(mlist) == 1:
                    usedmethod = mlist[0]
                else:
                    usedmethod = method
            else:
                usedmethod = method

            (status, _invoice,
             _processor) = manager.process_incoming_payment_for_invoice(
                 invoice, notification.amount,
                 'Adyen id %s' % notification.pspReference, 0,
                 pm.config('accounting_authorized'), 0, urls, invoice_logger,
                 usedmethod)

            if status != manager.RESULT_OK:
                # An error occurred, but nevertheless the money is in our account at this
                # point. The invoice itself will not have been flagged as paid since something
                # went wrong, and this also means no full accounting record has been created.
                # At this point we have no transaction cost, so we just have the payment itself.
                # Someone will manually have to figure out where to stick it.
                accrows = [
                    (pm.config('accounting_authorized'),
                     "Incorrect payment for invoice #{0}".format(invoice.id),
                     notification.amount, None),
                ]
                create_accounting_entry(date.today(), accrows, True, urls)

                send_simple_mail(
                    settings.INVOICE_SENDER_EMAIL,
                    pm.config('notification_receiver'),
                    'Error processing invoice from Adyen notification',
                    "An error occured processing the notification for invoice #{0} using {1}.\n\nThe messages given were:\n{2}\n\nAn incomplete accounting record has been created, and the situation needs to be handled manually.\n"
                    .format(invoice.id, method.internaldescription,
                            invoice_logger.invoice_log),
                )
                # Actually flag the notification as handled, so we don't end up repeating it.
                notification.confirmed = True
                notification.save()
                return

            if invoice.accounting_object:
                # Store the accounting object so we can properly tag the
                # fee for it when we process the settlement (since we don't
                # actually know the fee yet)
                trans.accounting_object = invoice.accounting_object
                trans.save()

            # If nothing went wrong, then this invoice is now fully
            # flagged as paid in the system.
            send_simple_mail(
                settings.INVOICE_SENDER_EMAIL,
                pm.config('notification_receiver'), 'Adyen payment authorized',
                "An Adyen payment of %s%s with reference %s was authorized on the Adyen platform for %s.\nInvoice: %s\nRecipient name: %s\nRecipient user: %s\nPayment method: %s\nAdyen reference: %s\n"
                % (settings.CURRENCY_ABBREV, notification.amount,
                   notification.merchantReference, method.internaldescription,
                   invoice.title, invoice.recipient_name,
                   invoice.recipient_email, notification.paymentMethod,
                   notification.pspReference))

        except AdyenProcessingException as ex:
            # Generate an email telling us about this exception!
            send_simple_mail(
                settings.INVOICE_SENDER_EMAIL,
                pm.config('notification_receiver'),
                'Exception occured processing Adyen notification',
                "An exception occurred processing the notification for %s on %s:\n\n%s\n"
                % (notification.merchantReference, method.internaldescription,
                   ex))
            # We have stored the notification already, but we want
            # to make sure it's not *confirmed*. That way it'll keep
            # bugging the user. So, return here instead of confirming
            # it.
            return
    else:
        send_simple_mail(
            settings.INVOICE_SENDER_EMAIL, pm.config('notification_receiver'),
            'Unsuccessful Adyen authorization received',
            "A credit card authorization for %s on account %s has failed.\nThe reason given was:\n%s\n\nYou don't need to take any further action, nothing has been confirmed in the systems."
            % (
                notification.merchantReference,
                notification.merchantAccountCode,
                notification.reason,
            ))
    notification.confirmed = True
    notification.save()
Exemplo n.º 5
0
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,
        })
Exemplo n.º 6
0
def process_authorization(notification):
	if notification.success:
		# This is a successful notification, so flag this invoice
		# as paid. We also create a TransactionStatus for it, so that
		# can validate that it goes from authorized->captured.
		trans = TransactionStatus(pspReference=notification.pspReference,
								  notification=notification,
								  authorizedat=datetime.now(),
								  amount=notification.amount,
								  method=notification.paymentMethod,
								  notes=notification.merchantReference,
								  capturedat=None)
		trans.save()

		# Generate urls pointing back to this entry in the Adyen online
		# system, for inclusion in accounting records.
		urls = ["https://ca-live.adyen.com/ca/ca/accounts/showTx.shtml?pspReference=%s&txType=Payment&accountKey=MerchantAccount.%s" % (notification.pspReference, notification.merchantAccountCode),]

		# We can receive authorizations on non-primary Adyen merchant
		# accounts. This happens for example with payments from POS
		# terminals. In those cases, just send an email, and don't
		# try to match it to any invoices.
		# We still store and track the transaction.
		if notification.merchantAccountCode != settings.ADYEN_MERCHANTACCOUNT:
			send_simple_mail(settings.INVOICE_SENDER_EMAIL,
							 settings.ADYEN_NOTIFICATION_RECEIVER,
							 'Manual Adyen payment authorized',
							 "An Adyen payment of %s%s was authorized on the Adyen platform.\nThis payment was not from the automated system, it was manually authorized, probably from a POS terminal.\nReference: %s\nAdyen reference: %s\nMerchant account: %s\n" % (settings.CURRENCY_ABBREV, notification.amount, notification.merchantReference, notification.pspReference, notification.merchantAccountCode))
			notification.confirmed = True
			notification.save()

			# For manual payments, we can only create an open-ended entry
			# in the accounting
			accstr = "Manual Adyen payment: %s (%s)" % (notification.merchantReference, notification.pspReference)
			accrows = [
				(settings.ACCOUNTING_ADYEN_AUTHORIZED_ACCOUNT, accstr, trans.amount, None),
				]
			create_accounting_entry(date.today(), accrows, True, urls)
			return

		# Process a payment on the primary account
		manager = InvoiceManager()
		try:
			# Figure out the invoiceid
			if not notification.merchantReference.startswith(settings.ADYEN_MERCHANTREF_PREFIX):
				raise AdyenProcessingException('Merchant reference does not start with %s' % settings.ADYEN_MERCHANTREF_PREFIX)
			invoiceid = int(notification.merchantReference[len(settings.ADYEN_MERCHANTREF_PREFIX):])

			# Get the actual invoice
			try:
				invoice = Invoice.objects.get(pk=invoiceid)
			except Invoice.DoesNotExist:
				raise AdyenProcessingException('Invoice with id %s does not exist' % invoiceid)

			def invoice_logger(msg):
				raise AdyenProcessingException('Invoice processing failed: %s', msg)

			manager.process_incoming_payment_for_invoice(invoice, notification.amount, 'Adyen id %s' % notification.pspReference, 0, settings.ACCOUNTING_ADYEN_AUTHORIZED_ACCOUNT, 0, urls, invoice_logger)

			if invoice.accounting_object:
				# Store the accounting object so we can properly tag the
				# fee for it when we process the settlement (since we don't
				# actually know the fee yet)
				trans.accounting_object = invoice.accounting_object
				trans.save()

			# If nothing went wrong, then this invoice is now fully
			# flagged as paid in the system.
			send_simple_mail(settings.INVOICE_SENDER_EMAIL,
							 settings.ADYEN_NOTIFICATION_RECEIVER,
							 'Adyen payment authorized',
							 "An Adyen payment of %s%s with reference %s was authorized on the Adyen platform.\nInvoice: %s\nRecipient name: %s\nRecipient user: %s\nAdyen reference: %s\n" % (settings.CURRENCY_ABBREV, notification.amount, notification.merchantReference, invoice.title, invoice.recipient_name, invoice.recipient_email, notification.pspReference))

		except AdyenProcessingException, ex:
			# Generate an email telling us about this exception!
			send_simple_mail(settings.INVOICE_SENDER_EMAIL,
							 settings.ADYEN_NOTIFICATION_RECEIVER,
							 'Exception occured processing Adyen notification',
							 "An exception occured processing the notification for %s:\n\n%s\n" % (
								 notification.merchantReference,
								 ex)
						 )
			# We have stored the notification already, but we want
			# to make sure it's not *confirmed*. That way it'll keep
			# bugging the user. So, return here instead of confirming
			# it.
			return