diff --git a/action.php b/action.php
index c489f8f..a8767ec 100644
--- a/action.php
+++ b/action.php
@@ -68,6 +68,8 @@ switch ($VARS['action']) {
if (!$database->has('punches', ['AND' => ['uid' => $_SESSION['uid'], 'out' => null]])) {
returnToSender("already_out");
}
+ // Stop active job
+ $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
$database->update('punches', ['uid' => $_SESSION['uid'], 'out' => date("Y-m-d H:i:s")], ['out' => null]);
returnToSender("punched_out");
case "gettime":
@@ -242,6 +244,130 @@ switch ($VARS['action']) {
}
returnToSender($removefailed ? "shift_assigned_removefailed" : "shift_assigned");
break;
+ case "setjob":
+ if ($database->count("job_groups") > 0) {
+ require_once __DIR__ . "/lib/userinfo.php";
+ $groups = getGroupsByUID($_SESSION['uid']);
+ $gids = [];
+ foreach ($groups as $g) {
+ $gids[] = $g['id'];
+ }
+ $job = $database->has('jobs', ['[>]job_groups' => ['jobid']], ["AND" => ['groupid' => $gids, 'jobs.jobid' => $VARS['job']]]);
+ } else {
+ $job = $database->has('jobs', 'jobid', ['jobid' => $VARS['job']]);
+ }
+ if ($job) {
+ // Stop other jobs
+ $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
+ $database->insert('job_tracking', ['uid' => $_SESSION['uid'], 'jobid' => $VARS['job'], 'start' => date("Y-m-d H:i:s")]);
+ returnToSender("job_changed");
+ } else if ($VARS['job'] == "-1") {
+ $database->update('job_tracking', ['end' => date("Y-m-d H:i:s")], ['AND' => ['uid' => $_SESSION['uid'], 'end' => null]]);
+ returnToSender("job_changed");
+ } else {
+ returnToSender("job_invalid");
+ }
+ break;
+ case "editjob":
+ if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
+ $name = htmlentities($VARS['jobname']);
+ $code = $VARS['jobcode'];
+ $color = $VARS['color'];
+
+ if (is_empty($VARS['jobid'])) {
+ if ($database->has('jobs', ['jobname' => $name])) {
+ returnToSender("job_name_used");
+ }
+ $database->insert('jobs', ["jobname" => $name, "jobcode" => $code, "color" => $color]);
+ returnToSender("job_added");
+ } else if ($database->has('jobs', ['jobid' => $VARS['jobid']])) {
+ $database->update('jobs', ["jobname" => $name, "jobcode" => $code, "color" => $color], ["jobid" => $VARS['jobid']]);
+ returnToSender("job_saved");
+ } else {
+ returnToSender("invalid_jobid");
+ }
+ } else {
+ returnToSender("no_permission");
+ }
+ break;
+ case "deletejob":
+ if (account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN")) {
+ if (is_empty($VARS['jobid'])) {
+ returnToSender("invalid_jobid");
+ } else if ($database->has('jobs', ['jobid' => $VARS['jobid']])) {
+ $database->update('jobs', ["deleted" => 1], ["jobid" => $VARS['jobid']]);
+ returnToSender("job_deleted");
+ } else {
+ returnToSender("invalid_jobid");
+ }
+ } else {
+ returnToSender("no_permission");
+ }
+ break;
+ case "editjobhistory":
+ require_once __DIR__ . "/lib/userinfo.php";
+
+ if ($database->has('job_tracking', ['id' => $VARS['jobid']])) {
+ $uid = $database->get('job_tracking', 'uid', ['id' => $VARS['jobid']]);
+ } else {
+ returnToSender("invalid_parameters");
+ }
+
+ if (!$database->has("jobs", ['jobid' => $VARS['job']])) {
+ returnToSender("invalid_jobid");
+ }
+
+ $start = strtotime($VARS['start']);
+ $end = strtotime($VARS['end']);
+ if ($start === false) {
+ returnToSender("invalid_datetime");
+ }
+ if ($end === false) {
+ returnToSender("invalid_datetime");
+ }
+ if ($end < $start) {
+ returnToSender("in_before_out");
+ }
+
+ if (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
+ ) || (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
+ )
+ ) {
+ $data = [
+ "jobid" => $VARS['job'],
+ "start" => date('Y-m-d H:i:s', $start),
+ "end" => date('Y-m-d H:i:s', $end)
+ ];
+ $database->update("job_tracking", $data, ["id" => $VARS['jobid']]);
+ returnToSender("job_saved");
+ } else {
+ returnToSender("no_permission");
+ }
+ case "deletejobhistory":
+ require_once __DIR__ . "/lib/userinfo.php";
+
+ if ($database->has('job_tracking', ['id' => $VARS['jobid']])) {
+ $uid = $database->get('job_tracking', 'uid', ['id' => $VARS['jobid']]);
+ } else {
+ returnToSender("invalid_parameters");
+ }
+
+ if (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_ADMIN") || (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_MANAGE") && isManagerOf($_SESSION['uid'], $uid)
+ ) || (
+ account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF") && $_SESSION['uid'] == $uid
+ )
+ ) {
+
+ $database->delete("job_tracking", ["id" => $VARS['jobid']]);
+ returnToSender("job_deleted");
+ } else {
+ returnToSender("no_permission");
+ }
case "autocomplete_user":
header("Content-Type: application/json");
$client = new GuzzleHttp\Client();
diff --git a/database.mwb b/database.mwb
index 398ab2f..e114da2 100644
Binary files a/database.mwb and b/database.mwb differ
diff --git a/database.sql b/database.sql
index 7df9f63..3caafb8 100644
--- a/database.sql
+++ b/database.sql
@@ -1,5 +1,5 @@
-- MySQL Script generated by MySQL Workbench
--- Mon 20 Nov 2017 08:04:01 PM MST
+-- Wed 03 Jan 2018 07:18:58 PM MST
-- Model: New Model Version: 1.0
-- MySQL Workbench Forward Engineering
@@ -89,6 +89,64 @@ CREATE TABLE IF NOT EXISTS `qwikclock`.`report_access_codes` (
ENGINE = InnoDB;
+-- -----------------------------------------------------
+-- Table `qwikclock`.`jobs`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`jobs` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`jobs` (
+ `jobid` INT NOT NULL AUTO_INCREMENT,
+ `jobname` VARCHAR(200) NOT NULL,
+ `jobcode` VARCHAR(200) NULL,
+ `color` VARCHAR(45) NULL,
+ `deleted` TINYINT(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`jobid`),
+ UNIQUE INDEX `jobid_UNIQUE` (`jobid` ASC))
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`job_groups`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`job_groups` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`job_groups` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `groupid` VARCHAR(45) NOT NULL,
+ `jobid` INT NOT NULL,
+ PRIMARY KEY (`id`, `groupid`, `jobid`),
+ UNIQUE INDEX `id_UNIQUE` (`id` ASC),
+ INDEX `fk_job_groups_jobs1_idx` (`jobid` ASC),
+ CONSTRAINT `fk_job_groups_jobs1`
+ FOREIGN KEY (`jobid`)
+ REFERENCES `qwikclock`.`jobs` (`jobid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+ENGINE = InnoDB;
+
+
+-- -----------------------------------------------------
+-- Table `qwikclock`.`job_tracking`
+-- -----------------------------------------------------
+DROP TABLE IF EXISTS `qwikclock`.`job_tracking` ;
+
+CREATE TABLE IF NOT EXISTS `qwikclock`.`job_tracking` (
+ `id` INT NOT NULL AUTO_INCREMENT,
+ `uid` INT NOT NULL,
+ `jobid` INT NOT NULL,
+ `start` DATETIME NULL,
+ `end` DATETIME NULL,
+ PRIMARY KEY (`id`, `uid`, `jobid`),
+ INDEX `fk_job_tracking_jobs1_idx` (`jobid` ASC),
+ UNIQUE INDEX `id_UNIQUE` (`id` ASC),
+ CONSTRAINT `fk_job_tracking_jobs1`
+ FOREIGN KEY (`jobid`)
+ REFERENCES `qwikclock`.`jobs` (`jobid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+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/database_upgrade/1.0.1_1.1.sql b/database_upgrade/1.0.1_1.1.sql
new file mode 100644
index 0000000..5777f8f
--- /dev/null
+++ b/database_upgrade/1.0.1_1.1.sql
@@ -0,0 +1,47 @@
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+CREATE TABLE IF NOT EXISTS `jobs` (
+ `jobid` INT(11) NOT NULL AUTO_INCREMENT,
+ `jobname` VARCHAR(200) NOT NULL,
+ `jobcode` VARCHAR(200) NULL DEFAULT NULL,
+ `color` VARCHAR(45) NULL DEFAULT NULL,
+ `deleted` TINYINT(1) NOT NULL DEFAULT 0,
+ PRIMARY KEY (`jobid`),
+ UNIQUE INDEX `jobid_UNIQUE` (`jobid` ASC))
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8;
+
+CREATE TABLE IF NOT EXISTS `job_groups` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `groupid` VARCHAR(45) NOT NULL,
+ `jobid` INT(11) NOT NULL,
+ PRIMARY KEY (`id`, `groupid`, `jobid`),
+ UNIQUE INDEX `id_UNIQUE` (`id` ASC),
+ INDEX `fk_job_groups_jobs1_idx` (`jobid` ASC),
+ CONSTRAINT `fk_job_groups_jobs1`
+ FOREIGN KEY (`jobid`)
+ REFERENCES `qwikclock`.`jobs` (`jobid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8;
+
+CREATE TABLE IF NOT EXISTS `job_tracking` (
+ `id` INT(11) NOT NULL AUTO_INCREMENT,
+ `uid` INT(11) NOT NULL,
+ `jobid` INT(11) NOT NULL,
+ `start` DATETIME NULL DEFAULT NULL,
+ `end` DATETIME NULL DEFAULT NULL,
+ PRIMARY KEY (`id`, `uid`, `jobid`),
+ INDEX `fk_job_tracking_jobs1_idx` (`jobid` ASC),
+ UNIQUE INDEX `id_UNIQUE` (`id` ASC),
+ CONSTRAINT `fk_job_tracking_jobs1`
+ FOREIGN KEY (`jobid`)
+ REFERENCES `qwikclock`.`jobs` (`jobid`)
+ ON DELETE NO ACTION
+ ON UPDATE NO ACTION)
+ENGINE = InnoDB
+DEFAULT CHARACTER SET = utf8;
diff --git a/lang/en_us.php b/lang/en_us.php
index 37741d4..aa040a0 100644
--- a/lang/en_us.php
+++ b/lang/en_us.php
@@ -32,6 +32,7 @@ define("STRINGS", [
"login server user data error" => "The login server refused to provide account information. Try again or contact technical support.",
"captcha error" => "There was a problem with the CAPTCHA (robot test). Try again.",
"home" => "Home",
+ "more" => "More",
"punch in out" => "Punch In/Out",
"punch in" => "Punch in",
"punch out" => "Punch out",
@@ -42,6 +43,7 @@ define("STRINGS", [
"punched in" => "You are now on the clock.",
"punched out" => "You are now off the clock.",
"punch card" => "Punch Card",
+ "punches" => "Punches",
"in" => "In",
"out" => "Out",
"notes" => "Notes",
@@ -56,6 +58,7 @@ define("STRINGS", [
"show all punches" => "Show other users",
"name" => "Name",
"start" => "Start",
+ "stop" => "Stop",
"end" => "End",
"days" => "Days",
"sunday" => "Sunday",
@@ -86,7 +89,7 @@ define("STRINGS", [
"choose a shift" => "Choose a shift",
"shift assigned" => "Shift assigned.",
"shift assigned but removal failed" => "Shift assigned successfully, but one or more users are not managed by you and were not removed.",
- "report export" => "Reports/Export",
+ "reports" => "Reports",
"report type" => "Report type",
"format" => "Format",
"generate report" => "Generate report",
@@ -121,5 +124,26 @@ define("STRINGS", [
"punch deleted" => "Punch deleted.",
"hours" => "Hours",
"hours:minutes" => "H:MM",
- "totals" => "Totals"
+ "totals" => "Totals",
+ "select a job" => "Select a Job",
+ "jobs" => "Jobs",
+ "job history" => "Job History",
+ "job changed" => "Job changed.",
+ "edit jobs" => "Edit Jobs",
+ "assign job" => "Assign Job",
+ "none" => "None",
+ "job" => "Job",
+ "add job" => "Add Job",
+ "code" => "Code",
+ "new job" => "New Job",
+ "edit job" => "Edit Job",
+ "save" => "Save",
+ "color" => "Color",
+ "delete" => "Delete",
+ "job name in use" => "Job name already used. Pick another.",
+ "invalid job" => "Invalid job",
+ "job saved" => "Job saved.",
+ "job added" => "Job added.",
+ "job deleted" => "Job deleted.",
+ "show all" => "Show all",
]);
\ No newline at end of file
diff --git a/lang/messages.php b/lang/messages.php
index 4b6f43b..a4016a7 100644
--- a/lang/messages.php
+++ b/lang/messages.php
@@ -106,4 +106,32 @@ define("MESSAGES", [
"string" => "punch deleted",
"type" => "success"
],
+ "job_changed" => [
+ "string" => "job changed",
+ "type" => "success"
+ ],
+ "job_invalid" => [
+ "string" => "invalid job",
+ "type" => "danger"
+ ],
+ "job_added" => [
+ "string" => "job added",
+ "type" => "success"
+ ],
+ "job_saved" => [
+ "string" => "job saved",
+ "type" => "success"
+ ],
+ "job_deleted" => [
+ "string" => "job deleted",
+ "type" => "success"
+ ],
+ "job_name_used" => [
+ "string" => "job name in use",
+ "type" => "danger"
+ ],
+ "invalid_jobid" => [
+ "string" => "invalid job",
+ "type" => "danger"
+ ],
]);
diff --git a/lib/getjobhistorytable.php b/lib/getjobhistorytable.php
new file mode 100644
index 0000000..59307d7
--- /dev/null
+++ b/lib/getjobhistorytable.php
@@ -0,0 +1,143 @@
+count('job_tracking');
+} else {
+ $out['recordsTotal'] = $database->count('job_tracking', ['uid' => $managed_uids]);
+}
+
+$filter = false;
+
+// sort
+$order = null;
+$sortby = "DESC";
+if ($VARS['order'][0]['dir'] == 'asc') {
+ $sortby = "ASC";
+}
+switch ($VARS['order'][0]['column']) {
+ case 2:
+ $order = ["jobname" => $sortby];
+ break;
+ case 3:
+ $order = ["start" => $sortby];
+ break;
+ case 4:
+ $order = ["end" => $sortby];
+ break;
+}
+
+// search
+if (!is_empty($VARS['search']['value'])) {
+ $filter = true;
+ $wherenolimit = [
+ "AND" => [
+ "OR" => [
+ "jobname[~]" => $VARS['search']['value'],
+ "jobcode[~]" => $VARS['search']['value'],
+ "start[~]" => $VARS['search']['value'],
+ "end[~]" => $VARS['search']['value'],
+ ],
+ "uid" => $managed_uids
+ ]
+ ];
+ if ($managed_uids !== false) {
+ $where["AND"]["uid"] = $managed_uids;
+ }
+ $where = $wherenolimit;
+ $where["LIMIT"] = [$VARS['start'], $VARS['length']];
+} else {
+ $where = ["LIMIT" => [$VARS['start'], $VARS['length']]];
+ if ($managed_uids !== false) {
+ $where["uid"] = $managed_uids;
+ }
+}
+
+if (!is_null($order)) {
+ $where["ORDER"] = $order;
+}
+
+
+$jobs = $database->select('job_tracking', ['[>]jobs' => ['jobid']], [
+ 'id',
+ 'job_tracking.jobid',
+ 'uid',
+ 'start',
+ 'end',
+ 'jobname',
+ 'jobcode',
+ 'color',
+ 'deleted'
+ ], $where);
+
+$usercache = [];
+
+$editself = account_has_permission($_SESSION['username'], "QWIKCLOCK_EDITSELF");
+
+for ($i = 0; $i < count($jobs); $i++) {
+ // Get user info
+ if (!isset($usercache[$jobs[$i]['uid']])) {
+ $usercache[$jobs[$i]['uid']] = getUserByID($jobs[$i]['uid']);
+ }
+
+ $jobs[$i][0] = "";
+ if ($_SESSION['uid'] == $jobs[$i]['uid']) {
+ if ($editself) {
+ $jobs[$i][1] = ' ' . lang("edit", false) . '';
+ } else {
+ $jobs[$i][1] = "";
+ }
+ } else if ($showmanaged) {
+ $jobs[$i][1] = ' ' . lang("edit", false) . '';
+ } else {
+ $jobs[$i][1] = "";
+ }
+ $jobs[$i][2] = ' ' . ($jobs[$i]['deleted'] == 1 ? "" : "") . $jobs[$i]['jobname'] . ($jobs[$i]['deleted'] == 1 ? "" : "");
+ $jobs[$i][3] = date(DATETIME_FORMAT, strtotime($jobs[$i]['start']));
+ if (is_null($jobs[$i]['end'])) {
+ $jobs[$i][4] = lang("na", false);
+ } else {
+ $jobs[$i][4] = date(DATETIME_FORMAT, strtotime($jobs[$i]['end']));
+ }
+ $jobs[$i][5] = $usercache[$jobs[$i]['uid']]['name'];
+}
+
+$out['status'] = "OK";
+if ($filter) {
+ $recordsFiltered = $database->count('job_tracking', ['[>]jobs' => ['jobid']], 'job_tracking.id', $wherenolimit);
+} else {
+ $recordsFiltered = $out['recordsTotal'];
+}
+$out['recordsFiltered'] = $recordsFiltered;
+$out['data'] = $jobs;
+
+echo json_encode($out);
diff --git a/pages.php b/pages.php
index 28fcb79..2f720a3 100644
--- a/pages.php
+++ b/pages.php
@@ -19,7 +19,7 @@ define("PAGES", [
"title" => "404 error"
],
"punches" => [
- "title" => "punch card",
+ "title" => "punches",
"navbar" => true,
"icon" => "clock-o",
"styles" => [
@@ -31,6 +31,50 @@ define("PAGES", [
"static/js/punches.js"
]
],
+ "jobs" => [
+ "title" => "jobs",
+ "navbar" => true,
+ "icon" => "briefcase",
+ "styles" => [
+ "static/css/datatables.min.css",
+ "static/css/tables.css"
+ ],
+ "scripts" => [
+ "static/js/datatables.min.js",
+ "static/js/jobs.js"
+ ]
+ ],
+ "editjobs" => [
+ "title" => "jobs",
+ "navbar" => false,
+ "icon" => "briefcase",
+ "styles" => [
+ "static/css/datatables.min.css",
+ "static/css/tables.css"
+ ],
+ "scripts" => [
+ "static/js/datatables.min.js",
+ "static/js/editjobs.js"
+ ]
+ ],
+ "editjob" => [
+ "title" => "edit job",
+ "navbar" => false
+ ],
+ "editjobhistory" => [
+ "title" => "edit job",
+ "navbar" => false,
+ "styles" => [
+ "static/css/bootstrap-datetimepicker.min.css",
+ "static/css/easy-autocomplete.min.css"
+ ],
+ "scripts" => [
+ "static/js/moment.min.js",
+ "static/js/bootstrap-datetimepicker.min.js",
+ "static/js/jquery.easy-autocomplete.min.js",
+ "static/js/editjobhistory.js"
+ ]
+ ],
"shifts" => [
"title" => "shifts",
"navbar" => true,
@@ -71,7 +115,7 @@ define("PAGES", [
]
],
"export" => [
- "title" => "report export",
+ "title" => "reports",
"navbar" => true,
"icon" => "download",
"styles" => [
diff --git a/pages/editjob.php b/pages/editjob.php
new file mode 100644
index 0000000..7ae42ff
--- /dev/null
+++ b/pages/editjob.php
@@ -0,0 +1,104 @@
+ "",
+ "jobname" => "",
+ "jobcode" => "",
+ "color" => ""
+];
+
+$editing = false;
+if (isset($VARS['job']) && $database->has('jobs', ['jobid' => $VARS['job']])) {
+ $editing = true;
+
+ $data = $database->get('jobs', [
+ "jobid",
+ "jobname",
+ "jobcode",
+ "color",
+ ], [
+ 'jobid' => $VARS['job']
+ ]);
+}
+?>
+
+
+ | + | + | + |
---|---|---|---|
" . ' ' . lang("edit", false) . '' . " | " . ' ' . $j['name'] . " | " . $j['code'] . " | |
+ | + | + | + |
+
+
+ | + | + | + | + | + |
---|---|---|---|---|---|
+ | + | + | + | + | + |