Open In App

Integrate the QuickBooks API with the Python Django

Last Updated : 09 Jul, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

QuickBooks is a powerful accounting software that helps businesses manage their finances efficiently. Integrating the QuickBooks API with a Django application can automate many financial processes, saving time and reducing errors. This article will guide you through the steps required to integrate the QuickBooks API with a Python Django application.

Integrate the QuickBooks API with Python Django

Before starting the integration, ensure you have the following:

Install Required Libraries

pip install intuit-oauth python-quickbooks django

Step 1: Setting Up QuickBooks Developer Account

  1. Sign Up: Create an account on the QuickBooks Developer Portal (https://developer.intuit.com/app/developer/homepage)
  2. Create an App: Once logged in, navigate to 'My Apps' and create a new app. Select 'QuickBooks Online and Payments'.
  3. Get Credentials: After creating the app, you will get the Client ID and Client Secret. These credentials are essential for authentication.

Then you have to use these credentials to the tokens.py file of the payment app in Django that you cloned from the GitHub. Congratulations you successfully created the credentials to use QuickBooks in your Django application.

Setting Up the Project Folder

django-admin startproject <project_name>
cd <project_name>
python manage.py startapp <app_name>

Directory Structure

myproject/
│
├── manage.py
└── myproject/
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py

Configure Django Settings

Add the required settings in your settings.py file:

# settings.py

QUICKBOOKS_CLIENT_ID = 'YOUR_CLIENT_ID'
QUICKBOOKS_CLIENT_SECRET = 'YOUR_CLIENT_SECRET'
QUICKBOOKS_REDIRECT_URI = 'http://localhost:8000/callback'

Step 2: Defining Models

Now you have to create your own model for storing the details(data) in the database.

Python
from django.db import models

class Payment(models.Model):
  	payment_id=models.CharField(max_length=255,primary_key=True,default=uuid4)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    status = models.CharField(max_length=20)
    order_id=models.CharField(max_length=255,null=True,blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
      return str(self.trans_id)

Step 4: Defining the Route

Here the first route naming payment-list-create which will create the payment , Second route which is payment-details will display all the detaills from the database and the last route naming verify will verify the given payment.And you have to add the function which refreshing the OAuth tokens using the AuthClient class and associataed with a specific set of client secrets and tokens.

Python
from django.urls import path, include
from payment_integration import views

urlpatterns = [
    ...
    path('api/payments/', views.PaymentListCreate.as_view(), name='payment-list-create'),
    path('api/payments/<int:pk>/', views.PaymentDetail.as_view(), name='payment-detail'),
    path("api/payments/verify/", views.QuickbooksVerifyPaymentView.as_view(), name='verify'),

]

Step 5: Writing API for Views

Now in this step you have to write an API class from create, verify and display the details operation. Incoming payment data communicate with Quickbooks online payment API and create payment transactions and returning the responses based on the success or failure of the opeartion.

API for create payment:

This view takes input a json payload containing the information required to create a payement. The payload containing the information required to create a payment . The payload includes details such as the payment amount , paymen_id , amount , status and related information depending upon the related informations.

Authorization and Headers:

  • The post call takes a refresh_token to obtain an access token, this will set up the necessary authorizationand headers for making any other requests to Quickbooks API.
  • Process the incoming request data which payment method to be used and structure it for card, digital wallet or internet banking.

API Request: It makes a post request to Quickbooks API with the payment data and process the response which is verifying if it was successfully created.

Database and Response - if payment creation is successful, it saves the details to Payment model and credentials a success response or returns an error responce.payment

Python
import uuid
import requests
from django.db import models
from django.utils.timezone import now
from rest_framework.views import APIView
from rest_framework.response import Response
from .models import Payment
from .views import *

class QuickbooksCreatePaymentView(APIView):
    def post(self, request):
        try:
            response = refresh_token()
            access_token = response["access_token"]
            base_url = 'https://sandbox.api.intuit.com/quickbooks/v4/payments/charges/'
            auth_header = 'Bearer {0}'.format(access_token)
            headers = {
                'Authorization': auth_header,
                'Request-Id': str(uuid.uuid4()),
                'Content-Type': 'application/json',
                'User-Agent': 'Mozilla/5.0',
                'Accept-Encoding': 'gzip, deflate, br'
            }
            data = request.data
            amount = data.get('amount')
            payment_method = data.get('payment_method')

            if payment_method == 'card':    
                payment_data = {
                    'amount': float(amount),
                    'currency': data.get('currency'),
                    'card': {
                        'name': data.get('card_name'),
                        'address': data.get('address'),
                        'expYear': data.get('exp_year'),
                        'expMonth': data.get('exp_month'),
                        'number': data.get('number'),
                        'cvc': data.get('cvc')
                    },
                    'context': {
                        'mobile': False,
                        'isEcommerce': True
                    }
                }
            elif payment_method == 'digital_wallet':
                payment_data = {
                    'amount': float(amount),
                    'currency': data.get('currency'),
                    'digitalWallet': {
                        'type': data.get('digital_wallet_type'),
                        'id': data.get('digital_wallet_id')
                    },
                    'context': {
                        'mobile': False,
                        'isEcommerce': True
                    }
                }
            elif payment_method == 'internet_banking':
                payment_data = {
                    'amount': float(amount),
                    'currency': data.get('currency'),
                    'bankTransfer': {
                        'account': data.get('bank_account_number'),
                        'routingNumber': data.get('bank_routing_number')
                    },
                    'context': {
                        'mobile': False,
                        'isEcommerce': True
                    }
                }
            else:
                return Response({'error': 'Invalid payment method'}, status=400)

            response = requests.post(base_url, headers=headers, json=payment_data)
            if response.status_code == 201:
                response_data = response.json()
                charge_id = response_data.get('id')
                Payment.objects.create(
                    payment_id=uuid.uuid4(),
                    amount=amount,
                    status='Success',
                    order_id=charge_id,
                    created_at=now()
                )
                return Response({'message': 'Payment Success', 'charge_id': charge_id, 'success': True}, status=201)
            else:
                return Response({'error': 'Failed to create a payment', 'success': False}, status=response.status_code)
        except Exception as e:
            return Response({'error': str(e)}, status=500)

This view returns an HTTP response to the client based on the outcome of the payment creation process:

JavaScript
{
    "amount": 100.00,
    "currency": "USD",
    "payment_method": "card",
    "card_name": "John Doe",
    "address": "123 Main St, Anytown, USA",
    "exp_year": 2025,
    "exp_month": 12,
    "number": "4111111111111111",
    "cvc": "123"
}

Success response

JavaScript
{
    "message": "Payment Success",
    "charge_id": "charge_id_from_quickbooks",
    "success": true
}

Failure response

JavaScript
{
    "error": "Invalid payment method",
    "success": false
}

QuickBooks API Failure

If there is a problem with the QuickBooks API or if the response status code is not 201 (Created):

JavaScript
{
    "error": "Failed to create a payment",
    "success": false
}

Exception Handling

If an exception occurs during the request processing:

JavaScript
{
    "error": "Detailed error message here",
    "success": false
}

API for display and verifyPayment:

  • Get Access Token: It expects a refresh_token function returning the access token.
  • Get Data From Request: Gets charge ID from request data.
  • Set Headers: This sets up authorization headers with the tokens.
  • Make GET Request: It makes the GET request to the QuickBooks API to verify if the payment is done.
  • Process Response:
    • After verifying that the status code of the response is 200, the payment status is extracted using the data of the response.
    • Using order_id, which is the charge ID, the respective Payment object is fetched.
    • The status is set and saved on the Payment object.
  • Error Handling:
    • If a Payment with the given order_id is not found, then a Payment.DoesNotExist exception is caught and a 404 Not Found Response is returned.
    • All other exceptions are caught and cause the response to return a 500 Internal Server Error.
Python
class QuickbooksVerifyPaymentView(APIView):
    def post(self, request):
        try:
            response = refresh_token()
            access_token = response["access_token"]
            data = request.data
            charge_id = data.get('charge_id')
            headers = {'Authorization': f'Bearer {access_token}'}
            response = requests.get(f'https://sandbox.api.intuit.com/quickbooks/v4/payments/charges/{charge_id}', headers=headers)

            if response.status_code == 200:
                response_data = response.json()
                status = response_data.get('status')
                payment = Payment.objects.get(order_id=charge_id)
                payment.status = status  # Assuming the status can be directly mapped
                payment.save()
                return Response({'status': status, 'message': 'Payment Successfully Verified', 'success': True})
            else:
                return Response({'error': 'Failed to verify payment', 'success': False}, status=response.status_code)
        except Payment.DoesNotExist:
            return Response({'error': 'Payment not found', 'success': False}, status=404)
        except Exception as e:
            return Response({'error': str(e), 'success': False}, status=500)

Input JSON Sample

JavaScript
{
    "charge_id": "charge_id_from_quickbooks"
}

Output JSON

JavaScript
{
    "status": "status_from_quickbooks",
    "message": "Payment Successfully Verified",
    "success": true
}

Failure Response

JavaScript
{
    "error": "Failed to verify payment",
    "success": false
}
{
    "error": "Payment not found",
    "success": false
}

These are all the steps you have to follow to integrate the QuickBooks into your DjangoRestFramework project. Hope this will help you to understand integrate the Quick books payment with the Django Rest Framework.

API testing Video:


Next Article
Practice Tags :

Similar Reads