def redeem(order_number, user, allocations): """ Settle payment for the passed set of account allocations Will raise UnableToTakePayment if any of the transfers is invalid """ # First, we need to check if the allocations are still valid. The accounts # may have changed status since the allocations were written to the # session. transfers = [] destination = core.redemptions_account() for code, amount in allocations.items(): try: account = Account.active.get(code=code) except Account.DoesNotExist: raise UnableToTakePayment( _("No active account found with code %s") % code) # We verify each transaction try: Transfer.objects.verify_transfer( account, destination, amount, user) except exceptions.AccountException as e: raise UnableToTakePayment(str(e)) transfers.append((account, destination, amount)) # All transfers verified, now redeem for account, destination, amount in transfers: facade.transfer(account, destination, amount, user=user, merchant_reference=order_number, description="Redeemed to pay for order %s" % order_number)
def create_giftcard(order_number, user, amount): source = core.paid_source_account() code = codes.generate() destination = Account.objects.create( code=code ) facade.transfer(source, destination, amount, user, "Create new account")
def test_account_exception_raised_for_runtime_error(self): user = UserFactory() source = AccountFactory(credit_limit=None) destination = AccountFactory() with mock.patch('oscar_accounts.abstract_models.PostingManager._wrap') as mock_method: mock_method.side_effect = RuntimeError() with self.assertRaises(exceptions.AccountException): facade.transfer(source, destination, D('100'), user)
def test_no_transaction_created_when_exception_raised(self): user = UserFactory() source = AccountFactory(credit_limit=None) destination = AccountFactory() with mock.patch('oscar_accounts.abstract_models.PostingManager._wrap') as mock_method: mock_method.side_effect = RuntimeError() try: facade.transfer(source, destination, D('100'), user) except Exception: pass self.assertEqual(0, Transfer.objects.all().count()) self.assertEqual(0, Transaction.objects.all().count())
def form_valid(self, form): account = self.object amount = form.cleaned_data['amount'] try: facade.transfer(form.get_source_account(), account, amount, user=self.request.user, description=_("Top-up account")) except exceptions.AccountException as e: messages.error(self.request, _("Unable to top-up account: %s") % e) else: messages.success( self.request, _("%s added to account") % currency(amount)) return http.HttpResponseRedirect(reverse('accounts_dashboard:accounts-detail', kwargs={'pk': account.id}))
def form_valid(self, form): account = self.object amount = form.cleaned_data['amount'] try: facade.transfer(form.get_source_account(), account, amount, user=self.request.user, description=_("Top-up account")) except exceptions.AccountException as e: messages.error(self.request, _("Unable to top-up account: %s") % e) else: messages.success( self.request, _("%s added to account") % currency(amount)) return http.HttpResponseRedirect(reverse('accounts-detail', kwargs={'pk': account.id}))
def setUp(self): self.user = UserFactory() self.source = AccountFactory(credit_limit=None, primary_user=None) self.destination = AccountFactory() self.transfer = facade.transfer( self.source, self.destination, D('100'), user=self.user, description="Give money to customer")
def form_valid(self, form): # O formulario foi validado e o obj do type ferramenta foi criado self.object = form.save() ferramenta = self.object account = self._get_user_account(form) amount = ferramenta.value try: transfer = facade.transfer( self._get_source_account(), account, amount, user=form.cleaned_data.get("user"), description=_(f"Inserção da Ferramenta: {ferramenta.name}"), ) ferramenta.transfer = transfer ferramenta.save() except exceptions.AccountException as e: messages.error( self.request, _("Tive um problema para inserir a sua ferramenta, procure o mario: %s" ) % e, ) else: messages.success( self.request, _("%s adicionado ao seu saldo") % currency(amount)) return HttpResponseRedirect(self.get_success_url())
def valid_payload(self, payload): """ Redeem an amount from the selected giftcard """ account = get_object_or_404(Account, code=self.kwargs['code']) if not account.is_active(): raise ValidationError(errors.ACCOUNT_INACTIVE) amt = payload['amount'] if not account.is_debit_permitted(amt): raise ValidationError(errors.INSUFFICIENT_FUNDS) redemptions = Account.objects.get(code=names.REDEMPTIONS_CODE) try: transfer = facade.transfer(account, redemptions, amt, merchant_reference=payload.get( 'merchant_reference', None)) except exceptions.AccountException as e: return self.forbidden(code=errors.CANNOT_CREATE_TRANSFER, msg=e.message) return self.created( reverse('oscar_accounts_api:transfer', kwargs={'reference': transfer.reference}), transfer.as_dict())
def form_valid(form, request): # O formulario foi validado e o obj do type ferramenta foi criado object = form.save() ferramenta = object account = get_imported_user_account(form) amount = ferramenta.value try: transfer = facade.transfer( get_imported_source_account(), account, amount, user=form.cleaned_data.get("user"), description= _(f"Inserção da Ferramenta via arquivo de solicitações: {ferramenta.name}" ), ) ferramenta.transfer = transfer ferramenta.save() except exceptions.AccountException as e: messages.error( resquest, _("Tive um problema para processar o arquivo de solicitação, procure o mario: %s" ) % e, ) else: messages.success( request, _("%s adicionado ao seu saldo via arquivo de solicitações") % currency(amount)) return render(request, 'import.html')
def valid_payload(self, payload): to_refund = get_object_or_404(Transfer, reference=self.kwargs['reference']) amount = payload['amount'] max_refund = to_refund.max_refund() if amount > max_refund: return self.forbidden( ("Refund not permitted: maximum refund permitted " "is %.2f") % max_refund) if not to_refund.source.is_active(): raise ValidationError(errors.ACCOUNT_INACTIVE) try: transfer = facade.transfer(to_refund.destination, to_refund.source, payload['amount'], parent=to_refund, merchant_reference=payload.get( 'merchant_reference', None)) except exceptions.AccountException as e: return self.forbidden(code=errors.CANNOT_CREATE_TRANSFER, msg=e.message) return self.created( reverse('oscar_accounts_api:transfer', kwargs={'reference': transfer.reference}), transfer.as_dict())
def form_valid(self, form): account = self.object amount = form.cleaned_data['amount'] try: facade.transfer(account, form.get_source_account(), amount, user=self.request.user, description=_("Return funds to source account")) except exceptions.AccountException as e: messages.error(self.request, _("Unable to withdraw funds from account: %s") % e) else: messages.success(self.request, _("%s withdrawn from account") % currency(amount)) return http.HttpResponseRedirect( reverse('accounts-detail', kwargs={'pk': account.id}))
def form_valid(self, form): account = form.save() # Load transaction source = form.get_source_account() amount = form.cleaned_data['initial_amount'] try: facade.transfer(source, account, amount, user=self.request.user, description=_("Creation of account")) except exceptions.AccountException as e: messages.error( self.request, _("Account created but unable to load funds onto new " "account: %s") % e) else: messages.success( self.request, _("New account created with code '%s'") % account.code) return http.HttpResponseRedirect( reverse('accounts_dashboard:accounts-detail', kwargs={'pk': account.id}))
def form_valid(self, form): account = form.save() # Load transaction source = form.get_source_account() amount = form.cleaned_data['initial_amount'] try: facade.transfer(source, account, amount, user=self.request.user, description=_("Creation of account")) except exceptions.AccountException as e: messages.error( self.request, _("Account created but unable to load funds onto new " "account: %s") % e) else: messages.success( self.request, _("New account created with code '%s'") % account.code) return http.HttpResponseRedirect( reverse('accounts-detail', kwargs={'pk': account.id}))
def reconcile(self, user=None): # Perform a transfer to make the account balance match WF. This will overtime # mirror customer payments into Wells Fargo (that we don't have notifications of) balance_wf = -(self.balance) balance_us = self.account.balance balance_change = balance_wf - balance_us if balance_change != Decimal('0.00'): logger.info('Reconciling balance offset of %s on account %s' % (balance_change, self.account)) facade.transfer( description=_('Automatic compensating transaction during reconciliation with Wells Fargo Retail Services.'), source=Account.objects.get(name=names.BANK), destination=self.account, amount=balance_change, user=user) else: logger.info('Reconciliation not needed. Recorded balance matches WFRS records for account %s' % (self.account)) assert self.account.balance == balance_wf # Adjust the credit limit to match WF. Should be equal to the sum of `balance` and `open_to_buy` self.account.credit_limit = (self.balance + self.open_to_buy) self.account.save()
def valid_payload(self, payload): account = get_object_or_404(Account, code=self.kwargs['code']) if not account.is_active(): raise ValidationError(errors.ACCOUNT_INACTIVE) redemptions = Account.objects.get(name=names.REDEMPTIONS) try: transfer = facade.transfer( redemptions, account, payload['amount'], merchant_reference=payload.get('merchant_reference', None)) except exceptions.AccountException as e: return self.forbidden( code=errors.CANNOT_CREATE_TRANSFER, msg=e.message) return self.created( reverse('transfer', kwargs={'reference': transfer.reference}), transfer.as_dict())
def submit_transaction(trans_request): client = soap.get_client(WFRS_TRANSACTION_WSDL, 'WFRS') request = client.factory.create('ns2:Transaction') request.userName = WFRS_USER_NAME request.setupPassword = WFRS_PASSWORD request.merchantNumber = WFRS_MERCHANT_NUM request.uuid = uuid.uuid1() request.transactionCode = trans_request.type_code request.localeString = trans_request.source_account.wfrs_metadata.locale request.accountNumber = trans_request.source_account.wfrs_metadata.account_number request.planNumber = trans_request.plan_number request.amount = _as_decimal(trans_request.amount) request.authorizationNumber = trans_request.auth_number request.ticketNumber = trans_request.ticket_number # Submit resp = client.service.submitTransaction(request) # Check for faults if resp.faults: for fault in resp.faults: logger.error(fault.faultDetailString) raise ValidationError(fault.faultDetailString) # Check for approval if resp.transactionStatus != TRANS_APPROVED: raise TransactionDenied('%s: %s' % (resp.transactionStatus, resp.transactionMessage)) # Persist transaction data and WF specific metadata with transaction.atomic(): transfer = facade.transfer( source=trans_request.source_account, destination=trans_request.dest_account, amount=_as_decimal(resp.amount), user=trans_request.user, merchant_reference=resp.uuid) TransferMetadata.objects.create( transfer=transfer, type_code=resp.transactionCode, ticket_number=resp.ticketNumber, plan_number=resp.planNumber, auth_number=resp.authorizationNumber, status=resp.transactionStatus, message=resp.transactionMessage, disclosure=resp.disclosure) return transfer
def debit_tokens_from_user(user, amount): """Tranfer from user account to sink account.""" # staff_member = User.objects.get(username="******") no_credit_limit_account_sink = None try: no_credit_limit_account_sink = models.Account.objects.get( name="sink_2016_no_limit") except models.Account.DoesNotExist: no_credit_limit_account_sink = create_no_limit_account( "sink_2016_no_limit") user_account = models.Account.objects.get( primary_user=user, account_type__name=django_settings.TOKEN_ACCOUNT) trans = facade.transfer( source=user_account, destination=no_credit_limit_account_sink, amount=amount, ) return trans
def credit_to_reimbursement_account(user, amount, merchant_reference=None): no_credit_limit_account_source = None try: no_credit_limit_account_source = models.Account.objects.get( name="source_2016_no_limit") except models.Account.DoesNotExist: no_credit_limit_account_source = create_no_limit_account( "source_2016_no_limit") user_account = models.Account.objects.get( primary_user=user, account_type__name=django_settings.REIMBURSEMENT_ACCOUNT) if not Transfer.objects.filter( merchant_reference=merchant_reference).exists(): trans = facade.transfer(source=no_credit_limit_account_source, destination=user_account, amount=amount, merchant_reference=merchant_reference) return trans
def valid_payload(self, payload): """ Redeem an amount from the selected giftcard """ account = get_object_or_404(Account, code=self.kwargs['code']) if not account.is_active(): raise ValidationError(errors.ACCOUNT_INACTIVE) amt = payload['amount'] if not account.is_debit_permitted(amt): raise ValidationError(errors.INSUFFICIENT_FUNDS) redemptions = Account.objects.get(name=names.REDEMPTIONS) try: transfer = facade.transfer( account, redemptions, amt, merchant_reference=payload.get('merchant_reference', None)) except exceptions.AccountException as e: return self.forbidden( code=errors.CANNOT_CREATE_TRANSFER, msg=e.message) return self.created( reverse('transfer', kwargs={'reference': transfer.reference}), transfer.as_dict())
def valid_payload(self, payload): to_refund = get_object_or_404(Transfer, reference=self.kwargs['reference']) amount = payload['amount'] max_refund = to_refund.max_refund() if amount > max_refund: return self.forbidden( ("Refund not permitted: maximum refund permitted " "is %.2f") % max_refund) if not to_refund.source.is_active(): raise ValidationError(errors.ACCOUNT_INACTIVE) try: transfer = facade.transfer( to_refund.destination, to_refund.source, payload['amount'], parent=to_refund, merchant_reference=payload.get('merchant_reference', None)) except exceptions.AccountException as e: return self.forbidden( code=errors.CANNOT_CREATE_TRANSFER, msg=e.message) return self.created( reverse('transfer', kwargs={'reference': transfer.reference}), transfer.as_dict())
def credit_tokens_for_user(user, amount): """Tranfer from system wide accoutn to user account. Ideally this wiil be called after payment success by user. """ # staff_member = User.objects.get(username="******") no_credit_limit_account_source = None try: no_credit_limit_account_source = models.Account.objects.get( name="source_2016_no_limit") except models.Account.DoesNotExist: no_credit_limit_account_source = create_no_limit_account( "source_2016_no_limit") user_account = models.Account.objects.get( primary_user=user, account_type__name=django_settings.TOKEN_ACCOUNT) trans = facade.transfer( source=no_credit_limit_account_source, destination=user_account, amount=amount, ) return trans
def load_account(self, account, payload): bank = Account.objects.get(name=names.BANK) facade.transfer(bank, account, payload['amount'], description="Load from bank")
def test_reconcilation(self): source = self._build_account('9999999999999991') dest = core.redemptions_account() # Test initial state of the account self.assertEqual(source.credit_limit, Decimal('7500.00')) self.assertEqual(source.balance, Decimal('0.00')) # Buy something facade.transfer( source=source, destination=dest, amount=Decimal('999.99')) # Check account balance self.assertEqual(source.credit_limit, Decimal('7500.00')) self.assertEqual(source.balance, Decimal('-999.99')) # Build a fake inquiry response that shows they haven't paid anything yet inquiry = AccountInquiryResult() inquiry.account = source inquiry.balance = Decimal('999.99') inquiry.open_to_buy = Decimal('6500.01') inquiry.reconcile() # Check account balance self.assertEqual(source.credit_limit, Decimal('7500.00')) self.assertEqual(source.balance, Decimal('-999.99')) # Customer made a payment inquiry = AccountInquiryResult() inquiry.account = source inquiry.balance = Decimal('800.00') inquiry.open_to_buy = Decimal('6700.00') inquiry.reconcile() # Check account balance self.assertEqual(source.credit_limit, Decimal('7500.00')) self.assertEqual(source.balance, Decimal('-800.00')) # Wells Fargo lowered the Customer's credit limit inquiry = AccountInquiryResult() inquiry.account = source inquiry.balance = Decimal('800.00') inquiry.open_to_buy = Decimal('6000.00') inquiry.reconcile() # Check account balance self.assertEqual(source.credit_limit, Decimal('6800.00')) self.assertEqual(source.balance, Decimal('-800.00')) # Wells Fargo lowered the Customer's credit limit again and the customer made a payment inquiry = AccountInquiryResult() inquiry.account = source inquiry.balance = Decimal('700.00') inquiry.open_to_buy = Decimal('5000.00') inquiry.reconcile() # Check account balance self.assertEqual(source.credit_limit, Decimal('5700.00')) self.assertEqual(source.balance, Decimal('-700.00'))
def test_account_exception_raised_for_invalid_transfer(self): user = UserFactory() source = AccountFactory(credit_limit=D('0.00')) destination = AccountFactory() with self.assertRaises(exceptions.AccountException): facade.transfer(source, destination, D('100'), user)
def test_doesnt_explode(self): source = AccountFactory(credit_limit=None) destination = AccountFactory() facade.transfer(source, destination, D('1'))