How to Build a Node.js Inventory and Invoice Billing Application
Tags: webdev, devops, javascript, tutorial
Published: 2023-06-20 18:56:42

---
canonical_url: https://developer.mescius.com/blogs/how-to-build-a-node-js-inventory-and-invoice-billing-application
description: Learn how to build a responsive, web-based Node.js inventory and invoice billing application. See more from ActiveReportsJS today.
---
When running a business these days, it’s important to have access to your order, inventory, and financial data, regardless of location. That’s why it’s essential to have on-screen reports that are both flexible and interactive, as well as adaptable to a variety of screen resolutions. Doing so lets you stay on top of your business’s performance and make informed decisions whenever and wherever you need to.

ActiveReportsJS allows you to build responsive web applications with highly interactive reporting capabilities that work in any browser and support desktop and mobile devices.

In this article, we’ll show you how to build a responsive Node.js inventory management system, allowing users to track order reports using ActiveReportsJS. We’ll be covering the following topics:

*   Designing the Report Title
*   Defining Data Access in Node.js
*   Using Calculated Fields
*   Adding a Chart Control
*   Adding a Table Control
*   Defining Sub-Tables
*   Adding Drill-Down Functionality
*   Adding Sorting Columns to Tables
*   Creating the Node.js Invoice Application

If you’d like to follow along with the completed report and application, you can find the repository [here](https://github.com/joel-p-parks/ARJS-InventoryInvoice-Nodejs).

## Building a Web-Based Sales Report

For our scenario, we have a client named ACME Inc., who has contracted us to build them a sales report. The request comes with a mockup of the report, which looks like this:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/q3tog4h1/chart_complete.png?width=492&height=116&mode=max)

To create enterprise-level reports like the one above, GrapeCity offers the ActiveReportsJS Designer. This intuitive tool helps you configure your report to fetch data and render it using visual elements like tables, bar charts, pie charts, and more.

The ActiveReportsJS Designer stores report definitions in a special JSON format and saves them in files with the **.rdlx-json** extension.

## Designing the Report Title

To create a new report, in the Designer, open the **File** menu n the Designer toolbar and select the **Continuous Page Layout** report option:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/51yjr1zi/new_report.png?width=500&height=237.43500866551128)

Now that we have a new report, clicking the hamburger button on the left will expand the control panel. From here, you can drag and drop controls onto your report canvas to include them in the report:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/cwkjhwoi/control_panel.png?width=500&height=320.4747774480712)

For our report, we will have a container at the top that holds the logo image and a label. Drag and drop a container control from the control panel onto the report canvas, then drag and drop an image and textbox control into the container control on the report canvas.

To link an image to the image control, you can either pull the image from an external source, such as a URL or database or embed the image from a local file. Our image will be the ACME Inc. logo.

For the textbox, you can customize the font, size, and color as you see fit. For the title text, we’ll set this to **Monthly Orders**.

When complete, your title should look something like this:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/djrjkycn/report_title.png?width=500&height=117.5771971496437)

## Defining Data Access in Node.js

The ActiveReportsJS Designer manages data connections through two types of entities: data sources and data sets.

A data source works as a connection to external data storage, such as a URI or JSON file or a JSON document that can be embedded in the report.

A data set is an intermediate element that fetches data from the data source and binds it to fields in the report data model. You can also define calculated fields, which transform the source data using expressions. The data set fields can then be used by the report controls.

Our inventory invoice software will access data through an external API located at an HTTP service, returning results in JSON format. The report will show a variety of order information based on “live” data from that service.

To define access to customer data in your report, start by selecting the **Data Sources** tab and click the **Add** button in the “Data Sources” section:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/vz1fj4ut/data_source_panel.png?width=373.3583489681051&height=500)

This will bring up the **New Data Source** window:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/0bybg3n0/data_source_window.png?width=500&height=378.4994400895857)

This window names the data source, sets the data provider, and adds any additional HTTP header or parameters required.

