Add report generation
This commit is contained in:
parent
7568a18f67
commit
29fa41666d
@ -4,7 +4,9 @@
|
||||
"type": "project",
|
||||
"require": {
|
||||
"catfan/medoo": "^1.2",
|
||||
"guzzlehttp/guzzle": "^6.2"
|
||||
"guzzlehttp/guzzle": "^6.2",
|
||||
"league/csv": "^9.1",
|
||||
"lapinator/ods-php-generator": "^0.0.3"
|
||||
},
|
||||
"license": "OTHER",
|
||||
"authors": [
|
||||
|
120
composer.lock
generated
120
composer.lock
generated
@ -4,7 +4,8 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "1c8b61c5d506ae016285b99b20040cf0",
|
||||
"hash": "809fda99e7cc89e7857f8a5a7bb0bc78",
|
||||
"content-hash": "b8ba52c94c62ef0abbe09903ec2cdca8",
|
||||
"packages": [
|
||||
{
|
||||
"name": "catfan/medoo",
|
||||
@ -63,7 +64,7 @@
|
||||
"sql",
|
||||
"sqlite"
|
||||
],
|
||||
"time": "2017-05-22T04:39:48+00:00"
|
||||
"time": "2017-05-22 04:39:48"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
@ -125,7 +126,7 @@
|
||||
"rest",
|
||||
"web service"
|
||||
],
|
||||
"time": "2017-02-28T22:50:30+00:00"
|
||||
"time": "2017-02-28 22:50:30"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
@ -176,7 +177,7 @@
|
||||
"keywords": [
|
||||
"promise"
|
||||
],
|
||||
"time": "2016-12-20T10:07:11+00:00"
|
||||
"time": "2016-12-20 10:07:11"
|
||||
},
|
||||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
@ -241,7 +242,114 @@
|
||||
"uri",
|
||||
"url"
|
||||
],
|
||||
"time": "2017-03-20T17:10:46+00:00"
|
||||
"time": "2017-03-20 17:10:46"
|
||||
},
|
||||
{
|
||||
"name": "lapinator/ods-php-generator",
|
||||
"version": "v0.0.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Lapinator/odsPhpGenerator.git",
|
||||
"reference": "575314c003c2ec3032813bedcc1d27032b7b7ab2"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Lapinator/odsPhpGenerator/zipball/575314c003c2ec3032813bedcc1d27032b7b7ab2",
|
||||
"reference": "575314c003c2ec3032813bedcc1d27032b7b7ab2",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"src/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"LGPL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Laurent VUIBERT",
|
||||
"email": "lapinator@gmx.fr",
|
||||
"homepage": "http://lapinator.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Open Document Spreadsheet (.ods) generator ",
|
||||
"homepage": "https://odsphpgenerator.lapinator.net/",
|
||||
"keywords": [
|
||||
"LibreOffice",
|
||||
"ods"
|
||||
],
|
||||
"time": "2016-04-14 21:51:27"
|
||||
},
|
||||
{
|
||||
"name": "league/csv",
|
||||
"version": "9.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/thephpleague/csv.git",
|
||||
"reference": "bfa3aa8e755377cd6cc2242cfd074e48c7c300ba"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/thephpleague/csv/zipball/bfa3aa8e755377cd6cc2242cfd074e48c7c300ba",
|
||||
"reference": "bfa3aa8e755377cd6cc2242cfd074e48c7c300ba",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-mbstring": "*",
|
||||
"php": ">=7.0.10"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"friendsofphp/php-cs-fixer": "^2.0",
|
||||
"phpunit/phpunit": "^6.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-iconv": "Needed to ease transcoding CSV using iconv stream filters"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "9.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"League\\Csv\\": "src"
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ignace Nyamagana Butera",
|
||||
"email": "nyamsprod@gmail.com",
|
||||
"homepage": "https://github.com/nyamsprod/",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"description": "Csv data manipulation made easy in PHP",
|
||||
"homepage": "http://csv.thephpleague.com",
|
||||
"keywords": [
|
||||
"csv",
|
||||
"export",
|
||||
"filter",
|
||||
"import",
|
||||
"read",
|
||||
"write"
|
||||
],
|
||||
"time": "2017-10-20 08:03:26"
|
||||
},
|
||||
{
|
||||
"name": "psr/http-message",
|
||||
@ -291,7 +399,7 @@
|
||||
"request",
|
||||
"response"
|
||||
],
|
||||
"time": "2016-08-06T14:39:51+00:00"
|
||||
"time": "2016-08-06 14:39:51"
|
||||
}
|
||||
],
|
||||
"packages-dev": [],
|
||||
|
BIN
database.mwb
BIN
database.mwb
Binary file not shown.
@ -77,4 +77,17 @@ define("STRINGS", [
|
||||
"add" => "Add",
|
||||
"choose a shift" => "Choose a shift",
|
||||
"shift assigned" => "Shift assigned.",
|
||||
"report export" => "Reports/Export",
|
||||
"report type" => "Report type",
|
||||
"format" => "Format",
|
||||
"generate report" => "Generate report",
|
||||
"choose an option" => "Choose an option",
|
||||
"csv file" => "CSV text file",
|
||||
"ods file" => "ODS spreadsheet",
|
||||
"html file" => "HTML web page",
|
||||
"report filtered to" => "Report filtered to {name} ({username})",
|
||||
"all users" => "All users",
|
||||
"one user" => "One user",
|
||||
"choose user" => "Type to choose user",
|
||||
"filter" => "Filter"
|
||||
]);
|
212
lib/reports.php
Normal file
212
lib/reports.php
Normal file
@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
// Detect if loaded by the user or by PHP
|
||||
if (count(get_included_files()) == 1) {
|
||||
define("LOADED", true);
|
||||
} else {
|
||||
define("LOADED", false);
|
||||
}
|
||||
|
||||
require_once __DIR__ . "/../required.php";
|
||||
|
||||
use League\Csv\Writer;
|
||||
use League\Csv\HTMLConverter;
|
||||
use odsPhpGenerator\ods;
|
||||
use odsPhpGenerator\odsTable;
|
||||
use odsPhpGenerator\odsTableRow;
|
||||
use odsPhpGenerator\odsTableColumn;
|
||||
use odsPhpGenerator\odsTableCellString;
|
||||
use odsPhpGenerator\odsStyleTableColumn;
|
||||
use odsPhpGenerator\odsStyleTableCell;
|
||||
|
||||
// Allow access with a download code, for mobile app and stuff
|
||||
$date = date("Y-m-d H:i:s");
|
||||
if (isset($VARS['code']) && LOADED) {
|
||||
if (!$database->has('report_access_codes', ["AND" => ['code' => $VARS['code'], 'expires[>]' => $date]])) {
|
||||
dieifnotloggedin();
|
||||
}
|
||||
} else {
|
||||
dieifnotloggedin();
|
||||
}
|
||||
|
||||
// Delete old DB entries
|
||||
$database->delete('report_access_codes', ['expires[<=]' => $date]);
|
||||
|
||||
if (LOADED) {
|
||||
$user = null;
|
||||
require_once __DIR__ . "/userinfo.php";
|
||||
require_once __DIR__ . "/login.php";
|
||||
if ($VARS['users'] != "all" && !is_empty($VARS['user']) && user_exists($VARS['user'])) {
|
||||
$user = getUserByUsername($VARS['user']);
|
||||
}
|
||||
if (isset($VARS['type']) && isset($VARS['format'])) {
|
||||
generateReport($VARS['type'], $VARS['format'], $user);
|
||||
die();
|
||||
} else {
|
||||
lang("invalid parameters");
|
||||
die();
|
||||
}
|
||||
}
|
||||
|
||||
function getShiftReport($user = null) {
|
||||
global $database;
|
||||
if ($user != null && array_key_exists('uid', $user)) {
|
||||
$shifts = $database->select(
|
||||
"shifts", [
|
||||
"[>]assigned_shifts" => ["shiftid" => "shiftid"]
|
||||
], [
|
||||
"shifts.shiftid", "shiftname", "start", "end", "days"
|
||||
], [
|
||||
"uid" => $user['uid']
|
||||
]
|
||||
);
|
||||
} else {
|
||||
$shifts = $database->select(
|
||||
"shifts", [
|
||||
"shiftid", "shiftname", "start", "end", "days"
|
||||
]
|
||||
);
|
||||
}
|
||||
$header = [lang("shiftid", false), lang("shift name", false), lang("start", false), lang("end", false), lang("workers", false), lang("sunday", false), lang("monday", false), lang("tuesday", false), lang("wednesday", false), lang("thursday", false), lang("friday", false), lang("saturday", false)];
|
||||
$out = [$header];
|
||||
for ($i = 0; $i < count($shifts); $i++) {
|
||||
$daycodes = str_split($shifts[$i]['days'], 2);
|
||||
$assigned = $database->count("assigned_shifts", ['shiftid' => $shifts[$i]["shiftid"]]);
|
||||
$out[] = [
|
||||
$shifts[$i]["shiftid"],
|
||||
$shifts[$i]["shiftname"],
|
||||
date(TIME_FORMAT, strtotime($shifts[$i]['start'])),
|
||||
date(TIME_FORMAT, strtotime($shifts[$i]['end'])),
|
||||
$assigned . "",
|
||||
(in_array("Su", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("Mo", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("Tu", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("We", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("Th", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("Fr", $daycodes) == true ? "Y" : "N"),
|
||||
(in_array("Sa", $daycodes) == true ? "Y" : "N")
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
function getReportData($type, $user = null) {
|
||||
switch ($type) {
|
||||
case "shifts":
|
||||
return getShiftReport($user);
|
||||
break;
|
||||
default:
|
||||
return [["error"]];
|
||||
}
|
||||
}
|
||||
|
||||
function dataToCSV($data, $name = "report", $user = null) {
|
||||
$csv = Writer::createFromString('');
|
||||
$usernotice = "";
|
||||
$usertitle = "";
|
||||
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);
|
||||
$usertitle = "_" . $user['username'];
|
||||
$csv->insertOne([$usernotice]);
|
||||
}
|
||||
$csv->insertAll($data);
|
||||
header('Content-type: text/csv');
|
||||
header('Content-Disposition: attachment; filename="' . $name . $usertitle . "_" . date("Y-m-d_Hi") . ".csv" . '"');
|
||||
echo $csv;
|
||||
die();
|
||||
}
|
||||
|
||||
function dataToODS($data, $name = "report", $user = null) {
|
||||
$ods = new ods();
|
||||
$styleColumn = new odsStyleTableColumn();
|
||||
$styleColumn->setUseOptimalColumnWidth(true);
|
||||
$headerstyle = new odsStyleTableCell();
|
||||
$headerstyle->setFontWeight("bold");
|
||||
$table = new odsTable($name);
|
||||
|
||||
for ($i = 0; $i < count($data[0]); $i++) {
|
||||
$table->addTableColumn(new odsTableColumn($styleColumn));
|
||||
}
|
||||
|
||||
$usernotice = "";
|
||||
$usertitle = "";
|
||||
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);
|
||||
$usertitle = "_" . $user['username'];
|
||||
$row = new odsTableRow();
|
||||
$row->addCell(new odsTableCellString($usernotice));
|
||||
$table->addRow($row);
|
||||
}
|
||||
|
||||
$rowid = 0;
|
||||
foreach ($data as $datarow) {
|
||||
$row = new odsTableRow();
|
||||
foreach ($datarow as $cell) {
|
||||
if ($rowid == 0) {
|
||||
$row->addCell(new odsTableCellString($cell, $headerstyle));
|
||||
} else {
|
||||
$row->addCell(new odsTableCellString($cell));
|
||||
}
|
||||
}
|
||||
$table->addRow($row);
|
||||
$rowid++;
|
||||
}
|
||||
$ods->addTable($table);
|
||||
$ods->downloadOdsFile($name . $usertitle . "_" . date("Y-m-d_Hi") . ".ods");
|
||||
}
|
||||
|
||||
function dataToHTML($data, $name = "report", $user = null) {
|
||||
global $SECURE_NONCE;
|
||||
// HTML exporter doesn't like null values
|
||||
for ($i = 0; $i < count($data); $i++) {
|
||||
for ($j = 0; $j < count($data[$i]); $j++) {
|
||||
if (is_null($data[$i][$j])) {
|
||||
$data[$i][$j] = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
$usernotice = "";
|
||||
$usertitle = "";
|
||||
if ($user != null && array_key_exists('username', $user) && array_key_exists('name', $user)) {
|
||||
$usernotice = "<span>" . lang2("report filtered to", ["name" => $user['name'], "username" => $user['username']], false) . "</span><br />";
|
||||
$usertitle = "_" . $user['username'];
|
||||
}
|
||||
header('Content-type: text/html');
|
||||
$converter = new HTMLConverter();
|
||||
$out = "<!DOCTYPE html>\n"
|
||||
. "<meta charset=\"utf-8\">\n"
|
||||
. "<meta name=\"viewport\" content=\"width=device-width\">\n"
|
||||
. "<title>" . $name . $usertitle . "_" . date("Y-m-d_Hi") . "</title>\n"
|
||||
. <<<STYLE
|
||||
<style nonce="$SECURE_NONCE">
|
||||
.table-csv-data {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.table-csv-data tr:first-child {
|
||||
font-weight: bold;
|
||||
}
|
||||
.table-csv-data tr td {
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
STYLE
|
||||
. $usernotice
|
||||
. $converter->convert($data);
|
||||
echo $out;
|
||||
}
|
||||
|
||||
function generateReport($type, $format, $user = null) {
|
||||
$data = getReportData($type, $user);
|
||||
switch ($format) {
|
||||
case "ods":
|
||||
dataToODS($data, $type, $user);
|
||||
break;
|
||||
case "html":
|
||||
dataToHTML($data, $type, $user);
|
||||
break;
|
||||
case "csv":
|
||||
default:
|
||||
echo dataToCSV($data, $type, $user);
|
||||
break;
|
||||
}
|
||||
}
|
12
pages.php
12
pages.php
@ -51,6 +51,18 @@ define("PAGES", [
|
||||
"static/js/addshift.js"
|
||||
]
|
||||
],
|
||||
"export" => [
|
||||
"title" => "report export",
|
||||
"navbar" => true,
|
||||
"icon" => "download",
|
||||
"styles" => [
|
||||
"static/css/easy-autocomplete.min.css"
|
||||
],
|
||||
"scripts" => [
|
||||
"static/js/jquery.easy-autocomplete.min.js",
|
||||
"static/js/export.js"
|
||||
]
|
||||
],
|
||||
"assignshift" => [
|
||||
"title" => "assign shift",
|
||||
"navbar" => false,
|
||||
|
48
pages/export.php
Normal file
48
pages/export.php
Normal file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
require_once __DIR__ . '/../required.php';
|
||||
|
||||
redirectifnotloggedin();
|
||||
?>
|
||||
|
||||
<form action="lib/reports.php" method="GET" target="_BLANK">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-md-4">
|
||||
<label for="type"><?php lang("report type"); ?></label>
|
||||
<select name="type" class="form-control" required>
|
||||
<option value="shifts"><?php lang("shifts") ?></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-4">
|
||||
<label for="users"><?php lang("filter"); ?></label>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input name="users" value="all" checked="" type="radio"> <i class="fa fa-users fa-fw"></i>
|
||||
<?php lang("all users") ?>
|
||||
</label>
|
||||
</div>
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input name="users" value="one" type="radio"> <i class="fa fa-user fa-fw"></i>
|
||||
<?php lang("one user") ?>
|
||||
<input type="text" name="user" class="form-control" id="user-box" placeholder="<?php lang("choose user") ?>" />
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-md-4">
|
||||
<label for="type"><?php lang("format"); ?></label>
|
||||
<select name="format" class="form-control" required>
|
||||
<option value="csv"><?php lang("csv file") ?></option>
|
||||
<option value="ods"><?php lang("ods file") ?></option>
|
||||
<option value="html"><?php lang("html file") ?></option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<?php
|
||||
$code = uniqid(rand(10000000, 99999999), true);
|
||||
$database->insert('report_access_codes', ['code' => $code, 'expires' => date("Y-m-d H:i:s", strtotime("+5 minutes"))]);
|
||||
?>
|
||||
<input type="hidden" name="code" value="<?php echo $code; ?>" />
|
||||
|
||||
<button type="submit" class="btn btn-success" id="genrptbtn"><i class="fa fa-download"></i> <?php lang("generate report"); ?></button>
|
||||
</form>
|
@ -78,6 +78,10 @@
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
#user-box {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/*
|
||||
==============================
|
||||
THEMING
|
||||
|
31
static/js/export.js
Normal file
31
static/js/export.js
Normal file
@ -0,0 +1,31 @@
|
||||
$("#genrptbtn").click(function () {
|
||||
setTimeout(function () {
|
||||
window.location.reload();
|
||||
}, 1000)
|
||||
});
|
||||
|
||||
var options = {
|
||||
url: "action.php",
|
||||
ajaxSettings: {
|
||||
dataType: "json",
|
||||
method: "GET",
|
||||
data: {
|
||||
action: "autocomplete_user"
|
||||
}
|
||||
},
|
||||
preparePostData: function (data) {
|
||||
data.q = $("#user-box").val();
|
||||
return data;
|
||||
},
|
||||
getValue: function (element) {
|
||||
return element.username;
|
||||
},
|
||||
template: {
|
||||
type: "custom",
|
||||
method: function (value, item) {
|
||||
return item.name + " <i class=\"small\">" + item.username + "</i>";
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$("#user-box").easyAutocomplete(options);
|
Loading…
x
Reference in New Issue
Block a user