diff options
Diffstat (limited to 'postgresqleu/transferwise/api.py')
-rw-r--r-- | postgresqleu/transferwise/api.py | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/postgresqleu/transferwise/api.py b/postgresqleu/transferwise/api.py new file mode 100644 index 00000000..1f26486e --- /dev/null +++ b/postgresqleu/transferwise/api.py @@ -0,0 +1,150 @@ +from django.conf import settings + +import requests +from datetime import datetime, timedelta +from decimal import Decimal +import uuid + +from .models import TransferwiseRefund + + +class TransferwiseApi(object): + def __init__(self, pm): + self.pm = pm + self.session = requests.session() + self.session.headers.update({ + 'Authorization': 'Bearer {}'.format(self.pm.config('apikey')), + }) + + self.profile = self.account = None + + def format_date(self, dt): + return dt.strftime('%Y-%m-%dT00:00:00.000Z') + + def parse_datetime(self, s): + return datetime.strptime(s, '%Y-%m-%dT%H:%M:%S.%fZ') + + def get(self, suburl, params=None): + r = self.session.get( + 'https://api.transferwise.com/v1/{}'.format(suburl), + params=params, + ) + if r.status_code != 200: + r.raise_for_status() + return r.json() + + def post(self, suburl, params): + r = self.session.post( + 'https://api.transferwise.com/v1/{}'.format(suburl), + json=params, + ) + r.raise_for_status() + return r.json() + + def get_profile(self): + if not self.profile: + try: + self.profile = next((p['id'] for p in self.get('profiles') if p['type'] == 'business')) + except Exception as e: + raise Exception("Failed to get profile: {}".format(e)) + pass + return self.profile + + def get_account(self): + if not self.account: + try: + self.account = next((a for a in self.get('borderless-accounts', {'profileId': self.get_profile()}) if a['balances'][0]['currency'] == settings.CURRENCY_ABBREV)) + except Exception as e: + raise Exception("Failed to get account: {}".format(e)) + return self.account + + def get_balance(self): + for b in self.get_account()['balances']: + if b['currency'] == settings.CURRENCY_ABBREV: + return b['amount']['value'] + return None + + def get_transactions(self, startdate=None, enddate=None): + if not enddate: + enddate = (datetime.today() + timedelta(days=1)).date() + + if not startdate: + startdate = enddate - timedelta(days=60) + + return self.get( + 'borderless-accounts/{0}/statement.json'.format(self.get_account()['id']), + { + 'currency': settings.CURRENCY_ABBREV, + 'intervalStart': self.format_date(startdate), + 'intervalEnd': self.format_date(enddate), + }, + )['transactions'] + + def validate_iban(self, iban): + return self.get('validators/iban?iban={}'.format(iban))['validation'] == 'success' + + def get_structured_amount(self, amount): + if amount['currency'] != settings.CURRENCY_ABBREV: + raise Exception("Invalid currency {} found, exepcted {}".format(amount['currency'], settings.CURRENCY_ABBREV)) + return Decimal(amount['value']).quantize(Decimal('0.01')) + + def refund_transaction(self, origtrans, refundid, refundamount, refundstr): + if not origtrans.counterpart_valid_iban: + raise Exception("Cannot refund transaction without valid counterpart IBAN!") + + # This is a many-step process, unfortunately complicated. + twr = TransferwiseRefund(origtransaction=origtrans, uuid=uuid.uuid4(), refundid=refundid) + + # Create a recipient account + acc = self.post( + 'accounts', + { + 'profile': self.get_profile(), + 'currency': settings.CURRENCY_ABBREV, + 'accountHolderName': origtrans.counterpart_name, + 'type': 'iban', + 'details': { + 'IBAN': origtrans.counterpart_account, + }, + } + ) + twr.accid = acc['id'] + + # Create a quote (even though we're not doing currency exchange) + quote = self.post( + 'quotes', + { + 'profile': self.get_profile(), + 'source': settings.CURRENCY_ABBREV, + 'target': settings.CURRENCY_ABBREV, + 'rateType': 'FIXED', + 'targetAmount': refundamount, + 'type': 'BALANCE_PAYOUT', + }, + ) + twr.quoteid = quote['id'] + + # Create the actual transfer + transfer = self.post( + 'transfers', + { + 'targetAccount': twr.accid, + 'quote': twr.quoteid, + 'customerTransactionId': str(twr.uuid), + 'details': { + 'reference': refundstr, + }, + }, + ) + twr.transferid = transfer['id'] + twr.save() + + # Fund the transfer from our account + fund = self.post( + 'transfers/{0}/payments'.format(twr.transferid), + { + 'type': 'BALANCE', + }, + ) + + return twr.id |