Skip to main content Skip to footer

How to Build a Node.js Inventory and Invoice Billing Application

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.

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

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.

Ready to Start Building Inventory and Invoice Billing Apps? Download ActiveReportsJS Today!

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

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

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

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

This will bring up the New Data Source window:

Node.js Invoice Billing App

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

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

This will bring up the New Data Set window:

Node.js Invoice Billing App

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

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

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

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

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

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

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

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:

Element

Relevant Properties

Header

Title: “Sales Volume by Month”

X Axis

Title: “Month”

Y Axis

Title: “Volume ($)”

Major Interval: 20,000

Min: 0

Max: 150,000

Plot

Label Text Template: “Value Field Value”

Tooltip Template: “Value Field Value”

When complete, your report should look like so:

Node.js Inventory App

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

Node.js Inventory App

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

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:

Element

Relevant Properties

Table

Name: “tableMonths”

Data Set Name: “Orders”

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

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

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

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

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

Node.js Inventory App

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:

Element

Relevant Properties

Table

Name: “tableOrders”

Data Set Name: “Orders”

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

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.

Element

Relevant Properties

Table

Name: “tableOrderTotal”

Data Set Name: “OrderDetails”

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

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

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

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:

Element

Relevant Properties

Table

Name: “tableOrderDetails”

Data Set Name: “OrderDetails”

Header Row

Column 1 Value: Item

Column 2 Value: Qty

Column 3 Value: Unit Price

Column 4 Value: Discount

Column 5 Value: Discounted Price

Column 6 Value: Total Price

Details Row

Cell 1 Formula: {Lookup(ProductId, ProductId, ProductName, "Products")}

Cell 2 Formula: {Quantity}

Cell 3 Formula: {UnitPrice}

Cell 4 Formula: {Discount}

Cell 5 Formula: {UnitPrice - UnitPrice * Discount}

Cell 6 Formula: {Subtotal}

Footer Row

Cell 1 Formula: TOTAL INVOICE VALUE

Cell 2 Formula: {SUM(Subtotal)}

Filter

Filter Expression: {OrderId}

Operator: =

Value: OrderId

When complete, the table should look like so:

Node.js Inventory App

Clicking Preview will show the new table:

Node.js Inventory App

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

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

Select the tableOrderDetails table and make it collapsible too:

Node.js Inventory App

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

Node.js Inventory App

Node.js Inventory App

Node.js Inventory App

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:

Element

Value

Second Row

Column 1: Contact Name:

Merged Cells: {Lookup(Lookup(OrderId, OrderId, CustomerId, "Orders"), CustomerId, CompanyName, "Customers")}

Third Row

Column 1: Order Date:

Merged Cells: {DateTime.Parse(Lookup(OrderId, OrderId, OrderDate, "Orders")).ToString("dd/MM/yyyy")}

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

Node.js Inventory App

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:

Column Header

Sort Expression

Item

{Lookup(ProductId, ProductId, ProductName, "Products")}

Qty

{Quantity}

Unit Price

{UnitPrice}

Discount

{Discount}

Discounted Price

{UnitPrice - UnitPrice * Discount}

Total Price

{Subtotal}

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

Sort the order by Total Price:

Node.js Inventory App

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

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

Node.js Inventory App

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. Happy coding!

Ready to Start Building Inventory and Invoice Billing Apps? Download ActiveReportsJS Today!

comments powered by Disqus