diff --git a/action.php b/action.php
index 9599709..e697b3c 100644
--- a/action.php
+++ b/action.php
@@ -35,7 +35,29 @@ switch ($VARS['action']) {
if ($database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]])) {
returnToSender("already_in");
}
- $database->insert('punches', ['uid' => $_SESSION['uid'], 'in' => date("Y-m-d H:i:s"), 'out' => null, 'notes' => '']);
+
+ $shiftid = null;
+ if ($database->has('assigned_shifts', ['uid' => $_SESSION['uid']])) {
+ $minclockintime = strtotime("now + 5 minutes");
+ $shifts = $database->select('shifts', ["[>]assigned_shifts" => ['shiftid' => 'shiftid']], ["shifts.shiftid", "start", "end", "days"], ["AND" =>['uid' => $_SESSION['uid'], 'start[<=]' => date("H:i:s", $minclockintime)]]);
+ foreach ($shifts as $shift) {
+ $curday = substr(date("D"), 0, 2);
+ if (strpos($shift['days'], $curday) === FALSE) {
+ continue;
+ }
+ if (strtotime($shift['end']) >= strtotime($shift['start'])) {
+ if (strtotime("now") >= strtotime($shift['end'])) {
+ continue; // shift is already over
+ }
+ }
+ $shiftid = $shift['shiftid'];
+ }
+ if (is_null($shiftid)) {
+ returnToSender("not_assigned_to_work");
+ }
+ }
+
+ $database->insert('punches', ['uid' => $_SESSION['uid'], 'in' => date("Y-m-d H:i:s"), 'out' => null, 'notes' => '', 'shiftid' => $shiftid]);
returnToSender("punched_in");
case "punchout":
if (!$database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]])) {
diff --git a/database.mwb b/database.mwb
index 2d9040b..06f6e70 100644
Binary files a/database.mwb and b/database.mwb differ
diff --git a/database.sql b/database.sql
new file mode 100644
index 0000000..ca96393
--- /dev/null
+++ b/database.sql
@@ -0,0 +1,93 @@
+-- MySQL Script generated by MySQL Workbench
+-- Mon 20 Nov 2017 04:45:50 PM MST
+-- Model: New Model Version: 1.0
+-- MySQL Workbench Forward Engineering
+
+SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
+SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
+SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL,ALLOW_INVALID_DATES';
+
+-- -----------------------------------------------------
+-- Schema qwikclock
+-- -----------------------------------------------------
+DROP SCHEMA IF EXISTS `qwikclock` ;
+
+-- -----------------------------------------------------
+-- Schema qwikclock
+-- -----------------------------------------------------
+CREATE SCHEMA IF NOT EXISTS `qwikclock` DEFAULT CHARACTER SET utf8 ;
+USE `qwikclock` ;
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`shifts`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`shifts` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`shifts` (
+ `shiftid` INT NOT NULL AUTO_INCREMENT,
+ `shiftname` VARCHAR(255) NOT NULL,
+ `start` TIME NOT NULL,
+ `end` TIME NOT NULL,
+ `days` VARCHAR(14) NOT NULL DEFAULT 'MoTuWeThFr',
+ PRIMARY KEY (`shiftid`),
+ UNIQUE INDEX `shiftid_UNIQUE` (`shiftid` ASC))
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`punches`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`punches` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`punches` (
+ `punchid` INT NOT NULL AUTO_INCREMENT,
+ `uid` INT NOT NULL,
+ `in` DATETIME NOT NULL,
+ `out` DATETIME NULL,
+ `notes` TEXT(1000) NULL,
+ `shiftid` INT NULL,
+ PRIMARY KEY (`punchid`),
+ UNIQUE INDEX `punchid_UNIQUE` (`punchid` ASC),
+ INDEX `fk_punches_shifts1_idx` (`shiftid` ASC),
+ CONSTRAINT `fk_punches_shifts1`
+ FOREIGN KEY (`shiftid`)
+ REFERENCES `qwikclock`.`shifts` (`shiftid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`assigned_shifts`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`assigned_shifts` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`assigned_shifts` (
+ `uid` INT NOT NULL,
+ `shiftid` INT NOT NULL,
+ PRIMARY KEY (`uid`, `shiftid`),
+ INDEX `fk_assigned_shifts_shifts_idx` (`shiftid` ASC),
+ CONSTRAINT `fk_assigned_shifts_shifts`
+ FOREIGN KEY (`shiftid`)
+ REFERENCES `qwikclock`.`shifts` (`shiftid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`report_access_codes`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`report_access_codes` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`report_access_codes` (
+ `id` INT NOT NULL,
+ `code` VARCHAR(45) NULL,
+ `expires` DATETIME NULL,
+ PRIMARY KEY (`id`))
+ENGINE = InnoDB;
+
+
+SET SQL_MODE=@OLD_SQL_MODE;
+SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
+SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
diff --git a/lang/en_us.php b/lang/en_us.php
index 47a583a..51cef41 100644
--- a/lang/en_us.php
+++ b/lang/en_us.php
@@ -85,9 +85,17 @@ define("STRINGS", [
"csv file" => "CSV text file",
"ods file" => "ODS spreadsheet",
"html file" => "HTML web page",
- "report filtered to" => "Report filtered to {name} ({username})",
+ "report filtered to user" => "Report filtered to {name} ({username})",
+ "report filtered to start date" => "Only showing entries later than {date}",
+ "report filtered to end date" => "Only showing entries earlier than {date}",
"all users" => "All users",
"one user" => "One user",
"choose user" => "Type to choose user",
- "filter" => "Filter"
+ "filter" => "Filter",
+ "date range" => "Date range",
+ "punchid" => "Punch ID",
+ "shiftid" => "Shift ID",
+ "shiftname" => "Shift Name",
+ "punches" => "Punches",
+ "not assigned to work now" => "You are not assigned to work right now."
]);
\ No newline at end of file
diff --git a/lang/messages.php b/lang/messages.php
index b051d5d..a65340d 100644
--- a/lang/messages.php
+++ b/lang/messages.php
@@ -60,5 +60,9 @@ define("MESSAGES", [
"shift_assigned" => [
"string" => "shift assigned",
"type" => "success"
+ ],
+ "not_assigned_to_work" => [
+ "string" => "not assigned to work now",
+ "type" => "danger"
]
]);
diff --git a/lib/reports.php b/lib/reports.php
index d70e2b8..f5f3a21 100644
--- a/lib/reports.php
+++ b/lib/reports.php
@@ -40,7 +40,7 @@ if (LOADED) {
$user = getUserByUsername($VARS['user']);
}
if (isset($VARS['type']) && isset($VARS['format'])) {
- generateReport($VARS['type'], $VARS['format'], $user);
+ generateReport($VARS['type'], $VARS['format'], $user, $VARS['startdate'], $VARS['enddate']);
die();
} else {
lang("invalid parameters");
@@ -90,33 +90,93 @@ function getShiftReport($user = null) {
return $out;
}
-function getReportData($type, $user = null) {
+function getPunchReport($user = null, $start = null, $end = null) {
+ global $database;
+ $where = [];
+ if ((bool) strtotime($start) == TRUE) {
+ $where["OR #start"] = [
+ "in[>=]" => date("Y-m-d", strtotime($start)),
+ "out[>=]" => date("Y-m-d", strtotime($start))
+ ];
+ }
+ if ((bool) strtotime($end) == TRUE) {
+ // Make the date be the end of the day, not the start
+ $where["in[<=]"] = date("Y-m-d", strtotime($end)) . " 23:59:59";
+ }
+ if ($user != null && array_key_exists('uid', $user)) {
+ $where["uid"] = $user['uid'];
+ }
+ if (count($where) > 1) {
+ $where = ["AND" => $where];
+ }
+ $punches = $database->select(
+ "punches", [
+ "[>]shifts" => ["shiftid" => "shiftid"]
+ ], [
+ "punchid", "uid", "in", "out", "notes", "punches.shiftid", "shiftname"
+ ], $where
+ );
+ $header = [lang("punchid", false), lang("name", false), lang("in", false), lang("out", false), lang("shiftid", false), lang("shiftname", false), lang("notes", false)];
+ $out = [$header];
+ $usercache = [];
+ for ($i = 0; $i < count($punches); $i++) {
+ if (!array_key_exists($punches[$i]["uid"], $usercache)) {
+ $usercache[$punches[$i]["uid"]] = getUserByID($punches[$i]["uid"]);
+ }
+ $out[] = [
+ $punches[$i]["punchid"],
+ $usercache[$punches[$i]["uid"]]["name"] . " (" . $usercache[$punches[$i]["uid"]]["username"] . ")",
+ date(DATETIME_FORMAT, strtotime($punches[$i]['in'])),
+ (is_null($punches[$i]['out']) ? "" : date(DATETIME_FORMAT, strtotime($punches[$i]['out']))),
+ $punches[$i]['shiftid'],
+ $punches[$i]['shiftname'],
+ $punches[$i]['notes']
+ ];
+ }
+ return $out;
+}
+
+function getReportData($type, $user = null, $start = null, $end = null) {
switch ($type) {
case "shifts":
return getShiftReport($user);
break;
+ case "punches":
+ return getPunchReport($user, $start, $end);
+ break;
default:
return [["error"]];
}
}
-function dataToCSV($data, $name = "report", $user = null) {
+function dataToCSV($data, $name = "report", $user = null, $start = null, $end = null) {
$csv = Writer::createFromString('');
$usernotice = "";
$usertitle = "";
+ $datetitle = "";
if ($user != null && array_key_exists('username', $user) && array_key_exists('name', $user)) {
- $usernotice = lang2("report filtered to", ["name" => $user['name'], "username" => $user['username']], false);
+ $usernotice = lang2("report filtered to user", ["name" => $user['name'], "username" => $user['username']], false);
$usertitle = "_" . $user['username'];
$csv->insertOne([$usernotice]);
}
+ if ($start != null && (bool) strtotime($start)) {
+ $datenotice = lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false);
+ $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
+ $csv->insertOne([$datenotice]);
+ }
+ if ($end != null && (bool) strtotime($end)) {
+ $datenotice = lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false);
+ $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
+ $csv->insertOne([$datenotice]);
+ }
$csv->insertAll($data);
header('Content-type: text/csv');
- header('Content-Disposition: attachment; filename="' . $name . $usertitle . "_" . date("Y-m-d_Hi") . ".csv" . '"');
+ header('Content-Disposition: attachment; filename="' . $name . $usertitle . $datetitle . "_" . date("Y-m-d_Hi") . ".csv" . '"');
echo $csv;
die();
}
-function dataToODS($data, $name = "report", $user = null) {
+function dataToODS($data, $name = "report", $user = null, $start = null, $end = null) {
$ods = new ods();
$styleColumn = new odsStyleTableColumn();
$styleColumn->setUseOptimalColumnWidth(true);
@@ -130,13 +190,28 @@ function dataToODS($data, $name = "report", $user = null) {
$usernotice = "";
$usertitle = "";
+ $datetitle = "";
if ($user != null && array_key_exists('username', $user) && array_key_exists('name', $user)) {
- $usernotice = lang2("report filtered to", ["name" => $user['name'], "username" => $user['username']], false);
+ $usernotice = lang2("report filtered to user", ["name" => $user['name'], "username" => $user['username']], false);
$usertitle = "_" . $user['username'];
$row = new odsTableRow();
$row->addCell(new odsTableCellString($usernotice));
$table->addRow($row);
}
+ if ($start != null && (bool) strtotime($start)) {
+ $datenotice = lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false);
+ $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
+ $row = new odsTableRow();
+ $row->addCell(new odsTableCellString($datenotice));
+ $table->addRow($row);
+ }
+ if ($end != null && (bool) strtotime($end)) {
+ $datenotice = lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false);
+ $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
+ $row = new odsTableRow();
+ $row->addCell(new odsTableCellString($datenotice));
+ $table->addRow($row);
+ }
$rowid = 0;
foreach ($data as $datarow) {
@@ -152,10 +227,10 @@ function dataToODS($data, $name = "report", $user = null) {
$rowid++;
}
$ods->addTable($table);
- $ods->downloadOdsFile($name . $usertitle . "_" . date("Y-m-d_Hi") . ".ods");
+ $ods->downloadOdsFile($name . $usertitle . $datetitle . "_" . date("Y-m-d_Hi") . ".ods");
}
-function dataToHTML($data, $name = "report", $user = null) {
+function dataToHTML($data, $name = "report", $user = null, $start = null, $end = null) {
global $SECURE_NONCE;
// HTML exporter doesn't like null values
for ($i = 0; $i < count($data); $i++) {
@@ -167,16 +242,26 @@ function dataToHTML($data, $name = "report", $user = null) {
}
$usernotice = "";
$usertitle = "";
+ $datenotice = "";
+ $datetitle = "";
if ($user != null && array_key_exists('username', $user) && array_key_exists('name', $user)) {
- $usernotice = "" . lang2("report filtered to", ["name" => $user['name'], "username" => $user['username']], false) . "
";
+ $usernotice = "" . lang2("report filtered to user", ["name" => $user['name'], "username" => $user['username']], false) . "
";
$usertitle = "_" . $user['username'];
}
+ if ($start != null && (bool) strtotime($start)) {
+ $datenotice = "" . lang2("report filtered to start date", ["date" => date(DATE_FORMAT, strtotime($start))], false) . "
";
+ $datetitle = "_" . date(DATE_FORMAT, strtotime($start));
+ }
+ if ($end != null && (bool) strtotime($end)) {
+ $datenotice .= "" . lang2("report filtered to end date", ["date" => date(DATE_FORMAT, strtotime($end))], false) . "
";
+ $datetitle .= ($datetitle == "" ? "_" : "-") . date(DATE_FORMAT, strtotime($end));
+ }
header('Content-type: text/html');
$converter = new HTMLConverter();
$out = "\n"
. "\n"
. "\n"
- . "