Esempio n. 1
0
    def validate_data_for(self, instance):
        pm = instance.get_implementation()
        trustly = Trustly(pm)

        # Test the Trustly setup by getting the balance
        trustly.get_balance()

        return "Trustly API setup works"
    def fetch_one_account(self, method):
        pm = method.get_implementation()

        trustly = Trustly(pm)

        transactions = trustly.getledgerforrange(
            datetime.today() - timedelta(days=7), datetime.today())

        for t in transactions:
            if t['accountname'] == 'BANK_WITHDRAWAL_QUEUED' and not t[
                    'orderid']:
                # If it has an orderid, it's a refund, but if not, then it's a transfer out (probably)
                w, created = TrustlyWithdrawal.objects.get_or_create(
                    paymentmethod=method,
                    gluepayid=t['gluepayid'],
                    defaults={
                        'amount': -Decimal(t['amount']),
                        'message': t['messageid'],
                    },
                )
                w.save()

                if created:
                    TrustlyLog(
                        message='New bank withdrawal of {0} found'.format(
                            -Decimal(t['amount'])),
                        paymentmethod=method).save()

                    accstr = 'Transfer from Trustly to bank'
                    accrows = [
                        (pm.config('accounting_income'), accstr, -w.amount,
                         None),
                        (pm.config('accounting_transfer'), accstr, w.amount,
                         None),
                    ]
                    entry = create_accounting_entry(
                        dateutil.parser.parse(t['datestamp']).date(),
                        accrows,
                        True,
                        [],
                    )
                    if is_managed_bank_account(
                            pm.config('accounting_transfer')):
                        register_pending_bank_matcher(
                            pm.config('accounting_transfer'),
                            '.*TRUSTLY.*{0}.*'.format(w.gluepayid), w.amount,
                            entry)
Esempio n. 3
0
    def autorefund(self, refund):
        try:
            trans = TrustlyTransaction.objects.get(invoiceid=refund.invoice.id)
        except TrustlyTransaction.DoesNotExist:
            raise Exception("Transaction matching invoice not found")

        t = Trustly(self)
        try:
            t.refund(trans.orderid, refund.fullamount)
        except TrustlyException as e:
            TrustlyLog(message='Refund API failed: {0}'.format(e),
                       error=True,
                       paymentmethod=self.method).save()
            return False

        # Will raise exception if something goes wrong
        refund.payment_reference = trans.orderid

        return True
    def verify_one_account(self, method):
        method = method
        pm = method.get_implementation()

        trustly = Trustly(pm)

        trustly_balance = trustly.get_balance()

        accounting_balance = get_latest_account_balance(pm.config('accounting_income'))

        if accounting_balance != trustly_balance:
            send_simple_mail(settings.INVOICE_SENDER_EMAIL,
                             pm.config('notification_receiver'),
                             'Trustly balance mismatch!',
                             """Trustly balance ({0}) for {1} does not match the accounting system ({2})!

This could be because some entry has been missed in the accounting
(automatic or manual), or because of an ongoing booking of something
that the system doesn't know about.

Better go check manually!
""".format(trustly_balance, method.internaldescription, accounting_balance))
    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),
                       paymentmethod=notification.rawnotification.paymentmethod
                       ).save()

            t = Trustly(notification.rawnotification.paymentmethod.
                        get_implementation())
            result = t.process_notification(notification)
        if not result:
            raise CommandError("Reprocessing failed, see log!")

        self.stdout.write("Completed reprocessing notification {0}.".format(
            notification.id))
    def process_one_account(self, method):
        pm = method.get_implementation()

        trustly = Trustly(pm)
        manager = InvoiceManager()

        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,
                                                  paymentmethod=method))
            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 w['currency'] != settings.CURRENCY_ABBREV:
                # If somebody paid in a different currency (and Trustly converted it for us),
                # the withdrawal entry is specified in the original currency, which is more than
                # a little annoying. To deal with it, attempt to fetch the ledger for the day
                # and if we can find it there, use the amount from that one.
                day = dateutil.parser.parse(w['datestamp']).date()
                ledgerrows = trustly.getledgerforday(day)
                for lr in ledgerrows:
                    if int(lr['orderid']) == trustlytrans.orderid and lr[
                            'accountname'] == 'BANK_WITHDRAWAL_QUEUED':
                        # We found the corresponding accounting row. So we take the amount from
                        # this and convert the difference to what we expeced into the fee. This
                        # can end up being a negative fee, but it should be small enough that
                        # it's not a real problem.
                        fees = (
                            r.fullamount +
                            Decimal(lr['amount']).quantize(Decimal('0.01')))
                        TrustlyLog(
                            message=
                            "Refund for order {0}, invoice {1}, was made as {2} {3} instead of {4} {5}. Using ledger mapped to {6} {7} with difference of {8} {9} booked as fees"
                            .format(
                                trustlytrans.orderid,
                                r.invoice.pk,
                                Decimal(w['amount']),
                                w['currency'],
                                r.fullamount,
                                settings.CURRENCY_ABBREV,
                                Decimal(lr['amount']).quantize(
                                    Decimal('0.01')),
                                settings.CURRENCY_ABBREV,
                                fees,
                                settings.CURRENCY_ABBREV,
                            ),
                            error=False,
                            paymentmethod=method,
                        ).save()
                        break
                else:
                    # Unable to find the refund in the ledger. This could be a matter of timing,
                    # so yell about it but try agian.
                    raise CommandError(
                        "Trustly refund for invoice {0} was made in {1} instead of {2}, but could not be found in ledger."
                        .format(r.invoice.pk, w['currency'],
                                settings.CURRENCY_ABBREV))
            else:
                # Currency is correct, so check that the refunded amount is the same as
                # the one we expected.
                if Decimal(w['amount']) != r.fullamount:
                    raise CommandError(
                        "Mismatch in amount on Trustly refund for invoice {0} ({1} vs {2})"
                        .format(r.invoice.pk, Decimal(w['amount']),
                                r.fullamount))
                fees = 0

            # Ok, things look good!
            TrustlyLog(
                message="Refund for order {0}, invoice {1}, completed".format(
                    trustlytrans.orderid, r.invoice.pk),
                error=False,
                paymentmethod=method).save()
            manager.complete_refund(r.id, r.fullamount, fees,
                                    pm.config('accounting_income'),
                                    pm.config('accounting_fee'), [], method)