When adding your data provider, you can choose between remote JSON or embedding your JSON into the report via a local file. We’ll load our data for this inventory invoice application from a remote source. When everything is added, click the **Save** button to save your data source.

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/3wclncuw/data_source_complete.png?width=500&height=377.93952967525195)

**Note:** A data source is a simple connection configuration; no request has been made yet.

Now that we have created a data source, we need to create a data set that uses that source to retrieve the data. To create a data set, click on the **Plus** button that appears next to our data source:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/y5vnpap1/add_data_set.png?width=368.6200378071834&height=500)

This will bring up the **New Data Set** window:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/tqvbg4k5/data_set_window.png?width=500&height=487.41610738255036)

We usually need to set two properties here: the **Uri/path** and the **Json Path**. The Uri/path tells ActiveReportsJS where to look for the JSON file once reaching the API endpoint, and the Json Path is used to tell our Node.js invoice application what part of the JSON we want to grab.

For the Uri/path, we’ll use **_/Customers_ **to return data on our customers. In our case, we’ll want to grab all entries, so we’ll pass **$.*** as the Json path.

Finally, we need to validate the data source so that ActiveReportsJS can confirm that it can retrieve the data. You’ll know that your data source was validated if you see that the **Database Fields** array is populated with values:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/swnj2sly/data_set_complete.png?width=500&height=445.067264573991)

We will need another data source for our application, which we’ll use to retrieve data on orders placed through the node.js invoice app. Your second data source should look like so:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/vwnlwviv/data_source_two_complete.png)

We’ll need two more data sets: one based on the NWAPI data source, using **_/Products_ **as the Uri/path, and the other based on the NWOData source, using **_/Orders_ **as the Uri/path. For the **Orders** data set, also set the Json path to **$.value[*]**.

When set up, the data panel should look like so:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/qshfnywj/data_panel_setup.png?width=444.015444015444&height=500)

## Using Calculated Fields

Occasionally, you’ll need to transform one or more source fields into a new calculated field to be used in the report. ActiveReportsJS offers an expression language with rich built-in functions to meet this need.

In this example, let’s transform the OrderDate field into a “month/year” format. You must add a custom field to the list of automatically bound database fields to achieve this.

Edit the **Orders** data set and expand the **Calculated Fields** section; this is where we can add our new calculated field. Name the field **MonthYear** and set the value as **{DateTime.Parse(OrderDate).ToString("MM/yyyy")}**:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/abeaobnz/calculated_field.png?width=500&height=154.10573678290214)

Create a new data set named **OrderDetails** based on the NWOData source; set the Uri/path to **_/OrderDetails_ **and the Json path to **$.value[*]**.

Note that the OrderDetails data set does not include a field for a total value per item. This value is likely to be required more than once in your report. Therefore, you’ll have to calculate this value every time it’s needed or create a new calculated field. The latter option is way more efficient.

Expand the **CalculatedFields** section of the OrderDetails data set, name the field **Subtotal** and set the value as **{Round(100 * (UnitPrice - UnitPrice * Discount) * Quantity) / 100}**.

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/jroilinq/calculated_field_two.png?width=500&height=156)

## Adding a Chart Control

Now that we’ve set up several data sources, it's time to incorporate them into the report; to do so, we will add a chart. Dragging and dropping a chart control from the control panel onto the report will bring up the chart wizard:

