Medbasin Evaporation Data
Laboratory of Reclamation Works & Water Resources Management
Misc Files
mime-type/not-avalible
10/20/2021
: Create unlimited professional invoices with unique reference numbers.
Imports System.Data.SqlClient Public Class FormBilling Private SelectedProductID As Integer = 0 Private Sub FormBilling_Load(sender As Object, e As EventArgs) Handles MyBase.Load GenerateInvoiceNumber() ConfigureDataGridView() ClearItemInputs() End Sub Private Sub ConfigureDataGridView() dgvItems.Columns.Clear() dgvItems.Columns.Add("Code", "Product Code") dgvItems.Columns.Add("Name", "Product Name") dgvItems.Columns.Add("Price", "Unit Price") dgvItems.Columns.Add("Qty", "Quantity") dgvItems.Columns.Add("Total", "Line Total") dgvItems.Columns.Add("ID", "ProductID") dgvItems.Columns("ID").Visible = False ' Hidden system column End Sub Private Sub GenerateInvoiceNumber() txtInvoiceNo.Text = "INV-" & DateTime.Now.ToString("yyyyMMddHHmmss") End Sub ' Fetches product details when an operator types or scans a Product Code Private Sub txtProductCode_KeyDown(sender As Object, e As KeyEventArgs) Handles txtProductCode.KeyDown If e.KeyCode = Keys.Enter AndAlso Not String.IsNullOrWhiteSpace(txtProductCode.Text) Then Using conn As SqlConnection = GetConnection() Dim query As String = "SELECT ProductID, ProductName, UnitPrice FROM Products WHERE ProductCode = @Code" Using cmd As New SqlCommand(query, conn) cmd.Parameters.AddWithValue("@Code", txtProductCode.Text.Trim()) Using reader As SqlDataReader = cmd.ExecuteReader() If reader.Read() Then SelectedProductID = Convert.ToInt32(reader("ProductID")) txtProductName.Text = reader("ProductName").ToString() txtUnitPrice.Text = Convert.ToDecimal(reader("UnitPrice")).ToString("F2") txtQuantity.Focus() Else MsgBox("Product not found!", MsgBoxStyle.Exclamation, "Invalid Code") ClearItemInputs() End If End Using End Using End Using e.SuppressKeyPress = True End If End Sub ' Adds the configured line item to the visual DataGridView matrix Private Sub btnAddItem_Click(sender As Object, e As EventArgs) Handles btnAddItem.Click Dim qty As Integer = 0 Dim price As Decimal = 0 If SelectedProductID = 0 OrElse Not Integer.TryParse(txtQuantity.Text, qty) OrElse qty <= 0 Then MsgBox("Please enter a valid product and quantity.", MsgBoxStyle.Warning, "Input Validation") Exit Sub End If Decimal.TryParse(txtUnitPrice.Text, price) Dim lineTotal As Decimal = qty * price ' Append row to grid dgvItems.Rows.Add(txtProductCode.Text, txtProductName.Text, price, qty, lineTotal, SelectedProductID) CalculateInvoiceTotals() ClearItemInputs() txtProductCode.Focus() End Sub 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("Total").Value) End If Next Dim taxRate As Decimal = 0 Dim discount As Decimal = 0 Decimal.TryParse(txtTaxRate.Text, taxRate) Decimal.TryParse(txtDiscount.Text, discount) Dim taxAmount As Decimal = subTotal * (taxRate / 100) Dim grandTotal As Decimal = (subTotal + taxAmount) - discount lblSubTotal.Text = subTotal.ToString("F2") lblGrandTotal.Text = grandTotal.ToString("F2") End Sub Private Sub ClearItemInputs() SelectedProductID = 0 txtProductCode.Clear() txtProductName.Clear() txtUnitPrice.Clear() txtQuantity.Clear() End Sub ' Saves the invoice using a secure SQL transaction block Private Sub btnSaveInvoice_Click(sender As Object, e As EventArgs) Handles btnSaveInvoice.Click If dgvItems.Rows.Count = 0 Then MsgBox("Cannot save an empty invoice.", MsgBoxStyle.Warning, "Validation Error") Exit Sub End If Using conn As SqlConnection = GetConnection() Dim tx As SqlTransaction = conn.BeginTransaction() Try Dim masterQuery As String = "INSERT INTO Invoices (InvoiceNumber, CustomerName, SubTotal, TaxAmount, Discount, GrandTotal) " & "VALUES (@InvNo, @Customer, @Sub, @Tax, @Disc, @Grand); SELECT SCOPE_IDENTITY();" Dim newInvoiceID As Integer = 0 Dim subTotal As Decimal = Convert.ToDecimal(lblSubTotal.Text) Dim taxRate As Decimal = 0 Decimal.TryParse(txtTaxRate.Text, taxRate) Dim taxAmt As Decimal = subTotal * (taxRate / 100) Dim discount As Decimal = 0 Decimal.TryParse(txtDiscount.Text, discount) Using cmdMaster As New SqlCommand(masterQuery, conn, tx) cmdMaster.Parameters.AddWithValue("@InvNo", txtInvoiceNo.Text.Trim()) cmdMaster.Parameters.AddWithValue("@Customer", If(String.IsNullOrEmpty(txtCustomer.Text), "Walk-In Customer", txtCustomer.Text.Trim())) cmdMaster.Parameters.AddWithValue("@Sub", subTotal) cmdMaster.Parameters.AddWithValue("@Tax", taxAmt) cmdMaster.Parameters.AddWithValue("@Disc", discount) cmdMaster.Parameters.AddWithValue("@Grand", Convert.ToDecimal(lblGrandTotal.Text)) newInvoiceID = Convert.ToInt32(cmdMaster.ExecuteScalar()) End Using ' Insert details and process real-time stock deductions For Each row As DataGridViewRow In dgvItems.Rows If Not row.IsNewRow Then Dim pID As Integer = Convert.ToInt32(row.Cells("ID").Value) Dim qty As Integer = Convert.ToInt32(row.Cells("Qty").Value) Dim price As Decimal = Convert.ToDecimal(row.Cells("Price").Value) Dim total As Decimal = Convert.ToDecimal(row.Cells("Total").Value) ' Insert item detail record Dim itemQuery As String = "INSERT INTO InvoiceItems (InvoiceID, ProductID, Quantity, UnitPrice, LineTotal) " & "VALUES (@InvID, @ProdID, @Qty, @Price, @Total)" Using cmdItem As New SqlCommand(itemQuery, conn, tx) cmdItem.Parameters.AddWithValue("@InvID", newInvoiceID) cmdItem.Parameters.AddWithValue("@ProdID", pID) cmdItem.Parameters.AddWithValue("@Qty", qty) cmdItem.Parameters.AddWithValue("@Price", price) cmdItem.Parameters.AddWithValue("@Total", total) cmdItem.ExecuteNonQuery() End Using ' Deduct inventory levels safely inside the current transaction block Dim stockQuery As String = "UPDATE Products SET StockQuantity = StockQuantity - @Qty WHERE ProductID = @ProdID" Using cmdStock As New SqlCommand(stockQuery, conn, tx) cmdStock.Parameters.AddWithValue("@Qty", qty) cmdStock.Parameters.AddWithValue("@ProdID", pID) cmdStock.ExecuteNonQuery() End Using End If Next tx.Commit() MsgBox("Invoice saved successfully!", MsgBoxStyle.Information, "Success") ' Reset for next transaction dgvItems.Rows.Clear() GenerateInvoiceNumber() txtCustomer.Clear() CalculateInvoiceTotals() Catch ex As Exception tx.Rollback() MsgBox("Transaction failed: " & ex.Message, MsgBoxStyle.Critical, "Database Write Failure") End Try End Using End Sub Private Sub txtTaxRate_TextChanged(sender As Object, e As EventArgs) Handles txtTaxRate.TextChanged, txtDiscount.TextChanged CalculateInvoiceTotals() End Sub End Class Use code with caution. 5. Security and Performance Optimization Tips
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.
Seamless integration with SQL Server, Access, and MySQL via ADO.NET.
Never concatenate text boxes directly into raw SQL strings (e.g., WHERE ProductCode = ' + txtProductCode.Text + ' ). Doing so exposes your database to catastrophic attacks. Always use explicit Parameters.AddWithValue() wrappers as shown in the source code above. High-Concurrency Transactions vb.net billing software source code
' Update stock Dim cmdStock As New SqlCommand("UPDATE tbl_Product SET StockQuantity = StockQuantity - @qty WHERE ProductID = @pid", con, transaction) cmdStock.Parameters.AddWithValue("@qty", row.Cells("Quantity").Value) cmdStock.Parameters.AddWithValue("@pid", row.Cells("ProductID").Value) cmdStock.ExecuteNonQuery() Next
Here is an example of the VB.NET code for generating an invoice:
Handles tax calculations, discounts, and inventory validation.
: Apply a percentage for tax and add it to the subtotal to get the final amount. 2. Source Code: Generate Text Invoice Seamless integration with SQL Server, Access, and MySQL
If you would like to expand this system further,g., generating daily or monthly sales reports)
'Total yPos += 20 e.Graphics.DrawString("Grand Total: " & lblGrandTotal.Text, New Font("Arial", 14, FontStyle.Bold), Brushes.Black, leftMargin, yPos)
Encapsulate all calculations here.
-- 1. Products Table CREATE TABLE Products ( ProductID INT IDENTITY(1,1) PRIMARY KEY, ProductCode VARCHAR(50) UNIQUE NOT NULL, ProductName VARCHAR(100) NOT NULL, UnitPrice DECIMAL(18, 2) NOT NULL, StockQuantity INT NOT NULL ); -- 2. Invoice Master Table CREATE TABLE Invoices ( InvoiceID INT IDENTITY(1,1) PRIMARY KEY, InvoiceNumber VARCHAR(50) UNIQUE NOT NULL, InvoiceDate DATETIME DEFAULT GETDATE(), CustomerName VARCHAR(100) NOT NULL, SubTotal DECIMAL(18, 2) NOT NULL, TaxAmount DECIMAL(18, 2) NOT NULL, Discount DECIMAL(18, 2) NOT NULL, GrandTotal DECIMAL(18, 2) NOT NULL ); -- 3. Invoice Items (Details) Table CREATE TABLE InvoiceItems ( ItemID INT IDENTITY(1,1) PRIMARY KEY, InvoiceID INT FOREIGN KEY REFERENCES Invoices(InvoiceID) ON DELETE CASCADE, ProductID INT FOREIGN KEY REFERENCES Products(ProductID), Quantity INT NOT NULL, UnitPrice DECIMAL(18, 2) NOT NULL, LineTotal DECIMAL(18, 2) NOT NULL ); Use code with caution. 3. Database Connection Module ( DbConnection.vb ) Always use explicit Parameters
A well-structured database is critical. Here’s a conceptual schema for our billing application.
-- Customers Table CREATE TABLE tbl_Customers ( CustomerID INT PRIMARY KEY IDENTITY(1,1), CustomerName NVARCHAR(100), Phone NVARCHAR(15), GST_No NVARCHAR(15) -- For B2B invoices );
: Logic for subtotaling, tax/VAT application, and discounts.