|
<?php |
|
class Leave { |
|
// (A) CONSTRUCTOR - CONNECT TO DATABASE |
|
private $pdo = null; |
|
private $stmt = null; |
|
public $error = ""; |
|
function __construct () { |
|
$this->pdo = new PDO( |
|
"mysql:host=".DB_HOST.";dbname=".DB_NAME.";charset=".DB_CHARSET, |
|
DB_USER, DB_PASSWORD, [ |
|
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, |
|
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC |
|
]); |
|
} |
|
|
|
// (B) DESTRUCTOR - CLOSE DATABASE CONNECTION |
|
function __destruct () { |
|
if ($this->stmt!==null) { $this->stmt = null; } |
|
if ($this->pdo!==null) { $this->pdo = null; } |
|
} |
|
|
|
// (C) HELPER FUNCTION - EXECUTE SQL QUERY |
|
function query ($sql, $data=null) : void { |
|
$this->stmt = $this->pdo->prepare($sql); |
|
$this->stmt->execute($data); |
|
} |
|
|
|
// (D) SET HOLIDAY |
|
function holiday ($name, $date, $half=0, $id=null) { |
|
if ($id==null) { |
|
$sql = "INSERT INTO `holidays` (`holiday_name`, `holiday_date`, `holiday_half`) VALUES (?, ?, ?)"; |
|
$data = [$name, $date, $half]; |
|
} else { |
|
$sql = "UPDATE `holidays` SET `holiday_name`=?, `holiday_date`=?, `holiday_half`=? WHERE `holiday_id`=?"; |
|
$data = [$name, $date, $half, $id]; |
|
} |
|
$this->query($sql, $data); |
|
return true; |
|
} |
|
|
|
// (E) SET ENTITLED LEAVE |
|
function entitle ($id, $type, $days) { |
|
$this->query( |
|
"REPLACE INTO `leave_entitled` (`user_id`, `leave_type`, `leave_days`) VALUES (?, ?, ?)", |
|
[$id, $type, $days] |
|
); |
|
return true; |
|
} |
|
|
|
// (F) CHECK GIVEN PERIOD |
|
function check ($id, $from, $to) { |
|
// (F1) CHECK START & END DATES |
|
$start = strtotime($from); |
|
$end = strtotime($to); |
|
if ($start<strtotime(LEAVE_MIN)) { return ["error"=>"Earliest leave is ".LEAVE_MIN]; } |
|
if ($end < $start) { return ["error"=>"End date is earlier than start date?"]; } |
|
|
|
// (F2) DATE RANGE |
|
$days = []; |
|
for ($unix=$start; $unix<=$end; $unix+=86400) { |
|
$weekend = date("N", $unix) > 5; |
|
$days[date("Y-m-d", $unix)] = [ |
|
"a" => $weekend ? 0 : 1, |
|
"n" => $weekend ? "Weekend" : "" |
|
]; |
|
} |
|
|
|
// (F3) HOLIDAYS |
|
$this->query( |
|
"SELECT * FROM `holidays` WHERE `holiday_date` BETWEEN ? AND ?", |
|
[$from, $to] |
|
); |
|
while ($r = $this->stmt->fetch()) { |
|
$days[$r["holiday_date"]] = [ |
|
"a" => $r["holiday_half"]==1 ? 2 : 0, |
|
"n" => $r["holiday_name"] |
|
]; |
|
} |
|
|
|
// (F4) GET LEAVE ALREADY TAKEN WITHIN PERIOD |
|
$this->query( |
|
"SELECT d.* FROM `leave_taken_days` d |
|
LEFT JOIN `leave_taken` t |
|
ON (d.`leave_id`=t.`leave_id` AND t.`user_id`=?) |
|
WHERE d.`leave_day` BETWEEN ? AND ? AND t.`leave_status`!='D'", |
|
[$id, $from, $to] |
|
); |
|
while ($r = $this->stmt->fetch()) { |
|
$days[$r["leave_day"]] = [ |
|
"a" => 0, |
|
"n" => "Already taken leave on this day" |
|
]; |
|
} |
|
|
|
// (F5) RESULTS |
|
// $days[YYYY-MM-DD] = ["a"=>CODE BELOW, "n"=>NOTES]; |
|
// 2 : Can apply half/none |
|
// 1 : Can apply full/half/none |
|
// 0 : No need to apply leave |
|
return $days; |
|
} |
|
|
|
// (G) APPLY LEAVE |
|
function apply ($id, $type, $days) { |
|
// (G1) APPLIED LEAVE DAYS |
|
$days = json_decode($days, true); |
|
$from = array_key_first($days); |
|
$to = array_key_last($days); |
|
$year = substr($from, 0, 4); |
|
$total = 0; |
|
foreach ($days as $day=>$half) { $total += $half=="F" ? 1 : 0.5 ; } |
|
|
|
// (G2) GET ENTITLED LEAVE |
|
$this->query( |
|
"SELECT `leave_days` FROM `leave_entitled` WHERE `user_id`=? AND `leave_type`=?", |
|
[$id, $type] |
|
); |
|
$entitled = $this->stmt->fetchColumn(); |
|
if (!is_numeric($entitled)) { |
|
$this->error = "Insufficient leave days."; |
|
return false; |
|
} |
|
|
|
// (G3) CALCULATE REMAINING LEAVE |
|
$this->query( |
|
"SELECT SUM(`leave_days`) FROM `leave_taken` |
|
WHERE `user_id`=? AND `leave_type`=? |
|
AND `leave_status`!='D' AND `leave_from` BETWEEN ? AND ?", |
|
[$id, $type, "$year-01-01", "$year-12-31"] |
|
); |
|
$taken = $this->stmt->fetchColumn(); |
|
if (is_numeric($taken)) { $entitled -= $taken; } |
|
if ($total > $entitled) { |
|
$this->error = "Insufficient leave days."; |
|
return false; |
|
} |
|
|
|
// (G4) AUTO-COMMIT OFF |
|
$this->pdo->beginTransaction(); |
|
|
|
// (G5) CREATE "MAIN LEAVE ENTRY" |
|
$this->query( |
|
"INSERT INTO `leave_taken` |
|
(`user_id`, `leave_type`, `leave_from`, `leave_to`, `leave_days`) |
|
VALUES (?, ?, ?, ?, ?)", |
|
[$id, $type, $from, $to, $total] |
|
); |
|
$id = $this->pdo->lastInsertId(); |
|
|
|
// (G6) LEAVE DAYS |
|
$sql = "INSERT INTO `leave_taken_days` (`leave_id`, `leave_day`, `leave_half`) VALUES "; |
|
$data = []; |
|
foreach ($days as $d=>$h) { |
|
$sql .= "(?,?,?),"; |
|
$data[] = $id; $data[] = $d; $data[] = $h; |
|
} |
|
$this->query(substr($sql,0,-1).";", $data); |
|
|
|
// (G7) DONE |
|
$this->pdo->commit(); |
|
return true; |
|
} |
|
} |
|
|
|
// (H) DATABASE SETTINGS - CHANGE TO YOUR OWN! |
|
define("DB_HOST", "localhost"); |
|
define("DB_NAME", "test"); |
|
define("DB_CHARSET", "utf8mb4"); |
|
define("DB_USER", "root"); |
|
define("DB_PASSWORD", ""); |
|
|
|
// (I) DEFINITIONS |
|
define("LEAVE_MIN", date("Y-m-d")); |
|
define("LEAVE_TYPES", [ |
|
"P" => "Paid", |
|
"U" => "Unpaid", |
|
"M" => "Medical" |
|
]); |
|
define("LEAVE_STATUS", [ |
|
"P" => "Pending", |
|
"A" => "Approved", |
|
"D" => "Denied" |
|
]); |
|
|
|
// (J) NEW LEAVE OBJECT |
|
$_LEAVE = new Leave(); |