Skip to main content

Restaurant Management System with PHP & MySQL

In our previous tutorial, we have explained how to develop Visitor Management System with PHP and MySQL. In this tutorial, we will explain how to develop Restaurant Management System with PHP and MySQL.

Restaurant Management System are widely used to manage food category, food items, tables, orders, tax and billing. The Restaurant Management System allows waiter or cashier to manage order with items and finally create bill instead of handling everything manually.

So if you’re a web developer or programmer and looking for solution to develop Restaurant Management System, then you’re here at the right place. In this tutorial you learn how to develop your own restaurant system with PHP and MySQL.

Also, read:

Here we will develop an example of online Restaurant Management System and cover following.

The Administrator will do the following:

  • Manage Food Category.
  • Manage Food Items.
  • Manage Tables.
  • Manage Orders.
  • Manage Taxes.
  • Manage Billing.

The Cashier will do the following:

  • Manage Orders.
  • Manage Billing.

The Waiter will do the following:

  • Manage Orders.

So let’s implement Restaurant Management System . The major files are:

  • index.php
  • category.php
  • items.php
  • tables.php
  • orders.php
  • taxes.php
  • User.php: User class to hold methods related to user.
  • Category.php: Category class to hold methods related to food category.
  • Item.php: Item class to hold methods related to food items.
  • Tables.php: Tables class to hold methods related to manage tables.
  • Order.php: Order class to hold methods related to manage orders.

Step1: Create MySQL Database Table

Firs we will create restaurant_user table to store user information with login details to access system.

