def post(self, request, *args, **kwargs): ser = self.serializer_class(request.user, data=request.data) if ser.is_valid(): user = ser.save() request_body = { 'firstName': user.first_name, 'lastName': user.last_name, 'email': user.email, 'phone': user.phone, } dw = DwollaApi() try: id = dw.create_customer(request_body) except Exception as e: return Response(e, status=400) Customer = apps.get_model('bank', 'Customer') customer = Customer.objects.create(user=user) customer.dwolla_id = id customer.save() user.signup() return Response(sers.UserSerializer(user).data, status=200) return Response(ser.errors, status=400)
def update_dwolla_transfer(self, id, is_test=False): """ If less than 15 minutes from last check, do nothing. """ tds = self.model.objects.get(id=id) if not tds.can_update: return if not is_test: now = timezone.now() if tds.updated_at + datetime.timedelta(minutes=15) > now: return dw = DwollaApi() d = dw.get_transfer(tds.dwolla_id) if d is None: logger.error('Can not retrieve transfer: {}'.format(tds.dwolla_id)) return status = d['status'] if status == self.model.PENDING: tds.updated_at = timezone.now() elif status == self.model.PROCESSED: tds.is_sent = True tds.updated_at = timezone.now() tds.sent_at = timezone.now() else: tds.updated_at = timezone.now() tds.is_failed = True tds.status = status tds.save()
def process_sandbox_transfers(): """ For sandbox transfers. They are not processed by default. """ dw = DwollaApi() dw.press_sandbox_button()
def post(self, request, **kwargs): customer_id = kwargs['dwolla_customer_id'] d = DwollaApi() token = d.get_iav_token(customer_id) if token is None: return Response({'message': 'Server error.'}, status=400) return Response({'token': token})
def update_micro_deposits(self, id): """ Updates status of micro-deposits verification. """ fs = self.model.objects.get(id=id) if fs.md_status is not None and fs.md_status != self.model.PROCESSED: dw = DwollaApi() d = dw.get_micro_deposits(fs.dwolla_id) fs.md_status = d['status'] fs.md_created_at = d['created'] fs.save()
def get_or_create_customer(): """ Get or create dwolla customer. """ dw = DwollaApi() customer = dw.get_customer_by_email(TEST_EMAIL) if customer is not None: return customer customer = CustomerFactory.get_customer(email=TEST_EMAIL) Customer.objects.create_dwolla_customer(customer.id) customer.refresh_from_db() return dw.get_customer(customer.dwolla_id)
def update_customers(self): """ Currently method updates only status. """ dw = DwollaApi() for d in dw.get_customers(): try: c = self.model.objects.get(dwolla_id=d['id']) except self.model.DoesNotExist: continue if c.status != d['status']: c.status = d['status'] c.save()
def initiate_dwolla_customer(self, id): """ Get data of created, but not initiated yet customer. """ c = self.model.objects.get(id=id) if c.dwolla_id is not None and c.created_at is None\ and not c.user.is_admin: dw = DwollaApi() d = dw.get_customer(c.dwolla_id) if d is not None: assert d['id'] == c.dwolla_id c.dwolla_type = d['type'] c.status = d['status'] c.created_at = d['created'] c.save()
def save(self): data = self.validated_data request_body = { 'firstName': data['first_name'], 'lastName': data['last_name'], 'email': data['email'], 'type': data['type'], 'address1': data['address1'], 'city': data['city'], 'state': data['state'], 'postalCode': data['postal_code'], 'dateOfBirth': str(data['date_of_birth']), 'ssn': data['ssn'], 'phone': data['phone'], } dw = DwollaApi() try: id = dw.create_customer(request_body) except Exception as e: raise Exception(e) if id is not None: user = User.objects.create_user(data['email'], data['password']) user.first_name = data['first_name'] user.last_name = data['last_name'] user.address1 = data['address1'] user.postal_code = data['postal_code'] user.city = data['city'] user.state = data['state'] user.date_of_birth = data['date_of_birth'] user.phone = data['phone'] user.save() Customer = apps.get_model('bank', 'Customer') customer = Customer.objects.create(user=user) customer.dwolla_id = id customer.save() # Post save operations, send email e.t.c user.signup() return None
def init_dwolla_funding_source(self, id): """ Currently not used. Init funding source in Dwolla from manually created account. """ fs = self.model.objects.get(id=id) if fs.dwolla_id is not None and fs.created_at is None: dw = DwollaApi() d = dw.get_funding_source(fs.dwolla_id) fs.dwolla_id = d['id'] fs.created_at = d['created'] fs.status = d['status'] fs.is_removed = d['removed'] fs.typeb = d['type'] fs.save()
def transfer_money(amount, funding_source): TransferCalculation = apps.get_model('finance', 'TransferCalculation') FundingSource = apps.get_model('finance', 'FundingSource') dw = DwollaApi() destination = settings.DWOLLA_TEMP_BUSINESS_ACCOUNT request_body = { '_links': { 'source': { 'href': funding_source }, 'destination': { 'href': destination } }, 'amount': { 'currency': 'USD', 'value': amount } } try: transfer = dw.token.post('transfers', request_body) print(transfer.headers['location']) trans_calc = TransferCalculation.objects.get( user=FundingSource.objects.get( funding_sources_url=funding_source).user) trans_calc.applied_funds = Decimal(amount) trans_calc.save() except Exception as error: logger.info(error)
def create_funding_source_iav(self, account_id, dwolla_id, test_dic=None): """ User creates funding source via dwolla.js script in iframe using username and password on frontend. At first the funding source is created in Dwolla, then calling this function from API funding source created in database. test_dic - used for tests not calling Dwolla API. If Dwolla API fail, we can run this method later. FundingSourceIAVLog will contain failed data. If this is first FundingSource, set it as active funding source for user. """ Account = apps.get_model('finance', 'Account') FundingSourceIAVLog = apps.get_model('bank', 'FundingSourceIAVLog') fs_log = FundingSourceIAVLog.objects.create(account_id, dwolla_id) account = Account.objects.get(id=account_id) if test_dic: d = test_dic else: dw = DwollaApi() d = dw.get_funding_source(dwolla_id) fs = self.model(account=account) fs.dwolla_id = d['id'] fs.created_at = d['created'] fs.status = d['status'] fs.is_removed = d['removed'] fs.typeb = d['type'] fs.name = d['name'] fs.verification_type = self.model.IAV fs.save() fs_log.is_processed = True fs_log.save() count = self.model.objects.filter( account__item__user=account.item.user).count() if count == 1: Account.objects.set_funding_source(account.id) return fs
def create_dwolla_customer(self, id): """ Celery task POST call to dwolla to create customer. """ customer = self.model.objects.get(id=id) if customer.dwolla_id is not None\ or not customer.user.is_profile_completed\ or customer.user.is_admin: return dic = self.get_customer_data_for_create_request(customer) dw = DwollaApi() id = dw.create_customer(dic) if id is not None: customer.dwolla_id = id customer.save()
def initiate_dwolla_transfer(self, id): tds = self.model.objects.get(id=id) if not tds.can_initiate: return fs = tds.account.funding_source dw = DwollaApi() id = dw.initiate_transfer(fs.dwolla_id, str(tds.amount)) if id is None: logger.error('Can not initiate transfer: {}'.format(tds.dwolla_id)) return tds.dwolla_id = id tds.is_initiated = True tds.initiated_at = timezone.now() tds.updated_at = timezone.now() tds.save()
def update_dwolla_failure_code(self, id): tds = self.model.objects.get(id=id) if not tds.is_failed or tds.failure_code is not None: return dw = DwollaApi() code = dw.get_transfer_failure_code(tds.dwolla_id) if code is None: logger.error('Can not get failure code for: {}'.format( tds.dwolla_id)) return tds.failure_code = code tds.updated_at = timezone.now() tds.save() if code != 'R01': self.move_failed(tds.id)
def create_dwolla_funding_source(self, id): """ Currently not used. Create funding source in Dwolla from manually created account. """ fs = self.model.objects.get(id=id) if fs.dwolla_id is not None: return data = { 'routingNumber': fs.routing_number, 'accountNumber': fs.account_number, 'type': fs.type, 'name': fs.name } dw = DwollaApi() id = dw.create_funding_source(fs.customer.dwolla_id, data) if id is not None: fs.dwolla_id = id fs.save()
def take_monthly_fee(): dwa = DwollaApi() root = dwa.token.get(url='/') dwolla_account = root.body['_links']['account']['href'] Customer = apps.get_model('bank', 'Customer') account_token = dwa.client.Token(access_token=dwa.token.access_token, refresh_token=dwa.token.access_token) for customer in Customer.objects.exclude(user__is_paused=True).exclude( user__is_closed_account=True).exclude(user__active_days=30): customer.user.active_days += 1 customer.user.save() for customer in Customer.objects.exclude(user__is_paused=True).exclude( user__is_closed_account=True).filter(user__active_days=30): result = dwa.get_funding_sources(customer.dwolla_id)[0] customer_source_url = result['_links']['self']['href'] customer_balance_id = result[0]['id'] customer_balance = dwa.get_funding_source_balance( customer_balance_id)['balance']['value'] if float(customer_balance) < 1.99: request_body = { '_links': { 'source': { 'href': customer_source_url }, 'destination': { 'href': dwolla_account } }, 'amount': { 'currency': 'USD', 'value': '1.99' } } transfer = account_token.post('transfers', request_body) customer.user.active_days = 0 customer.user.save() else: logger.info("Not enough money to fee") logger.info("Got fee from customer{}".format(customer.dwolla_id))
def post(self, request, *args, **kwargs): ser = self.serializer_class(request.user, data=request.data) if ser.is_valid(): user = ser.save() request_body = { 'firstName': user.first_name, 'lastName': user.last_name, 'email': user.email, 'type': user.type, 'address1': user.address1, 'city': user.city, 'state': user.state, 'postalCode': user.postal_code, 'dateOfBirth': str(user.date_of_birth), 'ssn': user.ssn, 'phone': user.phone, } dw = DwollaApi() try: id = dw.create_customer(request_body) except Exception as e: return Response(e, status=400) Customer = apps.get_model('bank', 'Customer') customer = Customer.objects.create(user=user) customer.dwolla_id = id customer.save() user.signup() return Response(ser.data, status=200) return Response(ser.errors, status=400)
class TestTransferDonkiesDwolla(base.Mixin): """ Tests that use Dwolla API. Run from US server. """ def setup(self): self.dw = DwollaApi() @pytest.mark.django_db def notest01(self, dwolla): """ Do not run each time, because too many customers will be created in Dwolla. Test create customer. """ customer = CustomerFactory.get_customer() Customer.objects.create_dwolla_customer(customer.id) customer.refresh_from_db() assert customer.dwolla_id is not None @pytest.mark.django_db def notest02(self): """ Do not run each time, because too many customers will be created in Dwolla. Test create and initiate customer. """ customer = CustomerFactory.get_customer() Customer.objects.create_dwolla_customer(customer.id) customer.refresh_from_db() assert customer.dwolla_id is not None Customer.objects.initiate_dwolla_customer(customer.id) customer.refresh_from_db() assert customer.dwolla_type is not None assert customer.created_at is not None assert customer.status is not None @pytest.mark.django_db def notest03(self): """ Do not run each time, because too many customers will be created in Dwolla. Test create customer, then create the same customer again. Instead of error, should get the same customer. """ customer = CustomerFactory.get_customer() data = Customer.objects.get_customer_data_for_create_request(customer) c1 = self.dw.create_customer(data) c2 = self.dw.create_customer(data) assert c1 == c2 @pytest.mark.django_db def test04(self, dwolla): """ Test initiate transfer. """ funding_source = dwolla['funding_source'] e = Emulator(num_debit_accounts=1) e.init() e.make_transfer_prepare_condition() Emulator.run_transfer_prepare() Emulator.run_transfer_donkies_prepare() # Exchange dwolla_id for mock debit account with # real funding source dwolla_id account = e.debit_accounts[0] fs = account.funding_source fs.dwolla_id = funding_source['id'] fs.save() tds = TransferDonkies.objects.first() tds.save() TransferDonkies.objects.initiate_dwolla_transfer(tds.id) tds.refresh_from_db() assert tds.is_initiated is True assert tds.initiated_at is not None assert tds.updated_at is not None assert tds.dwolla_id is not None @pytest.mark.django_db def test05(self, dwolla): """ Test initiate and update transfer with success status. """ funding_source = dwolla['funding_source'] e = Emulator(num_debit_accounts=1) e.init() e.make_transfer_prepare_condition() Emulator.run_transfer_prepare() Emulator.run_transfer_donkies_prepare() # Exchange dwolla_id for mock debit account with # real funding source dwolla_id from API account = e.debit_accounts[0] fs = account.funding_source fs.dwolla_id = funding_source['id'] fs.save() tds = TransferDonkies.objects.first() tds.save() TransferDonkies.objects.initiate_dwolla_transfer(tds.id) for _ in range(20): TransferDonkies.objects.update_dwolla_transfer( tds.id, is_test=True) tds.refresh_from_db() print('Transfer status: ', tds.status) # Process sandbox transfers self.dw.press_sandbox_button() if tds.status and tds.status != TransferDonkies.PENDING: break time.sleep(5) assert tds.status == TransferDonkies.PROCESSED assert tds.is_sent is True assert tds.sent_at is not None assert tds.updated_at is not None @pytest.mark.django_db def test06(self, dwolla): """ Should be last test as it changes fixture's funding_source to R01. Test initiate and update transfer with insufficient funds. 1) Should get failed status. 2) Update failure_code. 3) Failure code should be "R01" """ customer = dwolla['customer'] funding_source = get_or_create_funding_source(customer, name='R01') e = Emulator(num_debit_accounts=1) e.init() e.make_transfer_prepare_condition() Emulator.run_transfer_prepare() Emulator.run_transfer_donkies_prepare() # Exchange dwolla_id for mock debit account with # real funding source dwolla_id from API account = e.debit_accounts[0] fs = account.funding_source fs.dwolla_id = funding_source['id'] fs.save() tds = TransferDonkies.objects.first() tds.save() TransferDonkies.objects.initiate_dwolla_transfer(tds.id) for _ in range(20): TransferDonkies.objects.update_dwolla_transfer( tds.id, is_test=True) tds.refresh_from_db() print('Transfer status: ', tds.status) # Process sandbox transfers self.dw.press_sandbox_button() if tds.status and tds.status != TransferDonkies.PENDING: break time.sleep(5) assert tds.status == TransferDonkies.FAILED assert tds.is_failed is True assert tds.failure_code is None TransferDonkies.objects.update_dwolla_failure_code(tds.id) tds.refresh_from_db() assert tds.failure_code == 'R01'
def get_or_create_funding_source(customer, name='My Bank'): """ Returns funding source (bank) or creates verified funding source (bank) in Dwolla for test customer. name is used to simulate different test cases. name = "R01" Insufficient Funds: failing from the source bank account. name = "R01-late" Simulate funds failing from the source bank account post-settlement. Must click "Process bank transfers" twice. """ dw = DwollaApi() for fs in dw.get_funding_sources(customer['id']): if fs['status'] == 'verified' and fs['type'] == 'bank': # Set funding source's name. dw.edit_funding_source_name(fs['id'], name) return fs data = { 'routingNumber': '222222226', 'accountNumber': '123456789', 'type': 'savings', 'name': name } print('Creating funding source --------') id = dw.create_funding_source(customer['id'], data) fs = dw.get_funding_source(id) print(fs) print('Initiating micro-deposits -------') res = dw.initiate_micro_deposits(fs['id']) print(res) print('Get status of micro-deposits -------') res = dw.get_micro_deposits(fs['id']) print('Verifying funding source -------') res = dw.verify_micro_deposits( fs['id'], '0.05', '0.05') print(res) print('Checking the status of funding source -------') fs = dw.get_funding_source(id) print(fs['status']) return fs
def init_micro_deposits(self, id): fs = self.model.objects.get(id=id) if fs.md_status is None: dw = DwollaApi() dw.init_micro_deposits(fs.dwolla_id)
def setup(self): self.dw = DwollaApi()