Tutorials
2022-06-08

Auto-approving purchase requests based on existing budgets

Expense approvals can be long, bureaucratic processes with multiple stakeholders and even more tooling. The flow of checking for existing budget, registering expenses that are pre-approved or approving ad-hoc purchases for members across different teams can sometimes delay critical decisions that affect business outcomes. But it doesn’t have to be a nightmare - you can compile all relevant information into a simple form with custom logic.

Let’s have a look at how to create a purchasing tool where you can check for existing budget and request expense approvals, based on information in a database.

We’ll use Forms to generate a clean user interface and deploy with just a click.

First, if you haven’t yet, sign up for free to access your workspace, where you can create your own forms.

Getting started

We’ll start out by importing our required packages. Since we’ll need retrieve relevant department budget data from a database, we need requests to access it over a REST API, json to treat received the data and datetime to deal with dates.


from hackerforms import *
import requests, json
from datetime import datetime

Now that we’ve got our environment configured, let’s log our user in so we make sure only authorized team members can use our tool. We can do this by using the auth function, and storing information in variables.


auth_info = get_user()
email = auth_info.email
name = auth_info.name

This is what our user will see:

Retrieving department budget

We can now begin to store details to calculate whether it should be approved. Let’s register expense title, value and if it’s a monthly recurring expense. Also, we’ll check to which department this expense belongs to. To simplify the getting the correct variable format we need, we can use different Forms functions like read() to get a string, read_number() to get an integer and read_multiple_choice() to get a list.


title = read("What is the title of this expense?")

value = read_number("How much was this expense?")

recurring = read_multiple_choice("Is this a monthly recurring expense?",
                                 [{'label': 'yes', 'value': True},
                                  {'label': 'no', 'value': False}])

id_department = read_multiple_choice("To which department does this expense belong?",
                                   [{'label': 'Marketing', 'value': 1},
                                   {'label': 'Sales', 'value': 2},
                                   {'label': 'Operations', 'value': 3},
                                   {'label': 'Product', 'value': 4},
                                   {'label': 'Human Resources', 'value': 5},
                                   {'label': 'Engineering', 'value': 6}])

Now that we know the department, we can check if it has enough budget to cover this purchase before allowing the user to continue. We can do this by running a requests.post to an endpoint, using the id we stored as a parameter. We’ll also use json to parse the data and store values in variables.


department = requests.post(
  "INSERT ENDPOINT URL HERE",
  json = {'iddepartment':id_department}
	)
department = department.json()[0]
department_name = department['name']
budget = department['budget']

Calculating existing budget

Now that we have the purchase value, department and relevant budget, we can check if we should allow the user to continue. If there is not enough budget, we can let the user know and close the request.


if value > budget:
  exit = True
else:
  exit = False

if exit = True:
	display(f"Sorry, the budget for the {department_name} department is not sufficient to cover this expense. Please speak to your manager.")
else:

This is how it will look like for our user:

Registering a new purchase request in a database

Now that we’ve checked if an expense fits in the department’s budget, we can continue to register important information like description, type and due date. We can use read_date to format responses into a datetime.date object.


description = read("Briefly describe what this expense is for.")
type = read_multiple_choice("What type of expense is this?", 
                            ['tool', 
                             'freelancer', 
                             'reimbursement',
                             'misc'])
due = read_date("When is this expense due?")

The user will see an intuitive date picker to help register the correct date:

Finally, let’s post this new purchase request in the PostgreSQL database that the Finance team uses to log operational costs, and let the user know their request has been registered correctly.


newexpense = requests.post("INSERT ENDPOINT URL HERE",
	                         json = {
	                            "name": title, 
		                          "description": description, 
                              "type": type, 
                              "value": value, 
                              "recurring_monthly": recurring, 
                              "due": due.strftime('%Y-%m-%d'),
                              }
                            )
display("We've registered this expense succesfully. Thanks! See ya next time.")

Sharing with our users

We’ve done the heavy lifting of authenticating our users, storing expense details, checking for existing budget and registering pre-approved purchases in a database. 🎉

Now, it’s show time - let’s share our tool with our users. To do so, we’ll click on the share button in our editor to generate a URL, and that’s it!

We have a sleek interactive form-like app, with requests and logic, deployed instantly, fully responsive and accessible in any browser.