First web gui prototype

This commit is contained in:
2024-04-09 10:26:32 +02:00
parent 0b534fa727
commit 793eda4bc4
39 changed files with 6760 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
*~
__pycache__/
+76
View File
@@ -0,0 +1,76 @@
YMS Installation
1. Install requirements
1.1 Generic
- MariaDB
- Python 3
- python3-bcrypt
- optional
- mupdf-tools for extended pdf file management
1.2 Native GUI
- Python GTK3
1.3 Web GUI
- Webserver
- PHP
2. Create database
Create a database for YMS on your server, as well as a MariaDB user who has
the privileges for accessing and modifying it.
CREATE DATABASE yms;
Create database-user for application with minimum necessary rights.
CREATE USER 'yms'@'localhost' IDENTIFIED BY '********';
GRANT SELECT, INSERT, UPDATE, DELETE ON yms.* TO 'yms'@'localhost';
3. Run database import
Import the mariadb.sql file into your database, which will create the tables
mariadb yms < mariadb.sql
Optional import some sample data
mariadb yms < mariadb_sample.sql
4. Initialize document storage
Customize path and accessrights to your needs
mkdir /var/local/yms
mkdir /var/local/yms/thumb
chown -R www-data /var/local/yms
chmod -R 750 /var/local/yms
5. Upload webgui files
Upload all files and directories (except the install directory) to your
webserver.
Disallow access to include files (.inc). There is an example _htaccess
file.
6. Create and edit webgui config file
Rename sample configfile config.php-sample:
mv config.inc-sample config.inc
Open config.inc in a text editor and fill in your database details.
7. Check file access rights for security
Configfile should be readable by webserver but not writeable.
chmod 640 config.inc
chgrp www-data config.inc
8. Start using YMS
Start your browser and login to YMS with the default username/password:
captain/captain
+275
View File
@@ -0,0 +1,275 @@
/* SPDX-License-Identifier: WTFPL */
/* MariaDB Scheme
Version: 1 */
CREATE TABLE user (
userid SMALLINT(6) NOT NULL AUTO_INCREMENT,
login VARCHAR(20) NOT NULL,
pass BINARY(60) NOT NULL,
displayname VARCHAR(100) NOT NULL,
role SET('vessel', 'captain','helmsman','sailor') NOT NULL DEFAULT 'sailor',
flags SET('deleted','locked'),
language CHAR(2) NOT NULL DEFAULT 'en',
PRIMARY KEY (userid),
UNIQUE INDEX ix_login (login)
);
/* Settings
E.g. the currently selected boat. Users logged in via the web are allowed
to write to this table. Therefore a separate table and not additional
fields in the user data record.
userid=0: Global program settings
sno=0: db_scheme_version
sno=1: doc_base_path
userid = -1: description of user settings for development and admin use
userid >=1: setings per user
sno=1 current vessel
*/
CREATE TABLE settings (
userid SMALLINT(6) NOT NULL,
sno SMALLINT(6) NOT NULL,
valstr VARCHAR(200) DEFAULT NULL,
valint INT(10) DEFAULT NULL,
PRIMARY KEY (userid, sno)
);
/* ddid=0 is list of lists, not editable
flags: fixed=not deletable, value not changeable
locked=not editable */
CREATE TABLE dropdown (
ddid TINYINT(3) UNSIGNED NOT NULL,
ddval TINYINT(3) NOT NULL,
sort TINYINT(3) DEFAULT NULL,
ddtext VARCHAR(50) NOT NULL,
ddshort VARCHAR(4) DEFAULT NULL,
color CHAR(6) DEFAULT NULL,
flags ENUM('locked', 'fixed') DEFAULT NULL,
PRIMARY KEY (ddid, ddval)
);
CREATE TABLE vessel (
vid SMALLINT(10) NOT NULL AUTO_INCREMENT,
vtype ENUM('mono','cat','tri') NOT NULL DEFAULT 'mono',
vesselname VARCHAR(40) NOT NULL,
model VARCHAR(20) DEFAULT NULL,
loa FLOAT(4,2) UNSIGNED DEFAULT NULL,
lwl FLOAT(4,2) UNSIGNED DEFAULT NULL,
beam FLOAT(4,2) UNSIGNED DEFAULT NULL,
draught FLOAT(3,2) UNSIGNED DEFAULT NULL,
draught_min FLOAT(3,2) UNSIGNED DEFAULT NULL,
displacement SMALLINT(6) UNSIGNED DEFAULT NULL,
ballast SMALLINT(6) UNSIGNED DEFAULT NULL,
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY (vid)
);
CREATE TABLE storage (
sid SMALLINT(6) NOT NULL AUTO_INCREMENT,
vid SMALLINT(6) NOT NULL DEFAULT 1,
sname VARCHAR(40) NOT NULL,
stype TINYINT(3) NOT NULL DEFAULT 0,
capacity SMALLINT(6) DEFAULT NULL,
capaunit ENUM('kg', 'l') DEFAULT NULL,
x SMALLINT(6) NOT NULL DEFAULT 0,
y SMALLINT(6) NOT NULL DEFAULT 0,
z SMALLINT(6) NOT NULL DEFAULT 0,
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY (sid)
);
/* TODO define cabins? CREATE TABLE cabin ... */
CREATE TABLE tag (
tagid SMALLINT(6) NOT NULL AUTO_INCREMENT,
tagname VARCHAR(20) NOT NULL,
color CHAR(6) DEFAULT NULL,
PRIMARY KEY (tagid),
UNIQUE INDEX ix_tagname (tagname)
);
CREATE TABLE tagref (
tagid SMALLINT(6) NOT NULL,
objid SMALLINT(6) NOT NULL,
objtype ENUM('equip','inv','prov','doc') NOT NULL,
PRIMARY KEY (tagid, objid, objtype)
);
/* TODO Boxes can be nested via parent
TODO boxsize: (LxWxH) in cm? */
CREATE TABLE box (
boxid SMALLINT(6) NOT NULL AUTO_INCREMENT,
sid SMALLINT(6) NOT NULL,
parent INT(10) DEFAULT NULL,
label VARCHAR(20) DEFAULT NULL,
color CHAR(6) DEFAULT NULL,
content VARCHAR(60) DEFAULT NULL,
weight FLOAT(5,2) UNSIGNED DEFAULT NULL,
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY (boxid),
INDEX ix_label (label)
);
CREATE TABLE equipment (
eid SMALLINT(6) NOT NULL AUTO_INCREMENT,
vid SMALLINT(6) NOT NULL DEFAULT 1,
ename VARCHAR(80) NOT NULL,
make VARCHAR(40),
model VARCHAR(40),
ecat TINYINT(3) DEFAULT NULL,
serial VARCHAR(30),
supplier SMALLINT(6) DEFAULT NULL,
manufacturer SMALLINT(6) DEFAULT NULL,
purchdate DATE DEFAULT NULL,
price DECIMAL(12,2) DEFAULT NULL,
weight FLOAT(5,2) UNSIGNED DEFAULT NULL,
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY(eid)
);
CREATE TABLE inventory (
invid INT(10) NOT NULL AUTO_INCREMENT,
invname VARCHAR(80) NOT NULL,
boxtype ENUM('storage','box') NOT NULL DEFAULT 'storage',
sid SMALLINT(6) NOT NULL DEFAULT 1,
boxid SMALLINT(6) NOT NULL DEFAULT 1,
number SMALLINT(6) UNSIGNED NOT NULL DEFAULT 1,
weight FLOAT(5,2) UNSIGNED DEFAULT NULL,
price DECIMAL(12,2) DEFAULT NULL,
purchdate DATE DEFAULT NULL,
invcond ENUM('unknown','good','normal','bad','repairable','defect') NOT NULL default 'unknown',
PRIMARY KEY (invid),
INDEX ix_invname (invname)
);
CREATE TABLE measurement (
mid SMALLINT(6) NOT NULL AUTO_INCREMENT,
mname VARCHAR(80) NOT NULL,
nval TINYINT(1) UNSIGNED NOT NULL DEFAULT 1,
val1 INT(10) NOT NULL,
val2 INT(10) NOT NULL,
val3 INT(10) NOT NULL,
unit TINYINT(3) NOT NULL DEFAULT 1,
accuracy ENUM('unknown', 'precise', 'normal', 'rough', 'estimated') NOT NULL DEFAULT 'unknown',
mdate DATE DEFAULT NULL,
note VARCHAR(80) DEFAULT NULL,
eid SMALLINT(6) DEFAULT NULL,
PRIMARY KEY (mid)
);
CREATE TABLE provisions (
provid INT(10) NOT NULL AUTO_INCREMENT,
provname VARCHAR(40) NOT NULL,
sid SMALLINT(6) DEFAULT NULL,
number SMALLINT(6) UNSIGNED NOT NULL DEFAULT 1,
unit TINYINT(3) DEFAULT NULL,
storedate DATE DEFAULT CURRENT_DATE,
shelflife DATE DEFAULT NULL,
PRIMARY KEY (provid)
);
CREATE TABLE document (
docid SMALLINT(6) NOT NULL AUTO_INCREMENT,
doctype ENUM('generic', 'manual', 'invoice', 'drawing', 'picture') NOT NULL DEFAULT 'generic',
mimetype VARCHAR(80) NOT NULL DEFAULT 'application/octet-stream',
filename VARCHAR(200) NOT NULL,
extension CHAR(3) NOT NULL,
hash VARCHAR(32) NOT NULL,
docsize INT(10) unsigned NOT NULL,
doctime DATETIME DEFAULT NULL,
title VARCHAR(40) DEFAULT NULL,
pages SMALLINT(6) unsigned NOT NULL DEFAULT 1,
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY (docid)
);
CREATE TABLE docref (
drid INT(10) NOT NULL AUTO_INCREMENT,
reftype ENUM('vessel', 'box', 'equipment', 'project', 'task') NOT NULL DEFAULT 'vessel',
docid SMALLINT(6) NOT NULL,
refid SMALLINT(6) NOT NULL,
PRIMARY KEY (drid),
UNIQUE INDEX ix_docref (docid, refid)
);
CREATE TABLE company (
compid SMALLINT(6) NOT NULL AUTO_INCREMENT,
compname VARCHAR(40) NOT NULL,
comptype TINYINT(3) NOT NULL DEFAULT 1,
street VARCHAR(30),
zip VARCHAR(10),
city VARCHAR(30),
country VARCHAR(30),
contact VARCHAR(30),
phone VARCHAR(30),
email VARCHAR(50),
web VARCHAR(40),
customerno VARCHAR(20),
contractno VARCHAR(20),
remarks VARCHAR(150) DEFAULT NULL,
PRIMARY KEY (compid),
UNIQUE INDEX ix_compname (compname)
);
/* TODO optional field: plan date, target date, completion date */
CREATE TABLE maintenance (
maintid INT(10) NOT NULL AUTO_INCREMENT,
vid SMALLINT(6) NOT NULL DEFAULT 1,
eid SMALLINT(6) DEFAULT NULL,
series SMALLINT(6) DEFAULT NULL,
activities VARCHAR(40) NOT NULL,
remarks VARCHAR(150) DEFAULT NULL,
maintstate ENUM('new','planned','ongoing','done') NOT NULL DEFAULT 'new',
PRIMARY KEY (maintid)
);
/* TODO? time recording */
CREATE TABLE project (
projid SMALLINT(6) NOT NULL AUTO_INCREMENT,
projname VARCHAR(40) NOT NULL,
vid SMALLINT(6) NOT NULL DEFAULT 1,
responsible SMALLINT(6) NOT NULL,
startdate date DEFAULT NULL,
duration SMALLINT(6) UNSIGNED DEFAULT NULL,
costs_plan DECIMAL(12,2) DEFAULT NULL,
costs_final DECIMAL(12,2) DEFAULT NULL,
remarks VARCHAR(150) DEFAULT NULL,
projstate ENUM('new','plan','ongoing','finished') NOT NULL DEFAULT 'new',
PRIMARY KEY (projid)
);
CREATE TABLE task (
taskid INT(10) NOT NULL AUTO_INCREMENT,
projid SMALLINT(6) DEFAULT NULL,
taskname VARCHAR(60) NOT NULL,
taskstate ENUM('new','finished') NOT NULL DEFAULT 'new',
PRIMARY KEY (taskid)
);
CREATE TABLE checklist (
clid SMALLINT(6) NOT NULL AUTO_INCREMENT,
title VARCHAR(30) NOT NULL,
clstate ENUM('new','open','closed') NOT NULL DEFAULT 'new',
PRIMARY KEY (clid)
);
CREATE TABLE checkitem (
checkid INT(10) NOT NULL AUTO_INCREMENT,
checkname VARCHAR(60) NOT NULL,
groupid TINYINT(3) DEFAULT NULL,
PRIMARY KEY (checkid)
);
CREATE TABLE checkref (
clid SMALLINT(6) NOT NULL,
checkid INT(10) NOT NULL,
sort SMALLINT(6) DEFAULT NULL,
PRIMARY KEY (clid, checkid)
);
+37
View File
@@ -0,0 +1,37 @@
/* Generic data suitable for all kind of boats
* SPDX-License-Identifier: WTFPL
*/
/* absolutely minimal data set */
-- Trick to get pk value 0 for autoincrement
INSERT INTO user (userid, login, pass, displayname, role) VALUES (0, '', '', 'SYSTEM', 'vessel');
UPDATE user SET userid=0 WHERE userid=1;
INSERT INTO user (userid, login, pass, displayname, role) VALUES
(1, 'captain', '$2y$10$naVMnC4S6bZ3IakxLJPJK.iSazlkYxVLeiRt9CB/j0jSExQZU1SCK', 'Captain', 'captain');
INSERT INTO settings (userid, sno, valint) VALUES
(0, 0, 1), -- Databankschema-Version
(1, 1, 0); -- Keine Bootszuordnung für Benutzer "captain"
/* Liste der Listen wird immer benötigt */
INSERT INTO dropdown (ddid, ddval, ddtext) VALUES
(0, 0, 'Liste der Listen'),
(0, 1, 'Rumpftypen'),
(0, 2, 'Firmentypen'),
(0, 3, 'Stauraumtypen'),
(0, 4, 'Ausrüstungskategorien'),
(0, 5, 'Proviantkategorien'),
(0, 6, 'Provianteinheiten'),
(0, 7, 'Sicherungstypen'),
(0, 8 , 'Einheiten');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(2, 1, 'Lieferant', 'fixed'),
(2, 2, 'Hersteller', 'fixed'),
(2, 9, 'Sonstiges', 'fixed');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(3, 0, 'Stauraum allgemein', 'fixed'),
(3, 1, 'Tank', 'fixed');
+37
View File
@@ -0,0 +1,37 @@
/* Generic data suitable for all kind of boats
* SPDX-License-Identifier: WTFPL
*/
/* absolutely minimal data set */
-- Trick to get pk value 0 for autoincrement
INSERT INTO user (userid, login, pass, displayname, role) VALUES (0, '', '', 'SYSTEM', 'vessel');
UPDATE user SET userid=0 WHERE userid=1;
INSERT INTO user (userid, login, pass, displayname, role) VALUES
(1, 'captain', '$2y$10$naVMnC4S6bZ3IakxLJPJK.iSazlkYxVLeiRt9CB/j0jSExQZU1SCK', 'Captain', 'captain');
INSERT INTO settings (userid, sno, valint) VALUES
(0, 0, 1), -- Database schema version
(1, 1, 0); -- No vessel for captain
/* list of lists needed */
INSERT INTO dropdown (ddid, ddval, ddtext) VALUES
(0, 0, 'list of lists'),
(0, 1, 'hull type'),
(0, 2, 'company type'),
(0, 3, 'storage type'),
(0, 4, 'equipment category'),
(0, 5, 'provision category'),
(0, 6, 'provision unit'),
(0, 7, 'fuse type'),
(0, 8 , 'unit');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(2, 1, 'Supplier', 'fixed'),
(2, 2, 'Manufacturer', 'fixed'),
(2, 9, 'Generic', 'fixed');
INSERT INTO dropdown (ddid, ddval, ddtext, flags) VALUES
(3, 0, 'Generic', 'fixed'),
(3, 1, 'Tank', 'fixed');
+8
View File
@@ -0,0 +1,8 @@
#!/usr/bin/python3
from getpass import getpass
import bcrypt
newpass = getpass('New Password: ')
cryptpass = bcrypt.hashpw(newpass.encode(), bcrypt.gensalt())
print("UPDATE user SET pass='{}' WHERE userid=1".format(cryptpass.decode()))
+3
View File
@@ -0,0 +1,3 @@
<FilesMatch "\.inc$">
Require all denied
</FilesMatch>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
+253
View File
@@ -0,0 +1,253 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Boxes');
$id = gpc_get_int($_REQUEST, 'id', 0);
// Storage options
$sql = "SELECT sid, sname FROM storage WHERE vid=? ORDER BY sname";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$opt_storage = array();
foreach ($sth->fetchAll() as $row) {
$opt_storage[$row['sid']] = $row['sname'];
}
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$p[':label'] = gpc_get_string($_POST, 'label');
$p[':sid'] = gpc_get_int($_POST, 'sid');
$p[':content'] = gpc_get_string($_POST, 'content');
$p[':remarks'] = gpc_get_string($_POST, 'remarks');
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO box ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->LastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$p[':label'] = gpc_get_string($_POST, 'label');
$p[':content'] = gpc_get_string($_POST, 'content');
$p[':color'] = gpc_get_color($_POST, 'color');
$p[':weight'] = min(gpc_get_float($_POST, 'weight'), 99.99);
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE box SET $fields WHERE boxid=:boxid");
$p[':boxid'] = $id;
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
default:
$g_error->Add(sprintf(_("Unknown function '%s'!"), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo "<h1>$pagetitle</h1>\n";
$sql = "SELECT boxid, sid, label, color, content, weight, remarks "
. "FROM box "
. "ORDER BY label";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Label') . "</th>";
echo "<th>" . _('Color') . "</th>";
echo "<th>" . _('Content') . "</th>";
echo '<th class="text-end">', _('Weight'), "</th>";
echo "<td></td>";
echo "</tr>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['label'] ."</td>\n";
$style = 'background-color:#' . $row['color'];
if (get_color_brightness($row['color']) < 0.4) {
$style .= ';color:white';
}
echo '<td><span style="', $style,'">#'. $row['color'] ."</span></td>\n";
echo "<td>". $row['content'] ."</td>\n";
echo '<td class="text-end">', format_float($row['weight'], 2), "</td>\n";
form_action_buttons($g_scriptname, $row['boxid']);
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="4">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button('box.php');
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Box'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="label" class="form-label"><?=_('Label')?></label>
<input type="text" maxlength="20" class="form-control" id="label" name="label" autofocus>
</div>
<div class="mb-3">
<label for="sid" class="form-label"><?=_('Storage')?></label>
<select name="sid" id="sid" class="form-control">
<?php
foreach ($opt_storage as $k => $v) {
echo '<option value="', $k, '">', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3">
<label for="content" class="form-label"><?=_('Content')?></label>
<input type="text" maxlength="60" class="form-control" id="content" name="content">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
</div>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT label, content, color, weight, remarks "
. "FROM box "
. "WHERE boxid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$box = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', $box->label, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Content'),"</th><td>", $box->content, "</td></tr>\n";
echo '<tr><th>', _('Color'), '</th><td style="background-color:#', $box->color, '">#', $box->color, "</td></tr>\n";
echo '<tr><th>', _('Weight'), '</th><td>', format_float($box->weight, 2, 'kg'), "</td></tr>\n";
echo '<tr><th>', _('Remarks'),"</th><td>", $box->remarks, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
// Inventory in box
// WIP
$sql = "SELECT invid, invname FROM inventory WHERE boxtype='box' AND boxid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$res = $sth->fetchAll();
echo '<h3>', _('Inventory in box'), "</h3>\n";
if ($res) {
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo '<th>', _('Inventory'), "</th>";
echo "<td></td>";
echo "</tr>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>", $row['invname'], "</td>\n";
form_action_buttons('inventory.php', $row['invid']);
echo "</tr>\n";
}
echo "</table>\n";
} else {
echo '<p>', _('Box is empty'), "</p>\n";
}
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT label, content, color, weight, remarks "
. "FROM box "
. "WHERE boxid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$box = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Edit Box'), "</h2>\n";
?>
<form method="post">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="label" class="form-label"><?=_('Label')?></label>
<input type="text" class="form-control" id="label" name="label" value="<?=$box->label ?>">
</div>
<div class="mb-3">
<label for="content" class="form-label"><?=_('Content')?></label>
<input type="text" class="form-control" id="content" name="content" value="<?=$box->content ?>">
</div>
<div class="mb-3">
<label for="color"><?=_('Color')?></label>
<input type="color" class="form-control" id="color" name="color" value="#<?=$box->color ?>">
</div>
<div class="mb-3">
<label for="weight" class="form-label"><?=_('Weight, kg')?></label>
<input type="text" class="form-control" id="weight" name="weight" value="<?=format_float($box->weight); ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$box->remarks ?></textarea>
</div>
<?php
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+23
View File
@@ -0,0 +1,23 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Checklists');
$id = gpc_get_int($_REQUEST, 'id', 0);
require 'header.php';
echo "<h1>$pagetitle</h1>\n";
?>
<p>Search will be implemented later.
This page is currently just a placeholder.</p>
<?php
include 'footer.php';
+338
View File
@@ -0,0 +1,338 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle=_('Company');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_comptype = db_get_options(2);
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$compname = gpc_get_string($_POST, 'compname');
$comptype = gpc_get_int($_POST, 'comptype');
$sql = "INSERT INTO company "
. " (compname, comptype) "
. "VALUES "
. " (:compname, :comptype)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':compname', $compname, PDO::PARAM_STR);
$sth->bindValue(':comptype', $comptype, PDO::PARAM_INT);
$sth->execute();
$id = $pdo->lastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$compname = gpc_get_string($_POST, 'compname');
$comptype = gpc_get_int($_POST, 'comptype');
$street = gpc_get_string($_POST, 'street', 30);
$zip = gpc_get_string($_POST, 'zip', 10);
$city = gpc_get_string($_POST, 'city', 30);
$country = gpc_get_string($_POST, 'country', 30);
$contact = gpc_get_string($_POST, 'contact', 30);
$phone = gpc_get_string($_POST, 'phone', 30);
$email = gpc_get_string($_POST, 'email', 50);
$web = gpc_get_string($_POST, 'web', 40);
$customerno = gpc_get_string($_POST, 'customerno', 20);
$contractno = gpc_get_string($_POST, 'contractno', 20);
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE company "
. "SET compname=:compname,"
. " comptype=:comptype,"
. " street=:street,"
. " zip=:zip,"
. " city=:city,"
. " country=:country,"
. " contact=:contact,"
. " phone=:phone,"
. " email=:email,"
. " web=:web,"
. " customerno=:customerno,"
. " contractno=:contractno,"
. " remarks=:remarks "
. "WHERE compid=:compid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':compid', $id, PDO::PARAM_INT);
$sth->bindValue(':compname', $compname, PDO::PARAM_STR);
$sth->bindValue(':comptype', $comptype, PDO::PARAM_INT);
$sth->bindValue(':street', $street, PDO::PARAM_STR);
$sth->bindValue(':zip', $zip, PDO::PARAM_STR);
$sth->bindValue(':city', $city, PDO::PARAM_STR);
$sth->bindValue(':country', $country, PDO::PARAM_STR);
$sth->bindValue(':contact', $contact, PDO::PARAM_STR);
$sth->bindValue(':phone', $phone, PDO::PARAM_STR);
$sth->bindValue(':email', $email, PDO::PARAM_STR);
$sth->bindValue(':web', $web, PDO::PARAM_STR);
$sth->bindValue(':customerno', $customerno, PDO::PARAM_STR);
$sth->bindValue(':contractno', $contractno, PDO::PARAM_STR);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
$sth->execute();
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
unset($_SESSION['token']);
$sth = $pdo->prepare("DELETE FROM company WHERE compid=?");
$sth->execute([$id]);
$g_message->Add(sprintf(_('Deleted company no. %d'), $id));
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo '<h1>', $pagetitle , "</h1>\n";
$sql = "SELECT compid, compname, comptype, remarks "
. "FROM company "
. "ORDER BY comptype, compname";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Name') . "</th>";
echo "<th>" . _('Type') . "</th>";
echo "<th>" . _('Remarks') . "</th>";
echo "<th>&nbsp;</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['compname'] ."</td>\n";
echo "<td>". $opt_comptype[$row['comptype']] ."</td>\n";
echo "<td>". $row['remarks'] ."</td>\n";
// Action buttons
echo "<td>";
echo '<a title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['compid'], '"><i class="bi-eye"></i></a>', "\n";
echo '<a title="', _('Edit'), '" href="', $g_scriptname, '?f=edit&id=', $row['compid'], '"><i class="bi-pencil"></i></a>';
echo "</td>\n";
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Company'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="compname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="compname" name="compname">
</div>
<?php form_create_select('comptype', _('Company type'), $opt_comptype); ?>
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT compname, comptype, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks "
. "FROM company "
. "WHERE compid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$company = $sth->fetch(PDO::FETCH_OBJ);
echo "<h2>", $company->compname, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th scope="row">', _('Name'),"</th><td>", $company->compname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Type'),"</th><td>", $opt_comptype[$company->comptype], "</td></tr>\n";
echo '<tr><th scope="row">', _('Street'),"</th><td>", $company->street, "</td></tr>\n";
echo '<tr><th scope="row">', _('Zip, City'),"</th><td>", $company->zip, ' ', $company->city, "</td></tr>\n";
echo '<tr><th scope="row">', _('Country'),"</th><td>", $company->country, "</td></tr>\n";
echo '<tr><th scope="row">', _('Contact'),"</th><td>", $company->contact, "</td></tr>\n";
echo '<tr><th scope="row">', _('Phone'),"</th><td>", $company->phone, "</td></tr>\n";
echo '<tr><th scope="row">', _('Email'),"</th><td>", $company->email, "</td></tr>\n";
echo '<tr><th scope="row">', _('Web'),"</th><td>", $company->web, "</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">', _('Remarks'),"</th><td>", $company->remarks, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
// show referenced equipment
$sql = "SELECT ename FROM equipment WHERE supplier=:id OR manufacturer=:id";
$sth = $pdo->prepare($sql);
$sth->bindValue(':id', $id, PDO::PARAM_INT);
$sth->execute();
if ($sth->rowCount > 0) {
echo "<p>Referenced in equipment:</p>\n";
echo "<ul>\n";
foreach ($sth->fetchAll() as $row) {
echo "<li>", $row['ename'], "</li>\n";
}
echo "</ul>\n";
} else {
echo '<p>', _('Not referenced in any equipment'), "<p>\n";
}
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
echo '<h2>', _('Edit Company'), "</h2>\n";
$sql = "SELECT compname, comptype, street, zip, city, country,"
. " contact, phone, email, web, customerno, contractno, remarks "
. "FROM company "
. "WHERE compid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$company = $sth->fetch(PDO::FETCH_OBJ);
?>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="compname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="compname" name="compname" value="<?=$company->compname ?>">
</div>
<div class="mb-3">
<label for="comptype" class="form-label"><?=_('Company type')?></label>
<select name="comptype" class="form-control">
<?php
foreach ($opt_comptype as $k => $v) {
echo '<option value="', $k ,'"';
if ($company->comptype == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3">
<label for="street" class="form-label"><?=_('Street')?></label>
<input type="text" class="form-control" id="street" name="street" value="<?=$company->street ?>">
</div>
<div class="mb-3">
<label for="zip" class="form-label"><?=_('Zip')?></label>
<input type="text" class="form-control" id="zip" name="zip" value="<?=$company->zip ?>">
</div>
<div class="mb-3">
<label for="city" class="form-label"><?=_('City')?></label>
<input type="text" class="form-control" id="city" name="city" value="<?=$company->city ?>">
</div>
<div class="mb-3">
<label for="country" class="form-label"><?=_('Country')?></label>
<input type="text" class="form-control" id="country" name="country" value="<?=$company->country ?>">
</div>
<div class="mb-3">
<label for="contact" class="form-label"><?=_('Contact')?></label>
<input type="text" class="form-control" id="contact" name="contact" value="<?=$company->contact ?>">
</div>
<div class="mb-3">
<label for="phone" class="form-label"><?=_('Phone')?></label>
<input type="text" class="form-control" id="phone" name="phone" value="<?=$company->phone ?>">
</div>
<div class="mb-3">
<label for="email" class="form-label"><?=_('Email')?></label>
<input type="text" class="form-control" id="email" name="email" value="<?=$company->email ?>">
</div>
<div class="mb-3">
<label for="web" class="form-label"><?=_('Web')?></label>
<input type="text" class="form-control" id="web" name="web" value="<?=$company->web ?>">
</div>
<div class="mb-3">
<label for="customerno" class="form-label"><?=_('Customer no.')?></label>
<input type="text" class="form-control" id="customerno" name="customerno" value="<?=$company->customerno ?>">
</div>
<div class="mb-3">
<label for="contractno" class="form-label"><?=_('Contract no.')?></label>
<input type="text" class="form-control" id="contractno" name="contractno" value="<?=$company->contractno ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$company->remarks ?></textarea>
</div>
<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>
</form>
<?php
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
$sql = "SELECT compname, remarks FROM company WHERE compid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$company = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Delete Company'), "</h2>\n";
echo '<p>', sprintf(_('Record no. %d'), $id), "</p>\n";
echo '<p>Name: ', $company->compname, "</p>";
echo '<p>Remarks: ', $company->remarks, "</p>";
// Still used as a supplier or manufacturer for equipment?
$sql = "SELECT COUNT(*) FROM equipment WHERE supplier=:id OR manufacturer=:id";
$sth = $pdo->prepare($sql);
$sth->bindValue(':id', $id, PDO::PARAM_INT);
$sth->execute();
$usecount = $sth->fetchColumn();
if ($usecount > 0) {
echo '<p class="alert alert-warning">', _('Company can not be deleted as there are equipment-references!'), "<p>\n";
echo '<a href="', $g_scriptname, '?f=view&id=', $id, '" class="btn btn-secondary">', _('Back'), "</a>\n";
} else {
echo '<p>', _('Deleting a company is final. There is no way back. Only delete if you are absolute sure.'), "</p>\n";
$_SESSION['token'] = bin2hex(random_bytes(8));
form_delete_buttons($g_scriptname, $id, $_SESSION['token']);
}
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+37
View File
@@ -0,0 +1,37 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
*****************************************************************************/
// ========== GLOBAL CONSTANTS ================================================
define('APP_TITLE', 'Yacht Management Software');
define('APP_TITLE_SHORT', 'YMS');
define('APP_SESSION', 'yms');
// ========== GLOBAL VARIABLES ================================================
// database connection
$g_db_host = 'localhost';
$g_db_username = 'yms';
$g_db_password = 'changeme!';
$g_db_schema = 'yms';
// mail settings
$g_mailto = 'captain@example.com';
$g_mailto_webmaster = 'webmaster@example.com';
// localization
$g_timezone = 'Europe/Berlin';
$g_locale = 'de_DE.UTF-8';
// documents and images
$g_doc_basepath = '/var/local/yms';
$g_doc_maxsize = 1024*1024*16; // 16 MB
$g_storage_limit = 1024; // MB
$g_thumb_size = 120;
+16
View File
@@ -0,0 +1,16 @@
body {
font-family: "Noto Sans", "Bitstream Vera Sans", Arial, sans;
}
h1 {
color: #444;
}
@media print {
footer {
display : none;
}
.noPrint {
display : none;
}
}
+47
View File
@@ -0,0 +1,47 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
/* Document Downloader
Doucuments are not directly accessible via filesystem
dl.php must be used with docid as parameter:
e,g, dl.php?id=23 */
require 'globals.inc';
$docid = gpc_get_int($_GET, 'id');
$sql = "SELECT doctype, docsize, mimetype, hash, extension, filename FROM document WHERE docid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$docid]);
$row = $sth->fetch();
$dtmap = array(
'generic' => 'doc',
'manual' => 'man',
'invoice' => 'inv',
'picture' => 'pic',
'drawing' => 'drw');
$file = sprintf("%s/%s-%s.%s", $g_doc_basepath, $dtmap[$row['doctype']], $row['hash'], $row['extension']);
if (file_exists($file)) {
header('Content-Description: File Transfer');
header('Content-Type: ' . $row['mimetype']);
header('Content-Disposition: attachment; filename="' . $row['filename'] . '"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
if ($row['docsize'] == 0) {
header('Content-Length: ' . filesize($file));
} else {
header('Content-Length: ' . $row['docsize']);
}
readfile($file);
exit;
} else {
// dynamically create error image
// TODO
}
+405
View File
@@ -0,0 +1,405 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Documents');
$id = gpc_get_int($_REQUEST, 'id', 0);
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
// WIP New standalone document
$title = gpc_get_string($_POST, 'title');
$remarks = gpc_get_string($_POST, 'remarks');
$g_message->Add(print_r($_FILES, true));
if (empty($_FILES['files']['tmp_name']) ) {
$g_warning->Add(_('No file for upload submitted. Try again by selecting a file first.'));
$action = ACT_ADD;
break;
}
$mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf'];
$nerr = 0;
$file_name = $_FILES['files']['name'];
$file_tmp = $_FILES['files']['tmp_name'];
$file_type = $_FILES['files']['type'];
$file_size = $_FILES['files']['size'];
$file_ext = strtolower(end(explode('.', $_FILES['files']['name'])));
$file_mimetype = mime_content_type($file_tmp);
if (!in_array($file_mimetype, $mimetypes)) {
$g_error->Add(sprintf(_("Mimetype '%s' not allowed for upload."), $file_mimetype));
$action = ACT_ADD;
break;
};
if ($file_type != $file_mimetype) {
$g_warning->Add(sprintf(_("Mimetype mismatch: '%s'."), $file_type));
}
// ok let's go
$file_hash = md5_file($file_tmp);
$file_timestamp = date('Y-m-d H:i:s', filemtime($file_tmp));
// check if the file already exists, in which case issue
// a notice and display the existing document
$sth = $pdo->prepare("SELECT docid FROM document WHERE hash=?");
$sth->execute([$file_hash]);
$id = $sth->fetchColumn();
if ($id) {
$g_warning->Add(_('Document already exists!'));
$action = ACT_VIEW;
break;
}
switch ($file_mimetype) {
case 'application/pdf':
$file_techname = $g_doc_basepath . '/doc-'.$file_hash.'.'.$file_ext;
$doctype = 'generic';
break;
case 'image/svg+xml':
$file_techname = $g_doc_basepath . '/drw-'.$file_hash.'.'.$file_ext;
$doctype = 'drawing';
break;
case 'image/png':
case 'image/jpeg':
$file_techname = $g_doc_basepath . '/pic-'.$file_hash.'.'.$file_ext;
$doctype = 'picture';
break;
}
$sql = "INSERT INTO document"
. " (doctype, filename, extension, hash, doctime, docsize, mimetype) "
. "VALUES"
. " (?, ?, ?, ?, ?, ?, ?)";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$doctype, $file_name, $file_ext, $file_hash, $file_timestamp, $file_size, $file_mimetype]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->lastInsertId();
move_uploaded_file($file_tmp, $file_techname);
$action = ACT_VIEW;
break;
case 'update':
$filename = gpc_get_string($_POST, 'filename');
$title = gpc_get_string($_POST, 'title', 40);
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE document "
. "SET filename=:filename,"
. " title=:title,"
. " remarks=:remarks "
. "WHERE docid=:docid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':docid', $id, PDO::PARAM_INT);
$sth->bindValue(':filename', $filename, PDO::PARAM_STR);
$sth->bindValue(':title', $title, PDO::PARAM_STR);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
try {
$sth->execute();
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
$action = ACT_DEFAULT;
break;
case 'addref':
$eid = gpc_get_int($_POST, 'eid');
$sql = "INSERT INTO docref "
. " (docid, refid, reftype) "
. "VALUES "
. " (:docid, :refid, 'equipment')";
$sth = $pdo->prepare($sql);
$sth->bindValue(':docid', $id, PDO::PARAM_INT);
$sth->bindValue(':refid', $eid, PDO::PARAM_INT);
$sth->execute();
$action = ACT_VIEW;
break;
case 'delref':
// remove only link, not critical so get without token is ok
$drid = gpc_get_int($_GET, 'drid');
$sql = "DELETE FROM docref WHERE drid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$drid]);
$g_message->Add(_('Removed document reference'));
$action = ACT_VIEW;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
// All documents
/* TODO show all documents which
- are completely unbound: no docref available
- assigned to the current boat: docref with doctype vessel
- are assigned to an equipment or project of current vesseö
There can be multiple docref entries for a document,
behavior still needs to be clarified. */
echo "<h1>$pagetitle</h1>\n";
$sql = "SELECT d.docid, d.doctype, d.filename, d.title, COUNT(r.drid) AS refcount "
. "FROM document AS d LEFT OUTER JOIN docref AS r USING (docid) "
. "GROUP BY d.docid, d.doctype, d.filename, d.title";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('ID') . "</th>";
echo "<th>" . _('Type') . "</th>";
echo "<th>" . _('Filename') . "</th>";
echo "<th>" . _('Title') . "</th>";
echo "<th>" . _('Links') . "</th>";
echo "<th>&nbsp;</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['docid'] ."</td>\n";
echo "<td>". $row['doctype'] ."</td>\n";
echo "<td>". $row['filename'] ."</td>\n";
echo "<td>". $row['title'] ."</td>\n";
echo "<td>". $row['refcount'] ."</td>\n";
// Action buttons
echo "<td>";
echo '<a title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['docid'], '"><i class="bi-eye"></i></a>', "\n";
echo '<a title="', _('Edit'), '" href="', $g_scriptname, '?f=edit&id=', $row['docid'], '"><i class="bi-pencil"></i></a>', "\n";
echo "</td>\n";
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Document'), "</h2>\n";
?>
<form method="post" enctype="multipart/form-data" action="<?=$g_scriptname?>">
<div class="mb-3">
<label for="title" class="form-label"><?=_('Title')?></label>
<input type="text" class="form-control" id="title" name="title" value="<?=$title?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$remarks?></textarea>
</div>
<div class="mb-3">
<label for="files" class="form-label"><?=_('Document')?></label>
<input class="form-control" type="file" id="files" name="files" onchange="preview()">
<img id="frame" src="" class="img-fluid">
<button class="btn btn-secondary" onclick="clearimg();return false;"><?=_('Clear')?></button>
<script>
function preview() {
var images = ["image/png", "image/jpeg", "image/svg+xml"];
console.log(event.target.files[0].type);
if (images.indexOf(event.target.files[0].type) > -1) {
frame.src = URL.createObjectURL(event.target.files[0]);
} else {
frame.src = "";
}
}
function clearimg() {
document.getElementById('file').value = null;
frame.src = "";
}
</script>
</div>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
/* mutool: preview of page thumbs */
$sql = "SELECT docid, doctype, mimetype, filename, extension, hash,"
. " docsize, doctime, title, remarks "
. "FROM document "
. "WHERE docid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$document = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('View Document'), "</h2>\n";
echo '<table class="table table-borderless">', "\n";
echo '<tr><th scope="row" style="width:20%">', _('Document type'),"</th><td>", $document->doctype, "</td></tr>\n";
if ($document->doctype == 'picture') {
$techname = 'pic-' . $document->hash . '.' . $document->extension;
echo '<tr><th scope="row">', _('Preview'), '</th><td>';
// echo '<a href="doc/', $techname, '" target="_blank"><img width="', $g_thumb_size, '" src="doc/', $techname, '" alt="', $document->title, '"></a>';
echo '<a href="dl.php?id=', $document->docid, '" target="_blank">';
echo '<img width="', $g_thumb_size, '" src="dl.php?id=', $document->docid, '" alt="', $document->title, '">';
echo '</a>';
echo "</td></tr>\n";
} elseif (($document->doctype == 'drawing')) {
echo '<tr><th scope="row">', _('Drawing'), '</th>';
echo '<td><img src="dl.php?id=', $document->docid, '" alt="', $document->title, '"></td></tr>', "\n";
} elseif (($document->doctype == 'generic')) {
$techname = 'doc-' . $document->hash . '.' . $document->extension;
if ($document->mimetype == 'application/pdf') {
// TODO show preview of previewpage, ctrate thumbnail if needed
// Download link
echo '<tr><th scope="row">', _('PDF'), '</th><td><a href="dl.php?id=', $document->docid, '">', $document->title ?? _('Download'), "</a></td></tr>\n";
}
}
echo '<tr><th scope="row">', _('Mimetype'),"</th><td>", $document->mimetype, "</td></tr>\n";
echo '<tr><th scope="row">', _('Filename'),"</th><td>", $document->filename, "</td></tr>\n";
echo '<tr><th scope="row">', _('File size'),"</th><td>", $document->docsize, "</td></tr>\n";
echo '<tr><th scope="row">', _('Upload date'),"</th><td>", $document->doctime, "</td></tr>\n";
echo '<tr><th scope="row">', _('Title'),"</th><td>", $document->title, "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $document->remarks, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
echo '<h3>', _('Document references'), "</h3>\n";
$sql = "SELECT drid, reftype, ename AS name, eid "
. "FROM docref INNER JOIN equipment ON (docref.reftype='equipment' AND docref.refid=equipment.eid) "
. "WHERE docid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
echo '<table class="table table-sm">', "\n";
echo "<thead>\n";
echo "<tr>";
echo '<th style="width:20%">' . _('Type') . "</th>";
echo "<th>" . _('Used by') . "</th>";
echo "<td></td>";
echo "</tr>\n";
echo "</thead>\n";
$eids = array();
foreach ($sth->fetchAll() as $row) {
$eids[] = $row['eid'];
echo "<tr>";
echo "<td>", $row['reftype'], "</td>";
echo "<td>", $row['name'], "</td>";
echo "<td>";
echo '<a title="', _('Remove'), '" href="', $script, '?f=delref&id=', $id, '&drid=', $row['drid'], '"><i class="bi-trash"></i></a>';
echo "</td>";
echo "</tr>\n";
}
echo "</table>\n";
// Equipment options
// Do not include equipment that has already been referenced in the list!
$opt_equipment = array();
$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 method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<select name="eid">
<?php
foreach ($opt_equipment as $k => $v) {
echo '<option value="', $k, '">', $v, "</option>\n";
}
?>
</select>
<button class="btn btn-secondary" name="submit[addref]">Referenzieren</button>
</form>
<?php
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
echo '<h2>', _('Edit Document'), "</h2>\n";
$sql = "SELECT docid, doctype, filename, extension, hash, title, remarks "
. "FROM document "
. "WHERE docid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$document = $sth->fetch(PDO::FETCH_OBJ);
if ($document->doctype == 'picture') {
echo '<img width="', $g_thumb_size, '" src="doc/pic-', $document->hash, '.', $document->extension, '">';
}
?>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="title" class="form-label"><?=_('Filename')?></label>
<input type="text" class="form-control" id="filename" name="filename" value="<?=$document->filename ?>">
</div>
<div class="mb-3">
<label for="title" class="form-label"><?=_('Title')?></label>
<input type="text" class="form-control" id="title" name="title" value="<?=$document->title ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$storage->remarks ?></textarea>
</div>
<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>
</form>
<?php
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
echo '<h2>', _('Delete Document'), "</h2>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+271
View File
@@ -0,0 +1,271 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Lists');
$id = gpc_get_int($_REQUEST, 'id', 0); // list id
$v = gpc_get_int($_REQUEST, 'v', -1); // list value id
function create_ddval_form($script, $ddid, $formtype, $row=NULL) {
// formtype: insert or update
$update = ($formtype == 'update');
echo '<form method="post" action="', $script, '">';
echo '<input type="hidden" name="id" value="', $ddid, '">';
if ($update) {
echo '<input type="hidden" name="v" value="', $row['ddval'], '">';
}
// text in one row
echo '<div class="form-floating">';
echo '<input type="text" name="ddtext" id="ddtext" class="form-control"';
if ($update) echo ' value="', $row['ddtext'],'"';
echo '><label for="ddtext">Description</label></div>', "\n";
// all other fields in secondary row
echo '<div class="row my-3">';
echo '<div class="col"><div class="form-floating">';
echo '<input type="text" name="ddshort" id="ddshort"class="form-control"';
if ($update) echo ' value="', $row['ddshort'],'"';
echo '><label for="ddshort">Short description</label></div></div>', "\n";
echo '<div class="col"><div class="form-floating">';
echo '<input type="color" name="color" id="color" class="form-control"';
if ($update) echo ' value="', $row['color'],'"';
echo '><label for="color">Color</label></div></div>', "\n";
echo '<div class="col"><div class="form-floating">';
echo '<input type="text" name="sort" id="sort" class="form-control"';
if ($update) echo ' value="', $row['sort'],'"';
echo '><label for="sort">Sort</label></div></div>', "\n";
echo '</div>'; // finish row
// buttons
echo '<button name="submit" value="', $formtype, '" class="btn btn-primary btn-sm" title="Save"><i class="bi-save"></i> Save</button>';
echo '&nbsp';
echo '<a href="', $script, '?f=edit&id=', $ddid, '" class="btn btn-secondary btn-sm" title="Cancel"><i class="bi-x-square"></i> Cancel</a>';
echo "</form>\n";
}
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $v = -2; $action = ACT_EDIT; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$p[':ddid'] = gpc_get_int($_POST, 'id');
$sth = $pdo->prepare("SELECT MAX(ddval)+1 FROM dropdown WHERE ddid=?");
$sth->execute([$p[':ddid']]);
$p[':ddval'] = $sth->fetchColumn() ?? 1;
$p[':ddtext'] = gpc_get_string($_POST, 'ddtext');
$p[':ddshort'] = gpc_get_string($_POST, 'ddshort');
$p[':color'] = gpc_get_color($_POST, 'color');
$p[':sort'] = gpc_get_string($_POST, 'sort');
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO dropdown ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_EDIT;
break;
case 'update':
$p[':ddtext'] = gpc_get_string($_POST, 'ddtext');
$p[':ddshort'] = gpc_get_string($_POST, 'ddshort');
$p[':color'] = gpc_get_color($_POST, 'color');
$p[':sort'] = gpc_get_string($_POST, 'sort');
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE dropdown SET $fields WHERE ddid=:ddid AND ddval=:ddval");
$p[':ddid'] = gpc_get_int($_POST, 'id');
$p[':ddval'] = gpc_get_int($_POST, 'v');
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
unset($v);
$action = ACT_EDIT;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
// record counts
$num = array();
$sql = "SELECT ddid, COUNT(*) AS n FROM dropdown WHERE ddid>0 GROUP BY ddid";
$sth = $pdo->query($sql);
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) {
$num[$row[0]] = $row[1];
}
$sql = "SELECT ddval, ddtext FROM dropdown WHERE ddid=0 AND ddval>0";
$sth = $pdo->query($sql);
echo "<h1>$pagetitle</h1>\n";
echo '<p>', _('Danger! Only adjust if it is clear what impact this will have!'), "<br>\n";
// <p>Achtung! Nur anpassen wenn klar ist was das für Auswirkungen hat!</p>
echo _('Adding values is usually not critical.'), "</p>\n";
// <p>Hinzufügen von Werten ist in der Regel unkritisch.</p>
echo '<table class="table">', "\n";
echo '<thead>';
echo '<tr>';
echo '<th>#</th>';
echo '<th>', _('Description'),'</th>';
echo '<th>', _('Number'),'</th>';
echo '<td></td>';
echo '</tr>';
echo '</thead>';
foreach ($sth->fetchAll() as $row) {
echo '<tr><td>', $row['ddval'],'</td>';
echo '<td>', $row['ddtext'], '</td>';
echo '<td>', $num[$row['ddval']] ?? 0, '</td>';
form_action_buttons($g_scriptname, $row['ddval']);
echo "</tr>\n";
}
echo "</table>\n";
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sth = $pdo->prepare("SELECT ddtext FROM dropdown WHERE ddid=0 AND ddval=?");
$sth->execute([$id]);
$listname = $sth->fetchColumn();
echo '<h2>', sprintf(_('View List: %s'), $listname), "</h2>\n";
$sql = "SELECT ddval, ddtext, ddshort, color, sort FROM dropdown WHERE ddid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
echo '<table class="table">';
echo "<thead>\n";
echo "<tr>\n";
echo '<th>#</th>';
echo '<th>', _('Name'), "</th>";
echo '<th>', _('Short'), "</th>";
echo '<th>', _('Color'), "</th>";
echo '<th>', _('Sort'), "</th>";
echo "<th></th>\n";
echo "</tr>\n";
echo "</thead>\n";
foreach ($sth->fetchAll() as $row) {
echo '<tr>';
echo '<td>', $row['ddval'],'</td>';
echo '<td>', $row['ddtext'], '</td>';
echo '<td>', $row['ddshort'], '</td>';
echo '<td>', $row['color'], '</td>';
echo '<td>', $row['sort'], '</td>';
echo "</tr>\n";
}
echo "</table>\n";
echo '<a href="', $g_scriptname, '" class="btn btn-secondary">', _('Back'), "</a>\n";
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sth = $pdo->prepare("SELECT ddtext FROM dropdown WHERE ddid=0 AND ddval=?");
$sth->execute([$id]);
$listname = $sth->fetchColumn();
echo '<h2>', sprintf(_('Edit List: %s'), $listname), "</h2>\n";
$sql = "SELECT ddval, ddtext, ddshort, color, sort FROM dropdown WHERE ddid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
echo '<table class="table">';
echo "<thead>\n";
echo "<tr>\n";
echo '<th>#</th>';
echo '<th>', _('Name'), "</th>";
echo '<th>', _('Short'), "</th>";
echo '<th>', _('Color'), "</th>";
echo '<th>', _('Sort'), "</th>";
echo "<th></th>\n";
echo "</tr>\n";
echo "</thead>\n";
foreach ($sth->fetchAll() as $row) {
echo '<tr>';
if ($row['ddval'] == $v) {
echo '<td>', $row['ddval'], '</td>';
echo '<td colspan="4">';
create_ddval_form($g_scriptname, $id, 'update', $row);
echo '</td>';
echo "<td></td>\n";
} else {
echo '<td>', $row['ddval'],'</td>';
echo '<td>', $row['ddtext'], '</td>';
echo '<td>', $row['ddshort'], '</td>';
echo '<td>', $row['color'], '</td>';
echo '<td>', $row['sort'], '</td>';
// Action links
echo '<td>';
echo '<a href="', $g_scriptname, '?f=edit&id=', $id, '&v=', $row['ddval'], '"><i class="bi-pencil"></i></a>';
echo '&nbsp;';
echo '<i class="bi-trash"></i>';
echo '</td>', "\n";
// TODO extend function to accept additional parameters
// form_action_buttons($g_scriptname, $row['ddid'];
}
echo "</tr>\n";
}
if ($v == -2) {
echo '<tr>';
echo '<td>(+)</td>';
echo '<td colspan="4">';
create_ddval_form($g_scriptname, $id, 'insert');
echo '</td>';
echo "<td></td>\n";
echo "</tr>";
}
echo "</table>\n";
echo '<a href="', $g_scriptname, '?f=add&id=', $id, '" class="btn btn-primary">', _('Add'), "</a>\n";
echo '<a href="', $g_scriptname, '" class="btn btn-secondary">', _('Back'), "</a>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+474
View File
@@ -0,0 +1,474 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Equipment');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_supplier = db_get_opt_supp(array(-1 => _('unknown')));
$opt_manufacturer = db_get_opt_manuf(array(-1 => _('unknown')));
$opt_ecat = db_get_options(4); // Equipment categories
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$ename = gpc_get_string($_POST, 'ename');
$ecat = gpc_get_int($_POST, 'category');
$manufacturer = gpc_get_int($_POST, 'manufacturer');
$model = gpc_get_string($_POST, 'model');
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "INSERT INTO equipment "
. " (vid, ename, manufacturer, model, ecat, remarks) "
. "VALUES "
. " (:vid, :ename, :manufacturer, :model, :ecat, :remarks)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->bindValue(':ename', $ename, PDO::PARAM_STR);
$sth->bindValue(':model', $model, PDO::PARAM_STR);
$sth->bindValue(':ecat', $ecat, PDO::PARAM_INT);
$sth->bindValue(':manufacturer', $manufacturer, PDO::PARAM_INT);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
try {
$sth->execute();
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->lastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$ename = gpc_get_string($_POST, 'ename');
$model = gpc_get_string($_POST, 'model');
$serial = gpc_get_string($_POST, 'serial');
$weight = min(gpc_get_float($_POST, 'weight'), 999.99); // limit max value
$price = gpc_get_currency($_POST, 'price');
$purchdate = gpc_get_date($_POST, 'purchdate');
$supplier = gpc_get_int($_POST, 'supplier');
$manufacturer = gpc_get_int($_POST, 'manufacturer');
$ecat = gpc_get_int($_POST, 'category');
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE equipment "
. "SET ename=:ename,"
. " model=:model,"
. " serial=:serial,"
. " weight=:weight,"
. " price=:price,"
. " purchdate=:purchdate,"
. " supplier=:supplier,"
. " manufacturer=:manufacturer,"
. " ecat=:ecat,"
. " remarks=:remarks "
. "WHERE eid=:eid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':eid', $id, PDO::PARAM_INT);
$sth->bindValue(':ename', $ename, PDO::PARAM_STR);
$sth->bindValue(':model', $model, PDO::PARAM_STR);
$sth->bindValue(':serial', $serial, PDO::PARAM_STR);
$sth->bindValue(':weight', $weight);
$sth->bindValue(':price', $price);
$sth->bindValue(':purchdate', $purchdate, PDO::PARAM_STR);
$sth->bindValue(':supplier', $supplier, PDO::PARAM_INT);
$sth->bindValue(':manufacturer', $manufacturer, PDO::PARAM_INT);
$sth->bindValue(':ecat', $ecat, PDO::PARAM_INT);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
try {
$sth->execute();
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
unset($_SESSION['token']);
$sth = $pdo->prepare("DELETE FROM docref WHERE reftype='equipment' AND refid=?");
try {
$sth->execute([$id]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$refcount = $sth->rowCount();
$sth = $pdo->prepare("DELETE FROM equipment WHERE eid=?");
try {
$sth->execute([$id]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$g_message->Add(sprintf(_('Deleted equipment no. %d'), $id));
if ($refcount > 0) {
$g_message->Add(sprintf(_('%d document links were removed'), $refcount));
}
$action = ACT_DEFAULT;
break;
case 'upload':
$action = ACT_VIEW;
if (!isset($_FILES['files'])) {
$g_warning->Add(_('No files for upload submitted'));
break;
}
$extensions = ['jpg', 'png'];
$mimetypes = ['image/png', 'image/jpeg', 'image/svg+xml', 'application/pdf'];
$all_files = count($_FILES ["files"]["tmp_name"]);
$nerr = 0;
for ($i = 0; $i < $all_files; $i++) {
$file_name = $_FILES['files']['name'][$i];
$file_tmp = $_FILES['files']['tmp_name'][$i];
$file_type = $_FILES['files']['type'][$i];
$file_size = $_FILES['files']['size'][$i];
$file_ext = strtolower(end(explode('.', $_FILES['files']['name'][$i])));
// $file = $g_doc_basepath . '/' . $file_name;
$file_mimetype = mime_content_type($file_tmp);
if (!in_array($file_mimetype, $mimetypes)) {
$g_error->Add(sprintf(_("Mimetype '%s' not allowed for upload."), $file_mimetype));
$nerr += 1;
}
if (!in_array($file_ext, $extensions)) {
$g_error->Add(_('Filetype not allowed for upload:') . ' ' . $file_type);
$nerr += 1;
}
if ($file_size > 2097152) {
$g_error->Add(sprintf(_('File to big: %s.%s'), $file_name, $file_type));
$nerr += 1;
}
if ($nerr > 0) {
break;
}
$file_hash = md5_file($file_tmp);
$file_timestamp = date('Y-m-d H:i:s', filemtime($file_tmp));
// check whether the file already exists, in this case issue
// a message and just create a link to the already known file
$sql = "SELECT docid FROM document WHERE hash=?";
$sth = $pdo->prepare($sql);
$sth->execute([$file_hash]);
$row = $sth->fetch();
if (!$row) {
$sql = "INSERT INTO document"
. " (doctype, filename, extension, hash, doctime, docsize, mimetype) "
. "VALUES"
. " (?, ?, ?, ?, ?, ?, ?)";
$sth = $pdo->prepare($sql);
$sth->execute(['picture', $file_name, $file_ext, $file_hash, $file_timestamp, $file_size, $file_mimetype]);
$docid = $pdo->lastInsertId();
$file_techname = $g_doc_basepath . '/pic-'.$file_hash.'.'.$file_ext;
move_uploaded_file($file_tmp, $file_techname);
} else {
// A document record definitely exists here, now just
// connect it to the selected equipment
$docid = $row['docid'];
}
$sql = "INSERT INTO docref (docid, refid) VALUES (?, ?)";
$sth = $pdo->prepare($sql);
// Reference may already exist!
try {
$sth->execute([$docid, $id]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
} // for
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
$sql = "SELECT eid, ename, manufacturer, model, serial, remarks,"
. " TIMESTAMPDIFF(MONTH, purchdate, NOW()) AS age_mon "
. "FROM equipment WHERE vid=? "
. "ORDER BY eid";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll();
echo "<h1>$pagetitle</h1>\n";
// Filter
?>
<form method="post">
<div id="filter" class="card">
<div class="card-header">Filter</div>
<div class="card-body">
<label>Category</label>
<select>
<?php
foreach ($opt_ecat as $k => $v) {
echo '<option value="', $k,'">', $v, '</option>';
}
?>
</select>
<button class="btn btn-sm btn-primary" title="<?=_('Apply')?>">Go</button>
</div>
</div>
</form>
<?php
// Data
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Description') . "</th>";
echo "<th>" . _('Manufacturer') . "</th>";
echo "<th>" . _('Model') . "</th>";
echo "<th>" . _('Serial') . "</th>";
echo "<th>" . _('Age') . "</th>";
echo "<th>" . _('Remarks') . "</th>";
echo "<th>&nbsp;</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
// calc nice age display
if (!isset($row['age_mon'])) {
$age = '';
} elseif ($row['age_mon'] < 12) {
$age = sprintf(_('%dm'), $row['age_mon']);
} else {
$age = sprintf(_('%dy'), intdiv($row['age_mon'], 12));
}
echo "<tr>\n";
echo "<td>". $row['ename'] ."</td>\n";
echo "<td>". $opt_manufacturer[$row['manufacturer']] ."</td>\n";
echo "<td>". $row['model'] ."</td>\n";
echo "<td>". $row['serial'] ."</td>\n";
echo "<td>". $age ."</td>\n";
echo "<td>". $row['remarks'] ."</td>\n";
// Action buttons
form_action_buttons($g_scriptname, $row['eid']);
}
?>
<tfoot>
<tr><td colspan="6"><?php printf(_('%d records'), count($res)); ?></td></tr>
</tfoot>
</table>
<nav>
<ul class="pagination justify-content-center">
<li class="page-item"><a class="page-link" href="#">Previous</a></li>
<li class="page-item"><a class="page-link" href="#">1</a></li>
<li class="page-item"><a class="page-link" href="#">2</a></li>
<li class="page-item"><a class="page-link" href="#">Next</a></li>
</ul>
</nav>
<?php
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
?>
<h2><?=_('Add Equipment')?></h2>
<form method="post">
<div class="mb-3">
<label for="ename" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="ename" name="ename">
</div>
<?php
form_create_select('category', _('Category'), $opt_ecat);
form_create_select('manufacturer', _('Manufacturer'), $opt_manufacturer);
?>
<div class="mb-3">
<label for="model" class="form-label"><?=_('Model')?></label>
<input type="text" class="form-control" id="model" name="model">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
</div>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT eid, ename, model, serial, purchdate, price, weight, "
. " supplier, manufacturer, ecat, remarks "
. "FROM equipment "
. "WHERE eid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$equipment = $sth->fetch(PDO::FETCH_OBJ);
echo "<h2>", $equipment->ename, "</h2>\n";
// Bootstrap grid
echo '<div class="container">';
echo '<div class="row">';
echo '<div class="col">';
echo '<table class="table">', "\n";
echo '<tr><th>', _('Manufacturer'),"</th><td>", $opt_manufacturer[$equipment->manufacturer], "</td></tr>\n";
echo '<tr><th>', _('Model'),"</th><td>", $equipment->model, "</td></tr>\n";
echo '<tr><th>', _('Serial'),"</th><td>", $equipment->serial, "</td></tr>\n";
echo '<tr><th>', _('Weight'),"</th><td>", format_float($equipment->weight, 2, 'kg'), "</td></tr>\n";
echo '<tr><th>', _('Price'),"</th><td>", format_currency($equipment->price), "</td></tr>\n";
echo '<tr><th>', _('Purchase date'),"</th><td>", $equipment->purchdate, "</td></tr>\n";
echo '<tr><th>', _('Supplier'),"</th><td>", $opt_supplier[$equipment->supplier], "</td></tr>\n";
echo '<tr><th>', _('Category'),"</th><td>", $opt_ecat[$equipment->ecat], "</td></tr>\n";
echo '<tr><th>', _('Remarks'),"</th><td>", $equipment->remarks, "</td></tr>\n";
echo "</table>\n";
echo '</div>'; // Column break
echo '<div class="col">';
?>
<p>Images and documents go here</p>
<?php
$sql = "SELECT d.docid, d.doctype, d.title "
. "FROM docref AS r INNER JOIN document AS d using (docid) "
. "WHERE r.refid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$res = $sth->fetchAll();
foreach ($res as $row) {
if ($row['doctype'] == 'picture') {
echo '<a href="dl.php?id=', $row['docid'], '">';
// echo '<img width="120" src="doc/pic-', $row['hash'], '.', $row['extension'],'">';
echo '<img width="120" src="dl.php?id=', $row['docid'], '" alt="', $row['title'], '">';
echo "</a>\n";
} elseif ($row['doctype'] == 'generic') {
echo '<a href="dl.php?id=', $row['docid'], '">';
echo $row['title'];
echo "</a>\n";
}
}
?>
<form method="post" enctype="multipart/form-data" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="card">
<div class="card-body">
<input type="file" name="files[]" multiple accept="image/*" capture="camera">
<input type="submit" name="submit[upload]" value="Upload">
</div>
</div>
</form>
<?php
echo '</div>'; // col
echo '</div>'; // row
echo '</div>'; // container
// Buttons at bottom of data area
form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT compid, compname FROM company WHERE comptype=1 ORDER BY compname";
$sth = $pdo->query($sql);
$supplier = array();
foreach ($sth->fetchAll() as $row) {
$supplier[$row['compid']] = $row['compname'];
}
$sql = "SELECT eid, ename, model, serial, weight, price, purchdate,"
. " supplier, manufacturer, ecat, remarks "
. "FROM equipment "
. "WHERE eid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$equipment = $sth->fetch(PDO::FETCH_OBJ);
?>
<h2><?=_('Edit Equipment')?></h2>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="ename" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="ename" name="ename" value="<?=$equipment->ename ?>">
</div>
<?php form_create_select('manufacturer', _('Manufacturer'), $opt_manufacturer, $equipment->manufacturer); ?>
<div class="mb-3">
<label for="model" class="form-label"><?=_('Model')?></label>
<input type="text" class="form-control" id="model" name="model" value="<?=$equipment->model ?>">
</div>
<div class="mb-3">
<label for="serial" class="form-label"><?=_('Serial')?></label>
<input type="text" class="form-control" id="serial" name="serial" value="<?=$equipment->serial ?>">
</div>
<div class="mb-3">
<label for="weight" class="form-label"><?=_('Weight, kg')?></label>
<input type="text" class="form-control" id="weight" name="weight" value="<?=format_float($equipment->weight); ?>">
</div>
<div class="mb-3">
<label for="price" class="form-label"><?=sprintf(_('Price, %s'), $g_lconv['currency_symbol']); ?></label>
<input type="text" class="form-control" id="price" name="price" value="<?=format_float($equipment->price) ?>">
</div>
<div class="mb-3">
<label for="purchdate"><?=_('Purchase date')?></label>
<input type="date" class="form-control" id="startdate" name="purchdate" value="<?=$equipment->purchdate ?>">
</div>
<?php
form_create_select('supplier', _('Supplier'), $opt_supplier, $equipment->supplier);
form_create_select('category', _('Category'), $opt_ecat, $equipment->ecat);
?>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$equipment->remarks ?></textarea>
</div>
<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>
</form>
<?php
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
$_SESSION['token'] = bin2hex(random_bytes(8));
$sql = "SELECT ename, remarks FROM equipment WHERE eid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$equipment = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Delete equipment'),"</h2>\n";
echo '<p>', sprintf(_('Record no. %d'), $id), "</p>\n";
echo '<p>Name: ', $equipment->ename, "</p>";
echo '<p>Remarks: ', $equipment->remarks, "</p>";
echo '<p>', _('Deleting an equipment item is final. There is no way back. Only delete if you are absolute sure.'), "</p>\n";
form_delete_buttons($g_scriptname, $id, $_SESSION['token']);
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+7
View File
@@ -0,0 +1,7 @@
<footer class="bg-body-tertiary text-center">
<p>Prototyp YMS v0.1</p>
</footer>
</div><?php /* Main container */?>
</body>
</html>
+709
View File
@@ -0,0 +1,709 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************
******************
* Edition History
*
* # Date Changes by
* ------ ------------ ---------------------------------------------- -----
* 0.1.0 2024-03-12 Started development tho
*
*/
// ========== CONSTANT DEFINITIONS ============================================
define ('E_NONE', 0);
define ('OPTIONAL', 0);
define ('REQUIRED', 1);
define ('ENABLED', 1);
define ('DISABLED', 0);
define ('ACT_DEFAULT', 0);
define ('ACT_ADD', 1);
define ('ACT_VIEW', 2);
define ('ACT_EDIT', 3);
define ('ACT_DELETE', 4);
define ('ACT_COPY', 5);
define ('ACT_JOIN', 6);
define ('ACT_LEAVE', 7);
define ('ACT_EDIT_DETAIL', 8);
define ('ACT_DEL_DETAIL', 9);
define ('ACT_LINK', 10);
define ('ACT_UNLINK', 11);
define ('ACT_MAIL', 12);
define ('ACT_VIEW_LIST', 13);
// ========== PAGE START CODE =================================================
$g_scriptname = basename($_SERVER['SCRIPT_NAME']);
require 'config.inc';
// Localization
setlocale(LC_ALL, $g_locale);
$g_lconv = localeconv();
$g_lang = substr($g_locale, 0, 2); // short language identifier
bindtextdomain('yms', 'locale');
bind_textdomain_codeset('yms', 'UTF-8');
textdomain('yms');
date_default_timezone_set($g_timezone);
if ($g_scriptname != 'login.php') {
session_name(APP_SESSION);
session_start();
if (!isset($_SESSION['userid'])) {
$_SESSION['prelogin'] = $_SERVER['REQUEST_URI'];
header_location('login.php');
}
}
$pdo = new PDO("mysql:host=$g_db_host;dbname=$g_db_schema;charset=utf8mb4", $g_db_username, $g_db_password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
# $pdo->query("SET lc_time_names='de_DE'");
$sth = $pdo->query("SELECT valint FROM settings WHERE userid=0 AND sno=0");
$g_db_scheme_version = $sth->fetchColumn();
$user = User::GetInstance(); // There can be only one
if ($g_scriptname != 'login.php') {
$user->init_from_session();
$user->load_vessel();
}
$action = NULL;
$valid = FALSE;
// Initialize message system
$g_message = new Message;
$g_success = new MessageSuccess;
$g_warning = new MessageWarning;
$g_error = new MessageError;
// ========== MESSAGE FUNCTIONS ===============================================
class Message {
var $count = 0;
var $text = array();
var $caption;
var $alertclass;
function __construct() {
$this->caption = _('Information');
$this->alertclass = 'alert-info';
}
function SetCaption($str) {
$this->caption = $str;
}
function Add($msg) {
$this->count++;
$this->text[$this->count] = $msg;
}
function GetCount() {
return $this->count;
}
function PrintOut() {
if ($this->count > 0) {
echo '<div class="alert ', $this->alertclass, ' alert-dismissible fade show" role="alert">', "\n";
echo '<h4 class="alert-heading">', $this->caption, "</h4>\n";
echo "<ul>\n";
for ($i=1; $i<=$this->count; $i++) {
echo "\t<li>", $this->text[$i],"</li>\n";
}
echo "</ul>\n";
echo '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>', "\n";
echo "</div>\n";
}
}
}
class MessageSuccess extends Message {
function __construct() {
$this->caption = _('Success');
$this->alertclass = 'alert-success';
}
}
class MessageWarning extends Message {
function __construct() {
$this->caption = _('Warning');
$this->alertclass = 'alert-warning';
}
}
class MessageError extends Message {
function __construct() {
$this->caption = _('Error');
$this->alertclass = 'alert-danger';
}
}
// ========== USER FUNCTIONS ==================================================
class User {
private static $instance = NULL;
private $loggedin;
private $errormessage;
public $id;
public $login;
public $displayname;
public $role;
public $flags;
public $vid; // current selected vessel
public $vessel; // name of current vessel
private function __construct() {
$this->loggedin = FALSE;
$this->errormessage = NULL;
$this->flags = [];
$this->vid = 1;
$this->vessel = 'Yacht';
}
public static function getInstance() {
if (self::$instance == NULL) {
self::$instance = new User();
}
return self::$instance;
}
function login($user_name, $user_pass) {
global $pdo;
if ($user_name == '' or $user_pass == '') {
$this->loggedin = FALSE;
$this->errormessage = _('Username or password was empty');
return FALSE;
}
$sql = "SELECT userid, pass, displayname, role, flags FROM user WHERE login=?";
$sth = $pdo->prepare($sql);
$sth->execute([$user_name]);
$row = $sth->fetch(PDO::FETCH_OBJ);
$this->role = $row->role;
$this->flags = array_filter(explode(',', $row->flags));
if ($row->flags != 0 ) {
// deleted or locked, intentionally not return detailed reason
$this->errormessage = _('User account does not exist');
} elseif (password_verify($user_pass, $row->pass)) {
// password check successful
$_SESSION['userid'] = $row->userid;
$this->loggedin = TRUE;
header_location($_SESSION['prelogin'] ?? 'index.php');
} else {
$this->errormessage = _('Username or password invalid');
}
return FALSE;
}
function logout() {
global $pdo;
// remove session completely
$_SESSION = array();
if (ini_get("session.use_cookies")) {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
}
session_destroy();
}
function init_from_session() {
global $pdo;
if (!isset($_SESSION['userid'])) {
$this->loggedin = FALSE;
$this->errormessage = _('User not logged in');
$this->id = NULL;
return;
}
$this->id = $_SESSION['userid'];
$sql = "SELECT displayname, role FROM user WHERE userid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$this->id]);
$row = $sth->fetch();
$this->displayname = $row['displayname'];
$this->role = $row['role'];
//$this->displayname = $sth->fetchColumn();
}
function load_vessel() {
global $pdo;
$sql = "SELECT v.vid, v.vesselname "
. "FROM settings AS s INNER JOIN vessel AS v ON s.valint=v.vid "
. "WHERE s.userid=? and s.sno=1";
$sth = $pdo->prepare($sql);
$sth->execute([$this->id]);
$row = $sth->fetch();
$this->vid = $row['vid'];
$this->vessel = $row['vesselname'];
}
function get_last_error() {
return $this->errormessage;
}
}
function get_userlist() {
// Get list of all users for fast name lookup
global $pdo;
$ulist = array(-1 => ['-', 0]); // unknown
$sql = "SELECT userid, displayname, role, flags FROM user ORDER BY displayname";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
foreach ($res as $row) {
$flags = array_filter(explode(',', $row['flags']));
$deleted = in_array('deleted', $flags);
$locked = in_array('locked', $flags);
$ulist[$row['userid']] = [$row['displayname'], $deleted, $locked];
}
return $ulist;
}
// ========== DATABASE FUNCTIONS ==============================================
function db_load_enum($table, $column) {
// returns array of enum-values as defined in database
global $pdo;
$sql = "SELECT TRIM(TRAILING ')' FROM SUBSTRING(column_type,6)) "
. "FROM information_schema.columns "
. "WHERE table_name=? AND column_name=?";
$sth = $pdo->prepare($sql);
$sth->execute([$table, $column]);
// for PHP < 7.4
// return array_map(function($x) { return trim($x, "'"); }, explode(',', $sth->fetchColumn()));
// for PHP => 7.4
return array_map(fn($x) => trim($x, "'"), explode(',', $sth->fetchColumn()));
}
function db_get_ddtext($ddid, $ddval) {
// returns single value for dropdown
global $pdo;
global $g_error;
$sql = "SELECT ddtext FROM dropdown WHERE ddid=? AND ddval=?";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$ddid, $ddval]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
return '#err';
}
return $sth->fetchColumn();
}
function db_get_options($ddid, $orderby = '', $default = NULL) {
// returns list for dropdown
global $pdo;
$list = array();
if ($default != NULL) {
$list[0] = $default;
}
$sql = "SELECT ddval, ddtext FROM dropdown WHERE ddid=?";
if ($orderby == 'ddtext') {
$sql .= ' ORDER BY ddtext';
} elseif ($orderby == 'sort') {
$sql .= ' ORDER BY sort';
} else {
$sql .= ' ORDER BY ddval';
}
$sth = $pdo->prepare($sql);
$sth->execute([$ddid]);
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
$list[$rec[0]] = $rec[1];
}
return $list;
}
function db_get_opt_vessel() {
global $pdo;
$list = array();
$sth = $pdo->query("SELECT vid, vesselname, model FROM vessel ORDER BY vid");
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) {
$list[$rec[0]] = $rec[1];
}
return $list;
}
// Functions to get option lists (key/value)
function db_get_opt_storage($vid) {
global $pdo;
global $g_error;
$list = array();
$sql = "SELECT sid, sname FROM storage WHERE vid=? ORDER BY sname";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$vid]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
$list[$rec[0]] = $rec[1];
}
return $list;
}
function db_get_opt_box($vid) {
global $pdo;
global $g_error;
$list = array();
$sql = "SELECT boxid, label, content "
. "FROM box INNER JOIN storage USING (sid) "
. "WHERE vid=? "
. "ORDER BY label";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$vid]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
$list[$rec[0]] = $rec[1] . ' - '. $rec[2];
}
return $list;
}
function db_get_opt_equip($vid) {
}
function db_get_opt_manuf($default=NULL) {
global $pdo;
if (isset($default)) {
$list = $default;
} else {
$list = array();
}
$sql = "SELECT compid, compname FROM company WHERE comptype=2 ORDER BY compname";
$sth = $pdo->query($sql);
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) {
$list[$row[0]] = $row[1];
}
return $list;
}
function db_get_opt_supp($default=NULL) {
global $pdo;
if (isset($default)) {
$list = $default;
} else {
$list = array();
}
$sql = "SELECT compid, compname FROM company WHERE comptype=1 ORDER BY compname";
$sth = $pdo->query($sql);
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $row) {
$list[$row[0]] = $row[1];
}
return $list;
}
function db_get_opt_proj($vid, $default=NULL) {
global $pdo;
global $g_error;
if (isset($default)) {
$list = $default;
} else {
$list = array();
}
$sql = "SELECT projid, projname FROM project WHERE vid=? ORDER BY projname";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$vid]);
} catch(PDOException $e) {
$g_error->Add($e->getMessage());
}
foreach ($sth->fetchAll(PDO::FETCH_NUM) as $rec) {
$list[$rec[0]] = $rec[1];
}
return $list;
}
function date_to_sql($var) {
if (!isset($var) || $var == '') {
return NULL;
} else {
list($d, $m, $y) = explode('.', $var);
return sprintf("%04d-%02d-%02d", $y, $m, $d);
}
}
function float_to_sql($var) {
global $g_lconv;
if (!isset($var) || $var == '') {
return NULL;
} else {
// remove thousands separator
$var = str_replace($g_lconv['thousands_sep'], '', $var);
// force decimal point
if ($g_lconv['decimal_point'] != '.') {
$var = str_replace($g_lconv['decimal_point'], '.', $var);
}
return $var;
}
}
// ========== FORM FUNCTIONS ==================================================
function form_create_select($fieldname, $label, $optlist, $selval=NULL) {
//if (
echo '<div class="mb-3">', "\n";
echo '<label for="', $fieldname, '">', $label, "</label>\n";
echo '<select class="form-select" name="', $fieldname,'" id="', $fieldname,'">';
foreach ($optlist as $k => $v) {
echo '<option value="', $k, '"';
if (isset($selval) and ($k == $selval)) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
echo "</select>\n";
echo "</div>\n";
}
function form_action_buttons($script, $id) {
echo "<td>";
echo '<a title="', _('View'), '" href="', $script, '?f=view&id=', $id, '"><i class="bi-eye"></i></a>', "\n";
echo '<a title="', _('Edit'), '" href="', $script, '?f=edit&id=', $id, '"><i class="bi-pencil"></i></a>', "\n";
echo "</td>\n";
}
function form_add_button($script, $id=NULL, $idname='id') {
echo '<div class="container-fluid px-0 my-3">', "\n";
echo '<a href="', $script, '?f=add';
if (isset($id)) {
echo '&'.$idname.'='.$id;
}
echo '" class="btn btn-primary" role="button">', _('Add'), "</a>\n";
echo "</div>\n";
}
function form_view_buttons($script, $id) {
echo '<div class="container-fluid px-0 my-3">', "\n";
echo '<a href="', $script, '?f=edit&id=', $id, '" class="btn btn-primary" role="button">', _('Edit'), "</a>\n";
echo '&nbsp;';
echo '<a href="', $script, '?f=del&id=', $id, '" class="btn btn-secondary" role="button">', _('Delete'), "</a>\n";
echo '&nbsp;';
echo '<a href="', $script, '" class="btn btn-secondary">', _('Back'), "</a>\n";
echo "</div>\n";
}
function form_edit_buttons($script, $id) {
echo '<div class="container-fluid px-0 my-3">', "\n";
echo '<button type="submit" name="submit[update]" class="btn btn-primary">', _('Save'), "</button>\n";
echo '<a href="', $script, '?f=view&id=', $id, '" class="btn btn-secondary">', _('Back'), "</a>\n";
echo "</div>\n";
}
function form_delete_buttons($script, $id, $token) {
echo '<div class="container-fluid px-0 my-3">', "\n";
echo '<form method="post" action="', $script, '">', "\n";
echo '<input type="hidden" name="id" value="', $id .'">', "\n";
echo '<input type="hidden" name="token" value="', $token, '">', "\n";
echo '<button type="submit" name="submit[delete]" class="btn btn-primary">', _('Delete'), "</button>\n";
echo '<a href="', $script, '?f=view&id=', $id, '" class="btn btn-secondary">', _('Back'), "</a>\n";
echo "</div>\n";
echo "</form>\n";
}
// ========== COMMON FUNCTIONS ================================================
function header_location($location) {
header("Location: $location");
exit;
}
function form_get_action() {
if (!isset($_POST['submit'])) {
if (isset($_GET['f'])) {
$submit = $_GET['f'];
// strip parameters
/* $pos = strpos($submit, '?');
if ($pos > 2) {
$submit = substr($submit, 0, $pos);
} */
} else {
$submit = NULL;
}
} else {
$submit = $_POST['submit'];
}
if (is_array($submit)) {
$submit = key($submit);
}
return strtolower($submit);
}
function get_color_brightness($color) {
// returns a value between 0 and 1
// color is a 6 char hex string
list($red, $green, $blue) = array_map('hexdec', str_split($color, 2));
$red = $red / 255 * 0.2126;
$green = $green / 255 * 0.7152;
$blue = $blue / 255 * 0.0722;
return $red + $green + $blue;
}
function gpc_get_string(&$GPC, $varname, $maxlen = NULL, $default = NULL) {
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default;
}
$s = trim($GPC[$varname]);
if (isset($maxlen)) {
return substr($s, 0, $maxlen);
}
return $s;
}
function gpc_get_int(&$GPC, $varname, $default = NULL) {
if (!isset($GPC[$varname])) {
return $default;
}
return (int)$GPC[$varname];
}
function gpc_get_float(&$GPC, $varname, $default = NULL) {
global $g_lconv;
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default;
}
$var = str_replace($g_lconv['thousands_sep'], '', $GPC[$varname]);
if ($g_lconv['decimal_point'] != '.') {
$var = str_replace($g_lconv['decimal_point'], '.', $var);
}
return (double)$var;
}
function gpc_get_currency(&$GPC, $varname, $default = NULL) {
global $g_lconv;
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default;
}
$var = str_replace($g_lconv['thousands_sep'], '', $GPC[$varname]);
if ($g_lconv['decimal_point'] != '.') {
$var = str_replace($g_lconv['decimal_point'], '.', $var);
}
return (double)$var;
}
function gpc_get_bool(&$GPC, $varname, $default = FALSE) {
if (!isset($GPC[$varname])) {
return $default;
}
$gpcvar = trim($GPC[$varname]);
if (strcasecmp('off', $gpcvar) == 0 ||
strcasecmp('no', $gpcvar) == 0 ||
strcasecmp('false', $gpcvar) == 0 ||
strcasecmp('no', $gpcvar) == 0 ||
strcasecmp('0', $gpcvar) == 0 ||
strcasecmp('nein', $gpcvar) == 0)
{
return FALSE;
}
return TRUE;
}
function gpc_get_date(&$GPC, $varname, $default = NULL) {
if (!isset($GPC[$varname]) || $GPC[$varname] == '') {
return $default;
}
return $GPC[$varname];
}
function gpc_get_color(&$GPC, $varname, $default = NULL) {
if (!isset($GPC[$varname]) or (strlen(trim($GPC[$varname])) == 0)) {
return $default;
}
$color = $GPC[$varname];
if ((strlen($color) == 7) and (substr($color, 0, 1) == '#')) {
$color = substr($color, 1);
}
if ((strlen($color) != 6) or (! ctype_xdigit($color))) {
return $default;
}
return strtoupper($color);
}
function format_float($val, $decimals = 2, $suffix = '') {
global $g_lconv;
if (!isset($val) || $val == '') {
return '';
}
return number_format($val, $decimals, $g_lconv['decimal_point'], $g_lconv['thousands_sep']) . ($suffix ? "&thinsp;$suffix" : '');
}
function format_currency($val) {
global $g_lconv;
if (!isset($val) || $val == '') {
return '';
}
if ($g_lconv['currency_symbol'] == '$') {
return '$'.number_format($val, 2, $g_lconv['decimal_point'], $g_lconv['thousands_sep']);
} else {
return number_format($val, 2, $g_lconv['decimal_point'], $g_lconv['thousands_sep']) . ' ' . $g_lconv['currency_symbol'];
}
}
function format_filesize($size, $format=2) {
switch ($format) {
case 1: // short
if ($size < 1024) {
$size_string = sprintf(_('%d&tinysp;B'), $size);
} elseif ($size < 1048576) {
$size_string = sprintf(_('%.1f&tinysp;kB'), $size/1024);
} else {
$size_string = sprintf(_('%.1f&tinysp;MB'), $size/1048576);
}
break;
case 2: // medium
if ($size < 1024) {
$size_string = sprintf(_('%d&tinysp;Byte'), $size);
} elseif ($size < 1048576) {
$size_string = sprintf(_('%.1f&tinysp;kByte'), $size/1024);
} else {
$size_string = sprintf(_('%.1f&tinysp;MByte'), $size/1048576);
}
break;
case 3: // long
if ($size < 1024) {
$size_string = sprintf(_('%d Byte'), $size);
} elseif ($size < 1048576) {
$size_string = sprintf(_('approx. %.1f kByte'), $size/1024);
} else {
$size_string = sprintf(_('approx. %.1f MByte'), $size/1048576);
}
break;
default:
$size_string = trim($size);
}
return $size_string;
}
// ========== MENU FUNCTIONS ==================================================
$g_menu = Array (
'equipment.php' => [_('Equipment')],
'inventory.php' => [_('Inventory')],
'provisions.php' => [_('Provisions')],
'maintenance.php' => [_('Maintenance')],
'projects.php' => [_('Projects')],
'documents.php' => [_('Documents')],
'manual.php' => ['<i class="bi-book"></i>'],
'logout.php' => ['<i class="bi-door-open"></i>']
);
+44
View File
@@ -0,0 +1,44 @@
<!DOCTYPE html>
<html lang="<?=$g_lang?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title><?=APP_TITLE_SHORT?> - <?=$pagetitle?></title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap/bootstrap-icons.min.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.bundle.min.js"></script>
<link rel="stylesheet" href="default.css">
</head>
<body>
<div class="container-xxl">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="index.php"><?php echo $user->vessel ?? _('Ghost'); ?></a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav">
<?php
foreach ($g_menu as $key => $value) {
echo str_repeat(' ', 4);
echo '<li class="nav-item">';
$active = ($g_scriptname == $key) ? ' active' : '';
echo '<a class="nav-link', $active,'" href="', $key, '">', $value[0], "</a>";
echo "</li>\n";
}
?>
</ul>
</div>
</div>
</nav>
<?php
// ========== SYSTEM FEEDBACK =================================================
$g_error->PrintOut();
$g_warning->PrintOut();
$g_message->PrintOut();
$g_success->PrintOut();
+392
View File
@@ -0,0 +1,392 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Start');
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_DEFAULT; break;
case 'edit': $action = ACT_EDIT; break;
case 'select':
$vid = gpc_get_int($_POST, 'vid', 1);
$sql = "UPDATE settings SET valint=? WHERE userid=? AND sno=1";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$vid, $user->id]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$g_message->Add(sprintf(_('Selected vessel %d'), $vid));
$user->load_vessel();
break;
case 'insert':
$action = ACT_DEFAULT;
if ($user->role != 'captain') {
$g_error->Add(_('Access denied. You are not the captain.'));
break;
}
$p[':vesselname'] = gpc_get_string($_POST, 'vesselname');
$p[':model'] = gpc_get_string($_POST, 'model');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO vessel ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->LastInsertId();
// autoselect newly created vessel
$sql = "UPDATE settings SET valint=? WHERE userid=? AND sno=1";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$id, $user->id]);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$g_message->Add(sprintf(_('Selected new vessel %d'), $vid));
$user->load_vessel();
break;
case 'update':
if ($user->role != 'captain') {
$g_error->Add(_('Access denied. You are not the captain.'));
break;
}
// $p[':vtype'] = gpc_get_string($_POST, 'vtype');
$p[':vesselname'] = gpc_get_string($_POST, 'vesselname');
$p[':model'] = gpc_get_string($_POST, 'model');
$p[':loa'] = gpc_get_float($_POST, 'loa');
$p[':lwl'] = gpc_get_float($_POST, 'lwl');
$p[':beam'] = gpc_get_float($_POST, 'beam');
$p[':draught'] = gpc_get_float($_POST, 'draught');
$p[':draught_min'] = gpc_get_float($_POST, 'draught_min');
$p[':displacement'] = gpc_get_int($_POST, 'displacement');
$p[':ballast'] = gpc_get_int($_POST, 'ballast');
$p[':remarks'] = gpc_get_string($_POST, 'remarks', 150);
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE vessel SET $fields WHERE vid=:vid");
$p[':vid'] = gpc_get_int($_POST, 'id');
try {
$sth->execute($p);
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(_('Unknown function!'));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo '<h1>', _('Yacht data'), "</h1>\n";
echo '<p>', _('User'), ': ', $user->displayname, ' (', $user->role, ')', "</p>\n";
// Fetch current selected vessel number
$sql = "SELECT valint FROM settings WHERE userid=? AND sno=1";
$sth = $pdo->prepare($sql);
$sth->execute([$user->id]);
$res = $sth->fetch(PDO::FETCH_NUM);
$vid = ($res[0]);
// Switch between vessels
$sth = $pdo->query("SELECT vid, vesselname, model FROM vessel ORDER BY vid");
$res = $sth->fetchAll();
echo '<form class="row" method="post">', "\n";
echo '<div class="col-1">', "\n";
echo '<label class="form-label" for="vid">Yacht:</label>';
echo "</div>\n";
echo '<div class="col-4">', "\n";
echo '<select class="form-select" name="vid" id="vid">', "\n";
foreach ($res as $row) {
echo '<option value="', $row['vid'], '"', ($row['vid'] == $vid ? ' selected>' : '>');
echo $row['vesselname'], ' - ', $row['model'];
echo "</option>\n";
}
echo "</select>\n";
echo "</div>\n";
echo '<div class="col">', "\n";
echo '<button type="submit" class="btn btn-secondary" name="submit[select]">', _('Select'), '</button>', "\n";
echo '<button type="submit" class="btn btn-secondary" name="submit[add]">', _('Add yacht'), '</button>', "\n";
echo "</div>\n";
echo "</form>\n";
// Get current vessel data
$sql = "SELECT vesselname, model, loa, lwl, beam, draught, draught_min,"
. " displacement, ballast, remarks "
. "FROM vessel "
. "WHERE vid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$vid]);
$vessel = $sth->fetch();
?>
<?php /* <svg viewbox="0 0 1024 768">
<circle cx="50" cy="50" r="40" stroke="green" stroke-width="4" fill="yellow" />
<rect x="0" y="0" width="1024" height="768" stroke="black" fill="none" />
<text x="0" y="20" font-size="12" fill="#ccc" text-anchor="start">Elizabethan 29</text>
<line x1="0" y1="0" x2="100" y2="100" />
</svg> */ ?>
<br>
<svg
width="680.8349"
height="205.42085"
viewBox="0 0 180.13756 54.350934"
version="1.1"
id="svg5"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs2" />
<g
id="layer1"
transform="translate(-18.454117,-34.670903)">
<path
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.264583px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 18.719809,61.846371 18.587517,51.734929 c 0,0 14.698452,-6.829606 22.491781,-8.894215 18.280597,-4.842895 36.646466,-7.606499 56.167649,-7.993756 29.649633,-0.588182 48.780143,4.813228 71.891193,12.372959 10.39946,3.401709 29.38622,14.626454 29.38622,14.626454"
id="path245" />
<use
x="0"
y="0"
xlink:href="#path245"
id="use461"
transform="matrix(1,0,0,-1,-4.9118388e-8,123.69274)" />
</g>
</svg>
<div class="container-fluid">
<div class="row my-4">
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title"><?=_('Boat data') ?></h5>
<table class="table table-sm">
<tr><td><?=_('Loa')?></td><td><?=format_float($vessel['loa'], 2, 'm')?></td></tr>
<tr><td><?=_('Lwl')?></td><td><?=format_float($vessel['lwl'], 2, 'm')?></td></tr>
<tr><td><?=_('Beam')?></td><td><?=format_float($vessel['beam'], 2, 'm')?></td></tr>
<tr><td><?=_('Draught')?></td><td><?=format_float($vessel['draught'], 2, 'm')?></td></tr>
<tr><td><?=_('Draught, min.')?></td><td><?=format_float($vessel['draught_min'], 2, 'm')?></td></tr>
<tr><td><?=_('Displacement')?></td><td><?=$vessel['displacement']?>&thinsp;kg</td></tr>
<tr><td><?=_('Ballast')?></td><td><?=$vessel['ballast']?>&thinsp;kg</td></tr>
</table>
<?php
// Edit vessel only for captain
if ($user->role == 'captain') {
echo '<a href="', $script, '?f=edit&id=', $user->vid, '" class="btn btn-primary" role="button">', _('Edit'), "</a>\n";
}
?>
</div>
</div><?php /* card */ ?>
</div>
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title"><?=_('Statistics') ?></h5>
<?php
// Statistics
// Storage: 0 - default, 1 - tank
$stype = [ 0 => _('Default'), 1 => _('Tank')];
$sql = "SELECT stype, COUNT(stype) "
. "FROM storage "
. "WHERE vid=? "
. "GROUP BY stype "
. "ORDER BY stype";
$sth = $pdo->prepare($sql);
$sth->execute([$vid]);
$res = $sth->fetchAll(PDO::FETCH_NUM);
echo '<table class="table table-sm">', "\n";
echo '<tr><td colspan="2">', _('Storage type') , "</td>";
foreach ($res as $row) {
echo "<tr><td>", $stype[$row[0]], "</td><td>", $row[1], "</td></tr>\n";
}
// Boxes
$sth = $pdo->prepare("SELECT COUNT(*) FROM box INNER JOIN storage USING (sid) WHERE vid=?");
$sth->execute([$user->vid]);
echo '<tr><td>', _('Boxes'), '</td><td>', $sth->fetchColumn(), "</td></tr>\n";
// Equipment
$sth = $pdo->prepare("SELECT COUNT(*) FROM equipment WHERE vid=?");
$sth->execute([$user->vid]);
echo '<tr><td colspan="2">', _('Equipment') , "</td>";
echo '<tr><td>', _('Count'), '</td><td>', $sth->fetchColumn(), "</td></tr>\n";
// Inventory
// All items from vessel storage and all items from boxes in vessel storage
$sql = "SELECT SUM(n) FROM ("
. "SELECT COUNT(*) AS n FROM inventory JOIN storage USING (sid) WHERE boxtype='storage' AND vid=:vid "
. "UNION "
. "SELECT COUNT(*) AS n FROM inventory JOIN box USING (boxid) JOIN storage ON (box.sid=storage.sid) WHERE boxtype='box' AND vid=:vid"
. ") AS x";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->execute();
// Tasks
echo '<tr><td colspan="2">', _('Inventory') , "</td>";
echo '<tr><td>', _('Count'), '</td><td>', $sth->fetchColumn(), "</td></tr>\n";
echo "</table>\n";
?>
</div>
</div><?php /* card */ ?>
</div>
<div class="col">
<div class="card">
<div class="card-body">
<h5 class="card-title"><?=_('Base data')?></h5>
<ul class="list-group list-group-flush">
<li class="list-group-item"><a href="dropdown.php"><?=_('Selection lists')?></a></li>
<li class="list-group-item"><a href="storage.php"><?=_('Storage')?></a></li>
<li class="list-group-item"><a href="company.php"><?=_('Companies')?></a></li>
</ul>
<hr>
<h5 class="card-title"><?=_('Additional modules')?></h5>
<ul class="list-group list-group-flush">
<li class="list-group-item"><a href="measurement.php"><?=_('Measurements')?></a></li>
<li class="list-group-item"><a href="checklist.php"><?=_('Checklists')?></a></li>
<li class="list-group-item"><a href="search.php"><?=_('Search')?></a></li>
</ul>
</div>
</div>
</div><?php /* col */ ?>
</div><?php /* row */ ?>
</div>
<?php
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add additional yacht'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="vesselname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="vesselname" name="vesselname" required autofocus>
</div>
<div class="mb-3">
<label for="model" class="form-label"><?=_('Model')?></label>
<input type="text" class="form-control" id="model" name="model">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$project->remarks ?></textarea>
</div>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT vesselname, vtype, model, loa, lwl, beam, draught, draught_min,"
. " displacement, ballast, remarks "
. "FROM vessel "
. "WHERE vid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$vessel = $sth->fetch(PDO::FETCH_OBJ);
?>
<h2><?=_('Edit Yacht')?></h2>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$user->vid?>">
<div class="mb-3">
<label for="vesselname" class="form-label"><?=_('Vesselname')?></label>
<input type="text" class="form-control" id="vesselname" name="vesselname" value="<?=$vessel->vesselname ?>">
</div>
<div class="mb-3">
<label for="model" class="form-label"><?=_('Model')?></label>
<input type="text" class="form-control" id="model" name="model" value="<?=$vessel->model ?>">
</div>
<div class="mb-3">
<label for="loa" class="form-label"><?=_('LoA')?></label>
<input type="text" class="form-control" id="loa" name="loa" value="<?=format_float($vessel->loa, 2) ?>">
</div>
<div class="mb-3">
<label for="lwl" class="form-label"><?=_('LwL')?></label>
<input type="text" class="form-control" id="lwl" name="lwl" value="<?=format_float($vessel->lwl, 2) ?>">
</div>
<div class="mb-3">
<label for="beam" class="form-label"><?=_('Beam')?></label>
<input type="text" class="form-control" id="beam" name="beam" value="<?=format_float($vessel->beam, 2) ?>">
</div>
<div class="mb-3">
<label for="draught" class="form-label"><?=_('Draught')?></label>
<input type="text" class="form-control" id="draught" name="draught" value="<?=format_float($vessel->draught, 2) ?>">
</div>
<div class="mb-3">
<label for="draught_min" class="form-label"><?=_('Draught, min.')?></label>
<input type="text" class="form-control" id="draught_min" name="draught_min" value="<?=format_float($vessel->draught_min, 2) ?>">
</div>
<div class="mb-3">
<label for="displacement" class="form-label"><?=_('Displacement')?></label>
<input type="number" input-mode="decimal" min="0" max="100000" step="1" class="form-control" id="displacement" name="displacement" value="<?=$vessel->displacement ?>">
</div>
<div class="mb-3">
<label for="ballast" class="form-label"><?=_('Ballast')?></label>
<input type="number" input-mode="decimal" min="0" max="100000" step="1" class="form-control" id="ballast" name="ballast" value="<?=$vessel->ballast ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$vessel->remarks ?></textarea>
</div>
<?php
form_edit_buttons($g_scriptname, $user->vid);
echo "</form>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+353
View File
@@ -0,0 +1,353 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle=_('Inventory');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_storage = db_get_opt_storage($user->vid);
$opt_box = db_get_opt_box($user->vid);
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$invname = gpc_get_string($_POST, 'invname');
$number = gpc_get_int($_POST, 'number');
$boxtype = gpc_get_string($_POST, 'boxtype');
$sid = gpc_get_int($_POST, 'sid');
$boxid = gpc_get_int($_POST, 'boxid');
$sql = "INSERT INTO inventory "
. " (invname, invcond, number, boxtype, sid, boxid) "
. "VALUES "
. " (:invname, 'good', :number, :boxtype, :sid, :boxid)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':invname', $invname, PDO::PARAM_STR);
$sth->bindValue(':number', $number, PDO::PARAM_INT);
$sth->bindValue(':boxtype', $boxtype, PDO::PARAM_STR);
$sth->bindValue(':sid', $sid, PDO::PARAM_INT);
$sth->bindValue(':boxid', $boxid, PDO::PARAM_INT);
try {
$sth->execute();
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->LastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$invname = gpc_get_string($_POST, 'invname');
$number = gpc_get_int($_POST, 'number');
$boxtype = gpc_get_string($_POST, 'boxtype');
$sid = gpc_get_int($_POST, 'sid');
$boxid = gpc_get_int($_POST, 'boxid');
$weight = min(gpc_get_float($_POST, 'weight'), 999.99); // limit max value
$price = gpc_get_currency($_POST, 'price');
$purchdate = gpc_get_date($_POST, 'purchdate');
$invcond = gpc_get_string($_POST, 'invcond');
$sql = "UPDATE inventory "
. "SET invname=:invname,"
. " number=:number,"
. " boxtype=:boxtype,"
. " sid=:sid,"
. " boxid=:boxid,"
. " weight=:weight,"
. " price=:price,"
. " purchdate=:purchdate,"
. " invcond=:invcond "
. "WHERE invid=:invid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':invid', $id, PDO::PARAM_INT);
$sth->bindValue(':invname', $invname, PDO::PARAM_STR);
$sth->bindValue(':number', $number, PDO::PARAM_INT);
$sth->bindValue(':boxtype', $boxtype, PDO::PARAM_STR);
$sth->bindValue(':sid', $sid, PDO::PARAM_INT);
$sth->bindValue(':boxid', $boxid, PDO::PARAM_INT);
$sth->bindValue(':weight', $weight);
$sth->bindValue(':price', $price);
$sth->bindValue(':purchdate', $purchdate);
$sth->bindValue(':invcond', $invcond, PDO::PARAM_STR);
try {
$sth->execute();
} catch (PDOException $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
unset($_SESSION['token']);
$sth = $pdo->prepare("DELETE FROM inventory WHERE invid=?");
$sth->execute([$id]);
$g_message->Add(sprintf(_('Deleted inventory no. %d'), $id));
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
/*
The only way to find out whether the inventory is on the current boat is to use
the box assignment. But this is also intentional to allow easy rearrangement.
*/
echo "<h1>$pagetitle</h1>\n";
$sql = "SELECT i.invid, i.invname, i.number, i.invcond, s.sname AS container "
. "FROM inventory AS i JOIN storage AS s ON (i.boxtype='storage' AND i.sid=s.sid)"
. "WHERE s.vid=:vid "
. "UNION "
. "SELECT i.invid, i.invname, i.number, i.invcond, b.label AS container "
. "FROM inventory AS i JOIN box AS b ON (i.boxtype='box' AND i.boxid=b.boxid) "
. " JOIN storage AS s ON (b.sid=s.sid) "
. "WHERE s.vid=:vid "
. "ORDER BY invname";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->execute();
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>\n";
echo "<th>" . _('Name') . "</th>\n";
echo "<th>" . _('Container') . "</th>";
echo "<th>" . _('Number') . "</th>";
echo "<th>" . _('Condition') . "</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo '<td>', $row['invname'], "</td>\n";
echo "<td>". $row['container'] ."</td>\n";
echo "<td>". $row['number'] ."</td>\n";
echo "<td>". $row['invcond'] ."</td>\n";
form_action_buttons($g_scriptname, $row['invid']);
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Inventory'), "</h2>\n";
?>
<form method="post" action="<?=$g_scriptname?>">
<div class="mb-3">
<label for="invname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="invname" name="invname">
</div>
<div class="mb-3">
<label for="number" class="form-label"><?=_('Number')?></label>
<input type="number" class="form-control" id="number" name="number" value="1">
</div>
<div class="mb-3">
<label for="boxtype" class="form-label"><?=_('Boxtype')?></label>
<select class="form-select" name="boxtype" id="boxtype">
<option value="box"><?=_('Box')?></option>
<option value="storage"><?=_('Storage')?></option>
</select>
</div>
<?php
form_create_select('sid', _('Storage'), $opt_storage);
form_create_select('boxid', _('Box'), $opt_box);
?>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT invname, boxtype, sid, boxid, number, weight, price, purchdate, invcond "
. "FROM inventory "
. "WHERE invid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$inventory = $sth->fetch(PDO::FETCH_OBJ);
// boxtype can be storage or box
switch ($inventory->boxtype) {
case 'storage':
$sql = "SELECT sname, vid FROM storage WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$inventory->sid]);
$row = $sth->fetch();
$storagename = $row['sname'];
$vid = $row['vid'];
break;
case 'box':
// Future: Boxes can also be nested!
// Recursive Function "get_storage_for_box()"
$sql = "SELECT sid, label FROM box WHERE boxid=?";
// TODO Load additional box data
$sth = $pdo->prepare($sql);
$sth->execute([$inventory->boxid]);
$box = $sth->fetch();
$sql = "SELECT sname, vid FROM storage WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$box['sid']]);
$row = $sth->fetch();
$storagename = $row['sname'];
$vid = $row['vid'];
break;
}
echo '<h2>', $inventory->invname, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Box type'),"</th><td>", $inventory->boxtype, "</td></tr>\n";
// Container with link
echo "<tr><th>", _('Container'),"</th><td>", sprintf(_('%s in %s'), $box['label'], $storagename);
echo "</td></tr>\n";
echo "<tr><th>", _('Location ID'), "</th><td>", $inventory->locationid, "</td></tr>\n";
echo "<tr><th>", _('Number'), "</th><td>", $inventory->number, "</td></tr>\n";
echo "<tr><th>", _('Weight'), "</th><td>", format_float($inventory->weight, 2, 'kg'), "</td></tr>\n";
echo "<tr><th>", _('Price'), "</th><td>", format_currency($inventory->price), "</td></tr>\n";
echo "<tr><th>", _('Purchase date'), "</th><td>", $inventory->purchdate, "</td></tr>\n";
echo "<tr><th>", _('Condition'), "</th><td>", $inventory->invcond, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT invname, boxtype, sid, boxid, number, weight, price, purchdate, invcond "
. "FROM inventory "
. "WHERE invid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$inventory = $sth->fetch(PDO::FETCH_OBJ);
?>
<h2><?=_('Edit Inventory')?></h2>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="invname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="invname" name="invname" value="<?=$inventory->invname ?>">
</div>
<div class="mb-3">
<label for="number" class="form-label"><?=_('Number')?></label>
<input type="number" class="form-control" id="number" name="number" value="<?=$inventory->number ?>">
</div>
<div class="mb-3">
<label for="weight" class="form-label"><?=_('Weight, kg')?></label>
<input type="text" class="form-control" id="weight" name="weight" value="<?=format_float($inventory->weight); ?>">
</div>
<div class="mb-3">
<label for="boxtype" class="form-label"><?=_('Boxtype')?></label>
<select class="form-select" name="boxtype" id="boxtype">
<option value="box"><?=_('Box')?></option>
<option value="storage"><?=_('Storage')?></option>
</select>
</div>
<?php
form_create_select('sid', _('Storage'), $opt_storage);
form_create_select('boxid', _('Box'), $opt_box);
?>
<div class="mb-3">
<label for="price" class="form-label"><?=sprintf(_('Price, %s'), $g_lconv['currency_symbol']); ?></label>
<input type="text" class="form-control" id="price" name="price" value="<?=format_float($inventory->price) ?>">
</div>
<div class="mb-3">
<label for="purchdate"><?=_('Purchase date')?></label>
<input type="date" class="form-control" id="purchdate" name="purchdate" value="<?=$inventory->purchdate ?>">
</div>
<div class="mb-3">
<label for="invcond" class="form-label"><?=_('Condition')?></label>
<select name="invcond" id="invcond" class="form-control">
<?php
$cond = array(
'good' => _('Good'),
'normal' => _('Normal'),
'bad' => _('Bad'),
'repairable' => _('Repairable'),
'defect' => _('Defect'),
'unknown' => _('Unknown')
);
foreach ($cond as $k => $v) {
echo '<option value="', $k, '"';
if ($k == $inventory->invcond) {
echo ' selected';
}
echo '>', $v. "</option>\n";
}
?>
</select>
</div>
<?php
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
$sql = "SELECT invname FROM inventory WHERE invid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$inventory = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Delete Inventory'), "</h2>\n";
echo '<p>', sprintf(_('Record no. %d'), $id), "</p>\n";
echo '<p>Name: ', $inventory->invname, "</p>";
echo '<p>', _('Deleting an inventory item is final. There is no way back. Only delete if you are absolute sure.'), "</p>\n";
$_SESSION['token'] = bin2hex(random_bytes(8));
form_delete_buttons($g_scriptname, $id, $_SESSION['token']);
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
Binary file not shown.
File diff suppressed because it is too large Load Diff
+80
View File
@@ -0,0 +1,80 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
// TODO Code to handle page call with already logged on user
require 'globals.inc';
session_name(APP_SESSION);
session_start();
if (isset($_POST['login'])) {
$username = substr($_POST['username'], 0, 20);
$password = substr($_POST['password'], 0, 32);
if (!$user->login($username, $password)) {
$err = $user->get_last_error();
}
} else {
$username = '';
}
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title><?=APP_TITLE_SHORT?> - Login</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="bootstrap/bootstrap-icons.min.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<section class="mx-auto my-5" style="max-width:32rem;">
<div class="card card-form mt-2 mb-4">
<div class="card-header">
<?=APP_TITLE?>
</div>
<div class="row my-3">
<div class="col">
<img src="sailboat.svg" class="img-fluid rounded-start" alt="sailboat">
</div>
<div class="col">
<div class="card-body">
<h5 class="card-title"><?=sprintf(_('Login to %s'), APP_TITLE_SHORT)?></h5>
<form id="login" action="login.php" method="post">
<div class="mb-3 mt-3">
<label for="username" class="form-label"><?=_('Username:')?></label>
<input type="text" class="form-control" required autofocus size="20" maxlength="20" name="username" id="username" value="<?=$username?>">
</div>
<div class="mb-3 mt-3">
<label for="password" class="form-label"><?=_('Password:')?></label>
<input type="password" class="form-control" required size="20" maxlength="32" name="password" id="password">
</div>
<?php
if (isset($err)) {
echo '<div class="alert alert-danger alert-dismissible fade show role="alert"">';
echo '<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>';
echo '<b>', _('Error'), ':</b> ', $err;
echo "</div>\n";
}
?>
<button type="submit" class="btn btn-primary" title="<?php printf(_('Logon to %s'), APP_TITLE_SHORT); ?>" name="login" value="1">
<span class="bi bi-caret-right"></span>
<?=_('Login')?>
</button>
</form>
</div> <!-- card body -->
</div>
</div>
</div>
</section>
</div>
</body>
</html>
+39
View File
@@ -0,0 +1,39 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$user->logout();
?>
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex,nofollow">
<title><?=APP_TITLE_SHORT?> - Login</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
<script src="bootstrap/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<section class="mx-auto my-5" style="max-width:23rem;">
<div class="card">
<div class="card-header">
<?=_('Logout')?>
</div>
<div class="card-body">
<h5 class="card-title"><?=sprintf(_('<b>%s</b> is now logged out'), $user->displayname)?></h5>
<p class="card-text"><?=sprintf(_('Thank you for using %s.'), APP_TITLE_SHORT)?></p>
<p class="card-text"><?=sprintf(_('Always feel free to send improvements, suggestions, error messages or anything else to %s.'), $g_mailto_webmaster)?></p>
<a class="btn btn-primary" href="login.php"><?=_('New login')?></a>
</div>
</div>
</section>
</div>
</body>
</html>
+257
View File
@@ -0,0 +1,257 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Maintenance');
$id = gpc_get_int($_REQUEST, 'id', 0);
// Equipment options
$opt_equipment = array( 0 => _('*** unassigned ***'));
$sql = "SELECT eid, ename FROM equipment WHERE vid=? ORDER BY ename";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
foreach ($sth->fetchAll() as $row) {
$opt_equipment[$row['eid']] = $row['ename'];
}
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$eid = gpc_get_int($_POST, 'eid');
$activities = gpc_get_string($_POST, 'activities', 80);
$sql = "INSERT INTO maintenance "
. " (vid, eid, activities) "
. "VALUES "
. " (:vid, :eid, :activities)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->bindValue(':eid', $eid, PDO::PARAM_INT);
$sth->bindValue(':activities', $activities, PDO::PARAM_STR);
$sth->execute();
$id = $pdo->LastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$eid = gpc_get_int($_POST, 'eid');
$activities = gpc_get_string($_POST, 'activities', 80);
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE maintenance "
. "SET activities=:activities,"
. " eid=:eid,"
. " remarks=:remarks "
. "WHERE maintid=:maintid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':maintid', $id, PDO::PARAM_INT);
$sth->bindValue(':eid', $eid, PDO::PARAM_INT);
$sth->bindValue(':activities', $activities, PDO::PARAM_STR);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
$sth->execute();
$action = ACT_VIEW;
break;
default:
$g_error->Add(sprintf(_("Unknown function '%s'!"), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo '<h1>', $pagetitle, "</h1>\n";
$sql = "SELECT m.maintid, m.activities, m.remarks, e.ename "
. "FROM maintenance AS m LEFT OUTER JOIN equipment AS e USING (eid)"
. "WHERE m.vid=? "
. "ORDER BY m.maintid";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Activities') . "</th>";
echo "<th>" . _('Equipment') . "</th>";
echo "<th>" . _('Remarks') . "</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['activities'] ."</td>\n";
echo "<td>". $row['ename'] ."</td>\n";
echo "<td>". $row['remarks'] ."</td>\n";
// Action buttons
echo "<td>";
echo '<a title="', _('View'), '" href="', $g_scriptname, '?f=view&id=', $row['maintid'], '"><i class="bi-eye"></i></a>', "\n";
echo '<a title="', _('Edit'), '" href="', $g_scriptname, '?f=edit&id=', $row['maintid'], '"><i class="bi-pencil"></i></a>', "\n";
echo "</td>\n";
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Maintenance'), "</h2>\n";
?>
<form method="post" action="<?=$g_scriptname?>">
<div class="mb-3">
<label for="activities" class="form-label"><?=_('Activities')?></label>
<input type="text" class="form-control" id="activities" name="activities">
</div>
<?php
// TODO
// Add link to equipment, perhaps later with modal dialog?
?>
<div class="mb-3">
<label for="eid" class="form-label"><?=_('Equipment')?></label>
<select name="eid" id="eid" class="form-control">
<?php
foreach ($opt_equipment as $k => $v) {
echo '<option value="', $k, '">', $v, "</option>\n";
}
?>
</select>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
echo '<h2>', _('View Maintenance'), "</h2>\n";
$sql = "SELECT m.activities, m.eid, m.remarks, e.ename "
. "FROM maintenance AS m LEFT OUTER JOIN equipment AS e USING (eid) "
. "WHERE m.maintid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$maint = $sth->fetch(PDO::FETCH_OBJ);
if (isset($maint->eid)) {
$sql = "SELECT r.docid, d.filename, d.title, d.hash, d.extension "
. "FROM docref AS r INNER JOIN document AS d USING (docid) "
. "WHERE r.reftype='equipment' AND r.refid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$maint->eid]);
$docs = $sth->fetchAll();
} else {
$maint->ename = _('n/a');
}
// Bootstrap grid
echo '<div class="container">';
echo '<div class="row">';
echo '<div class="col">';
echo '<table class="table">', "\n";
echo '<tr><th>', _('Activities'),"</th><td>", $maint->activities, "</td></tr>\n";
echo '<tr><th>', _('Equipment'),"</th><td>", $maint->ename, "</td></tr>\n";
echo '<tr><th>', _('Remarks'),"</th><td>", $maint->remarks, "</td></tr>\n";
echo "</table>\n";
echo '</div>'; // Column break
echo '<div class="col">';
// TODO Show documents for equipment
?>
<p>Documents</p>
<?php
echo '<ul>', "\n";
foreach ($docs as $d) {
echo '<li>', $d['title'] ?? $d['filename'], ' (', $d['docid'], ")</li>\n";
}
echo "</ul>\n";
echo '</div>'; // col
echo '</div>'; // row
echo '</div>'; // container
form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT activities, eid, remarks "
. "FROM maintenance "
. "WHERE maintid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$maint = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Edit Maintenance'), "</h2>\n";
?>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="activities" class="form-label"><?=_('Activities')?></label>
<input type="text" class="form-control" id="activities" name="activities" value="<?=$maint->activities ?>">
</div>
<div class="mb-3">
<label for="eid" class="form-label"><?=_('Equipment')?></label>
<select name="eid" id="eid" class="form-control">
<?php
foreach ($opt_equipment as $k => $v) {
echo '<option value="', $k;
if ($maint->eid == $k) {
echo ' selected';
}
echo '">', $v, "</option>\n";
}
?>
</select>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$maint->remarks ?></textarea>
</div>
<?php
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
echo '<h2>', _('Delete Maintenance'), "</h2>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+106
View File
@@ -0,0 +1,106 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle=_('Manual');
require 'header.php';
?>
<h1>Yacht Management System</h1>
<h2>Integriertes Handbuch</h2>
<p>Es können mehrere Yachten mit dem Programm verwaltet werden.
Die Umschaltung erfolgt über eine Auswahlliste auf der Übersichtsseite.</p>
<p>Die Yachtdaten können nur mit de Berechtigungsebene <em>captain</em>
verändert werden.</p>
<p>Bei Neuanlage eines Datensatzes werden nur die wichtigsten Felder
angezeigt. Weitere Felder können im Anschluß über die Bearbeiten-Funktion
ausgefüllt werden.</p>
<h3>Stauraum</h3>
<p>Der Stauraum teilt sich in verschiedene Bereiche auf.
Diese sind über eine fixe Position an Bord einstellbar.</p>
<p>Zusätzlich zum festen Stauraum können auch Kisten definiert werden.
Eine Kiste kann in einen Stauraum gelegt werden. Da sie beweglich ist,
kann sie auch als Ganzes auf eine andere Yacht übergeben werden.</p>
<p>Es existiert ein Koordinatensystem. Die Einheit ist Millimeter (mm).
Der Ursprung ist achtern Mittschiffs. Die X-Achse verläuft in Längsrichtung
der Yacht. Die Y-Achse verläuft zur Querrichtung, Koorinaten auf der Backbordseite
sind negativ, auf der Steuerbordseite positiv.
Die Z-Achse geht in Richtung Mastspitze. Der Nullpunkt liegt auf Höhe der
Wasserlinie.</p>
<h3>Ausrüstung</h3>
<p>Ausrüstung ist zumeist fest mit der Yacht verbunden, jeder Ausrüstungsgegenstand
existiert nur ein mal und kann eine Seriennummer besitzen.</p>
<p>Ausrüstung kann gewartet werden.</p>
<h3>Inventar</h3>
<p>Unter Inventar sind bewegliche Dinge zusammengefaßt.
Ein Inventargegenstand kann auch mehrfach vorkommen.
Beispiel: <em>Winschkurbel, Anzahl: 3</em></p>
<p>Inventar kann in einem Stauraum abgelegt werden oder aber in einer
Kiste.</p>
<h3>Proviant</h3>
<p>Proviant ist verderblich.
Es wird das Einlagerungsdatum erfaßt und das Haltbarkeitsdatum</p>
<h3>Wartung</h3>
<p>Es können einmalige und wiederkehrende Wartungen erfaßt werden</p>
<p>Eine wiederkehrende Wartung kann aufgrund Zeit, z.B. 1x jährlich,
oder nach Betriebsstunden definiert werden.</p>
<h3>Projekte</h3>
<p>Einem Projekt werden Aufgaben zugeordnet, es hat einen Status wie
z.B. <em>neu</em>, <em>laufend</em> oder <em>erledigt</em>.</p>
<h3>Firmen</h3>
<p>Es können verschiedene Arten von Firmen hinterlegt werden, wie
beispielsweise Hersteller, Lieferanten oder Dienstleister.</p>
<h3>Dokumente</h3>
<p>Ein Dokument kann mehrfach zugeordnet werden. Z.B. einem
Ausrüstungsgegenstand und gleichzeitig einem Projekt oder einer Aufgabe.</p>
<p>Es stehen verschiedene Dokumentarten zur Verfügung:</p>
<ul>
<li>Fotos bzw. Bilder als png- oder jpg-Dateien</li>
<li>Zeichnungen als svg-Dateien</li>
<li>Dokumente als pdf-Dateien</li>
</ul>
<h3>Checklisten</h3>
<p>Es ist eine Historie vorgesehen.</p>
<h3>Ersatzteile</h3>
<p>Die Verwaltung von Ersatzteilen erfolgt normalerweise über das Inventar.</p>
<h3>Maße / Messungen</h3>
<p>Messungen können hier dokumentiert werden. Eine Zuordnung zur Ausrüstung
ist vorgesehen.</p>
<p>In einer Messung können ein bis drei Werte gespeichert werden. Damit
ist es möglich Flächen <span style="white-space:nowrap">(L x B)</span> oder
Volumen <span style="white-space:nowrap">(L x B x H)</span> zusammenhängend
zu erfassen.</p>
<h3>Benutzer</h3>
<p>Benutzer können nicht über die Web-GUI eingerichtet werden.</p>
<p>Es gibt die Berechtigungsebenen <em>Kapitän (captain)</em>,
<em>Steuermann (helmsman)</em> und <em>Matrose (sailor)</em>.
<h3>Stammdaten</h3>
<p>Diese Daten ändern sich nicht sehr häufig, sind aber für den Betrieb
essentiell. Stanndaten sind beispielsweise Firmen, Auswahllisten oder
auch der Stauraum.</p>
<?php
include 'footer.php';
+284
View File
@@ -0,0 +1,284 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Measurements');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_unit = db_get_options(8);
$opt_accuracy = array(
'unknown' => _('Unknown'),
'precise' => _('Precise'),
'normal' => _('Normal'),
'rough' => _('Rough'),
'estimated' => _('Estimated')
);
$opt_dimensions = array(
1 => _('1D'),
2 => _('2D'),
3 => _('3D')
);
$opt_equipment = array(-1 => _('unassigned'));
$sth = $pdo->prepare("SELECT eid, ename FROM equipment WHERE vid=? ORDER BY ename");
$sth->execute([$user->vid]);
foreach ($sth->fetchAll() as $row) {
$opt_equipment[$row['eid']] = $row['ename'];
}
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$p[':mname'] = gpc_get_string($_POST, 'mname');
$p[':note'] = gpc_get_string($_POST, 'note');
$p[':nval'] = gpc_get_int($_POST, 'nval'); // 1 to 3 dimensions
$p[':val1'] = gpc_get_int($_POST, 'val1');
$p[':val2'] = NULL;
$p[':val3'] = NULL;
if ($p[':nval'] > 1) {
$p[':val2'] = gpc_get_int($_POST, 'val2');
}
if ($p[':nval'] > 2) {
$p[':val3'] = gpc_get_int($_POST, 'val3');
}
$p[':unit'] = gpc_get_int($_POST, 'unit');
$p[':accuracy'] = gpc_get_string($_POST, 'accuracy');
$p[':eid'] = gpc_get_int($_POST, 'eid');
if ($p[':eid'] == -1) {
$p[':eid'] = NULL;
}
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO measurement ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->LastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$p[':mname'] = gpc_get_string($_POST, 'mname');
$p[':nval'] = gpc_get_int($_POST, 'nval'); // 1 to 3 dimensions
$p[':val1'] = gpc_get_int($_POST, 'val1');
$p[':val2'] = NULL;
$p[':val3'] = NULL;
if ($p[':nval'] > 1) {
$p[':val2'] = gpc_get_int($_POST, 'val2');
}
if ($p[':nval'] > 2) {
$p[':val3'] = gpc_get_int($_POST, 'val3');
}
$p[':unit'] = gpc_get_int($_POST, 'unit');
$p[':accuracy'] = gpc_get_string($_POST, 'accuracy');
$p[':mdate'] = gpc_get_date($_POST, 'mdate');
$p[':note'] = gpc_get_string($_POST, 'note');
$p[':eid'] = gpc_get_int($_POST, 'eid');
if ($p[':eid'] == -1) {
$p[':eid'] = NULL;
}
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE measurement SET $fields WHERE mid=:mid");
$p[':mid'] = $id;
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
function format_vals($n, $v1, $v2, $v3) {
if ($n == 1) {
return $v1;
} elseif ($n == 2) {
return $v1 . 'x'. $v2;
} else {
return $v1 . 'x'. $v2 . 'x' . $v3;
}
}
echo "<h1>$pagetitle</h1>\n";
$sql = "SELECT mid, mname, nval, val1, val2, val3, unit, accuracy, mdate, note, eid "
. "FROM measurement "
. "ORDER BY mname";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>\n";
echo '<th>', _('Measurement'), "</th>";
echo '<th>', _('Note'), "</th>";
echo '<th class="text-end">', _('Measured'), "</th>";
echo '<th>', _('Unit'), "</th>";
echo '<th>', _('Accuracy'), "</th>";
echo "<th></th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>", $row['mname'], "</td>\n";
echo "<td>", $row['note'], "</td>\n";
echo '<td class="text-end">', format_vals($row['nval'], $row['val1'], $row['val2'], $row['val3']), "</td>\n";
echo "<td>", $opt_unit[$row['unit']], "</td>\n";
echo "<td>", $opt_accuracy[$row['accuracy']], "</td>\n";
echo "<td>";
// Action buttons
form_action_buttons($g_scriptname, $row['mid']);
echo "</td>\n";
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add measurement'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="mname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="mname" name="mname" required autofocus>
</div>
<div class="mb-3">
<label for="note" class="form-label"><?=_('Note')?></label>
<input type="text" class="form-control" id="note" name="note">
</div>
<?php
form_create_select('nval', _('Dimensions'), $opt_dimensions);
?>
<div class="mb-3">
<label for="val1" class="form-label"><?=_('Value 1')?></label>
<input type="text" class="form-control" id="val1" name="val1">
</div>
<div class="mb-3">
<label for="val2" class="form-label"><?=_('Value 2')?></label>
<input type="text" class="form-control" id="val1" name="val2">
</div>
<div class="mb-3">
<label for="val3" class="form-label"><?=_('Value 3')?></label>
<input type="text" class="form-control" id="val3" name="val3">
</div>
<?php
form_create_select('unit', _('Unit'), $opt_unit);
form_create_select('accuracy', _('Accuracy'), $opt_accuracy);
form_create_select('eid', _('Equipment'), $opt_equipment);
?>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT mname, nval, val1, val2, val3, unit, accuracy, note "
. "FROM measurement "
. "WHERE mid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$measurement = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Edit measurement'), "</h2>\n";
?>
<form method="post">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="mname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="name" name="mname" value="<?=$measurement->mname ?>">
</div>
<div class="mb-3">
<label for="note" class="form-label"><?=_('Note')?></label>
<input type="text" class="form-control" id="note" name="note" value="<?=$measurement->note ?>">
</div>
<?php
form_create_select('nval', _('Dimensions'), $opt_dimensions, $measurement->nval);
?>
<div class="mb-3">
<label for="val1"><?=_('Value 1')?></label>
<input type="number" min="0" class="form-control" id="val1" name="val1" value="<?=$measurement->val1 ?>">
</div>
<div class="mb-3">
<label for="val2"><?=_('Value 2')?></label>
<input type="number" min="0" class="form-control" id="val2" name="val2" value="<?=$measurement->val2 ?>">
</div>
<div class="mb-3">
<label for="val3"><?=_('Value 3')?></label>
<input type="number" min="0" class="form-control" id="val3" name="val3" value="<?=$measurement->val3 ?>">
</div>
<?php
form_create_select('unit', _('Unit'), $opt_unit, $measurement->unit);
form_create_select('accuracy', _('Accuracy'), $opt_accuracy, $measurement->accuracy);
form_create_select('eid', _('Equipment'), $opt_equipment, $measurement->eid);
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+288
View File
@@ -0,0 +1,288 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Projects');
$id = gpc_get_int($_REQUEST, 'id', 0);
$sql = "SELECT userid, displayname FROM user WHERE userid>0";
$sth = $pdo->query($sql);
$opt_user = array();
foreach ($sth->fetchAll() as $row) {
$opt_user[$row['userid']] = $row['displayname'];
}
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$projname = gpc_get_string($_POST, 'projname');
$responsible = gpc_get_int($_POST, 'responsible');
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "INSERT INTO project "
. " (vid, projname, responsible, remarks) "
. "VALUES "
. " (:vid, :projname, :responsible, :remarks)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->bindValue(':projname', $projname, PDO::PARAM_STR);
$sth->bindValue(':responsible', $responsible, PDO::PARAM_INT);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
$sth->execute();
$id = $pdo->lastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$projname = gpc_get_string($_POST, 'projname');
$startdate = gpc_get_date($_POST, 'startdate');
$duration = gpc_get_int($_POST, 'duration');
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE project "
. "SET projname=:projname,"
. " startdate=:startdate,"
. " duration=:duration,"
. " remarks=:remarks "
. "WHERE projid=:projid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':projid', $id, PDO::PARAM_INT);
$sth->bindValue(':projname', $projname, PDO::PARAM_STR);
$sth->bindValue(':startdate', $startdate, PDO::PARAM_STR);
$sth->bindValue(':duration', $duration, PDO::PARAM_INT);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
$sth->execute();
$action = ACT_VIEW;
break;
case 'delete':
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_("Unknown function '%s'!"), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo '<h1>', $pagetitle, "</h1>\n";
$sql = "SELECT projid, projname, startdate, duration, remarks "
. "FROM project "
. "WHERE vid=? "
. "ORDER BY projid";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll();
echo '<table class="table table-striped">'. "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Name') . "</th>";
echo "<th>" . _('Start date') . "</th>";
echo "<th>" . _('Duration') . "</th>";
echo "<th>" . _('Remarks') . "</th>";
echo "<th>&nbsp;</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['projname'] ."</td>\n";
echo "<td>". $row['startdate'] ."</td>\n";
echo "<td>". $row['duration'] ."</td>\n";
echo "<td>". $row['remarks'] ."</td>\n";
// Action buttons
form_action_buttons($g_scriptname, $row['projid']);
echo "</tr>\n";
}
echo "<tfoot>\n";
echo '<tr><td colspan="5">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
echo "<h1>", _('Generic Tasks'), "</h1>\n";
echo "<p>", _('Tasks not assigned to any project'), "</p>\n";
$sql = "SELECT taskid, taskname "
. "FROM task "
. "WHERE projid IS NULL "
. "ORDER BY taskid";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Name') . "</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['taskname'] ."</td>\n";
form_action_buttons('task.php', $row['taskid']);
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="2">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button('task.php');
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Project'), "</h2>\n";
?>
<form method="post" action="<?=$g_scriptname?>">
<div class="mb-3">
<label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname">
</div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php
foreach ($opt_user as $k => $v) {
echo '<option value="', $k ,'">', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"></textarea>
</div>
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT projname, startdate, duration, responsible, remarks "
. "FROM project "
. "WHERE projid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$project = $sth->fetch(PDO::FETCH_OBJ);
echo "<h2>", $project->projname, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th scope="row" style="width:20%">', _('Name'),"</th><td>", $project->projname, "</td></tr>\n";
echo '<tr><th scope="row">', _('Responsible'),"</th><td>", $opt_user[$project->responsible], "</td></tr>\n";
echo '<tr><th scope="row">', _('Start date'),"</th><td>", $project->startdate, "</td></tr>\n";
echo '<tr><th scope="row">', _('Duration'),"</th><td>", $project->duration, "</td></tr>\n";
echo '<tr><th scope="row">', _('Remarks'),"</th><td>", $project->remarks, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
// assigned tasks
echo "<h2>", _('Assigned tasks'), "</h2>\n";
$sql = "SELECT taskid, taskname FROM task WHERE projid=? ORDER BY taskname";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
?>
<table class="table table-sm">
<thead>
<tr>
<th><?=_('Task')?></th>
</tr>
</thead>
<?php foreach ($sth->fetchAll() as $row):?>
<tr>
<td><?=$row['taskname']?></td>
</tr>
<?php endforeach; ?>
</table>
<?php
form_add_button('task.php', $id, 'projid');
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
echo '<h2>', _('Edit Project'), "</h2>\n";
$sql = "SELECT projname, responsible, startdate, duration, remarks "
. "FROM project "
. "WHERE projid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$project = $sth->fetch(PDO::FETCH_OBJ);
?>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="projname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="projname" name="projname" value="<?=$project->projname ?>">
</div>
<div class="mb-3">
<label for="responsible" class="form-label"><?=_('Responsible')?></label>
<select name="responsible" class="form-control">
<?php
foreach ($opt_user as $k => $v) {
echo '<option value="', $k ,'"';
if ($project->responsible == $k) {
echo ' selected';
}
echo '>', $v, "</option>\n";
}
?>
</select>
</div>
<div class="mb-3">
<label for="startdate"><?=_('Startdate')?></label>
<input type="date" class="form-control" id="startdate" name="startdate" value="<?=$project->startdate ?>">
</div>
<div class="mb-3">
<label for="duration"><?=_('Duration, days')?></label>
<input type="number" class="form-control" id="duration" name="duration" min="1" value="<?=$project->duration ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$project->remarks ?></textarea>
</div>
<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>
</form>
<?php
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
echo '<h2>', _('Delete Project'), "</h2>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+238
View File
@@ -0,0 +1,238 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle=_('Provisions');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_storage = db_get_opt_storage($user->vid);
$opt_catgory = db_get_options(5);
$opt_unit = db_get_options(6);
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$p[':provname'] = gpc_get_string($_POST, 'provname');
$p[':number'] = gpc_get_int($_POST, 'number');
$p[':unit'] = gpc_get_int($_POST, 'unit');
$p[':storedate'] = gpc_get_string($_POST, 'storedate');
$p[':shelflife'] = gpc_get_string($_POST, 'shelflife');
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO provisions ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$id = $pdo->LastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$p[':provname'] = gpc_get_string($_POST, 'provname');
$p[':number'] = gpc_get_int($_POST, 'number');
$p[':unit'] = gpc_get_int($_POST, 'unit');
$p[':storedate'] = gpc_get_string($_POST, 'storedate');
$p[':shelflife'] = gpc_get_string($_POST, 'shelflife');
$p[':sid'] = gpc_get_int($_POST, 'sid');
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE provisions SET $fields WHERE provid=:provid");
$p[':provid'] = $id;
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_('Unknown function!'), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo "<h1>", $pagetitle, "</h1>\n";
$sql = "SELECT provid, provname, number, unit, storedate, shelflife, "
. " DATEDIFF(shelflife, storedate) AS d0, DATEDIFF (CURDATE(), storedate) AS d1 "
. "FROM provisions "
. "ORDER BY provid";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>\n";
echo '<th>', _('Description'), "</th>";
echo '<th>', _('Number'), "</th>";
echo '<th>', _('Unit'), "</th>";
echo '<th>', _('Stored'), "</th>";
echo '<th>', _('Best before'), "</th>";
echo "<th></th>";
echo "<th></th>\n";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['provname'] ."</td>\n";
echo "<td>". $row['number'] ."</td>\n";
echo "<td>". $opt_unit[$row['unit']] ."</td>\n";
echo "<td>". $row['storedate'] ."</td>\n";
echo "<td>". $row['shelflife'] ."</td>\n";
echo "<td>";
echo '<meter min="0" max="', $row['d0'], '" value="', $row['d1'], '">';
// Action buttons
form_action_buttons($g_scriptname, $row['provid']);
echo "</td>\n";
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add provisions'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="provname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="provname" name="provname" required autofocus>
</div>
<div class="mb-3">
<label for="number"><?=_('Number')?></label>
<input type="number" min="0" max="1000" class="form-control" id="number" name="number" value="1">
</div>
<?php form_create_select('unit', _('Unit'), $opt_unit); ?>
<div class="mb-3">
<label for="storedate"><?=_('Storedate')?></label>
<input type="date" class="form-control" id="storedate" name="storedate" value="<?php echo date('Y-m-d'); ?>">
</div>
<div class="mb-3">
<label for="shelflife"><?=_('Shelflife')?></label>
<input type="date" class="form-control" id="shelflife" name="shelflife">
</div>
<?php form_create_select('sid', _('Storage'), $opt_storage); ?>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT provname, number, unit, storedate, shelflife, sid "
. "FROM provisions "
. "WHERE provid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$prov = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', $prov->provname, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Number'),"</th><td>", $prov->number, "</td></tr>\n";
echo '<tr><th>', _('Unit'),"</th><td>", $opt_unit[$prov->unit], "</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>', _('Storage'),"</th><td>", $opt_storage[$prov->sid], "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT provname, number, unit, storedate, shelflife, sid "
. "FROM provisions "
. "WHERE provid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$prov = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Edit provision'), "</h2>\n";
?>
<form method="post">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="provname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="provname" name="provname" value="<?=$prov->provname ?>">
</div>
<div class="mb-3">
<label for="number"><?=_('Number')?></label>
<input type="number" min="0" max="1000" class="form-control" id="number" name="number" value="<?=$prov->number ?>">
</div>
<?php form_create_select('unit', _('Unit'), $opt_unit, $prov->unit); ?>
<div class="mb-3">
<label for="storedate"><?=_('Storedate')?></label>
<input type="date" class="form-control" id="storedate" name="storedate" value="<?=$prov->storedate ?>">
</div>
<div class="mb-3">
<label for="shelflife"><?=_('Shelflife')?></label>
<input type="date" class="form-control" id="shelflife" name="shelflife" value="<?=$prov->shelflife ?>">
</div>
<?php
form_create_select('sid', _('Storage'), $opt_storage, $prov->sid);
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
echo '<h2>', _('Delete provisions'), "</h2>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 122 KiB

+40
View File
@@ -0,0 +1,40 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Search');
$needle = gpc_get_string($_REQUEST, 'needle', 40);
require 'header.php';
echo "<h1>$pagetitle</h1>\n";
?>
<p>Search will be implemented later.
This page is currently just a placeholder.</p>
<form method="post">
<div>
<label for="needle">Suche nach:</label>
<input type="text" id="needle" name="needle" value="<?=$needle?>" autofocus>
</div>
<div>
<input type="checkbox" id="remarks" name="ck_remarks">
<label for="remarks">Bemerkungsfelder Berücksichtigen</label>
</div>
<button type="submit" class="btn btn-primary" name="submit[search]"><?=_('Search')?></button>
</form>
<?php
if (isset($needle)) {
$sqlneedle = '%'.$needle.'%';
}
include 'footer.php';
+325
View File
@@ -0,0 +1,325 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Storage');
$id = gpc_get_int($_REQUEST, 'id', 0);
$stype = db_get_options(3);
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$sname = gpc_get_string($_POST, 'sname');
$stype = gpc_get_int($_POST, 'stype');
$sql = "INSERT INTO storage "
. " (vid, sname, stype) "
. "VALUES "
. " (:vid, :sname, :stype)";
$sth = $pdo->prepare($sql);
$sth->bindValue(':vid', $user->vid, PDO::PARAM_INT);
$sth->bindValue(':sname', $sname, PDO::PARAM_STR);
$sth->bindValue(':stype', $stype, PDO::PARAM_INT);
$sth->execute();
$id = $pdo->lastInsertId();
$action = ACT_VIEW;
break;
case 'update':
$sname = gpc_get_string($_POST, 'sname');
$x = gpc_get_int($_POST, 'x');
$y = gpc_get_int($_POST, 'y');
$z = gpc_get_int($_POST, 'z');
$remarks = gpc_get_string($_POST, 'remarks', 150);
$sql = "UPDATE storage "
. "SET sname=:sname,"
. " x=:x, y=:y, z=:z,"
. " remarks=:remarks "
. "WHERE sid=:sid";
$sth = $pdo->prepare($sql);
$sth->bindValue(':sid', $id, PDO::PARAM_INT);
$sth->bindValue(':sname', $sname, PDO::PARAM_STR);
$sth->bindValue(':x', $x, PDO::PARAM_INT);
$sth->bindValue(':y', $y, PDO::PARAM_INT);
$sth->bindValue(':z', $z, PDO::PARAM_INT);
$sth->bindValue(':remarks', $remarks, PDO::PARAM_STR);
$sth->execute();
$action = ACT_VIEW;
break;
case 'delete':
// Security token needed!
if (gpc_get_string($_POST, 'token', 16) != $_SESSION['token']) {
$g_error->Add(_('Delete prohibited, invalid security token!'));
$action = ACT_VIEW;
break;
}
unset($_SESSION['token']);
// check if storage is empty
// - no assigned boxes
$sth = $pdo->prepare("SELECT COUNT(*) FROM box WHERE sid=?");
$sth->execute([$id]);
if ($sth->fetchColumn() > 0) {
$g_error->Add(_('Delete failed, assigned boxes detected!'));
$action = ACT_VIEW;
break;
}
// - no assigned equipment
$sth = $pdo->prepare("SELECT COUNT(*) FROM inventory WHERE boxtype='storage' AND sid=?");
$sth->execute([$id]);
if ($sth->fetchColumn() > 0) {
$g_error->Add(_('Delete failed, assigned equipment detected!'));
$action = ACT_VIEW;
break;
}
$sth = $pdo->prepare("DELETE FROM storage WHERE sid=?");
$sth->execute([$id]);
$g_message->Add(sprintf(_('Deleted storage no. %d'), $id));
$action = ACT_DEFAULT;
break;
default:
$g_error->Add(sprintf(_("Unknown function '%s'!"), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo '<h1>', $pagetitle, "</h1>\n";
// Storage
// stype from dropdown
$sql = "SELECT sid, sname, remarks "
. "FROM storage "
. "WHERE vid=? "
. "ORDER BY sid";
$sth = $pdo->prepare($sql);
$sth->execute([$user->vid]);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Name') . "</th>";
echo "<th>" . _('Remarks') . "</th>";
echo "<th>&nbsp;</th>";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['sname'] ."</td>\n";
echo "<td>". $row['remarks'] ."</td>\n";
form_action_buttons($g_scriptname, $row['sid']);
echo "</tr>\n";
}
echo "<tfoot>\n";
echo '<tr><td colspan="3">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button($g_scriptname);
// Boxes
echo "<h1>", _('Box'), "</h1>\n";
$sql = "SELECT boxid, sid, label, color, content, remarks "
. "FROM box "
. "ORDER BY label";
$sth = $pdo->query($sql);
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>";
echo "<th>" . _('Label') . "</th>";
echo "<th>" . _('Color') . "</th>";
echo "<th>" . _('Content') . "</th>";
echo "<td></td>";
echo "</tr>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>". $row['label'] ."</td>\n";
echo '<td><span style="background-color:#', $row['color'],'">'. $row['color'] ."</span></td>\n";
echo "<td>". $row['content'] ."</td>\n";
form_action_buttons('box.php', $row['boxid']);
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="4">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
form_add_button('box.php');
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Storage'), "</h2>\n";
?>
<form method="post">
<div class="mb-3">
<label for="sname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="sname" name="sname">
</div>
<div class="mb-3">
<select name="stype" class="form-control">
<?php
foreach ($stype as $k => $v) {
echo '<option value="', $k ,'">', $v, "</option>\n";
}
?>
</select>
</div>
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$opt_unit = db_get_options(6);
$sql = "SELECT sid, sname, stype, capacity, capaunit, x, y, z, remarks "
. "FROM storage "
. "WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$storage = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', $storage->sname, "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th style="width:20%">', _('Typ'),"</th><td>", $stype[$storage->stype], "</td></tr>\n";
echo '<tr><th>', _('Capacity'),"</th><td>", $storage->capacity, ' ', $storage->capaunit, "</td></tr>\n";
echo '<tr><th>', _('Location (x, y, z)'),"</th><td>(", $storage->x ?? '?', ', ', $storage->y ?? '?', ', ', $storage->z, ")</td></tr>\n";
echo '<tr><th>', _('Remarks'),"</th><td>", $storage->remarks, "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
// Zugeordnete Kisten hier anzeigen
echo '<h3>', _('Boxes in storage'), "</h3>\n";
$sql = "SELECT boxid, label, color FROM box WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$res = $sth->fetchall();
if (count($res) > 0) {
foreach ($res as $row) {
echo "$boxid $label $color";
}
} else {
echo '<p>', _('No boxes contained'), "</p>\n";
}
echo '<h3>', _('Provisions in storage'), "</h3>\n";
$sql = "SELECT provid, provname, number, unit, storedate, shelflife FROM provisions WHERE 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['provname'], "</td>";
echo "<td>", $row['number'], ' ', $opt_unit[$row['unit']], "</td>";
echo "<td>", $row['storedate'], ' - ', $row['shelflife'], "</td>";
echo "</tr>\n";
}
echo "</table>\n";
} else {
echo '<p>', _('No provisions contained'), "</p>\n";
}
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
echo '<h2>', _('Edit Storage'), "</h2>\n";
$sql = "SELECT sid, sname, stype, remarks "
. "FROM storage "
. "WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$storage = $sth->fetch(PDO::FETCH_OBJ);
?>
<form method="post" action="<?=$g_scriptname?>">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="sname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="sname" name="sname" value="<?=$storage->sname ?>">
</div>
<div class="mb-3">
<label for="x" class="form-label"><?=_('Position x')?></label>
<input type="number" class="form-control" id="x" name="x" value="<?=$storage->x ?>">
</div>
<div class="mb-3">
<label for="y" class="form-label"><?=_('Position y')?></label>
<input type="number" class="form-control" id="y" name="y" value="<?=$storage->y ?>">
</div>
<div class="mb-3">
<label for="z" class="form-label"><?=_('Position z')?></label>
<input type="number" class="form-control" id="z" name="z" value="<?=$storage->z ?>">
</div>
<div class="mb-3">
<label for="remarks" class="form-label"><?=_('Remarks')?></label>
<textarea class="form-control" id="remarks" name="remarks" rows="3"><?=$storage->remarks ?></textarea>
</div>
<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>
</form>
<?php
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
$_SESSION['token'] = bin2hex(random_bytes(8));
$sql = "SELECT sname, remarks FROM storage WHERE sid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$storage = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Delete Storage'), "</h2>\n";
echo '<p>', sprintf(_('Record no. %d'), $id), "</p>\n";
echo '<p>Name: ', $storage->sname, "</p>";
echo '<p>Remarks: ', $storage->remarks, "</p>";
echo '<p>', _('Deleting a storage is final. There is no way back. Only delete if you are absolute sure.'), "</p>\n";
form_delete_buttons($g_scriptname, $id, $_SESSION['token']);
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';
+192
View File
@@ -0,0 +1,192 @@
<?php
/******************************************************************************
* YMS - Yacht Management Software
* Copyright (C) 2024 Thomas Hooge
*
* SPDX-License-Identifier: WTFPL
******************************************************************************/
require 'globals.inc';
$pagetitle = _('Task');
$id = gpc_get_int($_REQUEST, 'id', 0);
$opt_projects = db_get_opt_proj($user->vid, array(-1 => _('unassigned')));
// ========== ACTIONS START ===================================================
switch ($submit = form_get_action()) {
case NULL: break;
case 'add': $action = ACT_ADD; break;
case 'view': $action = ACT_VIEW; break;
case 'edit': $action = ACT_EDIT; break;
case 'del': $action = ACT_DELETE; break;
case 'insert':
$p[':projid'] = gpc_get_int($_POST, 'projid');
if ($p[':projid'] == -1) {
$p[':projid'] = NULL;
}
$p[':taskname'] = gpc_get_string($_POST, 'taskname');
$keys = array_keys($p);
$fields = join(',', array_map(function($s) { return ltrim($s, ':'); }, $keys));
$pnames = join(',', $keys);
$sth = $pdo->prepare("INSERT INTO task ($fields) VALUES ($pnames)");
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
break;
case 'update':
$p[':taskname'] = gpc_get_string($_POST, 'taskname');
$p[':projid'] = gpc_get_int($_POST, 'projid');
if ($p[':projid'] == -1) {
$p[':projid'] = NULL;
}
$fields = join(',', array_map(function($s) { return ltrim($s, ':') . '=' . $s; }, array_keys($p)));
$sth = $pdo->prepare("UPDATE task SET $fields WHERE taskid=:taskid");
$p[':taskid'] = $id;
try {
$sth->execute($p);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$action = ACT_VIEW;
break;
default:
$g_error->Add(sprintf(_("Unknown function '%s'!"), $submit));
$valid = FALSE;
}
// ========== ACTIONS END =====================================================
require 'header.php';
// ========== PAGE CONTENT ====================================================
if ($action == ACT_DEFAULT):
// ========== VARIANT: default behavior =======================================
echo "<h1>$pagetitle</h1>\n";
$sql = "SELECT t.taskid, t.projid, t.taskname, p.projname "
. "FROM task AS t LEFT JOIN project AS p USING (projid) "
. "WHERE p.projid IS NULL OR p.vid=? "
. "ORDER BY t.taskid";
$sth = $pdo->prepare($sql);
try {
$sth->execute([$user->vid]);
} catch (PDOexception $e) {
$g_error->Add('SQL-Error: '. $e->getMessage());
}
$res = $sth->fetchAll();
echo '<table class="table table-striped">', "\n";
echo "<thead>\n";
echo "<tr>\n";
echo '<th>#</th>';
echo '<th>', _('Task'), "</th>";
echo '<th>', _('Project'), "</th>";
echo "<th></th>";
echo "<th></th>\n";
echo "</tr>\n";
echo "</thead>\n";
foreach ($res as $row) {
echo "<tr>\n";
echo "<td>" . $row['taskid'] . "</td>\n";
echo "<td>" . $row['taskname'] . "</td>\n";
echo "<td>" . $row['projname'] . "</td>\n";
// Action buttons
form_action_buttons($g_scriptname, $row['taskid']);
echo "</tr>\n";
}
// Table summary
echo "<tfoot>\n";
echo '<tr><td colspan="6">', sprintf(_('%d records'), count($res)), '</td></tr>', "\n";
echo "</tfoot>\n";
echo "</table>\n";
elseif ($action == ACT_ADD):
// ========== VARIANT: add record =============================================
echo '<h2>', _('Add Task'), "</h2>\n";
?>
<form method="post">
<?php
// preselect project if parameter is set
$projid = gpc_get_int($_REQUEST, 'projid');
form_create_select('projid', _('Project'), $opt_projects, $projid);
?>
<div class="mb-3">
<label for="taskname" class="form-label"><?=_('Task')?></label>
<input type="text" class="form-control" id="taskname" name="taskname" required autofocus>
</div>
<div class="container-fluid px-0 my-3">
<button type="submit" name="submit[insert]" class="btn btn-primary"><?=_('Save')?></button>
<a href="<?=$g_scriptname?>" class="btn btn-secondary"><?=_('Back')?></a>
</div>
</form>
<?php
elseif ($action == ACT_VIEW):
// ========== VARIANT: view single record =====================================
$sql = "SELECT t.taskname, p.projname "
. "FROM task AS t LEFT JOIN project AS p USING (projid) "
. "WHERE taskid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$task = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('View Task'), "</h2>\n";
echo '<table class="table">', "\n";
echo '<tr><th>', _('Task'),"</th><td>", $task->taskname, "</td></tr>\n";
echo '<tr><th>', _('Project'),"</th><td>", $task->projname ?? _('unassigned'), "</td></tr>\n";
echo "</table>\n";
form_view_buttons($g_scriptname, $id);
elseif ($action == ACT_EDIT):
// ========== VARIANT: edit single record =====================================
$sql = "SELECT taskname "
. "FROM task "
. "WHERE taskid=?";
$sth = $pdo->prepare($sql);
$sth->execute([$id]);
$task = $sth->fetch(PDO::FETCH_OBJ);
echo '<h2>', _('Edit Task'), "</h2>\n";
?>
<form method="post">
<input type="hidden" name="id" value="<?=$id?>">
<div class="mb-3">
<label for="taskname" class="form-label"><?=_('Name')?></label>
<input type="text" class="form-control" id="taskname" name="taskname" value="<?=$task->taskname ?>">
</div>
<?php
form_create_select('projid', _('Project'), $opt_projects);
form_edit_buttons($g_scriptname, $id);
echo "</form>\n";
elseif ($action == ACT_DELETE):
// ========== VARIANT: delete record ==========================================
echo '<h2>', _('Delete Task'), "</h2>\n";
else:
// ========== ERROR UNKNOWN VARIANT ===========================================
echo '<p>', _('Unknown function call: Please report to system development!'), "</p>\n";
endif; // $action == ...
// ========== END OF VARIANTS =================================================
include 'footer.php';