![Node.js Invoice Billing App](https://files.grapecity.com/gc-website-media/kbiacxvk/chart_wizard.png?width=426.4069264069264&height=500)

Ensure the data set is set to use our **OrderDetails** set and click the **Next** button.

Now we can set our data and category fields. For “Data Values”, add a new field. Set the name to **{Subtotal}** and the aggregate to **Sum**. Then, for “Data Categories”, set the field to **{Lookup(OrderId, OrderId, MonthYear, “Orders”)}**. It should look like so:

![Chart Wizard Fields](https://files.grapecity.com/gc-website-media/dxupudnp/chart_wizard_fields.png?width=474.481658692185&height=500)

Click **Next** and then click **Finish**. The last thing to do before we view the chart is make some final changes to properties across various elements of the chart.

To modify elements of the chart, you only need to make sure you’re viewing the properties window instead of the data window and then click on an element of the chart. The properties window will update to show all of the properties of the currently-selected element. Define the chart properties as follows:

![Chart properties](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9y796442x29y6fbp9jl6.png)

When complete, your report should look like so:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/q3tog4h1/chart_complete.png?width=500&height=266.7464114832536)

Clicking **Preview** will show us the report with data being loaded:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/a5dl1xo1/chart_preview.png?width=500&height=253.89221556886224)

## Adding a Table Control

In addition to the chart, we want to allow users to view more data in our Node.js invoice app. Let’s create a tabular view of the month-by-month order volume. Drag and drop a table control from the control panel to the report beneath the chart:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/nj1ltjsu/base_table.png?width=500&height=113.55311355311355)

By default, an ActiveReportsJS table is created with three columns and three rows. The top row serves as the header row, the middle row is our details row and holds our data, and the bottom row is the footer row. Report authors can resize the table, add or remove rows and columns, define multiple headers and footers, and so on.

Now, select the table, navigate to the properties panel, and define the properties as follows:

![properties](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r6ypiy92jgn1qry7z2j2.png)

Then remove the header and footer rows of the table, as these aren’t needed. This is done by right-clicking a cell in the row that you want to delete, selecting the **Row** option, and clicking **Delete Row**:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/1v2fdbwv/table_delete_row.png?width=500&height=381.4866760168303)

Now, merge the cells for the detail row. This is done by selecting the cells that you want to merge, right-clicking one of the selected cells, selecting the **Cells** option from the menu, and clicking **Merge Cells**:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/ydtekckc/table_merge_cells.png?width=500&height=296.25)

Now select the newly merged cell, set its text box name to **txtMonth**, and set its value to **{MonthName(Month(OrderDate))}/{Year(OrderDate)}**:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/3i3ammdd/textmonth_value.png?width=500&height=146.2715105162524)

Finally, you have to define the table grouping. This can be done by selecting the cell and selecting **<Details Group>** from the popup menu.

Set the first level of the group with the formula **{Year(OrderDate)}** and the second level as **{Month(OrderDate)}**:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/mnfp4ezw/details_group.png?width=337&height=234)

The new table displays the first level of data in the tabular section:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/yxblobd3/table_first_level_preview.png?width=500&height=164.12661195779603)

Now we’ll start adding more levels of data. Create a new row beneath our current row, remove the header and footer rows, merge the detail row, and then drag and drop another table control into the new large cell.

Define the new table’s properties as follows:

![table properties](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qw218rsx1uqtqa9fgfei.png)

Now select the newly merged cell, set its text box name to **txtOrderId**, and set its value to the **Order ID: {OrderId}**. Once this is set up, preview the report to see the results:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/vucbatki/table_second_level_preview.png?width=128&height=200)

Notice that the **tableOrders** table is at the second level in your report; it details the orders placed within a particular month.

## Defining Sub-Tables

Now that we’re displaying orders by month, it’s time to add an order details section for each of the orders that come through our inventory invoice application.

Add a new detail row beneath the **OrderId** detail row, merge the cells, and put another table within that detail row. This time, instead of removing the header and footer rows, remove the detail and footer row, leaving the header row. Next, instead of merging all three cells into one, merge the center and right cells into one and leave the left cell as its own cell.

![new table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zcib6g6ok7eccynpszht.png)

Define the left cell formula as **Total:**. For the merged cell, use the properties panel to set the **Cell Alignment** to **Left** and its **format** property to **Currency**, and set the merged cell formula as **{SUM(Subtotal)}**:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/udzapn2n/table_second_subgrid.png?width=500&height=65.75463371579876)

