This guide was compiled from multiple open-source VB.NET billing projects and academic research. All source code mentioned is available for free download from their respective repositories.
Formatting invoices for standard receipt printers. 2. Database Schema Design
Imports System.Data.SqlClient Imports System.Configuration Public Class frmBilling ' Define the connection string (Modify security parameters as needed for production) Private ReadOnly connString As String = "Server=(localdb)\MSSQLLocalDB;Database=BillingDB;Trusted_Connection=True;" ' Temporary runtime storage for the selected Product's ID Private currentProductID As Integer = 0 ''' ''' Form Load event. Initializes structural components. ''' Private Sub frmBilling_Load(sender As Object, e As EventArgs) Handles MyBase.Load InitializeInvoiceGrid() LoadCustomers() GenerateInvoiceNumber() ResetProductInputs() End Sub ''' ''' Explicitly creates columns for the DataGridView to avoid structural mismatch. ''' Private Sub InitializeInvoiceGrid() With dgvItems .Columns.Clear() .Columns.Add("ProductID", "Product ID") .Columns.Add("ProductCode", "Item Code") .Columns.Add("ProductName", "Item Description") .Columns.Add("UnitPrice", "Unit Price") .Columns.Add("Quantity", "Qty") .Columns.Add("LineTotal", "Total Amount") ' UI Optimization .Columns("ProductID").Visible = False .Columns("ProductName").AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill .SelectionMode = DataGridViewSelectionMode.FullRowSelect .AllowUserToAddRows = False End With End Sub ''' ''' Hydrates the Customer dropdown selection. ''' Private Sub LoadCustomers() Dim query As String = "SELECT CustomerID, CustomerName FROM Customers" Using conn As New SqlConnection(connString) Using cmd As New SqlCommand(query, conn) Dim dt As New DataTable() Try conn.Open() Using reader As SqlDataReader = cmd.ExecuteReader() dt.Load(reader) End Using cmbCustomer.DataSource = dt cmbCustomer.DisplayMember = "CustomerName" cmbCustomer.ValueMember = "CustomerID" Catch ex As Exception MessageBox.Show($"Database Error loading customers: ex.Message", "DAL Error", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Using End Using End Sub ''' ''' Generates a unique, trackable string sequence for the current transaction instance. ''' Private Sub GenerateInvoiceNumber() Dim timestamp As String = DateTime.Now.ToString("yyyyMMddHHmmss") txtInvoiceNumber.Text = $"INV-timestamp" End Sub ''' ''' Fires when a product code is entered or scanned via barcode reader. ''' Private Sub txtProductCode_KeyDown(sender As Object, e As KeyEventArgs) Handles txtProductCode.KeyDown If e.KeyCode = Keys.Enter Then e.SuppressKeyPress = True ' Stop systemic beep sound on enter If String.IsNullOrWhiteSpace(txtProductCode.Text) Then Exit Sub Dim query As String = "SELECT ProductID, ProductName, UnitPrice FROM Products WHERE ProductCode = @ProductCode" Using conn As New SqlConnection(connString) Using cmd As New SqlCommand(query, conn) cmd.Parameters.AddWithValue("@ProductCode", txtProductCode.Text.Trim()) Try conn.Open() Using reader As SqlDataReader = cmd.ExecuteReader() If reader.Read() Then currentProductID = Convert.ToInt32(reader("ProductID")) txtProductName.Text = reader("ProductName").ToString() txtUnitPrice.Text = Convert.ToDecimal(reader("UnitPrice")).ToString("F2") txtQuantity.Focus() Else MessageBox.Show("Product not found in system storage.", "Inventory Check", MessageBoxButtons.OK, MessageBoxIcon.Warning) ResetProductInputs() End If End Using Catch ex As Exception MessageBox.Show($"Error pulling inventory details: ex.Message", "Query Error", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Using End Using End If End Sub ''' ''' Validates UI input state and appends entry record to active item grid list. ''' Private Sub btnAddToGrid_Click(sender As Object, e As EventArgs) Handles btnAddToGrid.Click If currentProductID = 0 OrElse String.IsNullOrWhiteSpace(txtProductName.Text) Then MessageBox.Show("Please select or scan a valid product first.", "Input Missing", MessageBoxButtons.OK, MessageBoxIcon.Warning) Exit Sub End If Dim qty As Integer If Not Integer.TryParse(txtQuantity.Text, qty) OrElse qty <= 0 Then MessageBox.Show("Please input a valid positive integer quantity.", "Input Error", MessageBoxButtons.OK, MessageBoxIcon.Warning) Exit Sub End If Dim price As Decimal = Convert.ToDecimal(txtUnitPrice.Text) Dim total As Decimal = price * qty ' Append items directly to the UI Matrix dgvItems.Rows.Add(currentProductID, txtProductCode.Text, txtProductName.Text, price, qty, total) CalculateInvoiceTotals() ResetProductInputs() End Sub ''' ''' Iterates grid data records to maintain computational totals real-time. ''' Private Sub CalculateInvoiceTotals() Dim subTotal As Decimal = 0 For Each row As DataGridViewRow In dgvItems.Rows If Not row.IsNewRow Then subTotal += Convert.ToDecimal(row.Cells("LineTotal").Value) End If Next Dim taxRate As Decimal = 0 Decimal.TryParse(txtTaxRate.Text, taxRate) Dim taxAmount As Decimal = subTotal * (taxRate / 100) Dim grandTotal As Decimal = subTotal + taxAmount lblSubTotal.Text = subTotal.ToString("F2") lblTaxAmount.Text = taxAmount.ToString("F2") lblGrandTotal.Text = grandTotal.ToString("F2") End Sub Private Sub txtTaxRate_TextChanged(sender As Object, e As EventArgs) Handles txtTaxRate.TextChanged CalculateInvoiceTotals() End Sub Private Sub ResetProductInputs() currentProductID = 0 txtProductCode.Clear() txtProductName.Clear() txtUnitPrice.Clear() txtQuantity.Text = "1" txtProductCode.Focus() End Sub ''' ''' Implements an ACID-compliant transaction workflow to save both master and detail layers. ''' Private Sub btnSavePrint_Click(sender As Object, e As EventArgs) Handles btnSavePrint.Click If dgvItems.Rows.Count = 0 Then MessageBox.Show("Cannot process an empty billing statement.", "Validation Halt", MessageBoxButtons.OK, MessageBoxIcon.Warning) Exit Sub End If Using conn As New SqlConnection(connString) conn.Open() ' Initialize SQL transaction pipeline for reliable multi-table commitment Using sqlTran As SqlTransaction = conn.BeginTransaction() Dim masterQuery As String = "INSERT INTO Invoices (InvoiceNumber, CustomerID, SubTotal, TaxRate, TaxAmount, GrandTotal) " & "VALUES (@InvNum, @CustID, @Sub, @TaxR, @TaxA, @Grand); SELECT SCOPE_IDENTITY();" Dim detailQuery As String = "INSERT INTO InvoiceDetails (InvoiceID, ProductID, Quantity, UnitPrice) " & "VALUES (@InvID, @ProdID, @Qty, @Price);" Dim stockQuery As String = "UPDATE Products SET StockQuantity = StockQuantity - @Qty WHERE ProductID = @ProdID" Try Dim newInvoiceID As Integer = 0 ' 1. Persist Master Record Using cmdMaster As New SqlCommand(masterQuery, conn, sqlTran) cmdMaster.Parameters.AddWithValue("@InvNum", txtInvoiceNumber.Text.Trim()) cmdMaster.Parameters.AddWithValue("@CustID", cmbCustomer.SelectedValue) cmdMaster.Parameters.AddWithValue("@Sub", Convert.ToDecimal(lblSubTotal.Text)) cmdMaster.Parameters.AddWithValue("@TaxR", Convert.ToDecimal(If(String.IsNullOrEmpty(txtTaxRate.Text), "0", txtTaxRate.Text))) cmdMaster.Parameters.AddWithValue("@TaxA", Convert.ToDecimal(lblTaxAmount.Text)) cmdMaster.Parameters.AddWithValue("@Grand", Convert.ToDecimal(lblGrandTotal.Text)) newInvoiceID = Convert.ToInt32(cmdMaster.ExecuteScalar()) End Using ' 2. Loop & Persist Line Items + Adjust Inventory Stock levels For Each row As DataGridViewRow In dgvItems.Rows Dim pID As Integer = Convert.ToInt32(row.Cells("ProductID").Value) Dim qty As Integer = Convert.ToInt32(row.Cells("Quantity").Value) Dim uPrice As Decimal = Convert.ToDecimal(row.Cells("UnitPrice").Value) ' Insert details record Using cmdDetail As New SqlCommand(detailQuery, conn, sqlTran) cmdDetail.Parameters.AddWithValue("@InvID", newInvoiceID) cmdDetail.Parameters.AddWithValue("@ProdID", pID) cmdDetail.Parameters.AddWithValue("@Qty", qty) cmdDetail.Parameters.AddWithValue("@Price", uPrice) cmdDetail.ExecuteNonQuery() End Using ' Deduct Stock allocation Using cmdStock As New SqlCommand(stockQuery, conn, sqlTran) cmdStock.Parameters.AddWithValue("@Qty", qty) cmdStock.Parameters.AddWithValue("@ProdID", pID) cmdStock.ExecuteNonQuery() End Using Next ' All stages complete without failure flags sqlTran.Commit() MessageBox.Show($"Invoice txtInvoiceNumber.Text successfully committed to ledger.", "Transaction Success", MessageBoxButtons.OK, MessageBoxIcon.Information) ClearFormToDefault() Catch ex As Exception ' Error encountered, roll state back to prevent fragmented/orphaned logs sqlTran.Rollback() MessageBox.Show($"Critical Database Transaction Exception: ex.Message", "Transaction Rollback Executed", MessageBoxButtons.OK, MessageBoxIcon.Error) End Try End Using End Using End Sub Private Sub ClearFormToDefault() dgvItems.Rows.Clear() lblSubTotal.Text = "0.00" lblTaxAmount.Text = "0.00" lblGrandTotal.Text = "0.00" txtTaxRate.Text = "0" GenerateInvoiceNumber() ResetProductInputs() End Sub End Class Use code with caution. Technical Analysis of the Code 1. Database Transaction Security (ACID Principles)
For professional reports, use or RDLC Reports (built into Visual Studio). vb.net billing software source code
Track customer profiles and billing history.
VB.NET offers several advantages for developing financial and administrative software:
Developing a robust billing and invoicing system is a foundational requirement for many enterprise desktop applications. Visual Basic .NET (VB.NET) paired with Windows Forms (WinForms) remains a highly efficient framework for building these data-centric business applications due to its rapid application development (RAD) capabilities and native Windows integration. This guide was compiled from multiple open-source VB
This specialized billing system, featured in academic research, was developed for bar owners to automatically calculate customer bills after sales. It was originally coded using VB.NET 2012 with MS Access 2003 as the database. Key characteristics include sign-in/sign-out, product inventory management, point-of-sale transactions, sales receipt generation, sales records listing, and user management.
Your preferred (SQL Server, MySQL, or MS Access) If you need barcode scanner integration
Building a Complete VB.NET Billing Software: Architecture, Source Code, and Implementation ''' Private Sub frmBilling_Load(sender As Object, e As
This example will create a simple form with the following features:
While Access databases are common in older VB projects, you want a source code that utilizes Microsoft SQL Server . It handles large volumes of transactions and ensures your data integrity—crucial for financial records.
You can modify the code to fit the specific needs of a business, such as specialized tax calculations or specific reporting formats.
Next steps you can take right now
Below is the structured production source code for the billing software. It utilizes standard System.Data.OleDb for database portability, making it compatible with MS Access databases ( .accdb ). Data Access Module ( modDatabase.vb )