Build Invoice Creation App using Hypi’s low code API

Here is another post on App creation using Hypi’s low code API!

In the previous post, we quickly built up a Customer Support Model App clone. Now we will accelerate to building Invoice Creation App (Your own Quickbooks clone)!

We will create a Customer Account Information System and create an Invoice for sale of products or services. At last, we will send the Invoice to the customer’s email address.

So, here are the features of Quickbooks clone app:

  • Store Customer Information
  • Store Product / Service Sale information
  • Create Orders and calculate Bill amount
  • Store Invoice details
  • Send Invoice to customer’s Email Address

Here is your sample schema for the Invoice Creation App

A) Customer data type stores Customer Information. In-built data type Account from core tables stores the customer details.
B) Product data type stores the sale details of each product or service to a customer.
C) Invoice data type stores the Invoice details.
D) Enum Terms has values for the term of the bill payment. (15/30/60 days or due on receipt)

type Customer {
    account: Account
    company: String
    taxRegistrationNo: String    
}
 
enum Terms {  
    NET15  
    NET30  
    NET60
    DUEONRECEIPT
}
 
type Invoice {
    customer: Customer
    terms: Terms
    invoiceDate: DateTime
    dueDate: DateTime
    invoiceNo: Int
    supplyPlace: String
    product:[Product]
    total: Float
    message: String
    attachment: File
}
 
type Product {
    name: String
    description: String
    quantity: Int
    rate: Float
    amount: Float
    tax: Float
    total: Float
    customer: Customer
    username: String
}

Create an Invoice Creation App on Hypi’s low code platform. Create a release and an instance. Enter the above schema in the release.

Now, let’s implement the following use cases in the Invoice Creation App.

=============================================================

A) Store Customer Information

i) Create Customer Objects to store customer information. Use this guide on how to insert data in an instance. .

You may write your own User defined function to create objects or use the variables method of Object creation as shown below.

mutation Upsert($values: HypiUpsertInputUnion!) {
    upsert(values: $values) {
      id
    }
  }
#input
{
  "values": {
      "Customer":  [
        {
          "account": {"hypi":{"id": "01FP05XKXM2R5V5WYWBPKV96YH"}},
          "company": "Tink",
          "taxRegistrationNo": "ABC12345678"
        }
      ]
    }
}
#result
{
  "data": {
    "upsert": [
      {
        "id": "01FP06RY86KMV4VQN8JD0RD9V3"
      }
    ]
  }
}

=============================================================

B) Store Product / Service Sale information

Let’s say you have sold a product/service to a customer. So you should store the details in a Product object. (The details of the Product, how much quantity sold, what is the rate, what is the tax on the sale and to whom the product is sold etc.)

Let’s create Product Objects…

 mutation Upsert($values: HypiUpsertInputUnion!) {
    upsert(values: $values) {
      id
    }
  }

#input A
{
  "values": {
      "Product":   [
        {
          "name": "Hypi",
          "description": "Low Code Backend",
          "quantity": 2,
          "rate": 150,
          "tax": 10,      
          "customer": {"hypi":{"id": "01FP06RY86KMV4VQN8JD0RD9V3"}}
        }
      ]
    }
}
#result
{
  "data": {
    "upsert": [
      {
        "id": "01FP07MS88YFP54FMTT85SEXFJ"
      }
    ]
  }
}

#input B
{
  "values": {
      "Product":   [
        {
          "name": "Hypi Tink",
          "description": "No Code",
          "quantity": 1,
          "rate": 200,
          "tax": 15,      
          "customer": {"hypi":{"id": "01FP06RY86KMV4VQN8JD0RD9V3"}}
        }
      ]
    }
}
#result
{
  "data": {
    "upsert": [
      {
        "id": "01FP07RQ96K56863Q9TPJTYQ4H"
      }
    ]
  }
}

==============================================================

C) Calculate Bill amount of the Orders of each Product

Customers may buy different products or services with varying rates. So, we will write a user defined function to calculate subtotal for the sale of each product to a particular customer.

Edit schema and write below User Defined Function under the Mutation data type. Below function multiplies rate with the quantity. It is assumed that tax was stored in terms of percentages. So the function calculates the tax amount and adds it to the result of previous multiplication. It also stores the subtotal in the Product data type.

type Mutation {
calculateAmount(a: ID):Json @tan(type:Groovy, inline: """
def rate = gql(\"""{get(type:Product,id:"$a"){...on Product{rate}}}\""").data.get.rate
def quantity = gql(\"""{get(type: Product,id:"$a"){...on Product {quantity}}}\""").data.get.quantity
float subtotal = (float)rate * (float)quantity
def tax = gql(\"""{get(type: Product,id:"$a"){...on Product {tax}}}\""").data.get.tax
def taxAmount =  (float)subtotal * (float)tax / 100
def user = gql(\"""{get(type:Product,id:"$a"){...on Product{customer{account{username}}}}}\""").data.get.customer.account.username
subtotal = subtotal + taxAmount
return upsert([
          Product: [
             amount: subtotal,
             username: user,
             hypi:
                [
                 id: a
                ]         
          ]
        ]
    )       
""")

#sample query :

mutation {
  calculateAmount(a: "01FP07MS88YFP54FMTT85SEXFJ")
}

mutation {
  calculateAmount(a: "01FP07RQ96K56863Q9TPJTYQ4H")
}

================================================================

D) Store Invoice details

i) Create an Invoice object. Pass on the values as variables or create User Defined Function.