Select the **tableOrderTotal** table in the Explorer and expand the **Filters** property. Click **Add Item** and add a new filter criteria with the following fields:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/a25nk4kp/table_filter.png?width=434&height=181)

As you can see, the new tableOrderTotals table is based on the OrderDetails data set. The total value is obtained by filtering the order details by the OrderId of the tableOrder row, and by summing up the Subtotal field values.

Clicking **Preview** will display the updated table:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/nitbsko2/table_third_level_preview.png?width=272&height=293)

Finally, we’ll create a table representing order items for our invoices.

Create a new detail row in the tableOrders table, then create a new table inside the new detail row called **tableOrderDetails**. Configure the table as follows:

![tableOrders table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rna4ubexp6in7gsjoxso.png)

When complete, the table should look like so:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/tnwn5fu3/table_third_subgrid.png?width=500&height=114.76510067114094)

Clicking **Preview** will show the new table:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/u31hoex0/table_subgrid_implementation_preview.png?width=500&height=252.6595744680851)

Before we move on, we will do a little styling to improve the table's look. Here’s what the finished version looks like:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/bt5nf3ga/table_subgrid_implementation_final.png?width=500&height=271.6216216216216)

## Adding Drill-Down Functionality

Now let’s add drill-down functionality to the report, allowing us to keep the **tableOrders** and **tableOrderDetails** tables collapsed until the user expands them.

Select the tableOrders table and change the **Hidden** and **Toggle Item** properties as follows:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/eemnrj5e/month_visibility.png?width=379&height=108)

Select the tableOrderDetails table and make it collapsible too:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/m04bxraf/orderid_visibility.png?width=382&height=104)

Now we can expand and collapse the detail levels by clicking the +/- symbols:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/pzgf4mfm/table_collapsed.png?width=500&height=26.347305389221553)

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/ys3hhebb/table_expand_one.png?width=500&height=54.36081242532856)

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/q4mnsaiq/table_expand_two.png?width=500&height=146.5005931198102)

Next, let’s add some more details to the reports of our Node.js invoice application.

Add four new rows above the existing header row in the **tableOrderDetails** table. The top and bottom of these four rows will serve as a buffer, and the middle two rows will hold the data we want to display.

In the second and third rows that were added, leave the far-left cell of each row by themselves, and merge the rest of the cells for each row. Then, fill out the rows as follows:

![tableOrderDetails table](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2ovxy9xo0v1wwjyoejbx.png)

Click **Preview,** and you can see the customer’s name and order date added to the invoice:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/cv5mtxsk/customer_order_labels.png?width=500&height=203.21811680572108)

## Adding Sorting Columns to Table

The last thing we’ll add to the report is the ability to sort the order details' columns.

Select each header cell and fill out the Sort Expression field under the User Sort section with the following formulas:

![formulas](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u1cbcba1n2a86p17g95w.png)

Click **Preview,** and you can now see the sort icons next to the column headers; sort the order items by Quantity:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/bn2ktxo5/quantity_sort.png?width=500&height=100.47562425683711)

Sort the order by Total Price:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/ocldznoq/total_price_sort.png?width=500&height=99.17355371900827)

## Creating the Node.JS Invoice Application

Now with the report defined, we can create our inventory invoice application. This application will need a responsive web display that looks good on both desktop and mobile devices. ActiveReportsJS offers this capability by default.

The sample application will use Node.js, a JavaScript runtime environment, to execute the web app on the server side.

To get started, create a new folder called **InventoryInvoice** and open it in your preferred IDE. Then, in the command line, run:

```
    npm init
```

This will run you through setting up your **package.json** file, which will be used to build your application. Once your file has been generated, run the following two commands:

```
    npm install express
    npm install @grapecity/activereports
```

This will install Express, a framework for Node.js, and ActiveReports, which we’ll use to display the invoices.

Now that we have Express installed, we need to put it to use. Create a new file in the **InventoryInvoice** folder named **index.js**. This file will use Express to serve our Node.js inventory invoice application.

