Collect payments in your Django ecommerce portal using Flutterwave ~PART 2
Tags: django, webdev, javascript, python
Published: 2021-07-27 19:49:28

Hello everyone and welcome to part 2 of the series where we are building an electronics store and then collect payments from users who can choose how to pay. In case you missed part 1 then [here it is](https://dev.to/nick_langat/collect-payments-in-your-django-ecommerce-portal-using-flutterwave-part-1-14kp).We ended it where we had the following page on (http://localhost:8000/)
![products](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8ukddxajfb704joz3d34.png)
Well, in this part we are going to create a detail page for an individual product and then add a form to collect payment details including the name, email and phone number of the user. Once we have that data, we shall connect with [Flutterwave](https://flutterwave.com/) to process the payment. We will then grab the response from Flutterwave in our callback function and do stuff with it. Sounds fun? Let's get dirty!
##PRODUCT DETAIL
We need to find a way of accessing a single product when its name is clicked. Open `views.py` and add the following code to it below what we already have:
```python
def product_detail(request, pk):
    data = Product.objects.get(id=pk)
    ctx={
        'product':data
    }
    return render(request,
                  'product.html',
                  ctx)
```
So we are grabbing the current product's ID and the asking the database to give us only its details. We add the details to our context variable and render it in the HTML. Open `urls.py` and add a path like so:
```python
path('product/<int:pk>/details', product_detail, name='details'),
```
Next up let's update the 'templates/products.html' like in the paste found [here](https://dpaste.org/rFrN)
Then open 'templates/product.html' and add to it the code found [here](https://dpaste.org/8xDx)
With all that in place access the homepage and click on any product and, hopefully, you should see its detailed page like the one below:
![product detail](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sl23711itg28mijpjgfu.png)
If you encounter an error please check the terminal console and fix before moving on.
##PAYMENTS FORM
We need to capture the details of the user trying to buy a given product. In django the best way to do this is to present the customer with a form which they fill and then on submission, we grab the values the user entered. Create a new file inside 'electronics' called `forms.py`:
```
touch electronics/forms.py
```
Add the following code to it:
```python
from django import forms

class PaymentForm(forms.Form):
    name = forms.CharField(label='Your name', max_length=100)
    email = forms.EmailField()
    phone=forms.CharField(max_length=15)
    amount = forms.FloatField()
    
```
Our form is ready, next let's update the product detail function to contain the form and the logic to get the form data once a user clicks submit button:
```python

def product_detail(request, pk):
    data = Product.objects.get(id=pk)
    if request.method=='POST':
        form = PaymentForm(request.POST)
        if form.is_valid():
             name=  form.cleaned_data['name']
             email = form.cleaned_data['email']
             amount = form.cleaned_data['amount']
             phone = form.cleaned_data['phone']
             return redirect(str(process_payment(name,email,amount,phone)))
    else:
        form = PaymentForm()
    ctx={
        'product':data,
        'form':form
    }
    return render(request,
                  'product.html',
                  ctx)
```

We are adding our form to capture payment info.We are checking if the request verb is 'POST'.We then clean the form and get the values the user entered i.e name,email,phone. The amount will be hidden since we can access it from the product details.
Let's move on to create a method that will call Flutterwave's endpoint, inside the `views.py` add the code below to it.
```python
def process_payment(name,email,amount,phone):
     auth_token= env('SECRET_KEY')
     hed = {'Authorization': 'Bearer ' + auth_token}
     data = {
                "tx_ref":''+str(math.floor(1000000 + random.random()*9000000)),
                "amount":amount,
                "currency":"KES",
                "redirect_url":"http://localhost:8000/callback",
                "payment_options":"card",
                "meta":{
                    "consumer_id":23,
                    "consumer_mac":"92a3-912ba-1192a"
                },
                "customer":{
                    "email":email,
                    "phonenumber":phone,
                    "name":name
                },
                "customizations":{
                    "title":"Supa Electronics Store",
                    "description":"Best store in town",
                    "logo":"https://getbootstrap.com/docs/4.0/assets/brand/bootstrap-solid.svg"
                }
                }
     url = ' https://api.flutterwave.com/v3/payments'
     response = requests.post(url, json=data, headers=hed)
     response=response.json()
     link=response['data']['link']
     return link
```
Notice that this method loads a secret key from a `.env` file. Thus create a file in 'electronics' called `.env` and add the code below:
```
SECRET_KEY='YOUR FLUTTERWAVE SECRET KEY'
```

##OBTAINING FLUTTERWAVE SECRET KEY
Login to your Flutterwave account and head over to [API settings](https://dashboard.flutterwave.com/dashboard/settings/apis). Generate new keys or copy what you already have if you had earlier generated. What we want in particular is the 'SECRET KEY'. Copy it and add it to the `.env` file you earlier created.
Next add the following code at the top of your `views.py` to initialize our environment variables:
```python
import environ
# Initialise environment variables
env = environ.Env()
environ.Env.read_env()
```
##REDIRECT URL
When we make a post request to Flutterwave with all the details collected,they will call your specified redirect_url and post the response to you. They will also append your transaction ID (transaction_id), transaction reference (tx_ref) and the transaction status (status) as query params to the redirect_url like: `/tx_ref=ref&transaction_id=30490&status=successful`. Once we have this response data we can verify transaction status and provide value to our customers like saving it in the database and providing feedback to users. In this case we are going to simply print the response on the console. Feel free to play around with the response.
Add the following function to `views.py`:
```python
from django.views.decorators.http import require_http_methods
from django.http import HttpResponse


@require_http_methods(['GET', 'POST'])
def payment_response(request):
    status=request.GET.get('status', None)
    tx_ref=request.GET.get('tx_ref', None)
    print(status)
    print(tx_ref)
    return HttpResponse('Finished')
```
Then update `urls.py` like so:
```python
from os import name
from django.contrib import admin
from django.urls import path
from django.conf import settings
from django.conf.urls.static import static
from electronics.views import list_products, payment_response, product_detail

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', list_products, name='list'),
    path('product/<int:pk>/details', product_detail, name='details'),
    path('callback', payment_response, name='payment_response')
 ]
if settings.DEBUG:
    urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
```
        
##UPDATE PRODUCT DETAIL HTML
We have all the logic to handle payment collection. The next thing is to update 'templates/product.html' to reflect this change as well. Copy the code found [on this paste](https://dpaste.org/6851) and paste it on your file. 
Spin the server and head over to the homepage. Select any one product and enter customer name, email and phone and click submit. You should see a payment modal similar to the one below:
![pay modal](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2sgqolbq0ctggl78lbs8.png)
You can also opt to pay using bank card:
![bank pay](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/srq3gwtjhecfxekuhrrp.png)
##DONE DEAL
Phew! If you followed up to this point then pat yourself! That was some load of work. Congratulations for completing the series. In the series we were able to create an electronics store, collect payment from the user who had a choice of picking mobile money or card and then retrieved the transaction status and reference number for value addition. 
If you have any questions leave them down below and I'll do my best to answer those. 
Find me on [Twitter](https://twitter.com/NicksonLangat20)
and
My [personal website](https://techwithnick.com/).
Untill next time, happy hacking!