def test_process_transaction_from_customer_profile(self): # TODO: return customer = CustomerFactory.create() customer.meta = self.customer.meta customer_data = CustomerData.objects.create(customer=customer, data={ 'id': '1235', }) payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer, ) transaction = AuthorizeNetTransactionFactory.create( state=Transaction.States.Initial, data={ 'id': '1235', }, payment_method=payment_method) payment_processor = get_instance(transaction.payment_processor) resp = payment_processor.execute_transaction(transaction, charge_profile=True) assert resp == True tok = payment_processor.client_token(customer) customer_data = CustomerData.objects.get(customer=customer) assert tok == customer_data.get('payment_id')
def test_fetch_transaction_status_with_null_tx_id(self): customer = CustomerFactory.create() customer.meta = self.customer.meta entry = EntryFactory.create(unit_price=25.00) invoice = InvoiceFactory.create( series="pytest", customer=customer, invoice_entries=[entry], state='issued', ) payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer) transaction = AuthorizeNetTransactionFactory.create( invoice=invoice, state=Transaction.States.Pending, data={ 'id': '1235', 'status': None, 'authorizenet_id': None, }, payment_method=payment_method, ) assert str(transaction.data.get('authorizenet_id')) == "None" payment_processor = get_instance(transaction.payment_processor) status = payment_processor.fetch_transaction_status(transaction) assert status == False
def test_process_create_customer_profile(self): customer = CustomerFactory.create() customer.meta = self.customer.meta customer_data = CustomerData.objects.create(customer=customer, data={ 'id': '1235', }) payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer, ) transaction = AuthorizeNetTransactionFactory.create( state=Transaction.States.Initial, data={ 'id': '1235', }, payment_method=payment_method) payment_processor = get_instance(transaction.payment_processor) resp = payment_processor.create_customer_profile(customer) import os print(os.environ) assert resp == True tok = payment_processor.client_token(customer) customer_data = CustomerData.objects.get(customer=customer) assert tok == customer_data.get('payment_id')
def test_process_transaction_with_credit_card(self): customer = CustomerFactory.create() customer.meta = self.customer.meta payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer ) transaction = AuthorizeNetTransactionFactory.create( state=Transaction.States.Initial, data={ 'id': '1235', 'status': None, 'authorizenet_id': None, }, payment_method=payment_method, ) assert transaction.state == transaction.States.Initial payment_processor = get_instance(transaction.payment_processor) status = payment_processor.process_transaction(transaction) assert status == True assert transaction.state == transaction.States.Pending
def test_process_transaction_with_nonce_nonrecurring(self): transaction = BraintreeTransactionFactory.create() payment_method = transaction.payment_method payment_method.nonce = 'some-nonce' payment_method.save() with patch('braintree.Transaction.sale') as sale_mock: sale_mock.return_value = self.result payment_processor = get_instance(transaction.payment_processor) payment_processor.process_transaction(transaction) sale_mock.assert_called_once_with({ # new customer 'customer': { 'first_name': payment_method.customer.first_name, 'last_name': payment_method.customer.last_name }, 'amount': transaction.amount, 'billing': { 'postal_code': None }, # don't store payment method in vault 'options': { 'store_in_vault': False, 'submit_for_settlement': True }, 'payment_method_nonce': payment_method.nonce }) assert transaction.state == transaction.States.Settled assert (transaction.external_reference == transaction.data['braintree_id'] == self.result.transaction.id) payment_method.refresh_from_db() assert not payment_method.token assert payment_method.details == { 'image_url': self.transaction.paypal_details.image_url, 'email': self.transaction.paypal_details.payer_email, 'type': self.transaction.payment_instrument_type, } assert (payment_method.display_info == self.transaction.paypal_details.payer_email) customer = transaction.customer customer_data = CustomerData.objects.filter(customer=customer) assert len(customer_data) == 1 customer_data = customer_data[0] assert customer_data.get( 'id') == self.transaction.customer_details.id assert transaction.data.get( 'status') == self.result.transaction.status
def get_context_data(self): context_data = super(BraintreeTransactionView, self).get_context_data() payment_processor = get_instance(self.transaction.payment_processor) context_data['client_token'] = payment_processor.client_token( self.transaction.customer) context_data[ 'is_recurring'] = payment_processor.is_payment_method_recurring( self.transaction.payment_method) return context_data
def test_process_transaction_with_token_recurring(self): payment_method = BraintreePaymentMethodFactory.create( payment_processor='BraintreeTriggeredRecurring') transaction = BraintreeTransactionFactory.create( payment_method=payment_method) payment_method = transaction.payment_method payment_method.token = 'kento' payment_method.save() customer = payment_method.customer customer_data = CustomerData.objects.create( customer=customer, data={'id': 'somethingelse'}) with patch('braintree.Transaction.sale') as sale_mock: sale_mock.return_value = self.result payment_processor = get_instance(transaction.payment_processor) payment_processor.process_transaction(transaction) sale_mock.assert_called_once_with({ # existing customer in vault 'customer_id': customer_data['id'], 'amount': transaction.amount, 'billing': { 'postal_code': None }, 'options': { 'submit_for_settlement': True }, # existing token 'payment_method_token': payment_method.token }) assert transaction.state == transaction.States.Settled assert (transaction.external_reference == transaction.data['braintree_id'] == self.result.transaction.id) payment_method.refresh_from_db() assert payment_method.token == self.transaction.paypal_details.token assert payment_method.details == { 'image_url': self.transaction.paypal_details.image_url, 'email': self.transaction.paypal_details.payer_email, 'type': self.transaction.payment_instrument_type, } assert payment_method.verified assert (payment_method.display_info == self.transaction.paypal_details.payer_email) assert transaction.data.get( 'status') == self.result.transaction.status
def test_process_transaction_with_payment_method_without_nonce_or_token( self): payment_method = BraintreePaymentMethodFactory.create( payment_processor='BraintreeTriggered', ) transaction = BraintreeTransactionFactory.create( payment_method=payment_method) with patch('braintree.Transaction.sale') as sale_mock: payment_processor = get_instance(transaction.payment_processor) assert payment_processor.process_transaction(transaction) is False assert sale_mock.call_count == 0
def test_update_status_transaction_with_no_braintree_id_case_1(self): # The transaction is not found after a search, which means it hasn't reached braintree transaction = BraintreeTransactionFactory.create( state=Transaction.States.Pending, data={'requested_at': datetime.utcnow().isoformat()}) with patch.multiple('braintree.Transaction', find=MagicMock(), search=MagicMock(items=[])): payment_processor = get_instance(transaction.payment_processor) payment_processor.fetch_transaction_status(transaction) assert transaction.state == transaction.States.Failed
def execute_transaction(self, transaction): """ :param transaction: A Silver transaction with a Braintree payment method, in Initial state. :return: True if the transaction was successfully sent to processing, False otherwise. """ payment_processor = get_instance(transaction.payment_processor) if not payment_processor == self: return False if transaction.state != transaction.States.Pending: return False return self._charge_transaction(transaction)
def void_transaction(self, transaction, payment_method=None): """ Void a transaction :param transaction: A Silver transaction with a AuthorizeNet payment method. :param payment_method: The payment method used to authorize the original transaction :returns True if the state transition was successful, False otherwise. """ payment_processor = get_instance(transaction.payment_processor) if not payment_processor == self: return False transId = str(transaction.data.get('authorizenet_id')) req = apicontractsv1.transactionRequestType() req.transactionType = "voidTransaction" req.refTransId = transId t_req = apicontractsv1.createTransactionRequest() t_req.merchantAuthentication = self.merchantAuth t_req.refId = self.merchantId t_req.transactionRequest = req controller = createTransactionController(t_req) try: controller.execute() except Exception as e: logger.warning('Error executing request to void transaction %s', { 'transaction_id': transId, 'exception': str(e) }) response = controller.getresponse() have_resp = response is not None if have_resp: status, resp_ok = self._get_authorizenet_transaction_status( response) return self._transition_silver_transaction_to( transaction, response, status, transaction.States.Canceled) else: logger.warning( 'Couldn\'t void transaction %s', { 'transaction_id': transId, 'messages': response.messages.message[0]['text'].text }) return False
def test_refund_transaction(self): customer = CustomerFactory.create() customer.meta = self.customer.meta entry = EntryFactory.create() invoice = InvoiceFactory.create( series = "pytest", customer = customer, invoice_entries = [entry], state = 'issued', ) payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer ) transaction = AuthorizeNetTransactionFactory.create( invoice=invoice, state=Transaction.States.Initial, data={ 'id': '1235', 'status': None, 'authorizenet_id': None, }, payment_method=payment_method, ) assert transaction.state == transaction.States.Initial payment_processor = get_instance(transaction.payment_processor) status = payment_processor.process_transaction(transaction) old_status = transaction.data.get('status') assert status == True assert transaction.state == transaction.States.Pending # assert transaction.data.get('status') != 0 # 0 implies the API sandbox is in test mode assert transaction.data.get('authorizenet_id') != 0 status = payment_processor.refund_transaction(transaction) # transaction.States.Settled assert status == True # 1 - success, even though it's void apparently assert transaction.data.get('status') == 1 assert transaction.data.get('authorizenet_id') != 0 assert transaction.data.get('status') != 0
def test_update_status_transaction_settle(self): transaction = BraintreeTransactionFactory.create( state=Transaction.States.Pending, data={'braintree_id': 'beertrain'}) with patch('braintree.Transaction.find') as find_mock: find_mock.return_value = self.transaction payment_processor = get_instance(transaction.payment_processor) payment_processor.fetch_transaction_status(transaction) find_mock.assert_called_once_with('beertrain') assert transaction.state == transaction.States.Settled assert transaction.data.get( 'status') == self.result.transaction.status
def test_process_transaction_with_canceled_payment_method(self): payment_method = BraintreePaymentMethodFactory.create( payment_processor='BraintreeTriggeredRecurring') transaction = BraintreeTransactionFactory.create( payment_method=payment_method) nonce = 'some-nonce' payment_method.nonce = nonce payment_method.canceled = True payment_method.save() with patch('braintree.Transaction.sale') as sale_mock: payment_processor = get_instance(transaction.payment_processor) assert payment_processor.process_transaction(transaction) is False assert sale_mock.call_count == 0
def test_update_status_transaction_with_no_braintree_id_case_2(self): # The transaction is found after a search and continues normally transaction = BraintreeTransactionFactory.create( state=Transaction.States.Pending, data={'requested_at': datetime.utcnow().isoformat()}) with patch.multiple('braintree.Transaction', find=MagicMock(return_value=self.transaction), search=MagicMock(return_value=self.search_result)): payment_processor = get_instance(transaction.payment_processor) payment_processor.fetch_transaction_status(transaction) assert transaction.state == transaction.States.Settled assert transaction.data.get( 'status') == self.result.transaction.status assert (transaction.data['braintree_id'] == transaction.external_reference == self.transaction.id)
def complete_payment_view(request, transaction, expired=None): if transaction.state == transaction.States.Initial: payment_processor = get_instance(transaction.payment_processor) payment_processor.handle_transaction_response(transaction, request) if 'return_url' in request.GET: redirect_url = furl(request.GET['return_url']).add({ 'transaction_uuid': transaction.uuid }).url return HttpResponseRedirect(redirect_url) else: return render(request, 'transactions/complete_payment.html', { 'transaction': transaction, 'document': transaction.document, 'fail_data': FAIL_CODES.get(transaction.fail_code), })
def client_token(request, transaction_uuid=None): transaction = get_object_or_None(Transaction, id=transaction_uuid) payment_processor = get_instance(transaction.payment_processor) if not isinstance(payment_processor, BraintreeTriggered): return Response( {'detail': 'Transaction is not a Braintree transaction.'}, status=status.HTTP_400_BAD_REQUEST ) token = payment_processor.client_token(transaction.customer) if not token: return Response({'detail': 'Braintree miscommunication.'}, status=status.HTTP_503_SERVICE_UNAVAILABLE) return Response({'token': token}, status=status.HTTP_200_OK)
def test_process_transaction_failed_braintree_response(self): payment_method = BraintreePaymentMethodFactory.create( payment_processor='BraintreeTriggeredRecurring') transaction = BraintreeTransactionFactory.create( payment_method=payment_method) nonce = 'some-nonce' payment_method.nonce = nonce payment_method.save() with patch('braintree.Transaction.sale') as sale_mock: self.result.is_success = False sale_mock.return_value = self.result payment_processor = get_instance(transaction.payment_processor) assert payment_processor.process_transaction(transaction) is False assert transaction.data.get('error_codes') == [ error.code for error in self.result.errors.deep_errors ]
def handle_transaction_response(self, transaction, request): payment_method_nonce = request.POST.get('payment_method_nonce') payment_method = transaction.payment_method if not payment_method_nonce: try: transaction.fail(fail_reason='payment_method_nonce was not provided.') transaction.save() except TransitionNotAllowed: pass finally: return if payment_method.nonce: try: transaction.fail(fail_reason='Payment method already has a nonce.') transaction.save() except TransitionNotAllowed: pass finally: return # initialize the payment method details = { 'postal_code': request.POST.get('postal_code') } payment_method.nonce = payment_method_nonce payment_method.update_details(details) payment_method.save() # manage the transaction payment_processor = get_instance(payment_method.payment_processor) if not payment_processor.process_transaction(transaction): try: transaction.fail() transaction.save() except TransitionNotAllowed: pass finally: return
def test_process_transaction_with_credit_card(self): customer = CustomerFactory.create() customer.meta = self.customer.meta payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer) entry = EntryFactory.create(unit_price=25.00) invoice = InvoiceFactory.create( series="pytest", customer=customer, invoice_entries=[entry], state='issued', ) transaction = AuthorizeNetTransactionFactory.create( state=Transaction.States.Initial, data={ 'id': '1235', 'status': None, 'authorizenet_id': None, }, payment_method=payment_method, amount=25.00, invoice=invoice) assert transaction.state == transaction.States.Initial payment_processor = get_instance(transaction.payment_processor) status = payment_processor.process_transaction(transaction) trx = Transaction.objects.all().first() assert Transaction.objects.all().count() > 0 assert trx.data.get('status') != "Null response." assert status == True assert transaction.state in [ transaction.States.Pending, transaction.States.Settled ]
def complete_payment_view(request, transaction, expired=None): if transaction.state == transaction.States.Initial: payment_processor = get_instance(transaction.payment_processor) payment_processor.handle_transaction_response(transaction, request) if 'return_url' in request.GET: redirect_url = six.moves.urllib.parse.unquote( furl(request.GET['return_url']).add( { 'transaction_uuid': transaction.uuid } ).url ) return HttpResponseRedirect(redirect_url) else: return render(request, 'transactions/complete_payment.html', { 'transaction': transaction, 'document': transaction.document, 'fail_data': FAIL_CODES.get(transaction.fail_code), })
def test_process_transaction_with_credit_card_is_success(self): customer = CustomerFactory.create() customer.meta = self.customer.meta entry = EntryFactory.create(unit_price=25.00) invoice = InvoiceFactory.create( series="pytest", customer=customer, invoice_entries=[entry], state='issued', ) payment_method = AuthorizeNetRecurringPaymentMethodFactory.create( payment_processor='AuthorizeNetTriggered', customer=customer) transaction = AuthorizeNetTransactionFactory.create( invoice=invoice, state=Transaction.States.Initial, data={ 'id': '1235', 'status': None, 'authorizenet_id': None, }, payment_method=payment_method, ) assert transaction.state == transaction.States.Initial payment_processor = get_instance(transaction.payment_processor) status = payment_processor.process_transaction(transaction) assert status == True assert transaction.state in [ transaction.States.Pending, transaction.States.Settled ] assert transaction.data.get('status') != 0 # 0 implies the API sandbox is in test mode assert transaction.data.get('authorizenet_id') != 0
def fetch_transaction_status(self, transaction): """ :param transaction: A Silver transaction with a Braintree payment method, in Pending state. :return: True if the transaction status was updated, False otherwise. """ payment_processor = get_instance(transaction.payment_processor) if not payment_processor == self: return False if transaction.state != transaction.States.Pending: return False if not transaction.data.get('braintree_id'): if not self.recover_lost_transaction_id(transaction): logger.warning('Found pending Braintree transaction with no ' 'braintree_id: %s', { 'transaction_id': transaction.id, 'transaction_uuid': transaction.uuid }) return False try: result_transaction = braintree.Transaction.find( transaction.data['braintree_id'] ) return self._update_transaction_status(transaction, result_transaction) except braintree.exceptions.NotFoundError: logger.warning('Couldn\'t find Braintree transaction from ' 'Braintree %s', { 'braintree_id': transaction.data['braintree_id'], 'transaction_id': transaction.id, 'transaction_uuid': transaction.uuid }) return False except TransitionNotAllowed: return False
def instamojo_webhook_view(request, transaction: Transaction, expired=None): payment_processor = get_instance(transaction.payment_processor) verify_instamojo_hmac(request.data, payment_processor.salt) payment_processor.handle_transaction_response_inner( transaction, request.data['payment_id']) # data -- # amount - Amount related to the payment # buyer - Buyer's email # buyer_name # buyer_phone # currency - Currency related to the payment INR # fees - Fees charged by Instamojo 125.00 # longurl - URL related to the payment request # mac - Message Authentication code of this webhook request # payment_id - ID of the payment # payment_request_id - ID of the payment request # purpose - Purpose of the Payment request # shorturl - Short URL of the payment request # status - Status of the Payment. This can be either "Credit" or "Failed". return HttpResponse(content="OK")
def get_object(self, view_name, view_args, view_kwargs): try: return payment_processors.get_instance(view_kwargs['processor_name']) except ImportError: raise ObjectDoesNotExist
def get_object(self, view_name, view_args, view_kwargs): try: return payment_processors.get_instance( view_kwargs['processor_name']) except ImportError: raise ObjectDoesNotExist
def fetch_transaction_status(self, transaction): """ Query payment processor for a transaction, and update the status of the silver transaction accordingly. :param transaction: A Silver transaction with a AuthorizeNet payment method, in Pending state. :return: True if the transaction status was updated, False otherwise. """ logger.info("transaction data: %s", transaction.data) payment_processor = get_instance(transaction.payment_processor) if not payment_processor == self: return False if transaction.state != transaction.States.Pending: return False tx_id = transaction.data.get('authorizenet_id') logger.info('tx id %s', {'tx_id': tx_id}) if not self.test_transaction_id_valid(tx_id): logger.warning( 'Transaction id %s is invalid. API does not support recovering lost transactions, will need to be manually entered.', { 'authorizenet_id': tx_id, }) return False req = apicontractsv1.getTransactionDetailsRequest() req.merchantAuthentication = self.merchantAuth req.transId = str(transaction.data.get('authorizenet_id')) status = transaction.data.get('status') transaction_controller = getTransactionDetailsController(req) try: transaction_controller.execute() except Exception as e: logger.warning('Error in request create transaction %s', {'exception': str(e)}) response = transaction_controller.getresponse() have_resp = response is not None resp_okay = response.messages.resultCode == apicontractsv1.messageTypeEnum.Ok if have_resp: t_resp = response.transaction t_resp_msgs = hasattr(t_resp, 'messages') is True if resp_okay: status = str(t_resp.responseCode) else: if t_resp_msgs: status = response.messages.message[0]['code'].text transaction.data.update({ 'status': status, }) transaction.save() return self._transition_silver_transaction_state( transaction, response, status)
def get_payment_processor(self): return payment_processors.get_instance(self.payment_processor)
def refund_transaction(self, transaction, payment_method=None): """ Refund a transaction :param transaction: A Silver transaction with a AuthorizeNet payment method. :param payment_method: The payment method used to authorize the original transaction :returns True if the state transition was successful, False otherwise. """ payment_processor = get_instance(transaction.payment_processor) if not payment_processor == self: return False transId = str(transaction.data.get('authorizenet_id')) payment = apicontractsv1.paymentType() payment.creditCard = self._create_credit_card( transaction.payment_method.customer) tr_req = apicontractsv1.transactionRequestType() tr_req.transactionType = "refundTransaction" tr_req.amount = transaction.amount tr_req.refTransId = transId tr_req.payment = payment create_req = apicontractsv1.createTransactionRequest() create_req.merchantAuthentication = self.merchantAuth create_req.refId = self.merchantId create_req.transactionRequest = tr_req controller = createTransactionController(create_req) try: controller.execute() except Exception as e: logger.warning('Error executing request to refund transaction %s', { 'transaction_id': transId, 'exception': str(e) }) response = controller.getresponse() have_resp = response is not None if have_resp: status, resp_okay = self._get_authorizenet_transaction_status( response) t_resp = response.transactionResponse if resp_okay: transaction.external_reference = t_resp.transId # TODO: wrong object for `response`? return self._transition_silver_transaction_to( transaction, response, status, transaction.States.Refunded) else: logger.warning( 'Couldn\'t refund transaction %s', { 'transaction_id': transId, 'messages': response.messages.message[0]['text'].text }) return False
def get_object(self): processor_name = self.kwargs.get('processor_name', '') try: return payment_processors.get_instance(processor_name) except (ImportError, KeyError): raise Http404
def payment_processor(): return payment_processors.get_instance('instamojo_manual')
def payment_processor_triggered(): return payment_processors.get_instance('instamojo_triggered')