{
  "values": {
      "Invoice":   [
        {
          "customer": {"hypi":{"id": "01FP06RY86KMV4VQN8JD0RD9V3"}},
          "terms": "DUEONRECEIPT",
          "invoiceDate": "2021-12-03",
          "dueDate":"2022-01-01",
          "invoiceNo": 12323,
          "supplyPlace": "Mumbai",
          "message": "This is an invoice from Hypi",
          "product": [
            {"hypi": {"id": "01FP07MS88YFP54FMTT85SEXFJ"}},
            {"hypi": {"id": "01FP07RQ96K56863Q9TPJTYQ4H"}}
          ]          
        }
      ]
   }
}
{
  "data": {
    "upsert": [
      {
        "id": "01FP0FRR5R4G1VVVDER89AQKDE"
      }
    ]
  }
}

ii) Calculate Invoice Total.

Calculate the Invoice Total amount by aggregating the subtotal amount of each product sold. calculateInvoiceTotal calculates the sum total by using aggregation API and stores the total amount in the Invoice object (created in the previous step)

calculateInvoiceTotal(a:ID):Json @tan(type:Groovy, inline: """   
def user = gql(\"""{get(type:Invoice,id:"$a"){...on Invoice{customer{account{username}}}}}\""").data.get.customer.account.username
def sumAmount = gql(\"""{
aggregate {
        product(where: "username='$user'") {
        amount {
                    sum
                }
            }
   }
}\""").data.aggregate.product.amount.sum

return upsert([
          Invoice: [
             total: sumAmount,
             hypi:
                [
                 id: a
                ]       
            ]
        ]
    )       
""")
}

#Sample Query: 

mutation {
  calculateInvoiceTotal(a: "01FP0FRR5R4G1VVVDER89AQKDE")
}

Here are the Final Invoice details retrieved using find function.

{
  "data": {
    "find": {
      "edges": [
        {
          "cursor": "01FP0FRR5R4G1VVVDER89AQKDE",
          "node": {
            "hypi": {
              "id": "01FP0FRR5R4G1VVVDER89AQKDE",
              "created": "2021-12-03T15:49:23Z"
            },
            "customer": {
              "account": {
                "username": "test-hypi@hypi.io",
                "emails": [
                  {
                    "value": "test-hypi@hypi.io"
                  }
                ],
                "owner": {
                  "addresses": [
                    {
                      "street": "17",
                      "town": "Pasir Ris",
                      "city": "Singapore",
                      "country": {
                        "name": "Singapore"
                      },
                      "postCode": "123456"
                    }
                  ]
                }
              }
            },
            "product": [
              {
                "name": "Hypi",
                "description": "Low Code Backend",
                "quantity": 2,
                "rate": 150,
                "tax": 10,
                "amount": 330
              },
              {
                "name": "Hypi Tink",
                "description": "No Code",
                "quantity": 1,
                "rate": 200,
                "tax": 15,
                "amount": 230
              }
            ],
            "terms": "DUEONRECEIPT",
            "invoiceDate": "2021-12-03T00:00:00Z",
            "dueDate": "2022-01-01T00:00:00Z",
            "invoiceNo": 12323,
            "supplyPlace": "Mumbai",
            "total": 560,
            "message": "This is an invoice from Hypi"
          }
        }
      ]
    }
  }
}

===============================================================

E) Send Invoice to customer Email Address

Invoice details stored on the Hypi’s low code backend can be retrieved using the find/get function. Frontend can do the job of creating a pdf/doc file out of those details. This file can be sent as an email attachment to the customer.

Let’s see how to send the email using Hypi’s serverless function!

We can use Mailgun service to send the emails programmatically.

****Please note you need to sign up for MailGun Services to send emails.

i) Create an OpenWhisk action using below JavaScript code. Invoke the action and configure the Hypi’s serverless function to send the Email.

require('mailgun-js');
function main(args) {
    return new Promise(function (resolve, reject) {
        //Your api key, from Mailgun's Control Panel
        var api_key = 'c2e4684382525364004c8d7e425722f8-64574a68-2bfc27ed';
        //Your domain, from the Mailgun Control Panel
        var domain = 'sandbox610e68e5b1884eaaa6f85026860b0a6b.mailgun.org';
        //Your sending email address
        var from_who = 'Your_Email_ID';
        // Store the invoice file in the current directory
        var path = require("path");
        var fp = path.join(__dirname, 'invoice.txt');

        var mailgun = require('mailgun-js')({ apiKey: api_key, domain: domain });
        var data = {
            from: from_who,
            to: args.toid,
            subject: 'Confirmation email',
            text: "You've got an Invoice from Hypi!",
            attachment: fp
        };
        mailgun.messages().send(data, function (error, body) {
            console.log(body);
        });
        var result = 1;
        resolve({ result: 'Success' });
    });
}
exports.main = main

Put the above code into a file called index.js. Then in the same directory run following command to create node_modules directory

npm install mailgun-js -g --prefix ./mailgun/node_modules

Add them to a zip file. Invoice.txt is the invoice file to be sent as an attachment.

zip -r action.zip index.js node_modules invoice.txt

Now, create the action using the zip file.

>wsk action create emailconfirm --kind nodejs:12 action.zip
ok: created action emailconfirm

>wsk action invoke emailconfirm --param toid asa@hypi.io --result
{
    "result": "Success"
}

Use the OpenWhisk Action in Hypi’s Serverless function.

#schema
type Query {
sendConfirmationEmail(toid: String): Json @tan(type:OpenWhisk, name:"emailconfirm")
}

#query
{
  sendConfirmationEmail(toid:"asa@hypi.io")
}

#result
{
  "data": {
    "sendConfirmationEmail": {
      "result": "Success"
    }
  }
}

This way you can build your own Invoice Creation App using Hypi’s low code APIs.
You may explore further to develop your own bookkeeping use cases (Like Quickbooks!)

Hypi is happy to help with the implementation!