CREATE TABLE `restaurant_user` (
  `id` int(11) UNSIGNED NOT NULL,
  `first_name` varchar(255) DEFAULT NULL,
  `last_name` varchar(255) DEFAULT NULL,
  `gender` enum('Male','Female') NOT NULL,
  `email` varchar(255) DEFAULT NULL,
  `password` varchar(64) NOT NULL,
  `mobile` varchar(12) NOT NULL,
  `address` text NOT NULL,
  `created` datetime NOT NULL DEFAULT current_timestamp(),
  `role` enum('admin','waiter','cashier') DEFAULT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

we will create table restaurant_category store food categories.

CREATE TABLE `restaurant_category` (
  `id` int(11) NOT NULL,
  `name` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
  `status` enum('Enable','Disable') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Enable'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

we will create table restaurant_items to store food items details.

CREATE TABLE `restaurant_items` (
  `id` int(11) NOT NULL,
  `name` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
  `price` decimal(10,2) NOT NULL,
  `category_id` int(11) NOT NULL,
  `status` enum('Enable','Disable') COLLATE utf8_unicode_ci NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

we will create table restaurant_table to store table details.

CREATE TABLE `restaurant_table` (
  `id` int(11) NOT NULL,
  `name` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
  `capacity` int(3) NOT NULL,
  `status` enum('Enable','Disable') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Enable'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

we will create table restaurant_tax to store taxes details.

CREATE TABLE `restaurant_tax` (
  `id` int(11) NOT NULL,
  `tax_name` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
  `percentage` decimal(4,2) NOT NULL,
  `status` enum('Enable','Disable') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'Enable'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

we will create table restaurant_order to store order details.

CREATE TABLE `restaurant_order` (
  `id` int(11) NOT NULL,
  `table_id` varchar(250) COLLATE utf8_unicode_ci NOT NULL,
  `gross_amount` decimal(12,2) NOT NULL,
  `tax_amount` decimal(12,2) NOT NULL,
  `net_amount` decimal(12,2) NOT NULL,
  `created` datetime NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
  `created_by` enum('admin','waiter','cashier') COLLATE utf8_unicode_ci NOT NULL,
  `status` enum('In Process','Completed') COLLATE utf8_unicode_ci NOT NULL DEFAULT 'In Process'
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

and we will create table restaurant_order_item to store order items details.

CREATE TABLE `restaurant_order_item` (
  `id` int(11) NOT NULL,
  `order_id` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  `item_id` int(11) NOT NULL,
  `quantity` int(4) NOT NULL,
  `rate` decimal(12,2) NOT NULL,
  `amount` decimal(12,2) NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Step2: Manage Food Category

We will create HTML in category.php file to list food categories. We will also create HTML to add, edit and delete categories.

<div> 	
	<div class="panel-heading">
		<div class="row">
			<div class="col-md-10">
				<h3 class="panel-title"></h3>
			</div>
			<div class="col-md-2" align="right">
				<button type="button" id="addCategory" class="btn btn-info" title="Add Category"><span class="glyphicon glyphicon-plus"></span></button>
			</div>
		</div>
	</div>
	<table id="categoryListing" class="table table-bordered table-striped">
		<thead>
			<tr>						
				<th>Id</th>					
				<th>Category Name</th>					
				<th>Status</th>					
				<th></th>
				<th></th>					
			</tr>
		</thead>
	</table>
</div>

<div id="categoryModal" class="modal fade">
	<div class="modal-dialog">
		<form method="post" id="categoryForm">
			<div class="modal-content">
				<div class="modal-header">
					<button type="button" class="close" data-dismiss="modal">×</button>
					<h4 class="modal-title"><i class="fa fa-plus"></i> Edit Category</h4>
				</div>
				<div class="modal-body">						
					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Category Name <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<input type="text" name="categoryName" id="categoryName" autocomplete="off" class="form-control" required />
							</div>
						</div>
					</div>	
					
					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Status <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<select name="status" id="status" class="form-control">
									<option value="Enable">Enable</option>
									<option value="Disable">Disable</option>
								</select>
							</div>
						</div>
					</div>							
				</div>
				<div class="modal-footer">
					<input type="hidden" name="id" id="id" />						
					<input type="hidden" name="action" id="action" value="" />
					<input type="submit" name="save" id="save" class="btn btn-info" value="Save" />
					<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
				</div>
			</div>
		</form>
	</div>
</div>

we will make ajax request to category_action.php with action listCategory to load categories.

var categoryRecords = $('#categoryListing').DataTable({
	"lengthChange": false,
	"processing":true,
	"serverSide":true,		
	"bFilter": true,
	'serverMethod': 'post',		
	"order":[],
	"ajax":{
		url:"category_action.php",
		type:"POST",
		data:{action:'listCategory'},
		dataType:"json"
	},
	"columnDefs":[
		{
			"targets":[0, 3, 4],
			"orderable":false,
		},
	],
	"pageLength": 10
});		

we will check for action listCategory in category_action.php and call method listCategory() from class Category.php.

if(!empty($_POST['action']) && $_POST['action'] == 'listCategory') {
	$category->listCategory();
}

we will implement method listCategory() in class Category.php to list categories.

public function listCategory(){			
		
	$sqlQuery = "
		SELECT id, name, status
		FROM ".$this->categoryTable." ";
					
	if(!empty($_POST["order"])){
		$sqlQuery .= ' ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
	} else {
		$sqlQuery .= ' ORDER BY id ASC ';
	}
	
	if($_POST["length"] != -1){
		$sqlQuery .= ' LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
	}
	
	$stmt = $this->conn->prepare($sqlQuery);
	$stmt->execute();
	$result = $stmt->get_result();	
	
	$stmtTotal = $this->conn->prepare($sqlQuery);
	$stmtTotal->execute();
	$allResult = $stmtTotal->get_result();
	$allRecords = $allResult->num_rows;
	
	$displayRecords = $result->num_rows;
	$records = array();	

	while ($category = $result->fetch_assoc()) { 				
		$rows = array();			
		$rows[] = $category['id'];			
		$rows[] = $category['name'];
		$rows[] = $category['status'];
		$rows[] = '<button type="button" name="update" id="'.$category["id"].'" class="btn btn-warning btn-xs update"><span class="glyphicon glyphicon-edit" title="Edit"></span></button>';			
		$rows[] = '<button type="button" name="delete" id="'.$category["id"].'" class="btn btn-danger btn-xs delete" ><span class="glyphicon glyphicon-remove" title="Delete"></span></button>';
		$records[] = $rows;
	}
	
	$output = array(
		"draw"	=>	intval($_POST["draw"]),			
		"iTotalRecords"	=> 	$displayRecords,
		"iTotalDisplayRecords"	=>  $allRecords,
		"data"	=> 	$records
	);
	
	echo json_encode($output);
}

We will also implement functionality to add new category, edit category and delete category.

Step3: Manage Food Items

We will create HTML in items.php to add, edit, delete and list food items.

<div> 	
	<div class="panel-heading">
		<div class="row">
			<div class="col-md-10">
				<h3 class="panel-title"></h3>
			</div>
			<div class="col-md-2" align="right">
				<button type="button" id="addItems" class="btn btn-info" title="Add Food Items"><span class="glyphicon glyphicon-plus"></span></button>
			</div>
		</div>
	</div>
	<table id="itemsListing" class="table table-bordered table-striped">
		<thead>
			<tr>						
				<th>Id</th>					
				<th>Item Name</th>
				<th>Price</th>						
				<th>Category</th>
				<th>Status</th>					
				<th></th>
				<th></th>					
			</tr>
		</thead>
	</table>
</div>

<div id="itemModal" class="modal fade">
	<div class="modal-dialog">
		<form method="post" id="itemForm">
			<div class="modal-content">
				<div class="modal-header">
					<button type="button" class="close" data-dismiss="modal">×</button>
					<h4 class="modal-title"><i class="fa fa-plus"></i> Edit Items</h4>
				</div>
				<div class="modal-body">						
					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Item Name <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<input type="text" name="itemName" id="itemName" autocomplete="off" class="form-control" required />
							</div>
						</div>
					</div>

					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Price <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<input type="text" name="price" id="price" autocomplete="off" class="form-control" required />
							</div>
						</div>
					</div>

					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Item Category <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<select name="itemCategory" id="itemCategory" class="form-control">
									<?php 
									$categoryResult = $item->getItemCategory();
									while ($category = $categoryResult->fetch_assoc()) { 	
									?>
										<option value="<?php echo $category['id']; ?>"><?php echo $category['name']; ?></option>							
									<?php } ?>									
								</select>
							</div>
						</div>
					</div>	
					
					<div class="form-group">
						<div class="row">
							<label class="col-md-4 text-right">Status <span class="text-danger">*</span></label>
							<div class="col-md-8">
								<select name="status" id="status" class="form-control">
									<option value="Enable">Enable</option>
									<option value="Disable">Disable</option>
								</select>
							</div>
						</div>
					</div>							
				</div>
				<div class="modal-footer">
					<input type="hidden" name="id" id="id" />						
					<input type="hidden" name="action" id="action" value="" />
					<input type="submit" name="save" id="save" class="btn btn-info" value="Save" />
					<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
				</div>
			</div>
		</form>
	</div>
</div>

we will make ajax request to items_action.php with action listItems to load items in datatables.

var itemRecords = $('#itemsListing').DataTable({
	"lengthChange": false,
	"processing":true,
	"serverSide":true,		
	"bFilter": true,
	'serverMethod': 'post',		
	"order":[],
	"ajax":{
		url:"items_action.php",
		type:"POST",
		data:{action:'listItems'},
		dataType:"json"
	},
	"columnDefs":[
		{
			"targets":[0, 5, 6],
			"orderable":false,
		},
	],
	"pageLength": 10
});		

we will check for action listItems and call method listItems() from class Items.php to load items list.

if(!empty($_POST['action']) && $_POST['action'] == 'listItems') {
	$item->listItems();
}

we will implement method listItems() in class Items.php to get items record and return as JSON data to load in datatables.

public function listItems(){			
		
	$sqlQuery = "
		SELECT item.id, item.name AS item_name, item.price, item.category_id, item.status, category.name AS category_name
		FROM ".$this->itemTable." item 
		LEFT JOIN ".$this->categoryTable." category ON item.category_id = category.id ";
					
	if(!empty($_POST["order"])){
		$sqlQuery .= ' ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
	} else {
		$sqlQuery .= ' ORDER BY item.id ASC ';
	}
	
	if($_POST["length"] != -1){
		$sqlQuery .= ' LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
	}
	
	$stmt = $this->conn->prepare($sqlQuery);
	$stmt->execute();
	$result = $stmt->get_result();	
	
	$stmtTotal = $this->conn->prepare($sqlQuery);
	$stmtTotal->execute();
	$allResult = $stmtTotal->get_result();
	$allRecords = $allResult->num_rows;
	
	$displayRecords = $result->num_rows;
	$records = array();	

	while ($items = $result->fetch_assoc()) { 				
		$rows = array();			
		$rows[] = $items['id'];			
		$rows[] = $items['item_name'];
		$rows[] = "$".$items['price'];
		$rows[] = $items['category_name'];
		$rows[] = $items['status'];
		$rows[] = '<button type="button" name="update" id="'.$items["id"].'" class="btn btn-warning btn-xs update"><span class="glyphicon glyphicon-edit" title="Edit"></span></button>';			
		$rows[] = '<button type="button" name="delete" id="'.$items["id"].'" class="btn btn-danger btn-xs delete" ><span class="glyphicon glyphicon-remove" title="Delete"></span></button>';
		$records[] = $rows;
	}
	
	$output = array(
		"draw"	=>	intval($_POST["draw"]),			
		"iTotalRecords"	=> 	$displayRecords,
		"iTotalDisplayRecords"	=>  $allRecords,
		"data"	=> 	$records
	);
	
	echo json_encode($output);
}

we have also implemented items add, edit and delete functionality.

Step4: Manage Orders

In order.php, we will create HTML to manage orders. We will implement to create new order, edit and delete order.

<div> 	
	<div class="panel-heading">
		<div class="row">
			<div class="col-md-10">
				<h3 class="panel-title"></h3>
			</div>
			<div class="col-md-2" align="right">
				<button type="button" id="addOrder" class="btn btn-info" title="Add Order"><span class="glyphicon glyphicon-plus"></span></button>
			</div>
		</div>
	</div>
	<table id="orderListing" class="table table-bordered table-striped">
		<thead>
			<tr>						
				<th>Order Id</th>					
				<th>Table</th>
				<th>Gross Amount</th>
				<th>Tax Amount</th>	
				<th>Net Amount</th>	
				<th>Date Time</th>	
				<th>Created By</th>
				<th>Status</th>					
				<th></th>
				<th></th>					
			</tr>
		</thead>
	</table>
</div>

<div id="orderModal" class="modal fade">
	<div class="modal-dialog" style="width">
		<form method="post" id="orderForm">
			<div class="modal-content">
				<div class="modal-header">
					<button type="button" class="close" data-dismiss="modal">×</button>
					<h4 class="modal-title"><i class="fa fa-plus"></i> Edit Order</h4>
				</div>
				<div class="modal-body">						
					<div class="form-group">
						<div class="row">
						
							<table class="table table-bordered table-hover">		
								<tr>
									<th width="10%">Table *</th>
								</tr>
								<tr>
									<td>
										<select name="tableName" id="tableName" class="form-control" required>
											<option value="">--Select--</option>
											<?php 
											$tableResult = $order->getTable();
											while ($table = $tableResult->fetch_assoc()) { 	
											?>
												<option value="<?php echo $table['id']; ?>"><?php echo $table['name']; ?></option>							
											<?php } ?>									
										</select>										
									</td>
								</tr>
							</table>		
								
							<table class="table table-bordered table-hover" id="orderItem">										
									
								<tr>
									<th width="2%"><input id="checkAll" class="formcontrol" type="checkbox"></th>										
									<th width="25%">Category</th>
									<th width="25%">Item</th>										
									<th width="15%">Price</th>
									<th width="10%">Quantity</th>										
									<th width="15%">Total</th>
								</tr>
								
								<tr>
									<td><input class="itemRow" type="checkbox"></td>										
									<td>
										<select name="itemCategory[]" id="itemCategory_1" class="form-control">
											<option value="">--Select--</option>
											<?php 
											$categoryResult = $item->getItemCategory();
											while ($category = $categoryResult->fetch_assoc()) { 	
											?>
												<option value="<?php echo $category['id']; ?>"><?php echo $category['name']; ?></option>							
											<?php } ?>									
										</select>										
									</td>
									<td>
										<select name="items[]" id="items_1" class="form-control"></select>	
									</td>
									<td><input type="number" name="price[]" id="price_1" class="form-control price" autocomplete="off"></td>				
									<td><input type="number" name="quantity[]" id="quantity_1" class="form-control quantity" autocomplete="off"></td>
									<td><input type="number" name="total[]" id="total_1" class="form-control total" autocomplete="off"></td>
									<input type="hidden" name="itemIds[]" id="itemIds_1" class="form-control" >
								</tr>						
							</table>
						</div>
						<div class="row">								
							 <button class="btn btn-danger delete" id="removeRows" type="button">- Delete</button>
							<button class="btn btn-success" id="addRows" type="button">+ Add More</button>								
						</div>
					</div>
					
					<div class="row">							
						<div class="col-xs-12 col-sm-8 col-md-8 col-lg-8">								
							<div class="form-group">
								<br><br><br><br><br><br><br><br><br><br>
								<label class="col-md-2">Status <span class="text-danger">*</span></label>
								<div class="col-md-9">
									<select name="status" id="status" class="form-control" required>
										<option value="In Process">In Process</option>
										<option value="Completed">Completed</option>
									</select>
								</div>	
								<br><br>
								<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
								<input type="submit" name="save" id="save" class="btn btn-info" value="Save" />									
							</div>								
						</div>
						<div class="col-xs-12 col-sm-4 col-md-4 col-lg-4">
							<span class="form-inline">
								<div class="form-group">
									<label>Subtotal:  </label>
									<div class="input-group">
										<div class="input-group-addon currency">$</div>
										<input value="" type="text" class="form-control" name="subTotal" id="subTotal" placeholder="Subtotal">
									</div>
								</div>
								<div class="form-group">
									<label>CGST Rate:  </label>
									<div class="input-group">
										<input value="" type="text" class="form-control" name="taxRate1" id="taxRate1" placeholder="CGST Rate">
										<div class="input-group-addon">%</div>
									</div>
								</div>
								<div class="form-group">
									<label>SGST Rate:  </label>
									<div class="input-group">
										<input value="" type="text" class="form-control" name="taxRate2" id="taxRate2" placeholder="SGST Rate">
										<div class="input-group-addon">%</div>
									</div>
								</div>
								<div class="form-group">
									<label>Tax Amount:  </label>
									<div class="input-group">
										<div class="input-group-addon currency">$</div>
										<input value="" type="text" class="form-control" name="taxAmount" id="taxAmount" placeholder="Tax Amount">
									</div>
								</div>							
								<div class="form-group">
									<label>Net Amount:  </label>
									<div class="input-group">
										<div class="input-group-addon currency">$</div>
										<input value="" type="text" class="form-control" name="totalAftertax" id="totalAftertax" placeholder="Total">
									</div>
								</div>									
							</span>
						</div>
					</div>

											
				</div>
				<div class="modal-footer">
					<input type="hidden" name="id" id="id" />						
					<input type="hidden" name="action" id="action" value="" />						
				</div>
			</div>
		</form>
	</div>
</div>

we will implement functionality to list order datatables. So we will initialize datatables and make ajax request to order_action.php with action listOrder.

var orderRecords = $('#orderListing').DataTable({
	"lengthChange": false,
	"processing":true,
	"serverSide":true,		
	"bFilter": true,
	'serverMethod': 'post',		
	"order":[],
	"ajax":{
		url:"order_action.php",
		type:"POST",
		data:{action:'listOrder'},
		dataType:"json"
	},
	"columnDefs":[
		{
			"targets":[0, 8, 9],
			"orderable":false,
		},
	],
	"pageLength": 10
});		

we will check for action listOrder and call method listOrder() from class Order.php to list orders.

if(!empty($_POST['action']) && $_POST['action'] == 'listOrder') {
	$order->listOrder();
}

and finally we will implement method listOrder() in class Order.php to get orders from database and list them.

public function listOrder(){			
		
	$sqlQuery = "
		SELECT orders.id, orders.gross_amount, orders.tax_amount, orders.net_amount, orders.created, orders.created_by, orders.status, tables.name AS table_name
		FROM ".$this->orderTable." orders 
		LEFT JOIN ".$this->tableTable." tables ON orders.table_id = tables.id ";
					
	if(!empty($_POST["order"])){
		$sqlQuery .= ' ORDER BY '.$_POST['order']['0']['column'].' '.$_POST['order']['0']['dir'].' ';
	} else {
		$sqlQuery .= ' ORDER BY orders.id DESC ';
	}
	
	if($_POST["length"] != -1){
		$sqlQuery .= ' LIMIT ' . $_POST['start'] . ', ' . $_POST['length'];
	}
	
	$stmt = $this->conn->prepare($sqlQuery);
	$stmt->execute();
	$result = $stmt->get_result();	
	
	$stmtTotal = $this->conn->prepare($sqlQuery);
	$stmtTotal->execute();
	$allResult = $stmtTotal->get_result();
	$allRecords = $allResult->num_rows;
	
	$displayRecords = $result->num_rows;
	$records = array();	

	while ($order = $result->fetch_assoc()) { 				
		$rows = array();			
		$rows[] = $order['id'];			
		$rows[] = $order['table_name'];
		$rows[] = "$".$order['gross_amount'];
		$rows[] = "$".$order['tax_amount'];
		$rows[] = "$".$order['net_amount'];
		$rows[] = $order['created'];
		$rows[] = $order['created_by'];
		$rows[] = $order['status'];
		$rows[] = '<button type="button" name="update" id="'.$order["id"].'" class="btn btn-warning btn-xs update"><span class="glyphicon glyphicon-edit" title="Edit"></span></button>';			
		$rows[] = '<button type="button" name="delete" id="'.$order["id"].'" class="btn btn-danger btn-xs delete" ><span class="glyphicon glyphicon-remove" title="Delete"></span></button>';
		$records[] = $rows;
	}
	
	$output = array(
		"draw"	=>	intval($_POST["draw"]),			
		"iTotalRecords"	=> 	$displayRecords,
		"iTotalDisplayRecords"	=>  $allRecords,
		"data"	=> 	$records
	);
	
	echo json_encode($output);
}

we have also implemented orders create, edit and delete functionality.

You may also like:

You can view the live demo from the Demo link and can download the source from the Download link below.
Demo Download

2 thoughts on “Restaurant Management System with PHP & MySQL

Comments are closed.