Inside the index.js file, add the following code:

```
    const express = require('express'); //import Express.js module
    const app = express();
    const path = require('path'); 
    app.use(express.static(path.join(__dirname)));

    app.listen(3000, () => {
        console.log(`Example app listening on port 3000`)
    })
```

Now, its time for a quick explanation of what we’re doing here:

*   The first two lines of code include Express in our server and give us a variable to use to reference Express methods and properties.
*   The third line creates a variable that leads to the relative path of the folder, and the fourth line tells Express that we want to use this path as the static path of our application.
*   Lines six through eight use Express to start the application; here, we’re telling it to run on port 3000, and when it starts running, we log a message to the terminal.

And that’s Express at a very basic level! Now that we have a server that we can start to launch the inventory invoice software, it's time to create a page to serve to the user.

Create a new file in the **InventoryInvoice** folder and name it **index.html**. Once created, insert the following code:

```
    <html>
       <head>
        <meta charset="utf-8" />
        <title>ActiveReportsJS Viewer</title>
        <meta name="viewport" content="width=device-width, initial-scale=1">

        <link rel="stylesheet" href="node_modules/@grapecity/activereports/styles/ar-js-ui.css" />
        <link rel="stylesheet" href="node_modules/@grapecity/activereports/styles/ar-js-viewer.css" />
        <script type="text/javascript" src="node_modules/@grapecity/activereports/dist/ar-js-core.js"></script>
        <script type="text/javascript" src="node_modules/@grapecity/activereports/dist/ar-js-viewer.js"></script>
        <style>
            #arjs-viewer {
                width: 100%;
                height: 100vh;
            }
        </style>
    </head>
    <body onload="load()">
        <div id="arjs-viewer"></div>
        <script>
            function load() {
                const viewer = new ActiveReports.Viewer('#arjs-viewer');
                viewer.open('MonthlyOrders.rdlx-json');
            }
        </script>
    </body>
    </html>
```

There are a few things to go over here. First, we’re including four files in our HTML file; **ar-js-ui.css**, **ar-js-viewer.css**, **ar-js-core.js**, and **ar-js-viewer.js**. The CSS files are the core CSS file for ActiveReportsJS and the CSS file used to style the viewer. The JS files are the same; a core JS file and a JS file for the viewer.

Second, for the HTML, we’re only using a single line to create the ActiveReportsJS Viewer. All we need is a single div with an ID that we can use to associate the viewer with the div.

Third, in the JavaScript, once the page loads, we’re creating a new ActiveReports.Viewer control, associating it with our div, and then telling it to open our report.

Finally, we’re including a small amount of CSS so that the viewer takes up the entirety of the screen.

Once this is done, all you need to do is move your report into the **InventoryInvoice** folder and run the following command to start your Node.js inventory invoice app:

```
    node index.js
```

Navigate to localhost:3000, and you should see and be able to interact with the report that you’ve created:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/f2vnzyw5/viewer_report.png?width=500&height=254.1070482246953)

The ActiveReportsJS Viewer component is also responsive; it is rendered appropriately on various devices in a wide range of screen sizes. You can use the developer tools available in your web browser to quickly emulate the various mobile devices, screen sizes, and page orientations:

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/ri4lbtub/viewer_tablet.png?width=500&height=346.3829787234043)

![Node.js Inventory App](https://files.grapecity.com/gc-website-media/b4td4lra/viewer_phone.png?width=500&height=278.3661119515885)

## Final Notes

And with that, we’re done! This article provided a hands-on approach to creating a monthly inventory invoice report using GrapeCity’s ActiveReportsJS Designer. We went over how to aggregate information to create a sales chart grouped by months, as well as an interactive, tabular report with drill-down functionality that consolidates sales by month and order ID.

If you would like to see the completed application and report, you can find it [here](https://github.com/joel-p-parks/ARJS-InventoryInvoice-Nodejs). Happy coding!