A role-based web application for tracking products, stock and sales, with printable sales reports.
- About
- Features
- User Roles
- Tech Stack
- Getting Started
- Demo Accounts
- Usage
- Project Structure
- Database Schema
- Security Notes
- Troubleshooting
- Contributing
- Authors
- Acknowledgements
- License
Inventory Management System is a web application that streamlines inventory tracking, stock management and sales reporting for small businesses and warehouses. Products, categories, product photos, sales and reports live in one dashboard, and three user roles (Admin, Special and User) control who can see and change what.
Recording a sale deducts the sold quantity from stock automatically. Reports summarize sales by day and by month, and the date-range report calculates the grand total and profit for any period, ready to print.
- Live counts of users, categories, products and sales, each linking to its management page
- Highest-selling products, latest sales and recently added products at a glance
- Create, edit and delete products with a category, stock quantity, buying price, selling price and photo
- Organize products into categories
- Media library for uploading product photos (JPG, PNG and GIF)
- Product search with as-you-type suggestions (AJAX)
- Sale totals calculated automatically from price × quantity
- Stock deducted automatically when a sale is recorded
- Review, edit and delete past sales
- Sales report for any date range, print-ready, with grand total and profit
- Daily sales for the current month and monthly sales for the current year
- Three roles (Admin, Special and User), each with its own navigation menu
- Every protected page checks the signed-in user's role before it loads
- User and group management; deactivating a group blocks its members from protected pages
- Every user can update their name, username and profile photo, and change their password
- Last sign-in time recorded for each account
| Role | Level | Main areas |
|---|---|---|
| Admin | 1 | Everything: dashboard, users and groups, categories, products, media, sales and reports |
| Special | 2 | Products and the media library |
| User | 3 | Sales and sales reports |
Access is hierarchical: a lower level number means more privileges, and each role can also open the pages available to the roles below it. Every role can view its profile, edit its account settings and change its password.
| Layer | Technology |
|---|---|
| Backend | PHP 7.4+ with the MySQLi extension |
| Database | MySQL or MariaDB |
| Frontend | Bootstrap 3.3.4, jQuery 1.11.2, bootstrap-datepicker 1.3.0 |
| Styling | Custom stylesheet (libs/css/main.css) |
| Web server | Apache, e.g. via XAMPP, WAMP, MAMP or LAMP |
- A local PHP stack such as XAMPP, which bundles Apache, PHP and MariaDB in one installer
- PHP 7.4 or newer with the
mysqliextension enabled (it is enabled by default in XAMPP) - MariaDB 10.x, or MySQL 5.7+ with one setting changed (see Troubleshooting)
- An internet connection in the browser: Bootstrap, jQuery and the datepicker load from public CDNs
-
Clone the repository
git clone https://github.com/Ahmedali1010/WebProject.git
-
Copy the app into your web root. Copy the
InventorySystem_PHPfolder into your server's document root, for example:- XAMPP on Windows:
C:\xampp\htdocs\InventorySystem_PHP - XAMPP on macOS:
/Applications/XAMPP/htdocs/InventorySystem_PHP - Apache on Linux:
/var/www/html/InventorySystem_PHP
- XAMPP on Windows:
-
Start Apache and MySQL from the XAMPP Control Panel, or your stack's equivalent.
-
Create and import the database. The SQL file creates the tables and sample data but not the database itself, so create the database first:
- Open phpMyAdmin at http://localhost/phpmyadmin.
- Create a database named
inventory_system. - Select it, open the Import tab and import
InventorySystem_PHP/DATABASE FILE/inventory_system.sql.
Or, from the repository root on the command line:
mysql -u root -p -e "CREATE DATABASE inventory_system" mysql -u root -p inventory_system < "InventorySystem_PHP/DATABASE FILE/inventory_system.sql"
On a fresh XAMPP install the
rootaccount has no password, so press Enter at the password prompt. -
Check the database settings in
includes/config.php. The defaults match a fresh XAMPP install:define( 'DB_HOST', 'localhost' ); define( 'DB_USER', 'root' ); define( 'DB_PASS', '' ); define( 'DB_NAME', 'inventory_system' );
-
Allow uploads (Linux and macOS only). Make sure the web server can write to
uploads/productsanduploads/users. On a local development machine,chmod -R 777 uploadsinside the app folder is enough; on a shared server, give ownership to the web server's user instead. -
Open the app at http://localhost/InventorySystem_PHP/ and sign in with one of the demo accounts.
Paths are relative to the InventorySystem_PHP folder.
| Setting | File | Default |
|---|---|---|
| Database host, user, password and name | includes/config.php |
localhost, root, empty, inventory_system |
| Time zone of the date shown in the header | layouts/header.php |
Asia/Baghdad |
| SQL error output | includes/database.php |
Development mode, which prints the failing query |
The sample database includes these accounts:
| Role | Username | Password |
|---|---|---|
| Admin | admin |
admin |
| Special | special |
special |
| User | user |
user |
Two more User accounts, natie and kevin, use the password password.
Warning
These credentials are public. Change or delete every sample account before running the system on a shared network or the internet.
The sample data also contains 7 categories, 13 products and 8 sales dated April 4, 2021. Run Sales by dates for that day to see a filled-in report.
A typical workflow, signed in as admin:
- Categories: add the categories you need.
- Media Files: upload product photos.
- Products → Add Products: enter the title, category, photo, quantity, and buying and selling prices.
- Sales → Add Sale: start typing a product name, pick a suggestion and click Find It. Adjust the quantity (the total updates automatically), then click Add sale. The product's stock drops by the quantity sold.
- Sales Report: choose Sales by dates for a printable report with grand total and profit, or open Daily sales or Monthly sales.
- User Management: create accounts, assign each one a role, and activate or deactivate groups.
WebProject/
├── README.md
└── InventorySystem_PHP/
├── DATABASE FILE/
│ └── inventory_system.sql # Database schema and sample data
├── includes/
│ ├── config.php # Database connection settings
│ ├── load.php # Loads all the includes below
│ ├── database.php # MySQLi wrapper class
│ ├── session.php # Sign-in session and flash messages
│ ├── sql.php # Queries, authentication and permission checks
│ ├── functions.php # Helpers: escaping, redirects, dates, totals
│ ├── upload.php # Image upload handling (Media class)
│ └── backup/ # Earlier versions of functions.php and sql.php
├── layouts/ # Header, footer and one sidebar menu per role
├── libs/
│ ├── css/main.css # Custom styles
│ └── js/functions.js # Product search, sale totals, datepicker
├── uploads/
│ ├── products/ # Product photos
│ └── users/ # Profile photos
├── index.php # Sign-in page
├── auth.php, logout.php # Sign-in and sign-out handlers
├── admin.php # Admin dashboard
├── home.php # Home page for the Special and User roles
├── product.php # Products (+ add_, edit_, delete_product.php)
├── categorie.php # Categories (+ edit_, delete_categorie.php)
├── media.php # Media library (+ delete_media.php)
├── sales.php # Sales (+ add_, edit_, delete_sale.php)
├── ajax.php # Product search endpoint for the sale form
├── sales_report.php # Date-range report form (→ sale_report_process.php)
├── daily_sales.php # Current month, by day
├── monthly_sales.php # Current year, by month
├── users.php # Users (+ add_, edit_, delete_user.php)
├── group.php # Groups (+ add_, edit_, delete_group.php)
└── profile.php, edit_account.php, change_password.php
The database is named inventory_system and has six tables:
erDiagram
user_groups ||--o{ users : "user_level"
categories ||--o{ products : "categorie_id"
media |o--o{ products : "media_id"
products ||--o{ sales : "product_id"
user_groups {
int id PK
varchar group_name
int group_level UK
int group_status
}
users {
int id PK
varchar name
varchar username
varchar password "SHA-1 hash"
int user_level FK
varchar image
int status
datetime last_login
}
categories {
int id PK
varchar name UK
}
media {
int id PK
varchar file_name
varchar file_type
}
products {
int id PK
varchar name UK
varchar quantity
decimal buy_price
decimal sale_price
int categorie_id FK
int media_id
datetime date
}
sales {
int id PK
int product_id FK
int qty
decimal price
date date
}
| Table | Stores |
|---|---|
users |
Accounts with their role level, profile photo and last sign-in time |
user_groups |
Roles (Admin, Special, User) and whether each one is active |
categories |
Product categories |
products |
Stock items with quantity, buying and selling price, category and photo |
media |
Uploaded product photos |
sales |
Recorded sales; each one reduces the product's stock |
Important
Foreign keys cascade on delete. Deleting a group deletes every user in it, deleting a category deletes its products, and deleting a product deletes its sales.
In its current form the application is best suited to local or trusted-network use. It includes these protections:
- Session-based sign-in, with a role check on every protected page
- User input escaped with
mysqli::real_escape_stringbefore it reaches SQL, and most output passed throughhtmlspecialchars - Uploads limited to image files (
.jpg,.jpeg,.png,.gif) - Passwords stored as SHA-1 hashes rather than plain text
Before deploying it publicly:
- Change or delete every demo account, and connect with a dedicated MySQL user and a strong password instead of
root. - Replace SHA-1 password hashing with PHP's
password_hash()andpassword_verify(). - Switch
includes/database.phpto its production error message and turn offdisplay_errorsinphp.ini, so failed queries and error details aren't shown to visitors. - Add CSRF tokens to forms, and turn the delete links (currently
GETrequests) intoPOSTforms. - Move database queries to prepared statements.
- Serve the application over HTTPS.
| Problem | Solution |
|---|---|
Database connection failed, or Uncaught mysqli_sql_exception on the first page |
Start MySQL, then check the credentials in includes/config.php. |
Failed to Select Database or Unknown database 'inventory_system' |
Create the inventory_system database and import the SQL file (step 4). |
Call to undefined function mysqli_connect() |
Enable the mysqli extension in php.ini, then restart Apache. |
Daily sales, Monthly sales or Sales by dates fail with Error on this Query or a GROUP BY error |
MySQL 5.7 and later enable ONLY_FULL_GROUP_BY by default, and the report queries need it turned off. See the command below, or use MariaDB. |
Blank page after signing in, or headers already sent warnings |
Turn on output_buffering in php.ini. XAMPP has it on by default. |
Photo upload fails with ... Must be writable!!!. |
Give the web server write access to uploads/products and uploads/users. |
| Pages load without styling | Bootstrap and jQuery load from CDNs, so check the browser's internet connection. |
To turn off ONLY_FULL_GROUP_BY on MySQL, run this as root:
-- Lasts until MySQL restarts. To make it permanent, set sql_mode in my.cnf / my.ini.
SET GLOBAL sql_mode = (SELECT REPLACE(@@GLOBAL.sql_mode, 'ONLY_FULL_GROUP_BY', ''));Contributions are welcome.
- Fork the repository.
- Create a branch:
git checkout -b feature/your-feature - Commit your changes:
git commit -m "Add your feature" - Push the branch:
git push origin feature/your-feature - Open a pull request.
Developed by Ahmad.
Portions of this project are derived from OSWA-INV, Copyright (c) 2015 Siamon Hasan, and are used under the MIT License.