Seat Booking System: Eusoff DP1516

Seat Booking System: Eusoff DP1516

This is a seat booking system for Eusoff Hall (NUS) dance production 15/16. They would like to sell tickets for their performance in UCC (University Culture Center NUS) and there was a need for the booking system. I participated in building this system and learnt a lot in doing this.

Overall Booking Process

Step 1

Go to the booking page:

Step 2

Select a seats:

  • The seat selected will be blocked by sending AJAX query to the sever
  • A summary of booking details will be shown below

Also, you cannot leave a seat between :P

Code for checking seat between.

Step 3

Collect information and start the blocking process.

Step 4

  • They may want to purchase additional items

  • Some of items have been marked as “Sold out”.

Step 5

Booking Success and need to transfer money.

Step 6

Admin will need to approve their booking at back-end.

Confirm the booking when money has been transfered.

Things that we did right

This is my first project in NUS and it was built during my first semester in the university. At that time, I hadn’t learnt things in software engineering yet. Nevertheless, there are still some good practices that I appreciated.

No magic number

1
2
3
4
define("DB_HOST", "localhost:8889");
define("DB_USERNAME", "root");
define("DB_PWD", "root");
define("DB_NAME", "dp_booking");

We define constant in the file constant.php and include it when necessary in every files. This is pretty good as there is no magic number inside the PHP script.

Dedicated file for interaction with the database

1
2
3
4
5
6
7
8
9
10
11
12
<?php
require_once("constant.php");
$db_conn = connectDB();

function connectDB() {
$con = new mysqli(DB_HOST, DB_USERNAME, DB_PWD, DB_NAME);
if ($con->connect_error) {
die("Connection failed: " . $con->connect_error);
}
return $con;
}
...

In a common file called db.php, we define all the method we need for interaction with database. Though at that time, I don’t really learn OOP programming. This practice is fair enough for abstraction.

Things that need improvements

Not very good code quality

Let’s take a look at the code for checking “No empty seat between booked seat”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
function check_seat_between(sc, all_seat, floor, ignore_id){
var indicate = true; // assume there is no seat alone

var ignore_seats = ["1_1_7", "1_1_8", "1_1_35", "1_1_36"] // these are all wheel chair seat

for(var i = 0; i < all_seat.length; i = i + 1) { // for every select seat

var id = all_seat[i]; // the current seat

if (ignore_seats.indexOf(id) >= 0) {
continue;
}

var prefix = id.split("_")[1];
var suffix = parseInt(id.split("_")[2]);
var new_seat_1 = floor + "_" + prefix + "_" + (suffix + 2); // seat two right from the current seat
var new_seat_2 = floor + "_" + prefix + "_" + (suffix + 1); // seat right from the current seat
var new_seat_3 = floor + "_" + prefix + "_" + (suffix - 1); // seat left from the current seat
var new_seat_4 = floor + "_" + prefix + "_" + (suffix - 2); // seat two left from the current seat

// get the status of the right and left side of the current seat
var new_seat_1_status = "unavailable";var new_seat_2_status = "unavailable"; // assume is unavailable for all
var new_seat_3_status = "unavailable";var new_seat_4_status = "unavailable";
try { new_seat_1_status = sc.get(new_seat_1).status(); } catch(err) {} // update the status
try { new_seat_2_status = sc.get(new_seat_2).status(); } catch(err) {} // the seat id may not exist, catch the error
try { new_seat_3_status = sc.get(new_seat_3).status(); } catch(err) {}
try { new_seat_4_status = sc.get(new_seat_4).status(); } catch(err) {}

// check the status of the right side of the current seat
if (new_seat_1 != ignore_id) {
if (all_seat.indexOf(new_seat_1) >= 0 || new_seat_1_status == "unavailable" || new_seat_1_status == "blocked") {
if (all_seat.indexOf(new_seat_2) >= 0 || new_seat_2_status == "unavailable" || new_seat_2_status == "blocked") {
// keep indicator
} else {
indicate = false;
break;
}
}
}

// check the status of the left side of the current seat
if (new_seat_4 != ignore_id) {
if (all_seat.indexOf(new_seat_4) >= 0 || new_seat_4_status == "unavailable" || new_seat_4_status == "blocked") {
if (all_seat.indexOf(new_seat_3) >= 0 || new_seat_3_status == "unavailable" || new_seat_3_status == "blocked") {
// keep indicator
} else {
indicate = false;
break;
}
}
}
}

if (indicate) {
// there is no seat between
$("#alert_box").hide();
} else {
// there is at least one seat between two booked seat
$("#booking_button").attr('class', 'pure-button pure-button-disabled');
$("#alert_box").show();
}

return indicate;
}

I appreciate that we have good comments on this. But we could absolutely do better for single level of abstraction and separation of concerns. For example, the code for toggling the UI should not be put here.

Hacking Solutions

We actually disable the button manually by adding disable to element. This can definitely don in database.

Manual testing

There is no testing concept at that time when doing this project. Everything is done manually (by visiting the local server to see if it works). And therefore, this results in LIVE issues.

LIVE issues

We forget to check the availability of seats in the back-end and result in double booking (two different person got the same seat). In this case, we have to manually negotiate with the person. This lessen also tells us how testing is important. For such system, testing for concurrent requests is necessary.

Author

Xiao Pu

Posted on

2015-12-13

Updated on

2020-11-21

Licensed under

Comments