TransWikia.com

Braintree payment form not working | Django

Stack Overflow Asked by Felipe Dourado on January 5, 2022

I’m trying to build a Braintree payment form following the ‘Django by Example 3’ book but the form is not able to be filled:

enter image description here

As you can see, the form is displayed in the browser but there’s no chance by editing this 3 fields. Actually is being shown like ‘images’.

Below my template:

{% extends "shop/base.html" %}

{% block title %}Pay by credit card{% endblock %}

{% block content %}
    <h1>Pay by credit card</h1>
    <form id="payment" method="post">
        <label for="card-number">Card Number</label>
        <div id="card-number" class="field"></div>
        
        <label for="cvv">CVV</label>
        <div id="cvv" class="field"></div>
        
        <label for="expiration-date">Expiration Date</label>
        <div id="expiration-date" class="field"></div>
        
        <input type="hidden" id="nonce" name="payment_method_nonce"
        value="">
        {% csrf_token %}
        <input type="submit" value="Pay">
    </form>

<!-- includes the Braintree JS client SDK -->
<script src="https://js.braintreegateway.com/web/3.44.2/js/client.
min.js"></script>
<script src="https://js.braintreegateway.com/web/3.44.2/js/hostedfields.
min.js"></script>

<script>
    var form = document.querySelector('#payment');
    var submit = document.querySelector('input[type="submit"]');

braintree.client.create({ 
 authorization: '{{ client_token }}'
}, function (clientErr, clientInstance) {
if (clientErr) {
    console.error(clientErr);
    return;
  }

braintree.hostedFields.create({
client: clientInstance,
styles: {
    'input': {'font-size': '13px'},
    'input.invalid': {'color': 'red'},
    'input.valid': {'color': 'green'}
  },
fields: {
    number: {selector: '#card-number'},
    cvv: {selector: '#cvv'},
    expirationDate: {selector: '#expiration-date'}
  }
}, function (hostedFieldsErr, hostedFieldsInstance) {
  if (hostedFieldsErr) {
console.error(hostedFieldsErr);
return;
  }

submit.removeAttribute('disabled');
form.addEventListener('submit', function (event) {
    event.preventDefault();
    
    hostedFieldsInstance.tokenize(function (tokenizeErr,
payload) {
    if (tokenizeErr) {
        console.error(tokenizeErr);
        return;
    }
    // set nonce to send to the server
    document.getElementById('nonce').value = payload.nonce;
    // submit form
    document.getElementById('payment').submit();
    });
   }, false);
  });
});
</script>
{% endblock %}

Here is what the book says:

"This is the template that displays the payment form and processes the payment.
You define containers instead of elements for the credit card input
fields: the credit card number, CVV number, and expiration date. This is how
you specify the fields that the Braintree JavaScript client will render in the iframe.
You also include an element named payment_method_nonce that you
will use to send the token nonce to your view once it is generated by the Braintree
JavaScript client."

Any help?

4 Answers

I had the same problem as koniecpolski. The book Django 3 By Example is right. When we copy and paste from the book (PDF) the symbol "-" is lost so it goes from: hosted-fields to hostedfields. Also, if we check the code that comes with the book, the code is right. So far in my experience all of the errors and mistakes come from copy and paste. When something is not working my best option is to check the code that comes with the book to see the right formatting or missing code.

Answered by adolfox on January 5, 2022

Check whether there are wrong codes in your views.py! I have same problem, but I check my coding with copying original coding. I found the "payment_process def " returned wrong value.The wrong code was "clinet". The correct is "client".Don't give up braintree and Djagno 3 by example.

Answered by 林鈺堂 on January 5, 2022

I managed to solve this problem (because I'm doing Packt Django 3 By Example course too) by copying from the Braintree site and replacing given in the book SDK script import lines.

<!-- includes the Braintree JS client SDK -->
<script src="https://js.braintreegateway.com/web/3.44.2/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.44.2/js/hosted-fields.min.js"></script>

I guess something was wrong in "original links" [from the book] for example hostedfields instead of hosted-fields. Now it's working for me

Answered by koniecpolski on January 5, 2022

I had the same problem going through the book and I eventually figured it out, here is my work around it. You should use the Drop-in UI which is a ready-made payment UI that offers the quickest way to integrate and start securely accepting payments with Braintree and then use:

https://js.braintreegateway.com/web/dropin/1.18.0/js/dropin.min.js

instead of:

<script src="https://js.braintreegateway.com/web/3.44.2/js/client.min.js"></script>
<script src="https://js.braintreegateway.com/web/3.44.2/js/hostedfields.min.js"></script>

In process.html do the following:

{% extends "shop/base.html" %} 

{% block title %} Pay by credit card {% endblock %}

{% block sidenavigation %}



{% endblock %}

{% block content %}
<h1>Pay by credit card</h1>

<!-- includes the Braintree JS client SDK -->

<script src="https://js.braintreegateway.com/web/dropin/1.18.0/js/dropin.min.js"></script>

<form autocomplete="off">
  {% if braintree_error %}
    <div class="alert alert-danger fade in">
        <button class="close" data-dismiss="alert">&times;</button>
        {{ braintree_error|safe }}
    </div>
  {% endif %}
  <div class="braintree-notifications"></div>
  <div id="braintree-dropin"></div>
  <input style="background-color: #0783ca" id="submit-button" class="btn btn-success btn-lg btn-block" type="button" value="Pay now!" />
</form>

<script>
  var braintree_client_token = "{{ client_token}}";
  var button = document.querySelector('#submit-button');

  braintree.dropin.create({
    authorization: "{{client_token}}",
    container: '#braintree-dropin',
    card: {
      cardholderName: {
          required: false
      }
    }
  }, function (createErr, instance) {
      button.addEventListener('click', function () {
          instance.requestPaymentMethod(function (err, payload) {
              $.ajax({
                  type: 'POST',
                  url: '{% url "payment:process" %}',
                  data: {
                    'paymentMethodNonce': payload.nonce,
                    'csrfmiddlewaretoken': '{{ csrf_token }}'}
              }).done(function (result) {
                 //do accordingly
              });
          });
      });
  });
</script>

{% endblock %}

In payment/views.py

def payment_process(request):
    """The view that processes the payment"""
    order_id = request.session.get('order_id')


    order = get_object_or_404(Order, id=order_id)

    total_cost = order.get_total_cost()


    if request.method == 'POST':
        # retrieve nonce 
        # retrieve nonce
        nonce = request.POST.get('paymentMethodNonce', None)

        # # create User 
        customer_kwargs = {
            "first_name": order.first_name,
            "last_name": order.last_name,
            "email": order.email
        }
        customer_create = gateway.customer.create(customer_kwargs)
        customer_id = customer_create.customer.id

        #create and submit transaction
        
        result = gateway.transaction.sale({
            'amount': f'{total_cost:.2f}',
            'payment_method_nonce': nonce,
            'options': {
                'submit_for_settlement': True
            }
        })

        print(result)
        if result.is_success:
            #mark the order as paid 

            order.paid = True
            
            # store the unique transaction id 
            order.braintree_id = result.transaction.id
            order.save()

            return redirect('payment:done')
        else:
            return redirect('payment:canceled')
    else:
        # generate token
        client_token = gateway.client_token.generate()

        return render(
            request,
            'payment/process.html',
            {
                'order':order,
                'client_token': client_token
            }
        )

As you have noticed we are using ajax after the result is a success you should do something. Hope that it helps

Answered by Philip Mutua on January 5, 2022

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP