More improvements e.g. flags and provision target

This commit is contained in:
2026-08-11 07:48:46 +02:00
parent a3d4825cbd
commit 41556cfe73
22 changed files with 961 additions and 484 deletions
+1 -1
View File
@@ -18,7 +18,7 @@ Yacht Management Software (YMS) Installation
1.3 Web GUI 1.3 Web GUI
- Webserver - Webserver
- PHP - PHP (>= 8.0)
- php-mysql - php-mysql
- php-xml - php-xml
+5 -2
View File
@@ -159,7 +159,7 @@ CREATE TABLE inventory (
weight float(5,2) UNSIGNED DEFAULT NULL, weight float(5,2) UNSIGNED DEFAULT NULL,
price decimal(12,2) DEFAULT NULL, price decimal(12,2) DEFAULT NULL,
purchdate date DEFAULT NULL, purchdate date DEFAULT NULL,
invcond enum('unknown','new','good','normal','bad','repairable','defect') NOT NULL default 'unknown', invcond enum('unknown','excellent','good','fair','bad','repairable','defect') NOT NULL default 'unknown',
remarks varchar(150) DEFAULT NULL, remarks varchar(150) DEFAULT NULL,
PRIMARY KEY (invid), PRIMARY KEY (invid),
INDEX ix_invname (invname) INDEX ix_invname (invname)
@@ -178,7 +178,7 @@ CREATE TABLE cable (
color char(6) DEFAULT NULL, color char(6) DEFAULT NULL,
supplier smallint(6) DEFAULT NULL, supplier smallint(6) DEFAULT NULL,
manufacturer smallint(6) DEFAULT NULL, manufacturer smallint(6) DEFAULT NULL,
cablecond enum('unknown','new','good','normal','bad','repairable','defect') NOT NULL default 'unknown', cablecond enum('unknown','new','excellent','good','fair','bad','repairable','defect') NOT NULL default 'unknown',
remarks varchar(150) DEFAULT NULL, remarks varchar(150) DEFAULT NULL,
PRIMARY KEY (cableid), PRIMARY KEY (cableid),
INDEX ix_cablename (vid, cablename) INDEX ix_cablename (vid, cablename)
@@ -222,11 +222,13 @@ CREATE TABLE provisions (
sid smallint(6) UNSIGNED DEFAULT NULL, sid smallint(6) UNSIGNED DEFAULT NULL,
boxid smallint(6) UNSIGNED NOT NULL DEFAULT 1, boxid smallint(6) UNSIGNED NOT NULL DEFAULT 1,
number smallint(6) UNSIGNED NOT NULL DEFAULT 1, number smallint(6) UNSIGNED NOT NULL DEFAULT 1,
target smallint(6) UNSIGNED DEFAULT NULL, -- for shopping list
weight float(5,2) UNSIGNED DEFAULT NULL, weight float(5,2) UNSIGNED DEFAULT NULL,
weight_net float(5,2) UNSIGNED DEFAULT NULL, weight_net float(5,2) UNSIGNED DEFAULT NULL,
unit tinyint(3) DEFAULT NULL, unit tinyint(3) DEFAULT NULL,
storedate date DEFAULT CURRENT_DATE, storedate date DEFAULT CURRENT_DATE,
shelflife date DEFAULT NULL, shelflife date DEFAULT NULL,
remarks varchar(150) DEFAULT NULL,
PRIMARY KEY (provid) PRIMARY KEY (provid)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
@@ -283,6 +285,7 @@ CREATE TABLE company (
customerno varchar(20), customerno varchar(20),
contractno varchar(20), contractno varchar(20),
remarks varchar(150) DEFAULT NULL, remarks varchar(150) DEFAULT NULL,
flags set('deleted','historic') DEFAULT NULL,
PRIMARY KEY (compid), PRIMARY KEY (compid),
UNIQUE INDEX ix_compname (compname, comptype) UNIQUE INDEX ix_compname (compname, comptype)
) ENGINE=InnoDB; ) ENGINE=InnoDB;
+45
View File
@@ -171,6 +171,11 @@ $box = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', $box->label, "</h2>\n"; echo '<h2>', $box->label, "</h2>\n";
// Bootstrap grid
echo '<div class="container">';
echo '<div class="row">';
echo '<div class="col">';
echo '<table class="table">', "\n"; echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Box type'),"</th><td>", ($opt_boxtype[$box->boxtype] ?? ''), "</td></tr>\n"; echo '<tr><th style="width:20%">', _('Box type'),"</th><td>", ($opt_boxtype[$box->boxtype] ?? ''), "</td></tr>\n";
echo '<tr><th>', _('Content'),"</th><td>", $box->content, "</td></tr>\n"; echo '<tr><th>', _('Content'),"</th><td>", $box->content, "</td></tr>\n";
@@ -184,6 +189,46 @@ echo "</table>\n";
form_view_buttons($g_scriptname, $id); form_view_buttons($g_scriptname, $id);
echo '</div>'; // Column break
echo '<div class="col">', "\n";
echo '<div class="card mb-2">', "\n";
echo '<div class="card-header">', _('Images'), "</div>\n";
echo '<div class="card-body d-flex flex-wrap gap-3">', "\n";
$sql = "SELECT d.docid, d.title "
. "FROM docref AS r INNER JOIN document AS d using (docid) "
. "WHERE d.doctype='picture' AND r.reftype='box' AND r.refid=? "
. "ORDER BY d.title";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$res = $sth->fetchAll();
// TODO hübsche Darstellung
$doccount = 0;
foreach ($res as $row) {
$doccount += 1;
echo '<div class="border rounded p-2 d-flex flex-column" style="width: 150px;">';
echo '<a href="dl.php?id=', $row['docid'], '">';
// echo '<img width="120" src="doc/pic-', $row['hash'], '.', $row['extension'],'">';
echo '<img class="img-fluid rounded mb-2" width="120" src="dl.php?id=', $row['docid'], '" alt="', $row['title'], '">';
echo "</a>\n";
// additionally direct download and go to document details page
echo '<div class="d-flex justify-content-between mt-auto">';
echo '<a href="documents.php?f=view&id=', $row['docid'], '" title="', _('View image details'), '"> <i class="bi bi-eye"></i></a>';
echo '<a href="dl.php?id=', $row['docid'], '" title="', _('Download image'), '"><i class="bi bi-download"></i></a>';
echo "</div>\n";
echo "</div\n";
}
if ($doccount == 0) {
echo _('No referenced images'), "\n";
}
echo "</div>\n"; // card-body
echo "</div>\n"; // card
echo '</div>'; // col
echo '</div>'; // row
echo '</div>'; // container
// Inventory in box // Inventory in box
// WIP // WIP
$sql = "SELECT invid, invname, weight, number FROM inventory WHERE conttype='box' AND boxid=?"; $sql = "SELECT invid, invname, weight, number FROM inventory WHERE conttype='box' AND boxid=?";
+18 -3
View File
@@ -63,6 +63,8 @@ switch ($submit = form_get_action()) {
$p[':customerno'] = gpc_get_string($_POST, 'customerno', 20); $p[':customerno'] = gpc_get_string($_POST, 'customerno', 20);
$p[':contractno'] = gpc_get_string($_POST, 'contractno', 20); $p[':contractno'] = gpc_get_string($_POST, 'contractno', 20);
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$allowed = db_load_enum('company', 'flags');
$p[':flags'] = gpc_get_set($_POST, 'flags', $allowed, true, NULL);
db_exec_update('company', $p, 'compid'); db_exec_update('company', $p, 'compid');
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
@@ -136,7 +138,7 @@ $page = gpc_get_int($_REQUEST, 'p', 1);
$rows_pp = gpc_get_int($_REQUEST, 'n', $user->rows_pp); $rows_pp = gpc_get_int($_REQUEST, 'n', $user->rows_pp);
$lastpage = ceil($numrows/$rows_pp); $lastpage = ceil($numrows/$rows_pp);
$sql = "SELECT compid, compname, comptype, remarks " $sql = "SELECT compid, compname, comptype, remarks, flags "
. "FROM company"; . "FROM company";
if ($where) $sql .= ' WHERE ' . $where; if ($where) $sql .= ' WHERE ' . $where;
$sql .= $order; $sql .= $order;
@@ -212,6 +214,14 @@ foreach ($res as $row) {
echo "<tr>\n"; echo "<tr>\n";
echo '<td>', $i; echo '<td>', $i;
echo '<a title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['compid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n"; echo '<a title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['compid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n";
// icons for some flags
$flags = explode(',', $row['flags']);
if (in_array('historic', $flags)) {
echo '<i class="bi bi-h-square ms-2" title="', _('Historic company'), '"></i>';
}
if (in_array('deleted', $flags)) {
echo '<i class="bi bi-recycle ms-2" title="', _('Deleted'), '"></i>';
}
echo "</td>\n"; echo "</td>\n";
echo "<td>", $row['compname'], "</td>\n"; echo "<td>", $row['compname'], "</td>\n";
echo "<td>", $opt_comptype[$row['comptype']], "</td>\n"; echo "<td>", $opt_comptype[$row['comptype']], "</td>\n";
@@ -251,7 +261,7 @@ elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT compname, comptype, comptype2, shortname, street, zip, city," $sql = "SELECT compname, comptype, comptype2, shortname, street, zip, city,"
. " country, contact, phone, email, web, customerno, contractno, remarks " . " country, contact, phone, email, web, customerno, contractno, remarks, flags "
. "FROM company " . "FROM company "
. "WHERE compid=?"; . "WHERE compid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -283,6 +293,7 @@ echo make_weblink($company->web), ' ', $company->web, "</td></tr>\n";
echo '<tr><th scope="row">', _('Customer no.'),"</th><td>", $company->customerno, "</td></tr>\n"; echo '<tr><th scope="row">', _('Customer no.'),"</th><td>", $company->customerno, "</td></tr>\n";
echo '<tr><th scope="row">', _('Contract no.'),"</th><td>", $company->contractno, "</td></tr>\n"; echo '<tr><th scope="row">', _('Contract no.'),"</th><td>", $company->contractno, "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $company->remarks, "</td></tr>\n"; echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $company->remarks, "</td></tr>\n";
echo '<tr><th scope="row">', _('Flags'),"</th><td>", $company->flags, "</td></tr>\n";
echo "</table>\n"; echo "</table>\n";
form_view_buttons($g_scriptname, $id); form_view_buttons($g_scriptname, $id);
@@ -330,7 +341,7 @@ elseif ($action == ACT_EDIT):
echo '<h2>', _('Edit Company'), "</h2>\n"; echo '<h2>', _('Edit Company'), "</h2>\n";
$sql = "SELECT compname, comptype, comptype2, street, zip, city, country," $sql = "SELECT compname, comptype, comptype2, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks " . " contact, phone, email, web, customerno, contractno, remarks, flags "
. "FROM company " . "FROM company "
. "WHERE compid=?"; . "WHERE compid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -409,6 +420,10 @@ form_create_select('comptype2', _('Secondary company type'), $g_opt_none + $opt_
<label for="remarks" class="form-label"><?=_('Remarks')?></label> <label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$company->remarks ?></textarea> <textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$company->remarks ?></textarea>
</div> </div>
<?php
$opt_flags = db_load_enum('company', 'flags', true, true, false);
form_create_checks('flags', _('Flags'), $opt_flags, explode(',', $company->flags));
?>
<button type="submit" name="submit[update]" class="btn btn-primary"><?=_('Save')?></button> <button type="submit" name="submit[update]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>?f=view&id=<?=$id?>" class="btn btn-secondary"><?=_('Back')?></a> <a href="<?=$g_scriptname?>?f=view&id=<?=$id?>" class="btn btn-secondary"><?=_('Back')?></a>
</form> </form>
+54 -20
View File
@@ -6,6 +6,14 @@
* SPDX-License-Identifier: WTFPL * SPDX-License-Identifier: WTFPL
******************************************************************************/ ******************************************************************************/
/*
doctype icons
generic: file-earmark
image: file-earmark-image
drawing: file-earmark-easel
pdf: file-earmark-pdf
*/
require 'globals.inc'; require 'globals.inc';
require 'lib/gpc.inc'; require 'lib/gpc.inc';
require 'lib/fileutils.inc'; require 'lib/fileutils.inc';
@@ -143,6 +151,12 @@ switch ($submit = form_get_action()) {
break; break;
case 'delete': case 'delete':
// check user rights
if ($user->role == ROLE_SAILOR) {
$g_error->Add(_('User level allows no deletion!'));
$action = ACT_VIEW;
break;
}
// Security token needed! // Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) { if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!')); $g_error->Add(_('Delete prohibited, invalid security token!'));
@@ -189,21 +203,18 @@ switch ($submit = form_get_action()) {
$p[':docid'] = $id; $p[':docid'] = $id;
$p[':refid'] = gpc_get_int($_POST, 'refid'); $p[':refid'] = gpc_get_int($_POST, 'refid');
$p[':reftype'] = gpc_get_enum($_POST, 'reftype', $opt_reftype, 'equipment'); $p[':reftype'] = gpc_get_enum($_POST, 'reftype', $opt_reftype, 'equipment');
/* $sql = "INSERT INTO docref "
. " (docid, refid, reftype) "
. "VALUES "
. " (:docid, :refid, :reftype)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':docid', $id, PDO::PARAM_INT);
$sth->bindValue(':refid', $refid, PDO::PARAM_INT);
$sth->bindValue(':reftype', $reftype, PDO::PARAM_STR);
$sth->execute(); */
db_exec_insert('docref', $p); db_exec_insert('docref', $p);
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
case 'delref': case 'delref':
// remove only link, not critical so get without token is ok // remove only link, not critical so get without token is ok
// check user rights
if ($user->role == ROLE_SAILOR) {
$g_error->Add(_('User level allows no deletion!'));
$action = ACT_VIEW;
break;
}
$drid = gpc_get_int($_GET, 'drid'); $drid = gpc_get_int($_GET, 'drid');
$sql = "DELETE FROM docref WHERE drid=?"; $sql = "DELETE FROM docref WHERE drid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -582,6 +593,18 @@ foreach ($sth->fetchAll() as $row) {
$compids[] = $row['refid']; $compids[] = $row['refid'];
} }
// Boxes
$boxids = array();
$sql = "SELECT drid, reftype, refid, CONCAT_WS(' - ', label, NULLIF(content, '')) AS target "
. "FROM docref INNER JOIN box ON (docref.reftype='box' AND docref.refid=box.boxid) "
. "WHERE docid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
foreach ($sth->fetchAll() as $row) {
$references[] = $row;
$boxids[] = $row['refid'];
}
echo '<table class="table table-sm">', "\n"; echo '<table class="table table-sm">', "\n";
echo "<thead>\n"; echo "<thead>\n";
echo "<tr>"; echo "<tr>";
@@ -600,6 +623,8 @@ foreach ($references as $ref) {
echo '<a title="', _('View'), '" href="equipment.php?f=view&id=', $ref['refid'],'"><i class="bi-eye ms-2"></i></a>'; echo '<a title="', _('View'), '" href="equipment.php?f=view&id=', $ref['refid'],'"><i class="bi-eye ms-2"></i></a>';
} elseif ($ref['reftype'] == 'company') { } elseif ($ref['reftype'] == 'company') {
echo '<a title="', _('View'), '" href="company.php?f=view&id=', $ref['refid'],'"><i class="bi-eye ms-2"></i></a>'; echo '<a title="', _('View'), '" href="company.php?f=view&id=', $ref['refid'],'"><i class="bi-eye ms-2"></i></a>';
} elseif ($ref['reftype'] == 'box') {
echo '<a title="', _('View'), '" href="box.php?f=view&id=', $ref['refid'],'"><i class="bi-eye ms-2"></i></a>';
} }
echo "</td>"; echo "</td>";
echo "<td>", get_enum($ref['reftype']), "</td>"; echo "<td>", get_enum($ref['reftype']), "</td>";
@@ -616,18 +641,12 @@ echo '<h4>', _('Add new reference'), "</h4>\n";
// enum('vessel','box','equipment','project','task','user','company') // enum('vessel','box','equipment','project','task','user','company')
// //
// Reference options
$opt_reference = db_load_enum('docref', 'reftype', lookup:true, as_dict:true);
// Equipment options // Equipment options
// Do not include equipment that has already been referenced in the list! // Do not include equipment that has already been referenced in the list!
$opt_equipment = array(); $opt_equipment = db_get_opt_equip($user->vid, exclude:$eids)
$sql = "SELECT eid, ename FROM equipment WHERE vid=? ORDER BY ename";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
foreach ($sth->fetchAll() as $row) {
if (!in_array($row['eid'], $eids)) {
$opt_equipment[$row['eid']] = $row['ename'];
}
}
?> ?>
<form class="mb-3" method="post" action="<?=$g_scriptname?>"> <form class="mb-3" method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>"> <input type="hidden" name="id" value="<?=$id?>">
@@ -656,8 +675,6 @@ foreach ($sth->fetchAll() as $row) {
$opt_company[$row['compid']] = $row['compname']; $opt_company[$row['compid']] = $row['compname'];
} }
} }
?> ?>
<form class="mb-3" method="post" action="<?=$g_scriptname?>"> <form class="mb-3" method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>"> <input type="hidden" name="id" value="<?=$id?>">
@@ -673,6 +690,23 @@ foreach ($opt_company as $k => $v) {
<button class="btn btn-sm btn-secondary" name="submit[addref]">Referenzieren</button> <button class="btn btn-sm btn-secondary" name="submit[addref]">Referenzieren</button>
</form> </form>
<?php
// Box options
$opt_box = db_get_opt_box($user->vid, exclude:$boxids)
?>
<form class="mb-3" method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<input type="hidden" name="reftype" value="box">
<label for="eid"><?=_('Box')?></label>
<select class="form-select mb-2" name="refid" id="boxid">
<?php
foreach ($opt_box as $k => $v) {
echo '<option value="', $k, '">', $v, "</option>\n";
}
?>
</select>
<button class="btn btn-sm btn-secondary" name="submit[addref]">Referenzieren</button>
</form>
<?php <?php
// Vessel options // Vessel options
// Do not include vessel that has already been referenced in the list! // Do not include vessel that has already been referenced in the list!
+18 -1
View File
@@ -74,6 +74,8 @@ switch ($submit = form_get_action()) {
$p[':ecat'] = gpc_get_int($_POST, 'category'); $p[':ecat'] = gpc_get_int($_POST, 'category');
if ($p[':ecat'] <= 0) $p[':ecat'] = NULL; if ($p[':ecat'] <= 0) $p[':ecat'] = NULL;
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150); $p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$allowed = db_load_enum('equipment', 'flags');
$p[':flags'] = gpc_get_set($_POST, 'flags', $allowed, true, NULL);
db_exec_update('equipment', $p, 'eid'); db_exec_update('equipment', $p, 'eid');
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
@@ -374,6 +376,17 @@ foreach ($res as $row) {
echo "<tr>\n"; echo "<tr>\n";
echo "<td>", $i; echo "<td>", $i;
echo '<a class="text-nowrap" title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['eid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n"; echo '<a class="text-nowrap" title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['eid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n";
// icons for some flags
$flags = explode(',', $row['flags']);
if (in_array('ordered', $flags)) {
echo '<i class="bi bi-cart3" title="', _('Ordered'), '"></i>';
}
if (in_array('deleted', $flags)) {
echo '<i class="bi bi-recycle" title="', _('Deleted'), '"></i>';
}
if (in_array('removed', $flags)) {
echo '<i class="bi bi-x-square" title="', _('Removed'), '"></i>';
}
echo "</td>\n"; echo "</td>\n";
echo "<td>", $row['ename'], "</td>\n"; echo "<td>", $row['ename'], "</td>\n";
echo "<td>", ($opt_manufacturer[$row['manufacturer']] ?? ''), "</td>\n"; echo "<td>", ($opt_manufacturer[$row['manufacturer']] ?? ''), "</td>\n";
@@ -624,7 +637,7 @@ foreach ($sth->fetchAll() as $row) {
} }
$sql = "SELECT eid, ename, model, serial, weight, price, purchdate," $sql = "SELECT eid, ename, model, serial, weight, price, purchdate,"
. " supplier, manufacturer, ecat, shortname, remarks " . " supplier, manufacturer, ecat, shortname, remarks, flags "
. "FROM equipment " . "FROM equipment "
. "WHERE eid=?"; . "WHERE eid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -671,6 +684,10 @@ form_create_select('category', _('Category'), $g_opt_unknown + $opt_ecat, $equip
<label for="remarks" class="form-label"><?=_('Remarks')?></label> <label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$equipment->remarks ?></textarea> <textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$equipment->remarks ?></textarea>
</div> </div>
<?php
$opt_flags = db_load_enum('equipment', 'flags', true, true, false);
form_create_checks('flags', _('Flags'), $opt_flags, explode(',', $equipment->flags));
?>
<button type="submit" name="submit[update]" class="btn btn-primary"><?=_('Save')?></button> <button type="submit" name="submit[update]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>?f=view&id=<?=$id?>" class="btn btn-secondary"><?=_('Back')?></a> <a href="<?=$g_scriptname?>?f=view&id=<?=$id?>" class="btn btn-secondary"><?=_('Back')?></a>
</form> </form>
+31 -9
View File
@@ -39,6 +39,11 @@ define ('ACT_UNLINK', 11);
define ('ACT_MAIL', 12); define ('ACT_MAIL', 12);
define ('ACT_VIEW_LIST', 13); define ('ACT_VIEW_LIST', 13);
define('ROLE_VESSEL', 'vessel');
define('ROLE_CAPTAIN', 'captain');
define('ROLE_HELMSMAN', 'helmsman');
define('ROLE_SAILOR', 'sailor');
// ========== PAGE START CODE ================================================= // ========== PAGE START CODE =================================================
// global version string // global version string
@@ -526,12 +531,15 @@ function get_enum($enum) {
'drawing' => _('Drawing'), 'drawing' => _('Drawing'),
'equipment' => _('Equipment'), 'equipment' => _('Equipment'),
'estimated' => _('Estimated'), 'estimated' => _('Estimated'),
'excellent' => _('Excellent'),
'fair' => _('Fair'),
'finished' => _('Finished'), 'finished' => _('Finished'),
'fixed' => _('Fixed'), 'fixed' => _('Fixed'),
'fuse' => _('Fuse'), 'fuse' => _('Fuse'),
'generic' => _('Generic'), 'generic' => _('Generic'),
'good' => _('Good'), 'good' => _('Good'),
'high' => _('High'), 'high' => _('High'),
'historic' => _('Historic'),
'invoice' => _('Invoice'), 'invoice' => _('Invoice'),
'locked' => _('Locked'), 'locked' => _('Locked'),
'low' => _('Low'), 'low' => _('Low'),
@@ -806,7 +814,7 @@ function db_get_opt_storage($vid) {
return $list; return $list;
} }
function db_get_opt_box($vid) { function db_get_opt_box($vid, $exclude=[]) {
global $pdo; global $pdo;
global $g_error; global $g_error;
$list = array(); $list = array();
@@ -821,12 +829,14 @@ function db_get_opt_box($vid) {
$g_error->Add($e->getMessage()); $g_error->Add($e->getMessage());
} }
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
$list[$rec[0]] = $rec[1] . ' - '. $rec[2]; if (! in_array($rec[0], $exclude)) {
$list[$rec[0]] = $rec[1] . ($rec[2] ? ' - '. $rec[2] : '');
}
} }
return $list; return $list;
} }
function db_get_opt_equip($vid, $default=NULL) { function db_get_opt_equip($vid, $default=NULL, $exclude=[]) {
global $pdo; global $pdo;
global $g_error; global $g_error;
if (isset($default)) { if (isset($default)) {
@@ -842,8 +852,10 @@ function db_get_opt_equip($vid, $default=NULL) {
$g_error->Add($e->getMessage()); $g_error->Add($e->getMessage());
} }
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) { foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
if (! in_array($rec[0], $exclude)) {
$list[$rec[0]] = $rec[1]; $list[$rec[0]] = $rec[1];
} }
}
return $list; return $list;
} }
@@ -1050,11 +1062,21 @@ function form_create_select($fieldname, $label, $optlist, $selval=NULL, $multipl
echo "</div>\n"; echo "</div>\n";
} }
function form_create_checks($fieldname, $label, $optlist, $selected) { function form_create_checks($fieldname, $label, $optlist, $selected = []) {
echo '<div class="mb-3">', "\n"; echo '<fieldset class="mb-3">';
echo '<label>', $label, "</label>\n"; echo '<legend class="fs-6 mb-1 border-bottom pb-1">', $label, "</legend>\n";
print_r($optlist); echo '<div class="d-flex flex-wrap gap-3">';
echo "</div>\n"; foreach ($optlist as $k => $v) {
echo '<div class="form-check">';
$checked = in_array($k, $selected, true) ? ' checked' : '';
echo '<label class="form-check-label">';
echo '<input type="checkbox" class="form-check-input" name="', $fieldname, '[', $k, ']"', $checked, '>';
echo $v;
echo '</label>';
echo '</div>';
}
echo '</div>';
echo '</fieldset>';
} }
// TODO DEPRECATED for touch multiple adjacent buttuns are not well suited. // TODO DEPRECATED for touch multiple adjacent buttuns are not well suited.
@@ -1418,7 +1440,7 @@ function make_weblink($dest) {
} elseif (!in_array($scheme, ['http', 'https'], true)) { } elseif (!in_array($scheme, ['http', 'https'], true)) {
return ''; return '';
} }
return '<a href="' . $dest . '"><i class="bi-globe"></i></a>'; return '<a href="' . $dest . '" target="_blank"><i class="bi-globe"></i></a>';
} }
function make_maillink($dest) { function make_maillink($dest) {
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

+5 -1
View File
@@ -242,7 +242,11 @@ if (isset($vessel->loa)) {
$h = round($row['wy'] * $f); $h = round($row['wy'] * $f);
$x = round($row['x'] * $f - $w / 2.0); $x = round($row['x'] * $f - $w / 2.0);
$y = round($row['y'] * $f + $shape['height'] / 2.0 - $h / 2.0); $y = round($row['y'] * $f + $shape['height'] / 2.0 - $h / 2.0);
$rect = $g->addChild('rect');
$a = $g->addChild('a');
$a->addAttribute('href', 'storage.php?f=view&id=' . $row['sid']);
$rect = $a->addChild('rect');
$rect->addChild('title', $row['sname']); $rect->addChild('title', $row['sname']);
$rect->addAttribute('x', $x); $rect->addAttribute('x', $x);
$rect->addAttribute('y', $y); $rect->addAttribute('y', $y);
+10 -5
View File
@@ -121,7 +121,7 @@ if ($action == ACT_DEFAULT):
page_caption_search($pagetitle); page_caption_search($pagetitle);
$flt = db_get_filter($user->id, 201, ['cond','name','txt']); $flt = db_get_filter($user->id, 201, ['stor', 'cond','txt']);
/* /*
The only way to find out whether the inventory is on the current boat is to use The only way to find out whether the inventory is on the current boat is to use
@@ -301,7 +301,7 @@ echo '<h2>', _('Add Inventory'), "</h2>\n";
<form method="post" action="<?=$g_scriptname?>"> <form method="post" action="<?=$g_scriptname?>">
<div class="mb-3"> <div class="mb-3">
<label for="invname" class="form-label"><?=_('Name')?></label> <label for="invname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="invname" name="invname"> <input type="text" class="form-control" id="invname" name="invname" autofocus>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<label for="number" class="form-label"><?=_('Number')?></label> <label for="number" class="form-label"><?=_('Number')?></label>
@@ -310,12 +310,14 @@ echo '<h2>', _('Add Inventory'), "</h2>\n";
<div class="mb-3"> <div class="mb-3">
<label for="conttype" class="form-label"><?=_('Container type')?></label> <label for="conttype" class="form-label"><?=_('Container type')?></label>
<select class="form-select" name="conttype" id="conttype"> <select class="form-select" name="conttype" id="conttype">
<option value="box"><?=_('Box')?></option>
<option value="storage"><?=_('Storage')?></option> <option value="storage"><?=_('Storage')?></option>
<option value="box"><?=_('Box')?></option>
</select> </select>
</div> </div>
<?php <?php
form_create_select('sid', _('Storage'), $g_opt_none + $opt_storage); // load current filter setting for storage default setting
$flt = db_get_filter($user->id, 201, ['stor','cond','txt']);
form_create_select('sid', _('Storage'), $g_opt_none + $opt_storage, $flt->stor);
form_create_select('boxid', _('Box'), $g_opt_none + $opt_box); form_create_select('boxid', _('Box'), $g_opt_none + $opt_box);
?> ?>
<div class="container-fluid px-0 my-3"> <div class="container-fluid px-0 my-3">
@@ -371,7 +373,10 @@ echo '<tr><th style="width:20%">', _('Box type'),"</th><td>", $inventory->contty
// Container with link // Container with link
echo '<tr><th>', $inventory->conttype == 'storage' ? _('Storage') : _('Container'); echo '<tr><th>', $inventory->conttype == 'storage' ? _('Storage') : _('Container');
echo '</th><td>', sprintf(_('%s in %s'), $box['label'], $storagename); echo '</th><td>', sprintf(_('%s in %s'), $box['label'], $storagename);
// TODO insert link // link to box
if ($inventory->conttype == 'box') {
echo '<a class="text-nowrap" title="', _('View Box'), '" href="box.php?f=view&id=', $inventory->boxid, '"><i class="bi bi-eye ms-2"></i></a>', "\n";
}
echo "</td></tr>\n"; echo "</td></tr>\n";
echo "<tr><th>", _('Location ID'), "</th><td>", $inventory->locationid, "</td></tr>\n"; echo "<tr><th>", _('Location ID'), "</th><td>", $inventory->locationid, "</td></tr>\n";
+10
View File
@@ -0,0 +1,10 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024-2026 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************
*/
+469 -405
View File
File diff suppressed because it is too large Load Diff
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
{
"name": "Shopping list",
"short_name": "Shopping",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#0d6efd",
"icons": [
{
"src": "img/pwa-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "img/pwa-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}
+2 -1
View File
@@ -134,7 +134,8 @@ Es handelt sich um die Eingabemöglichkeit in ein einzelnes Textfeld.</p>
<p>Benutzer können nicht über die Web-GUI eingerichtet werden.</p> <p>Benutzer können nicht über die Web-GUI eingerichtet werden.</p>
<p>Eine Kennwortänderung ist ebenfalls nicht über die Web-GUI möglich.</p> <p>Eine Kennwortänderung ist ebenfalls nicht über die Web-GUI möglich.</p>
<p>Es gibt die Berechtigungsebenen <em>Kapitän (captain)</em>, <p>Es gibt die Berechtigungsebenen <em>Kapitän (captain)</em>,
<em>Steuermann (helmsman)</em> und <em>Matrose (sailor)</em>. <em>Steuermann (helmsman)</em> und <em>Matrose (sailor)</em>.</p>
<p>Jeder Benutzer kann das Hauptmenü entsprechend seinen Anforderungen einstellen.</p>
<h3>Stammdaten</h3> <h3>Stammdaten</h3>
<p>Diese Daten ändern sich nicht sehr häufig, sind aber für den Betrieb <p>Diese Daten ändern sich nicht sehr häufig, sind aber für den Betrieb
+59 -8
View File
@@ -1,7 +1,7 @@
<?php <?php
/****************************************************************************** /******************************************************************************
* YMS - Yacht Management Software * YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge * Copyright (C) 2024-2026 Thomas Hooge
* *
* SPDX-License-Identifier: WTFPL * SPDX-License-Identifier: WTFPL
******************************************************************************/ ******************************************************************************/
@@ -27,6 +27,7 @@ switch ($submit = form_get_action()) {
case 'view': $action = ACT_VIEW; break; case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break; case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break; case 'del': $action = ACT_DELETE; break;
case 'list': $action = ACT_VIEW_LIST; break;
case 'filter': case 'filter':
$flt = array(); $flt = array();
@@ -55,7 +56,8 @@ switch ($submit = form_get_action()) {
$p[':provid'] = $id; $p[':provid'] = $id;
$p[':provname'] = gpc_get_string($_POST, 'provname'); $p[':provname'] = gpc_get_string($_POST, 'provname');
$p[':provcat'] = gpc_get_int($_POST, 'provcat'); $p[':provcat'] = gpc_get_int($_POST, 'provcat');
$p[':number'] = gpc_get_int($_POST, 'number'); $p[':number'] = gpc_get_uint($_POST, 'number');
$p[':target'] = gpc_get_uint($_POST, 'target');
$p[':weight'] = min(gpc_get_float($_POST, 'weight'), 999.99); // limit max value $p[':weight'] = min(gpc_get_float($_POST, 'weight'), 999.99); // limit max value
$p[':weight_net'] = min(gpc_get_float($_POST, 'weight_net'), 999.99); $p[':weight_net'] = min(gpc_get_float($_POST, 'weight_net'), 999.99);
$p[':unit'] = gpc_get_int($_POST, 'unit'); $p[':unit'] = gpc_get_int($_POST, 'unit');
@@ -63,6 +65,7 @@ switch ($submit = form_get_action()) {
$p[':shelflife'] = gpc_get_string($_POST, 'shelflife'); $p[':shelflife'] = gpc_get_string($_POST, 'shelflife');
$p[':sid'] = gpc_get_int($_POST, 'sid'); $p[':sid'] = gpc_get_int($_POST, 'sid');
if ($p[':sid'] <= 0) $p[':sid'] = NULL; if ($p[':sid'] <= 0) $p[':sid'] = NULL;
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
db_exec_update('provisions', $p, 'provid'); db_exec_update('provisions', $p, 'provid');
$action = ACT_VIEW; $action = ACT_VIEW;
break; break;
@@ -134,7 +137,7 @@ $lastpage = ceil($numrows/$rows_pp);
// d0 is the maximum number of days age // d0 is the maximum number of days age
// d1 is the current age in days. If negative then it is over limit // d1 is the current age in days. If negative then it is over limit
// TODO display over with warning levels: 50% over, 100% over etc. // TODO display over with warning levels: 50% over, 100% over etc.
$sql = "SELECT provid, provname, number, unit, storedate, shelflife, sid," $sql = "SELECT provid, provname, number, target, unit, storedate, shelflife, sid,"
. " DATEDIFF(shelflife, storedate) AS d0, DATEDIFF (shelflife, CURDATE()) AS d1 " . " DATEDIFF(shelflife, storedate) AS d0, DATEDIFF (shelflife, CURDATE()) AS d1 "
. "FROM provisions LEFT OUTER JOIN storage USING (sid)"; . "FROM provisions LEFT OUTER JOIN storage USING (sid)";
$sql .= ' WHERE ' . $where; $sql .= ' WHERE ' . $where;
@@ -195,7 +198,9 @@ foreach ($res as $row) {
echo '<a class="text-nowrap" title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['provid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n"; echo '<a class="text-nowrap" title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['provid'], '"><i class="bi bi-eye ms-2"></i></a>', "\n";
echo "</td>\n"; echo "</td>\n";
echo "<td>", ! isset($row['sid']) ? '<i class="bi bi-cart3"></i> ' : '', $row['provname'], "</td>\n"; echo "<td>", ! isset($row['sid']) ? '<i class="bi bi-cart3"></i> ' : '', $row['provname'], "</td>\n";
echo "<td>", $row['number'], "</td>\n"; echo '<td>', $row['number'];
if ($row['target']) echo ' (', $row['target'], ')';
echo "</td>\n";
echo "<td>", $opt_unit[$row['unit']], "</td>\n"; echo "<td>", $opt_unit[$row['unit']], "</td>\n";
echo "<td>", $row['storedate'], "</td>\n"; echo "<td>", $row['storedate'], "</td>\n";
echo "<td>", $row['shelflife'], "</td>\n"; echo "<td>", $row['shelflife'], "</td>\n";
@@ -224,6 +229,11 @@ echo $pagination;
form_add_button($g_scriptname); form_add_button($g_scriptname);
// Shopping list button
echo '<div class="container-fluid px-0 my-3">', "\n";
echo ' <a href="', $g_scriptname, '?f=list" class="btn btn-secondary">',_('Shopping list'), "</a>\n";
echo "</div>\n";
elseif ($action == ACT_ADD): elseif ($action == ACT_ADD):
// ========== VARIANT: add record ============================================= // ========== VARIANT: add record =============================================
@@ -258,7 +268,8 @@ echo '<h2>', _('Add provisions'), "</h2>\n";
elseif ($action == ACT_VIEW): elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record ===================================== // ========== VARIANT: view single record =====================================
$sql = "SELECT provname, provcat, number, unit, weight, weight_net, storedate, shelflife, sid " $sql = "SELECT provname, provcat, number, target, unit, weight, weight_net,"
. " storedate, shelflife, sid, remarks "
. "FROM provisions " . "FROM provisions "
. "WHERE provid=?"; . "WHERE provid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -269,13 +280,15 @@ echo '<h2>', $prov->provname, "</h2>\n";
echo '<table class="table">', "\n"; echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Number'),"</th><td>", $prov->number, "</td></tr>\n"; echo '<tr><th style="width:20%">', _('Number'),"</th><td>", $prov->number, "</td></tr>\n";
echo "<tr><th>", _('Target'), "</th><td>", $prov->target, "</td></tr>\n";
echo "<tr><th>", _('Weight'), "</th><td>", format_float($prov->weight, 2, 'kg'), "</td></tr>\n"; echo "<tr><th>", _('Weight'), "</th><td>", format_float($prov->weight, 2, 'kg'), "</td></tr>\n";
echo "<tr><th>", _('Weight net'), "</th><td>", format_float($prov->weight_net, 2, 'kg'), "</td></tr>\n"; echo "<tr><th>", _('Weight net'), "</th><td>", format_float($prov->weight_net, 2, 'kg'), "</td></tr>\n";
echo '<tr><th>', _('Unit'),"</th><td>", $opt_unit[$prov->unit], "</td></tr>\n"; echo '<tr><th>', _('Unit'),"</th><td>", $opt_unit[$prov->unit], "</td></tr>\n";
echo '<tr><th>', _('Category'),"</th><td>", $opt_category[$prov->provcat] ?? 'n/a', "</td></tr>\n"; echo '<tr><th>', _('Category'),"</th><td>", $opt_category[$prov->provcat] ?? 'n/a', "</td></tr>\n";
echo '<tr><th>', _('Storedate'),"</th><td>", $prov->storedate, "</td></tr>\n"; echo '<tr><th>', _('Storedate'),"</th><td>", $prov->storedate, "</td></tr>\n";
echo '<tr><th>', _('Shelflife'),"</th><td>$prov->shelflife</td></tr>\n"; echo '<tr><th>', _('Shelflife'),"</th><td>", $prov->shelflife, "</td></tr>\n";
echo '<tr><th>', _('Storage'),"</th><td>", ($opt_storage[$prov->sid] ?? ''), "</td></tr>\n"; echo '<tr><th>', _('Storage'),"</th><td>", ($opt_storage[$prov->sid] ?? ''), "</td></tr>\n";
echo '<tr><th>', _('Remarks'),"</th><td>", nl2br($prov->remarks), "</td></tr>\n";
echo "</table>\n"; echo "</table>\n";
form_view_buttons($g_scriptname, $id); form_view_buttons($g_scriptname, $id);
@@ -283,7 +296,8 @@ form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT): elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record ===================================== // ========== VARIANT: edit single record =====================================
$sql = "SELECT provname, provcat, number, weight, weight_net, unit, storedate, shelflife, sid " $sql = "SELECT provname, provcat, number, target, unit, weight, weight_net,"
. " storedate, shelflife, sid, remarks "
. "FROM provisions " . "FROM provisions "
. "WHERE provid=?"; . "WHERE provid=?";
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
@@ -302,6 +316,10 @@ echo '<h2>', _('Edit provision'), "</h2>\n";
<label for="number"><?=_('Number')?></label> <label for="number"><?=_('Number')?></label>
<input type="number" min="0" max="1000" class="form-control" id="number" name="number" value="<?=$prov->number ?>"> <input type="number" min="0" max="1000" class="form-control" id="number" name="number" value="<?=$prov->number ?>">
</div> </div>
<div class="mb-3">
<label for="target"><?=_('Target')?></label>
<input type="number" min="0" max="1000" class="form-control" id="target" name="target" value="<?=$prov->target ?>">
</div>
<div class="mb-3"> <div class="mb-3">
<label for="weight" class="form-label"><?=_('Weight, kg')?></label> <label for="weight" class="form-label"><?=_('Weight, kg')?></label>
<input type="text" class="form-control" id="weight" name="weight" value="<?=format_float($prov->weight); ?>"> <input type="text" class="form-control" id="weight" name="weight" value="<?=format_float($prov->weight); ?>">
@@ -324,7 +342,12 @@ form_create_select('provcat', _('Category'), $g_opt_none + $opt_category, $prov-
</div> </div>
<?php <?php
form_create_select('sid', _('Storage'), $g_opt_none + $opt_storage, $prov->sid); form_create_select('sid', _('Storage'), $g_opt_none + $opt_storage, $prov->sid);
?>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3" maxlength="150"><?=$prov->remarks ?></textarea>
</div>
<?php
form_edit_buttons($g_scriptname, $id); form_edit_buttons($g_scriptname, $id);
echo "</form>\n"; echo "</form>\n";
@@ -334,6 +357,34 @@ elseif ($action == ACT_DELETE):
echo '<h2>', _('Delete provisions'), "</h2>\n"; echo '<h2>', _('Delete provisions'), "</h2>\n";
?>
<p>Not yet implemented!</p>
<?php
elseif ($action == ACT_VIEW_LIST):
// ========== VARIANT: shopping list ==========================================
echo '<h2>', _('Shopping list'), "</h2>\n";
$sql = "SELECT provid, provname, unit, target - number AS buy "
. "FROM provisions "
. "WHERE target IS NOT NULL AND number < target "
. "ORDER BY provcat, provname";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo "<pre>";
foreach ($res as $row) {
echo $row['provname'];
echo ' ';
echo $row['buy'];
echo ' ';
echo $opt_unit[$row['unit']], "\n";
}
echo "</pre>";
echo '<div class="container-fluid px-0 my-3">', "\n";
echo ' <a href="shopping.php" class="btn btn-primary" target="_blank">',_('Use'), "</a>\n";
echo ' <a href="', $g_scriptname, '" class="btn btn-secondary">',_('Back'), "</a>\n";
echo "</div>\n";
else: else:
// ========== ERROR UNKNOWN VARIANT =========================================== // ========== ERROR UNKNOWN VARIANT ===========================================
+3 -1
View File
@@ -7,7 +7,9 @@
xml:space="preserve" xml:space="preserve"
xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"><defs xmlns:svg="http://www.w3.org/2000/svg">
<title id="title1">Bavaria 34</title>
<defs
id="defs2" /><g id="defs2" /><g
id="layer2" id="layer2"
transform="translate(-42.346999,-246.66202)" transform="translate(-42.346999,-246.66202)"

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

+91 -19
View File
@@ -15,49 +15,121 @@
id="title1472">Etap 23</title><defs id="title1472">Etap 23</title><defs
id="defs2" /><metadata id="defs2" /><metadata
id="metadata307"><rdf:RDF><cc:Work id="metadata307"><rdf:RDF><cc:Work
rdf:about=""><dc:title>Etap 23</dc:title></cc:Work></rdf:RDF></metadata><g rdf:about=""><dc:title>Etap 23</dc:title><dc:creator><cc:Agent><dc:title>Thomas Hooge</dc:title></cc:Agent></dc:creator></cc:Work></rdf:RDF></metadata><g
id="layer3"><path id="layer3"
style="display:inline"><path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 0.86350443,56.194479 c 0,0 0.69516577,-14.052372 2.35183327,-20.194909 1.6566675,-6.142538 7.2458203,-17.836033 7.2458203,-17.836033 0,0 26.514024,-8.2805452 34.450621,-9.6979403 12.412423,-2.2167318 31.13408,-6.4342996 53.931466,-6.3070386 19.314615,0.1078193 53.094175,5.573439 76.283115,12.8907639 16.69715,5.268824 40.14414,13.436259 63.79504,23.921131 14.71032,6.521353 26.48827,13.146633 30.48785,15.138539 1.11012,0.552872 0.96357,2.01622 0.96357,2.01622" d="m 1.1052856,54.788917 c 0,0 0.6951658,-14.052372 2.3518333,-20.194909 C 5.1137864,28.45147 10.70294,16.757975 10.70294,16.757975 c 0,0 26.514024,-8.2805456 34.450621,-9.6979407 12.412423,-2.2167318 31.13408,-5.292081 53.931466,-5.16482 19.314613,0.1078193 53.094173,4.4312204 76.283113,11.7485457 16.69715,5.268824 40.14414,13.436259 63.79504,23.921131 14.71032,6.521353 26.48827,13.146633 30.48785,15.138539 1.11012,0.552872 0.96357,2.01622 0.96357,2.01622"
id="path245" /><use id="path245" /><use
x="0" x="0"
y="0" y="0"
xlink:href="#path245" xlink:href="#path245"
id="use461" id="use461"
transform="matrix(1,0,0,-1,-0.01141454,112.22431)" /><path transform="matrix(1,0,0,-1,-0.02583644,109.41506)" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:2.11667, 1.05833, 0.529169, 1.05833;stroke-dashoffset:0;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:round;stroke-dasharray:2.11667, 1.05833, 0.529169, 1.05833;stroke-dashoffset:0;stroke-opacity:1"
d="M 8.579525e-7,56.091669 270.48373,56.091668" d="M 0.21617824,54.888403 270.69991,54.888402"
id="path271" /><path id="path271" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 243.01026,40.79159 V 71.25056" d="M 141.00077,5.7751708 V 53.289576"
id="path1051-5-20-3-5" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 143.32867,7.3151282 V 53.180623"
id="path1051-5-20-3-5-3" /><path id="path1051-5-20-3-5-3" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 164.7561,10.714004 V 99.134188"
id="path1051-5-20-3-5-3-12" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 143.01507,70.407464 V 105.23012" d="M 141.32706,69.583358 V 103.57843"
id="path1051-5-20-3-5-3-1" /><path id="path1051-5-20-3-5-3-1" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 117.33745,3.3521262 V 12.178617" d="m 115.51488,2.846606 v 9.332011"
id="path1051-5-20-3-5-3-5" /><path id="path1051-5-20-3-5-3-5" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 92.185244,2.3233771 V 12.236508" d="M 89.547681,2.0649268 V 11.978058"
id="path1051-5-20-3-5-3-5-3" /><path id="path1051-5-20-3-5-3-5-3" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 89.403808,97.231856 v 9.913134"
id="path1051-5-20-3-5-3-5-3-2" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529169;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="m 115.3589,96.85088 v 9.91313"
id="path1051-5-20-3-5-3-5-3-2-9" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 11.231469,16.757066 V 38.605287"
id="path1051-5-20-3-5-3-5-3-3" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 66.584543,4.8189868 V 107.726" d="M 46.665868,6.6905874 V 102.66283"
id="path1051-5-20-3-5-3-5-3-3-5" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 28.255622,38.31381 V 70.001248"
id="path1051-5-20-3-5-3-5-3-3-5-3" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529168;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 10.947278,70.017665 V 92.794003"
id="path1051-5-20-3-5-3-5-3-3-6" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 64.382325,3.7775863 V 105.52778"
id="path1051-5-20-3-5-3-6" /><path id="path1051-5-20-3-5-3-6" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 143.50598,12.19599 H 66.434472" d="M 141.11162,12.19599 H 64.556533"
id="path1051-5-20-3-5-3-6-7" /><path id="path1051-5-20-3-5-3-6-7" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 66.45163,38.498153 H 9.4379737" d="M 140.97949,96.975439 H 64.42441"
id="path1051-5-20-3-5-3-6-7-56" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 64.665465,38.455882 H 11.166755"
id="path1051-5-20-3-5-3-6-7-5" /><path id="path1051-5-20-3-5-3-6-7-5" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 66.508118,69.931578 H 9.494461" d="M 64.587907,69.851251 H 10.654816"
id="path1051-5-20-3-5-3-6-7-5-6" /><path id="path1051-5-20-3-5-3-6-7-5-6" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 142.7458,70.803411 H 67.016281" d="M 141.45143,69.865723 H 64.299657"
id="path1051-5-20-3-5-3-6-7-5-6-2" /><path id="path1051-5-20-3-5-3-6-7-5-6-2" /><path
style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1" style="display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-dasharray:none;stroke-opacity:1"
d="M 142.96058,38.598891 H 67.231062" d="M 141.09882,38.437352 H 64.500753"
id="path1051-5-20-3-5-3-6-7-5-6-2-9" /></g></svg> id="path1051-5-20-3-5-3-6-7-5-6-2-9" /><rect
style="display:inline;opacity:1;fill:none;stroke:#000001;stroke-width:0.529167;stroke-linejoin:round;stop-color:#000000;stroke-opacity:1"
id="rect461"
width="30.349583"
height="24.124964"
x="102.14861"
y="42.854198"
ry="1.7931767"
rx="1.7931769" /><rect
style="display:inline;fill:none;stroke:#000001;stroke-width:0.529167;stroke-linejoin:round;stroke-opacity:1;stop-color:#000000"
id="rect461-7"
width="17.982452"
height="21.87578"
x="9.5787125"
y="42.54187"
ry="0"
rx="0" /><rect
style="display:inline;fill:none;stroke:#000001;stroke-width:0.529167;stroke-linejoin:round;stroke-opacity:1;stop-color:#000000"
id="rect461-7-7"
width="22.108604"
height="21.87578"
x="141.91139"
y="18.752796"
ry="0"
rx="0" /><path
id="rect2003"
style="opacity:1;fill:none;stroke:#000001;stroke-width:0.529167;stroke-linecap:square;stop-color:#000000"
d="m 165.88922,26.293186 22.28178,-0.232456 52.51134,22.813644 0.10876,13.821074 -53.25092,21.869236 -21.75479,0.157275 z" /><g
id="g3019"
style="display:inline;stroke-width:0.671799"
transform="matrix(0,-0.39255093,0.39513982,0,121.23836,196.67126)"><rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.671799;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="rect940-6"
width="51.964359"
height="25.085226"
x="399.42645"
y="81.583931"
ry="1.2706145"
rx="1.2622898" /><ellipse
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.537439;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path942-2"
cx="413.8573"
cy="94.126541"
rx="6.0959363"
ry="6.1390719" /><ellipse
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0.537439;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
id="path942-2-9"
cx="436.95999"
cy="94.126541"
rx="6.0959363"
ry="6.1390719" /></g></g></svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

After

Width:  |  Height:  |  Size: 8.7 KiB

+75
View File
@@ -0,0 +1,75 @@
<!DOCTYPE html>
<?php
require 'config.inc';
$pdo = new PDO("mysql:host=$g_db_host;dbname=$g_db_schema;charset=utf8mb4", $g_db_username, $g_db_password);
$sql = "SELECT p.provid, p.provname, p.target - p.number AS buy, d.ddtext as unit "
. "FROM provisions AS p LEFT JOIN dropdown AS d ON p.unit=d.ddval AND d.ddid=6 "
. "WHERE p.target IS NOT NULL AND p.number < p.target "
. "ORDER BY p.provcat, p.provname";
$sth = $pdo->query($sql);
$res = $sth->fetchAll(PDO::FETCH_ASSOC);
// aktuelle Einkaufsliste laden
// localStorage.setItem("liste", JSON.stringify(meineListe));
// let liste = JSON.parse(localStorage.getItem("liste"));
//$liste = getEinkaufsliste();
?>
<html>
<head>
<title>Shopping list</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="manifest" href="manifest.json">
<script src="js/shopping.js" defer></script>
<script>
const initialList = <?= json_encode($res, JSON_UNESCAPED_UNICODE) ?>;
// only activate for production use
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('service-worker.js');
}
</script>
<style>
body{
font-family:Arial,sans-serif;
margin:12px;
}
h1{
text-align:center;
}
table{
width:100%;
border-collapse:collapse;
}
td{
padding:10px 6px;
border-bottom:1px solid #ddd;
font-size:1.1em;
}
td:first-child{
width:40px;
}
td:last-child{
text-align:right;
width:60px;
}
</style>
</head>
<body>
<h1>YMS Einkaufsliste</h1>
<button onclick="location.reload()">Aktualisieren</button>
<h2>Offen</h2>
<div id="shoppingList">
Loading ...
</div>
<h2>Erledigt</h2>
<div id="completedList">
Empty.
</div>
</body>
</html>
+21 -1
View File
@@ -222,7 +222,7 @@ $sql = "SELECT sid, sname, stype, capacity, capaunit, x, y, z, wx, wy, wz, angle
$sth = $pdo->prepare($sql); $sth = $pdo->prepare($sql);
$sth->execute([$id]); $sth->execute([$id]);
$storage = $sth->fetch(PDO::FETCH_OBJ); $storage = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', $storage->sname, "</h2>\n"; echo '<h1>', _('Storage'), ': ', $storage->sname, "</h1>\n";
echo '<table class="table">', "\n"; echo '<table class="table">', "\n";
echo '<tr><th style="width:33%">', _('Typ'),"</th><td>", $opt_stype[$storage->stype], "</td></tr>\n"; echo '<tr><th style="width:33%">', _('Typ'),"</th><td>", $opt_stype[$storage->stype], "</td></tr>\n";
@@ -257,6 +257,26 @@ if (count($res) > 0) {
echo '<p>', _('No boxes contained'), "</p>\n"; echo '<p>', _('No boxes contained'), "</p>\n";
} }
// show assigned inventory here
echo '<h3>', _('Inventory in storage'), "</h3>\n";
$sql = "SELECT invid, invname FROM inventory WHERE conttype='storage' and sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$res = $sth->fetchall();
if (count($res) > 0) {
echo '<table class="table table-sm">';
foreach ($res as $row) {
echo "<tr>";
echo '<td>', $row['invname'], "</td>";
echo '<td><a title="', _('View'), '" href="inventory.php?f=view&id=', $row['invid'], '"><i class="bi-eye"></i></a></td>';
echo "</tr>\n";
}
echo "</table>\n";
} else {
echo '<p>', _('No inventory contained'), "</p>\n";
}
// show assigned provisions here
echo '<h3>', _('Provisions in storage'), "</h3>\n"; echo '<h3>', _('Provisions in storage'), "</h3>\n";
$sql = "SELECT provid, provname, number, unit, storedate, shelflife FROM provisions WHERE sid=?"; $sql = "SELECT provid, provname, number, unit, storedate, shelflife FROM provisions WHERE sid=?";
+20 -3
View File
@@ -31,8 +31,9 @@ switch ($submit = form_get_action()) {
case 'filter': case 'filter':
$flt = array(); $flt = array();
$flt['prio'] = gpc_get_enum($_POST, 'flt_prio', array_merge(array_keys($opt_priority), ['-2', '-1'])); $flt['prio'] = gpc_get_enum($_POST, 'flt_prio', array_merge(array_keys($opt_priority), ['-2', '-1']));
$flt['stat'] = gpc_get_enum($_POST, 'flt_stat', array_merge(array_keys($opt_state), ['-2', '-1']));
$flt['txt'] = gpc_get_string($_POST, 'flt_txt'); $flt['txt'] = gpc_get_string($_POST, 'flt_txt');
$allowed = db_load_enum('task', 'taskstate');
$flt['stat'] = gpc_get_set($_POST, 'flt_stat', $allowed);
db_save_filter($flt, 206); db_save_filter($flt, 206);
$action = ACT_DEFAULT; $action = ACT_DEFAULT;
break; break;
@@ -138,10 +139,22 @@ if (strlen($flt->prio) > 2 ) {
} elseif ($flt->prio == -1) { } elseif ($flt->prio == -1) {
$w[] = 'priority IS NULL'; $w[] = 'priority IS NULL';
} }
if (strlen($flt->stat) > 2 ) { /*if (strlen($flt->stat) > 2 ) {
$w[] = 'taskstate=:taskstate'; $w[] = 'taskstate=:taskstate';
$p[':taskstate'] = $flt->stat; $p[':taskstate'] = $flt->stat;
} */
$parts = ["taskstate=''", 'taskstate IS NULL'];
foreach ($flt->stat as $f) {
$parts[] = "FIND_IN_SET('$f', taskstate)";
} }
if (!empty($parts)) {
if (count($parts) > 1) {
$w[] = '(' . join(' OR ', $parts) . ')';
} else {
$w[] = $parts[0];
}
}
$where = join(' AND ', $w); $where = join(' AND ', $w);
$order = ' ORDER BY t.taskid'; $order = ' ORDER BY t.taskid';
@@ -190,12 +203,16 @@ $res = $sth->fetchAll();
<div class="card-body d-flex flex-wrap gap-3"> <div class="card-body d-flex flex-wrap gap-3">
<?php <?php
filter_create_select('flt_prio', _('Priority'), $g_opt_all + $g_opt_none + $opt_priority, $flt->prio); filter_create_select('flt_prio', _('Priority'), $g_opt_all + $g_opt_none + $opt_priority, $flt->prio);
filter_create_select('flt_stat', _('State'), $g_opt_all + $opt_state, $flt->stat); //filter_create_select('flt_stat', _('State'), $g_opt_all + $opt_state, $flt->stat);
?> ?>
<div class="d-flex flex-nowrap gap-2"> <div class="d-flex flex-nowrap gap-2">
<label for="flt_txt">Text</label> <label for="flt_txt">Text</label>
<input type="text" class="form-control" name="flt_txt" size="15" maxlength="30" value="<?=$flt->txt ?>"> <input type="text" class="form-control" name="flt_txt" size="15" maxlength="30" value="<?=$flt->txt ?>">
</div> </div>
<?php
$opt_status = db_load_enum('task', 'taskstate', true, true, false);
filter_create_checks('flt_stat', _('Status'), $opt_status, $flt->stat);
?>
</div> </div>
<div class="card-footer"> <div class="card-footer">
<button name="submit[filter]" class="btn btn-sm btn-primary" title="<?=_('Apply')?>"><?=_('Go')?></button> <button name="submit[filter]" class="btn btn-sm btn-primary" title="<?=_('Apply')?>"><?=_('Go')?></button>