Merge branch 'test'
This commit is contained in:
commit
3765795dbb
@ -3,3 +3,5 @@
|
|||||||
There should be a description here
|
There should be a description here
|
||||||
|
|
||||||
Additional line
|
Additional line
|
||||||
|
|
||||||
|
additional line 2
|
||||||
|
@ -6,8 +6,11 @@ $db_user = 'dbname';
|
|||||||
$db_pass = 'dbpassword';
|
$db_pass = 'dbpassword';
|
||||||
$db_name = 'dbuser';
|
$db_name = 'dbuser';
|
||||||
|
|
||||||
|
# Email subject prefix
|
||||||
|
$email_subject_prefix = "System name: ";
|
||||||
|
|
||||||
# Address to use as the sender for reminder emails
|
# Address to use as the sender for reminder emails
|
||||||
$reminder_sender = 'noreply@example.com';
|
$sender = 'noreply@example.com';
|
||||||
|
|
||||||
# Address to send cron error messages to
|
# Address to send cron error messages to
|
||||||
$error_address = 'root@example.com';
|
$error_address = 'root@example.com';
|
||||||
@ -15,7 +18,7 @@ $error_address = 'root@example.com';
|
|||||||
# Discard notifications
|
# Discard notifications
|
||||||
# If this is set to an email address, the system will send a notification
|
# If this is set to an email address, the system will send a notification
|
||||||
# there each time a product is discarded.
|
# there each time a product is discarded.
|
||||||
#$notify_discard = 'inventory-tracking@example.com';
|
#$discard_notify = 'inventory-tracking@example.com';
|
||||||
$discard_notify = false;
|
$discard_notify = false;
|
||||||
|
|
||||||
# Directory to save attachments to
|
# Directory to save attachments to
|
||||||
|
2
cron.php
2
cron.php
@ -7,7 +7,7 @@ require('./include/functions.php');
|
|||||||
|
|
||||||
header('Content-Type: text/html; charset=UTF-8');
|
header('Content-Type: text/html; charset=UTF-8');
|
||||||
|
|
||||||
$cron = new Cron($reminder_sender, $error_address);
|
$cron = new Cron($sender, $error_address, $email_subject_prefix);
|
||||||
$cron->run();
|
$cron->run();
|
||||||
|
|
||||||
?>
|
?>
|
||||||
|
21
database.sql
21
database.sql
@ -147,3 +147,24 @@ create table `kvs` (
|
|||||||
`value` varchar(64) not null default ''
|
`value` varchar(64) not null default ''
|
||||||
) character set utf8mb4,
|
) character set utf8mb4,
|
||||||
collate utf8mb4_unicode_ci;
|
collate utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
create table `pending_receipt` (
|
||||||
|
`user` bigint(20) not null,
|
||||||
|
primary key (`user`),
|
||||||
|
constraint `pr_f_user`
|
||||||
|
foreign key(`user`) references `user`(`id`),
|
||||||
|
`send_time` bigint(20) not null,
|
||||||
|
`since_time` bigint(20) not null
|
||||||
|
) character set utf8mb4,
|
||||||
|
collate utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
create table `loan_extension` (
|
||||||
|
`loan` bigint(20) not null,
|
||||||
|
constraint `le_f_loan`
|
||||||
|
foreign key(`loan`) references `loan`(`event`),
|
||||||
|
`extend_time` bigint(20) not null,
|
||||||
|
primary key (`loan`, `extend_time`),
|
||||||
|
`old_end` bigint(20) not null,
|
||||||
|
`new_end` bigint(20) not null
|
||||||
|
) character set utf8mb4,
|
||||||
|
collate utf8mb4_unicode_ci;
|
||||||
|
@ -85,7 +85,7 @@
|
|||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody class="¤type¤">
|
||||||
¤rows¤
|
¤rows¤
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
@ -105,6 +105,25 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
||||||
|
¤¤ product_detail_row ¤¤
|
||||||
|
<tr>
|
||||||
|
<td class="status ¤status¤">
|
||||||
|
</td>
|
||||||
|
<td colspan="3">
|
||||||
|
<dl>
|
||||||
|
¤details¤
|
||||||
|
</dl>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
¤¤ product_detail ¤¤
|
||||||
|
<dt>
|
||||||
|
¤name¤:
|
||||||
|
</dt>
|
||||||
|
<dd>
|
||||||
|
¤value¤
|
||||||
|
</dd>
|
||||||
|
|
||||||
¤¤ template_management ¤¤
|
¤¤ template_management ¤¤
|
||||||
<div>
|
<div>
|
||||||
<h2>Mallar</h2>
|
<h2>Mallar</h2>
|
||||||
@ -133,7 +152,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
¤¤ product_details ¤¤
|
¤¤ product_form ¤¤
|
||||||
<div id="product-details">
|
<div id="product-details">
|
||||||
<h2>Artikeldata</h2>
|
<h2>Artikeldata</h2>
|
||||||
<form id="product-data"
|
<form id="product-data"
|
||||||
@ -287,16 +306,54 @@
|
|||||||
<button>Ladda upp</button>
|
<button>Ladda upp</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<div id="product-history"
|
|
||||||
class="¤hidden¤">
|
¤¤ product_meta ¤¤
|
||||||
|
<div id="product-history">
|
||||||
<h2>Artikelhistorik</h2>
|
<h2>Artikelhistorik</h2>
|
||||||
¤history¤
|
¤history¤
|
||||||
</div>
|
</div>
|
||||||
<div id="product-label"
|
<div id="product-label"
|
||||||
class="¤hidden¤">
|
class="¤label_hidden¤">
|
||||||
<h2>Etikett</h2>
|
<h2>Etikett</h2>
|
||||||
¤label¤
|
¤label¤
|
||||||
</div>
|
</div>
|
||||||
|
<div id="product-direct-checkout" class="¤checkout_hidden¤">
|
||||||
|
<h2>Låna ut</h2>
|
||||||
|
<form class="light"
|
||||||
|
onSubmit="JavaScript:checkoutProduct(event)">
|
||||||
|
<datalist id="user_suggest"></datalist>
|
||||||
|
<input type="hidden"
|
||||||
|
name="page"
|
||||||
|
value="checkout" />
|
||||||
|
<label for="user">Användarnamn:</label>
|
||||||
|
<input onFocus="JavaScript:suggest(this, 'user')"
|
||||||
|
type="text"
|
||||||
|
name="user"
|
||||||
|
list="user_suggest"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="Användarnamn"
|
||||||
|
required />
|
||||||
|
<input type="hidden"
|
||||||
|
id="product"
|
||||||
|
name="product"
|
||||||
|
value="¤serial¤" />
|
||||||
|
<button>
|
||||||
|
Låna ut
|
||||||
|
</button>
|
||||||
|
<br/>
|
||||||
|
<label>Löptid:</label>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 7, 'day')">1 vecka</button>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 1, 'year')">1 år</button>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 3, 'year')">3 år</button>
|
||||||
|
<br/>
|
||||||
|
<label for="end">Slutdatum:</label>
|
||||||
|
<input type="text"
|
||||||
|
id="end"
|
||||||
|
onClick="JavaScript:calendar(event)"
|
||||||
|
name="end"
|
||||||
|
value="¤end¤" />
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
¤¤ attachment_list ¤¤
|
¤¤ attachment_list ¤¤
|
||||||
<ul class="attachment-list">
|
<ul class="attachment-list">
|
||||||
@ -534,12 +591,22 @@
|
|||||||
list="user_suggest"
|
list="user_suggest"
|
||||||
autocomplete="off"
|
autocomplete="off"
|
||||||
placeholder="Användarnamn"
|
placeholder="Användarnamn"
|
||||||
value="¤user¤"
|
value="¤user¤" />
|
||||||
required />
|
|
||||||
<button type="submit" >
|
<button type="submit" >
|
||||||
Välj
|
Välj
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="email">
|
||||||
|
E-post:
|
||||||
|
</label>
|
||||||
|
<input type="text"
|
||||||
|
name="email"
|
||||||
|
id="email"
|
||||||
|
autocomplete="off"
|
||||||
|
placeholder="E-post"
|
||||||
|
value="¤email¤" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label for="displayname">
|
<label for="displayname">
|
||||||
Namn:
|
Namn:
|
||||||
@ -581,6 +648,11 @@
|
|||||||
Låna ut
|
Låna ut
|
||||||
</button>
|
</button>
|
||||||
<br/>
|
<br/>
|
||||||
|
<label>Löptid:</label>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 7, 'day')">1 vecka</button>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 1, 'year')">1 år</button>
|
||||||
|
<button onClick="JavaScript:loanLength(event, 3, 'year')">3 år</button>
|
||||||
|
<br/>
|
||||||
<label for="end">Slutdatum:</label>
|
<label for="end">Slutdatum:</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
id="end"
|
id="end"
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
class Ajax extends Responder {
|
class Ajax extends Responder {
|
||||||
private $action = '';
|
private $action = '';
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
if(isset($_GET['action'])) {
|
if(isset($_GET['action'])) {
|
||||||
$this->action = $_GET['action'];
|
$this->action = $_GET['action'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
$out = '';
|
$out = '';
|
||||||
switch($this->action) {
|
switch($this->action) {
|
||||||
@ -87,7 +87,7 @@ class Ajax extends Responder {
|
|||||||
}
|
}
|
||||||
$product = null;
|
$product = null;
|
||||||
try {
|
try {
|
||||||
$product = new Product($_POST['product'], 'serial');
|
$product = new Product(trim($_POST['product']), 'serial');
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
return new Failure('Ogiltigt serienummer.');
|
return new Failure('Ogiltigt serienummer.');
|
||||||
}
|
}
|
||||||
@ -98,11 +98,11 @@ class Ajax extends Responder {
|
|||||||
return new Failure('Artikeln är redan utlånad.');
|
return new Failure('Artikeln är redan utlånad.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function return_product() {
|
private function return_product() {
|
||||||
$product = null;
|
$product = null;
|
||||||
try {
|
try {
|
||||||
$product = new Product($_POST['serial'], 'serial');
|
$product = new Product(trim($_POST['serial']), 'serial');
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
return new Failure('Ogiltigt serienummer.');
|
return new Failure('Ogiltigt serienummer.');
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ class Ajax extends Responder {
|
|||||||
$user = $loan->get_user();
|
$user = $loan->get_user();
|
||||||
$userlink = replace(array('page' => 'users',
|
$userlink = replace(array('page' => 'users',
|
||||||
'id' => $user->get_id(),
|
'id' => $user->get_id(),
|
||||||
'name' => $user->get_displayname()),
|
'name' => $user->get_displayname($this->ldap)),
|
||||||
$this->fragments['item_link']);
|
$this->fragments['item_link']);
|
||||||
$productlink = replace(array('page' => 'products',
|
$productlink = replace(array('page' => 'products',
|
||||||
'id' => $product->get_id(),
|
'id' => $product->get_id(),
|
||||||
@ -138,7 +138,7 @@ class Ajax extends Responder {
|
|||||||
}
|
}
|
||||||
return new Failure('Lån saknas.');
|
return new Failure('Lån saknas.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function start_inventory() {
|
private function start_inventory() {
|
||||||
try {
|
try {
|
||||||
Inventory::begin();
|
Inventory::begin();
|
||||||
@ -147,7 +147,7 @@ class Ajax extends Responder {
|
|||||||
return new Failure('Inventering redan igång.');
|
return new Failure('Inventering redan igång.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function end_inventory() {
|
private function end_inventory() {
|
||||||
$inventory = Inventory::get_active();
|
$inventory = Inventory::get_active();
|
||||||
if($inventory === null) {
|
if($inventory === null) {
|
||||||
@ -156,7 +156,7 @@ class Ajax extends Responder {
|
|||||||
$inventory->end();
|
$inventory->end();
|
||||||
return new Success('Inventering avslutad.');
|
return new Success('Inventering avslutad.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function inventory_product() {
|
private function inventory_product() {
|
||||||
$inventory = Inventory::get_active();
|
$inventory = Inventory::get_active();
|
||||||
if($inventory === null) {
|
if($inventory === null) {
|
||||||
@ -164,7 +164,7 @@ class Ajax extends Responder {
|
|||||||
}
|
}
|
||||||
$product = null;
|
$product = null;
|
||||||
try {
|
try {
|
||||||
$product = new Product($_POST['serial'], 'serial');
|
$product = new Product(trim($_POST['serial']), 'serial');
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
return new Failure('Ogiltigt serienummer.');
|
return new Failure('Ogiltigt serienummer.');
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ class Ajax extends Responder {
|
|||||||
}
|
}
|
||||||
return new Success('Ändringarna sparade.');
|
return new Success('Ändringarna sparade.');
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update_user() {
|
private function update_user() {
|
||||||
$id = $_POST['id'];
|
$id = $_POST['id'];
|
||||||
$name = $_POST['name'];
|
$name = $_POST['name'];
|
||||||
@ -355,7 +355,7 @@ class Ajax extends Responder {
|
|||||||
return new Failure('Det finns ingen mall med det namnet.');
|
return new Failure('Det finns ingen mall med det namnet.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function suggest() {
|
private function suggest() {
|
||||||
return new Success(suggest($_POST['type']));
|
return new Success(suggest($_POST['type']));
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,72 @@
|
|||||||
<?php
|
<?php
|
||||||
class CheckoutPage extends Page {
|
class CheckoutPage extends Page {
|
||||||
private $userstr = '';
|
private $userstr = '';
|
||||||
|
private $emailstr = '';
|
||||||
private $user = null;
|
private $user = null;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
if(isset($_GET['user'])) {
|
if(isset($_GET['user'])) {
|
||||||
$this->userstr = trim(strtolower($_GET['user']));
|
$this->userstr = trim(strtolower($_GET['user']));
|
||||||
try {
|
}
|
||||||
$this->user = new User($this->userstr, 'name');
|
if(isset($_GET['email'])) {
|
||||||
} catch(Exception $ue) {
|
$this->emailstr = trim(strtolower($_GET['email']));
|
||||||
try {
|
}
|
||||||
$ldap = new Ldap();
|
try {
|
||||||
$ldap->get_user($this->userstr);
|
$this->user = $this->user_init($this->userstr,
|
||||||
$this->user = User::create_user($this->userstr);
|
$this->emailstr);
|
||||||
} catch(Exception $le) {
|
} catch(Exception $e) {
|
||||||
$this->error = "Användarnamnet '";
|
$this->error = $e->getMessage();
|
||||||
$this->error .= $this->userstr;
|
|
||||||
$this->error .= "' kunde inte hittas.";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function user_init($name, $email) {
|
||||||
|
$nameuser = null;
|
||||||
|
$emailuser = null;
|
||||||
|
if($name) {
|
||||||
|
try {
|
||||||
|
$nameuser = new User($name, 'name');
|
||||||
|
} catch(Exception $ue) {
|
||||||
|
# The user wasn't found locally
|
||||||
|
try {
|
||||||
|
$this->ldap->get_user($name);
|
||||||
|
$nameuser = User::create_user($name);
|
||||||
|
} catch(Exception $le) {
|
||||||
|
$err = "Användarnamnet '$name' kunde inte hittas.";
|
||||||
|
throw new Exception($err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($email) {
|
||||||
|
try {
|
||||||
|
$search = $email;
|
||||||
|
if(strpos($email, '@') === false) {
|
||||||
|
$search = $email .'@dsv.su.se';
|
||||||
|
}
|
||||||
|
# Lookup email directly in ldap since we don't store it
|
||||||
|
$emailuser = new User($this->ldap->search_email($search),
|
||||||
|
'name');
|
||||||
|
} catch(Exception $ue) {
|
||||||
|
$err = "E-postadressen '$search' kunde inte hittas.";
|
||||||
|
throw new Exception($err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($nameuser && $emailuser) {
|
||||||
|
if($nameuser != $emailuser) {
|
||||||
|
$err = "Användarnamn och e-post matchar olika användare.";
|
||||||
|
throw new Exception($err);
|
||||||
|
}
|
||||||
|
return $nameuser;
|
||||||
|
}
|
||||||
|
if($nameuser) {
|
||||||
|
return $nameuser;
|
||||||
|
}
|
||||||
|
return $emailuser;
|
||||||
|
}
|
||||||
|
|
||||||
protected function render_body() {
|
protected function render_body() {
|
||||||
$username = '';
|
$username = $this->userstr;
|
||||||
|
$email = $this->emailstr;
|
||||||
$displayname = '';
|
$displayname = '';
|
||||||
$notes = '';
|
$notes = '';
|
||||||
$loan_table = '';
|
$loan_table = '';
|
||||||
@ -33,7 +75,8 @@ class CheckoutPage extends Page {
|
|||||||
$disabled = 'disabled';
|
$disabled = 'disabled';
|
||||||
if($this->user !== null) {
|
if($this->user !== null) {
|
||||||
$username = $this->user->get_name();
|
$username = $this->user->get_name();
|
||||||
$displayname = $this->user->get_displayname();
|
$email = $this->user->get_email($this->ldap);
|
||||||
|
$displayname = $this->user->get_displayname($this->ldap);
|
||||||
$notes = $this->user->get_notes();
|
$notes = $this->user->get_notes();
|
||||||
$enddate = format_date(default_loan_end(time()));
|
$enddate = format_date(default_loan_end(time()));
|
||||||
$disabled = '';
|
$disabled = '';
|
||||||
@ -45,7 +88,8 @@ class CheckoutPage extends Page {
|
|||||||
$subhead = replace(array('title' => 'Lånade artiklar'),
|
$subhead = replace(array('title' => 'Lånade artiklar'),
|
||||||
$this->fragments['subtitle']);
|
$this->fragments['subtitle']);
|
||||||
}
|
}
|
||||||
print(replace(array('user' => $this->userstr,
|
print(replace(array('user' => $username,
|
||||||
|
'email' => $email,
|
||||||
'displayname' => $displayname,
|
'displayname' => $displayname,
|
||||||
'notes' => $notes,
|
'notes' => $notes,
|
||||||
'end' => $enddate,
|
'end' => $enddate,
|
||||||
|
368
include/Cron.php
368
include/Cron.php
@ -4,22 +4,194 @@ class Cron {
|
|||||||
private $sender = '';
|
private $sender = '';
|
||||||
private $error = '';
|
private $error = '';
|
||||||
private $kvs;
|
private $kvs;
|
||||||
public function __construct($sender, $error) {
|
private $ldap;
|
||||||
$this->now = time();
|
public function __construct($sender, $error, $prefix) {
|
||||||
|
$this->now = new DateTimeImmutable();
|
||||||
$this->sender = $sender;
|
$this->sender = $sender;
|
||||||
$this->error = $error;
|
$this->error = $error;
|
||||||
|
$this->subject_prefix = $prefix;
|
||||||
|
$this->warn_time = DateInterval::createFromDateString('3 days');
|
||||||
|
$this->warn_date = $this->now->add($this->warn_time);
|
||||||
|
$this->run_interval = DateInterval::createFromDateString('1 day');
|
||||||
$this->kvs = new Kvs();
|
$this->kvs = new Kvs();
|
||||||
|
$this->ldap = new Ldap();
|
||||||
|
|
||||||
|
$days = $this->warn_time->d;
|
||||||
|
$this->strings = array(
|
||||||
|
'en' => array(
|
||||||
|
'new' => array(
|
||||||
|
'single' => "The following loan has been registered in your name:",
|
||||||
|
'multi' => "The following loans have been registered in your name:",
|
||||||
|
'expiry' => "expires on",
|
||||||
|
'serial' => "serial number",
|
||||||
|
),
|
||||||
|
'extend' => array(
|
||||||
|
'single' => "The following loan has been extended:",
|
||||||
|
'multi' => "The following loans have been extended:",
|
||||||
|
'expiry' => "extended to",
|
||||||
|
'serial' => "serial number",
|
||||||
|
),
|
||||||
|
'expiring' => array(
|
||||||
|
'single' => "The following loan expires in less than $days days:",
|
||||||
|
'multi' => "The following loans expire in less than $days days:",
|
||||||
|
'expiry' => "expires on",
|
||||||
|
'serial' => "serial number",
|
||||||
|
),
|
||||||
|
'overdue' => array(
|
||||||
|
'single' => "The following loan has expired:",
|
||||||
|
'multi' => "The following loans have expired:",
|
||||||
|
'expiry' => "expired on",
|
||||||
|
'serial' => "serial number",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'sv' => array(
|
||||||
|
'new' => array(
|
||||||
|
'single' => "Följande lån har registrerats på din användare:",
|
||||||
|
'multi' => "Följande lån har registrerats på din användare:",
|
||||||
|
'expiry' => "går ut",
|
||||||
|
'serial' => "artikelnummer",
|
||||||
|
),
|
||||||
|
'extend' => array(
|
||||||
|
'single' => "Följande lån har förlängts:",
|
||||||
|
'multi' => "Följande lån har förlängts:",
|
||||||
|
'expiry' => "förlängt till",
|
||||||
|
'serial' => "artikelnummer",
|
||||||
|
),
|
||||||
|
'expiring' => array(
|
||||||
|
'single' => "Följande lån går ut om mindre än $days dagar:",
|
||||||
|
'multi' => "Följande lån går ut om mindre än $days dagar:",
|
||||||
|
'expiry' => "går ut",
|
||||||
|
'serial' => "artikelnummer",
|
||||||
|
),
|
||||||
|
'overdue' => array(
|
||||||
|
'single' => "Följande lån har gått ut:",
|
||||||
|
'multi' => "Följande lån har gått ut:",
|
||||||
|
'expiry' => "gick ut",
|
||||||
|
'serial' => "artikelnummer",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run() {
|
public function run() {
|
||||||
$lastrun = $this->kvs->get_value('lastrun');
|
$this->run_receipts();
|
||||||
$interval = 3600*24; //1 day in seconds
|
$this->run_reminders();
|
||||||
|
}
|
||||||
if($lastrun && $this->now - $lastrun < $interval) {
|
|
||||||
|
private function run_receipts() {
|
||||||
|
begin_trans();
|
||||||
|
$get = prepare('select * from `pending_receipt`
|
||||||
|
where `send_time` < ?');
|
||||||
|
bind($get, 'i', $this->now->getTimestamp());
|
||||||
|
execute($get);
|
||||||
|
foreach(result_list($get) as $row) {
|
||||||
|
$user = new User($row['user']);
|
||||||
|
$since_time = $row['since_time'];
|
||||||
|
|
||||||
|
$new_loans = array();
|
||||||
|
$extended_loans = array();
|
||||||
|
foreach($user->get_loans('active') as $loan) {
|
||||||
|
if($loan->get_starttime() >= $since_time) {
|
||||||
|
$new_loans[] = $loan;
|
||||||
|
} else if($loan->get_last_extension() >= $since_time) {
|
||||||
|
$extended_loans[] = $loan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if($new_loans || $extended_loans) {
|
||||||
|
$this->send_receipt($user, $new_loans, $extended_loans);
|
||||||
|
}
|
||||||
|
$delete = prepare('delete from `pending_receipt`
|
||||||
|
where `user` = ? and `send_time` < ?');
|
||||||
|
bind($delete, 'ii', $user->get_id(), $this->now->getTimestamp());
|
||||||
|
execute($delete);
|
||||||
|
}
|
||||||
|
commit_trans();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function make_receipt_subject($num_new, $num_extended) {
|
||||||
|
$subject = $this->subject_prefix;
|
||||||
|
$messages = array();
|
||||||
|
if($num_new > 1) {
|
||||||
|
$messages[] = $num_new." nya";
|
||||||
|
} else if($num_new > 0) {
|
||||||
|
$messages[] = $num_new." nytt";
|
||||||
|
}
|
||||||
|
if($num_extended > 1) {
|
||||||
|
$messages[] = $num_extended." förlängda";
|
||||||
|
} else if($num_extended > 0) {
|
||||||
|
$messages[] = $num_extended." förlängt";
|
||||||
|
}
|
||||||
|
return $subject.implode(" och ", $messages)." lån";
|
||||||
|
}
|
||||||
|
|
||||||
|
private function send_receipt($user, $new, $extended) {
|
||||||
|
$uid = $user->get_name();
|
||||||
|
$name = $this->ldap->get_firstname($uid);
|
||||||
|
|
||||||
|
$new_count = count($new);
|
||||||
|
$extended_count = count($extended);
|
||||||
|
$subject = $this->make_receipt_subject($new_count, $extended_count);
|
||||||
|
|
||||||
|
$list_sv = array();
|
||||||
|
$list_en = array();
|
||||||
|
if($new_count > 0) {
|
||||||
|
$list_sv[] = $this->make_notice('sv', 'new', $new);
|
||||||
|
$list_en[] = $this->make_notice('en', 'new', $new);
|
||||||
|
}
|
||||||
|
if($extended_count > 0) {
|
||||||
|
$list_sv[] = $this->make_notice('sv', 'extend', $extended);
|
||||||
|
$list_en[] = $this->make_notice('en', 'extend', $extended);
|
||||||
|
}
|
||||||
|
$list_sv = implode("\n\n", $list_sv);
|
||||||
|
$list_en = implode("\n\n", $list_en);
|
||||||
|
|
||||||
|
$info_sv = array();
|
||||||
|
$info_en = array();
|
||||||
|
if($new_count > 0) {
|
||||||
|
$info_sv[] = "Eventuella artiklar du inte hämtat ut redan kan hämtas från Helpdesk.";
|
||||||
|
$info_en[] = "Any products you haven't already picked up can be collected from Helpdesk.";
|
||||||
|
}
|
||||||
|
$info_sv[] = "Svara på det här mailet om du har några frågor.";
|
||||||
|
$info_en[] = "Please reply to this email if you have any questions.";
|
||||||
|
$info_sv = implode(' ', $info_sv);
|
||||||
|
$info_en = implode(' ', $info_en);
|
||||||
|
|
||||||
|
$message = <<<EOF
|
||||||
|
Hej $name!
|
||||||
|
|
||||||
|
Det här är ett automatiskt meddelande från Helpdesk.
|
||||||
|
|
||||||
|
$list_sv
|
||||||
|
|
||||||
|
$info_sv
|
||||||
|
|
||||||
|
----
|
||||||
|
|
||||||
|
This is an automated message from Helpdesk.
|
||||||
|
|
||||||
|
$list_en
|
||||||
|
|
||||||
|
$info_en
|
||||||
|
|
||||||
|
Mvh
|
||||||
|
DSV Helpdesk
|
||||||
|
helpdesk@dsv.su.se
|
||||||
|
08 - 16 16 48
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
$this->send_email($uid, $subject, $message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function run_reminders() {
|
||||||
|
$lastrun = $this->kvs->get_value('lastrun', 0);
|
||||||
|
$nextrun = $this->now
|
||||||
|
->setTimestamp($lastrun)
|
||||||
|
->add($this->run_interval);
|
||||||
|
if($nextrun > $this->now) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$this->kvs->set_key('lastrun', $this->now);
|
$this->kvs->set_key('lastrun', $this->now->getTimestamp());
|
||||||
|
|
||||||
$users = get_items('user');
|
$users = get_items('user');
|
||||||
foreach($users as $user) {
|
foreach($users as $user) {
|
||||||
$this->check_loans($user);
|
$this->check_loans($user);
|
||||||
@ -27,89 +199,151 @@ class Cron {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private function check_loans($user) {
|
private function check_loans($user) {
|
||||||
|
$expiring = $user->get_expiring_loans($this->warn_date);
|
||||||
$overdue = $user->get_overdue_loans();
|
$overdue = $user->get_overdue_loans();
|
||||||
if($overdue) {
|
if($expiring || $overdue) {
|
||||||
$this->send_reminder($user, $overdue);
|
$this->send_reminder($user, $expiring, $overdue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function send_reminder($user, $loans) {
|
|
||||||
$subject_template = "DSV Helpdesk: Du har ¤count¤ ¤late¤ lån";
|
|
||||||
$reminder_template_sv = "¤brand¤ ¤name¤, försenad sedan ¤due¤\n";
|
|
||||||
$reminder_template_en = "¤brand¤ ¤name¤, late since ¤due¤\n";
|
|
||||||
$message_template = <<<EOF
|
|
||||||
Hej ¤name¤
|
|
||||||
|
|
||||||
Vi vill påminna dig om att ditt lån har gått ut på följande ¤product_sv¤:
|
private function make_reminder_subject($num_expiring, $num_expired) {
|
||||||
|
$subject = $this->subject_prefix;
|
||||||
|
$messages = array();
|
||||||
|
if($num_expiring > 0) {
|
||||||
|
$messages[] = $num_expiring." utgående";
|
||||||
|
}
|
||||||
|
if($num_expired > 1) {
|
||||||
|
$messages[] = $num_expired." försenade";
|
||||||
|
} elseif($num_expired > 0) {
|
||||||
|
$messages[] = $num_expired." försenat";
|
||||||
|
}
|
||||||
|
return $subject.implode(" och ", $messages)." lån";
|
||||||
|
}
|
||||||
|
|
||||||
¤list_sv¤
|
private function make_notice($lang, $type, $list) {
|
||||||
|
if(!$list) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if(!array_key_exists($lang, $this->strings)) {
|
||||||
|
throw new Exception("Invalid languange: $lang");
|
||||||
|
}
|
||||||
|
$strings = $this->strings[$lang];
|
||||||
|
if(!array_key_exists($type, $strings)) {
|
||||||
|
throw new Exception("Invalid type: $type");
|
||||||
|
}
|
||||||
|
$strings = $strings[$type];
|
||||||
|
|
||||||
Vänligen återlämna ¤it_sv¤ till Helpdesk så snart som möjligt, alternativt svara på det här meddelandet för att förlänga ¤loan_sv¤.
|
$lines = array();
|
||||||
|
foreach($list as $loan) {
|
||||||
|
$product = $loan->get_product();
|
||||||
|
$serial = $product->get_serial();
|
||||||
|
$brand = $product->get_brand();
|
||||||
|
$name = $product->get_name();
|
||||||
|
$endtime = format_date($loan->get_endtime());
|
||||||
|
|
||||||
|
$lines[] = "$brand $name, ".$strings['serial']
|
||||||
|
." $serial, ".$strings['expiry']." $endtime";
|
||||||
|
}
|
||||||
|
|
||||||
|
$msg = $strings['single'];
|
||||||
|
if(count($list) > 1) {
|
||||||
|
$msg = $strings['multi'];
|
||||||
|
}
|
||||||
|
return $msg."\n\n".implode("\n", $lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function make_return_info($lang, $count) {
|
||||||
|
switch($lang) {
|
||||||
|
case 'sv':
|
||||||
|
if($count > 1) {
|
||||||
|
$loan = "lånen";
|
||||||
|
$product = "artiklarna";
|
||||||
|
} else {
|
||||||
|
$loan = "lånet";
|
||||||
|
$product = "artikeln";
|
||||||
|
}
|
||||||
|
return "Vänligen kontakta Helpdesk för att förlänga $loan eller lämna tillbaka $product.";
|
||||||
|
break;
|
||||||
|
case 'en':
|
||||||
|
if($count > 1) {
|
||||||
|
$loan = "loans";
|
||||||
|
$product = "items";
|
||||||
|
} else {
|
||||||
|
$loan = "loan";
|
||||||
|
$product = "item";
|
||||||
|
}
|
||||||
|
return "Please contact Helpdesk in order to extend the $loan or return the $product.";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Invalid language: ".$lang);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function send_reminder($user, $expiring, $overdue) {
|
||||||
|
$uid = $user->get_name();
|
||||||
|
$name = $this->ldap->get_firstname($uid);
|
||||||
|
|
||||||
|
$expiring_count = count($expiring);
|
||||||
|
$overdue_count = count($overdue);
|
||||||
|
$total = $expiring_count + $overdue_count;
|
||||||
|
|
||||||
|
$subject = $this->make_reminder_subject($expiring_count,
|
||||||
|
$overdue_count);
|
||||||
|
|
||||||
|
$info_sv = array();
|
||||||
|
$info_en = array();
|
||||||
|
if($expiring_count > 0) {
|
||||||
|
$info_sv[] = $this->make_notice('sv', 'expiring', $expiring);
|
||||||
|
$info_en[] = $this->make_notice('en', 'expiring', $expiring);
|
||||||
|
}
|
||||||
|
if($overdue_count > 0) {
|
||||||
|
$info_sv[] = $this->make_notice('sv', 'overdue', $overdue);
|
||||||
|
$info_en[] = $this->make_notice('en', 'overdue', $overdue);
|
||||||
|
}
|
||||||
|
$info_sv = implode("\n\n", $info_sv);
|
||||||
|
$returns_sv = $this->make_return_info('sv', $total);
|
||||||
|
|
||||||
|
$info_en = implode("\n\n", $info_en);
|
||||||
|
$returns_en = $this->make_return_info('en', $total);
|
||||||
|
|
||||||
|
$message = <<<EOF
|
||||||
|
Hej $name!
|
||||||
|
|
||||||
|
Det här är en automatisk påminnelse om lånade artiklar från Helpdesk.
|
||||||
|
|
||||||
|
$info_sv
|
||||||
|
|
||||||
|
$returns_sv
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
We would like to remind you that your loan has expired on the following ¤product_en¤:
|
This is an automated reminder regarding items on loan from Helpdesk.
|
||||||
|
|
||||||
¤list_en¤
|
$info_en
|
||||||
|
|
||||||
Please return ¤it_en¤ to the Helpdesk as soon as possible, or reply to this message in order to extend the ¤loan_en¤.
|
$returns_en
|
||||||
|
|
||||||
Mvh
|
Mvh
|
||||||
DSV Helpdesk
|
DSV Helpdesk
|
||||||
helpdesk@dsv.su.se
|
helpdesk@dsv.su.se
|
||||||
08 - 16 16 48
|
08 - 16 16 48
|
||||||
|
|
||||||
EOF;
|
EOF;
|
||||||
|
$this->send_email($uid, $subject, $message);
|
||||||
|
}
|
||||||
|
|
||||||
$overdue_count = count($loans);
|
private function send_email($uid, $subject, $message) {
|
||||||
$reminder_list_sv = '';
|
|
||||||
$reminder_list_en = '';
|
|
||||||
$late = 'försenat';
|
|
||||||
$product_sv = 'artikel';
|
|
||||||
$product_en = 'product';
|
|
||||||
$it_sv = 'den';
|
|
||||||
$it_en = 'it';
|
|
||||||
$loan_sv = 'lånet';
|
|
||||||
$loan_en = 'loan';
|
|
||||||
if($overdue_count > 1) {
|
|
||||||
$late = 'försenade';
|
|
||||||
$product_sv = 'artiklar';
|
|
||||||
$product_en = 'products';
|
|
||||||
$it_sv = 'dem';
|
|
||||||
$it_en = 'them';
|
|
||||||
$loan_sv = 'lånen';
|
|
||||||
$loan_en = 'loans';
|
|
||||||
}
|
|
||||||
foreach($loans as $loan) {
|
|
||||||
$replacements = array('name' => $loan->get_product()->get_name(),
|
|
||||||
'brand' => $loan->get_product()->get_brand(),
|
|
||||||
'due' => format_date($loan->get_endtime()));
|
|
||||||
$reminder_list_sv .= replace($replacements, $reminder_template_sv);
|
|
||||||
$reminder_list_en .= replace($replacements, $reminder_template_en);
|
|
||||||
}
|
|
||||||
|
|
||||||
$subject = replace(array('count' => $overdue_count,
|
|
||||||
'late' => $late), $subject_template);
|
|
||||||
$message = replace(array('name' => $user->get_displayname(),
|
|
||||||
'list_sv' => $reminder_list_sv,
|
|
||||||
'product_sv' => $product_sv,
|
|
||||||
'it_sv' => $it_sv,
|
|
||||||
'loan_sv' => $loan_sv,
|
|
||||||
'list_en' => $reminder_list_en,
|
|
||||||
'product_en' => $product_en,
|
|
||||||
'it_en' => $it_en,
|
|
||||||
'loan_en' => $loan_en),
|
|
||||||
$message_template);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mb_send_mail($user->get_email(),
|
mb_send_mail($this->ldap->get_user_email($uid),
|
||||||
$subject,
|
$subject,
|
||||||
$message,
|
$message,
|
||||||
'From: '.$this->sender);
|
'From: '.$this->sender);
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
|
error_log($e->getMessage());
|
||||||
mb_send_mail($this->error,
|
mb_send_mail($this->error,
|
||||||
"Kunde inte skicka påminnelse",
|
"Kunde inte skicka mail",
|
||||||
"Påminnelse kunde inte skickas till "
|
"Mail kunde inte skickas till ".$uid);
|
||||||
.$user->get_name());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
class Entity {
|
abstract class Entity {
|
||||||
protected function __construct() {
|
protected function __construct() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function specify_search($searchterms, $searchfields) {
|
abstract public function matches($term, $ldap);
|
||||||
if(array_key_exists('fritext', $searchterms)) {
|
|
||||||
$freeterm = $searchterms['fritext'];
|
|
||||||
unset($searchterms['fritext']);
|
|
||||||
foreach($searchfields as $field) {
|
|
||||||
if(array_key_exists($field, $searchterms)) {
|
|
||||||
$term = $searchterms[$field];
|
|
||||||
if(is_array($term)) {
|
|
||||||
$term[] = $freeterm;
|
|
||||||
} else {
|
|
||||||
$searchterms[$field] = array($term, $freeterm);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$searchterms[$field] = $freeterm;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $searchterms;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -44,7 +44,7 @@ class Event {
|
|||||||
$event_id = $insert->insert_id;
|
$event_id = $insert->insert_id;
|
||||||
return new Event($event_id);
|
return new Event($event_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($id) {
|
public function __construct($id) {
|
||||||
$search = prepare('select `id` from `event`
|
$search = prepare('select `id` from `event`
|
||||||
where `id`=?');
|
where `id`=?');
|
||||||
@ -57,7 +57,7 @@ class Event {
|
|||||||
$this->id = $result['id'];
|
$this->id = $result['id'];
|
||||||
$this->update_fields();
|
$this->update_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function update_fields() {
|
protected function update_fields() {
|
||||||
$get = prepare('select * from `event` where `id`=?');
|
$get = prepare('select * from `event` where `id`=?');
|
||||||
bind($get, 'i', $this->id);
|
bind($get, 'i', $this->id);
|
||||||
@ -83,7 +83,7 @@ class Event {
|
|||||||
public function get_returntime() {
|
public function get_returntime() {
|
||||||
return $this->returntime;
|
return $this->returntime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function is_active() {
|
public function is_active() {
|
||||||
if($this->returntime === null) {
|
if($this->returntime === null) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -16,11 +16,11 @@ class Kvs {
|
|||||||
return array_keys($this->items);
|
return array_keys($this->items);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_value($key) {
|
public function get_value($key, $default=null) {
|
||||||
if(isset($this->items[$key])) {
|
if(isset($this->items[$key])) {
|
||||||
return $this->items[$key];
|
return $this->items[$key];
|
||||||
}
|
}
|
||||||
return null;
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set_key($key, $value) {
|
public function set_key($key, $value) {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
class Ldap {
|
class Ldap {
|
||||||
private $conn;
|
private $conn;
|
||||||
private $base_dn = "dc=su,dc=se";
|
private $base_dn = "dc=su,dc=se";
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->conn = ldap_connect('ldaps://ldap.su.se');
|
$this->conn = ldap_connect('ldaps://ldap.su.se');
|
||||||
ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
ldap_set_option($this->conn, LDAP_OPT_PROTOCOL_VERSION, 3);
|
||||||
@ -13,32 +13,36 @@ class Ldap {
|
|||||||
$result = ldap_search($this->conn, $this->base_dn, $term, $attributes);
|
$result = ldap_search($this->conn, $this->base_dn, $term, $attributes);
|
||||||
return ldap_get_entries($this->conn, $result);
|
return ldap_get_entries($this->conn, $result);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_user($uid) {
|
public function get_attribute($uid, $attribute) {
|
||||||
$data = $this->search("uid=$uid", 'cn', 'uid');
|
$data = $this->search("uid=$uid", $attribute);
|
||||||
if($data['count'] !== 1) {
|
if($data['count'] !== 1) {
|
||||||
throw new Exception("LDAP search for '$uid' did not return exactly one result");
|
$err = "LDAP search for '$uid' did not return exactly one result";
|
||||||
|
throw new Exception($err);
|
||||||
}
|
}
|
||||||
return $data[0]['cn'][0];
|
return $data[0][strtolower($attribute)][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_user($uid) {
|
||||||
|
return $this->get_attribute($uid, 'cn');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_firstname($uid) {
|
||||||
|
return $this->get_attribute($uid, 'givenName');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_user_email($uid) {
|
public function get_user_email($uid) {
|
||||||
$data = $this->search("uid=$uid", 'mail', 'uid');
|
return $this->get_attribute($uid, 'mail');
|
||||||
if($data['count'] !== 1) {
|
|
||||||
throw new Exception("LDAP search for '$uid' did not return exactly one result");
|
|
||||||
}
|
|
||||||
return $data[0]['mail'][0];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function search_user($uid) {
|
public function search_email($email) {
|
||||||
$data = $this->search("uid=$uid", 'cn', 'uid');
|
$data = $this->search("mail=$email", 'mail', 'uid');
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach($data as $result) {
|
if($data['count'] !== 1) {
|
||||||
if(isset($result['uid'])) {
|
$err = "LDAP search for '$email' did not return exactly one result.";
|
||||||
$out[$result['uid'][0]] = $result['cn'][0];
|
throw new Exception($err);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return $out;
|
return $data[0]['uid'][0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -12,10 +12,12 @@ class Loan extends Event {
|
|||||||
$endtime .= '13:00';
|
$endtime .= '13:00';
|
||||||
bind($insert, 'iii', $event_id, $user->get_id(), strtotime($endtime));
|
bind($insert, 'iii', $event_id, $user->get_id(), strtotime($endtime));
|
||||||
execute($insert);
|
execute($insert);
|
||||||
|
$loan = new Loan($event_id);
|
||||||
|
$loan->queue_receipt($user);
|
||||||
commit_trans();
|
commit_trans();
|
||||||
return new Loan($event_id);
|
return $loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function __construct($id) {
|
public function __construct($id) {
|
||||||
parent::__construct($id);
|
parent::__construct($id);
|
||||||
$search = prepare('select * from `loan` where `event`=?');
|
$search = prepare('select * from `loan` where `event`=?');
|
||||||
@ -27,17 +29,40 @@ class Loan extends Event {
|
|||||||
}
|
}
|
||||||
$this->update_fields();
|
$this->update_fields();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function update_fields() {
|
protected function update_fields() {
|
||||||
parent::update_fields();
|
parent::update_fields();
|
||||||
$get = prepare('select * from `loan` where `event`=?');
|
$get = prepare('select * from `loan` where `event`=?');
|
||||||
bind($get, 'i', $this->id);
|
bind($get, 'i', $this->get_id());
|
||||||
execute($get);
|
execute($get);
|
||||||
$loan = result_single($get);
|
$loan = result_single($get);
|
||||||
$this->user = $loan['user'];
|
$this->user = $loan['user'];
|
||||||
$this->endtime = $loan['endtime'];
|
$this->endtime = $loan['endtime'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function queue_receipt($user) {
|
||||||
|
$now = time();
|
||||||
|
$sendtime = $now + 3600;
|
||||||
|
$pending = prepare('select * from `pending_receipt` where `user` = ?
|
||||||
|
and `since_time` < ? and `send_time` > ?');
|
||||||
|
bind($pending, 'iii', $user->get_id(), $now, $now);
|
||||||
|
execute($pending);
|
||||||
|
$result = result_single($pending);
|
||||||
|
if($result === null) {
|
||||||
|
$add = prepare('insert into `pending_receipt`
|
||||||
|
(`user`, `since_time`, `send_time`)
|
||||||
|
values(?, ?, ?)');
|
||||||
|
bind($add, 'iii', $user->get_id(), $now, $sendtime);
|
||||||
|
execute($add);
|
||||||
|
} else {
|
||||||
|
$update = prepare('update `pending_receipt` set `send_time` = ?
|
||||||
|
where `user` = ? and `since_time` < ?
|
||||||
|
and `send_time` > ?');
|
||||||
|
bind($update, 'iiii', $sendtime, $user->get_id(), $now, $now);
|
||||||
|
execute($update);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function get_user() {
|
public function get_user() {
|
||||||
return new User($this->user);
|
return new User($this->user);
|
||||||
}
|
}
|
||||||
@ -47,18 +72,40 @@ class Loan extends Event {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function extend($time) {
|
public function extend($time) {
|
||||||
|
$oldend = $this->get_endtime();
|
||||||
|
$now = time();
|
||||||
$ts = strtotime($time . ' 13:00');
|
$ts = strtotime($time . ' 13:00');
|
||||||
$query = prepare('update `loan` set `endtime`=? where `event`=?');
|
|
||||||
bind($query, 'ii', $ts, $this->id);
|
begin_trans();
|
||||||
execute($query);
|
$extend = prepare('update `loan` set `endtime`=? where `event`=?');
|
||||||
|
bind($extend, 'ii', $ts, $this->get_id());
|
||||||
|
execute($extend);
|
||||||
|
|
||||||
|
$log = prepare('insert into `loan_extension`
|
||||||
|
(`loan`, `extend_time`, `old_end`, `new_end`)
|
||||||
|
values (?, ?, ?, ?)');
|
||||||
|
bind($log, 'iiii', $this->get_id(), $now, $oldend, $ts);
|
||||||
|
execute($log);
|
||||||
|
|
||||||
|
$this->queue_receipt($this->get_user());
|
||||||
|
|
||||||
$this->endtime = $ts;
|
$this->endtime = $ts;
|
||||||
|
commit_trans();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_last_extension() {
|
||||||
|
$select = prepare('select max(`extend_time`) as `extend_time`
|
||||||
|
from `loan_extension` where `loan`=?');
|
||||||
|
bind($select, 'i', $this->get_id());
|
||||||
|
execute($select);
|
||||||
|
return result_single($select)['extend_time'];
|
||||||
|
}
|
||||||
|
|
||||||
public function end() {
|
public function end() {
|
||||||
$now = time();
|
$now = time();
|
||||||
$query = prepare('update `event` set `returntime`=? where `id`=?');
|
$query = prepare('update `event` set `returntime`=? where `id`=?');
|
||||||
bind($query, 'ii', $now, $this->id);
|
bind($query, 'ii', $now, $this->get_id());
|
||||||
execute($query);
|
execute($query);
|
||||||
$this->returntime = $now;
|
$this->returntime = $now;
|
||||||
return true;
|
return true;
|
||||||
@ -75,6 +122,18 @@ class Loan extends Event {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function expires_before($datetime) {
|
||||||
|
if($this->returntime !== null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$endtime = new DateTime();
|
||||||
|
$endtime->setTimestamp($this->endtime);
|
||||||
|
if(!$this->is_overdue() && $endtime < $datetime) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function get_status() {
|
public function get_status() {
|
||||||
if($this->is_overdue()) {
|
if($this->is_overdue()) {
|
||||||
return 'overdue_loan';
|
return 'overdue_loan';
|
||||||
|
@ -49,7 +49,7 @@ class NewPage extends Page {
|
|||||||
'info' => $fields,
|
'info' => $fields,
|
||||||
'label' => '',
|
'label' => '',
|
||||||
'hidden' => 'hidden'),
|
'hidden' => 'hidden'),
|
||||||
$this->fragments['product_details']);
|
$this->fragments['product_form']);
|
||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
126
include/Page.php
126
include/Page.php
@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
abstract class Page extends Responder {
|
abstract class Page extends Responder {
|
||||||
protected abstract function render_body();
|
protected abstract function render_body();
|
||||||
|
|
||||||
protected $page = 'checkout';
|
protected $page = 'checkout';
|
||||||
protected $title = "DSV Utlåning";
|
protected $title = "DSV Utlåning";
|
||||||
protected $subtitle = '';
|
protected $subtitle = '';
|
||||||
@ -15,11 +15,11 @@ abstract class Page extends Responder {
|
|||||||
'history' => 'Historik',
|
'history' => 'Historik',
|
||||||
'search' => 'Sök');
|
'search' => 'Sök');
|
||||||
private $template_parts = array();
|
private $template_parts = array();
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->template_parts = get_fragments('./html/base.html');
|
$this->template_parts = get_fragments('./html/base.html');
|
||||||
|
|
||||||
if(isset($_GET['page'])) {
|
if(isset($_GET['page'])) {
|
||||||
$this->page = $_GET['page'];
|
$this->page = $_GET['page'];
|
||||||
}
|
}
|
||||||
@ -27,7 +27,7 @@ abstract class Page extends Responder {
|
|||||||
$this->subtitle = $this->menuitems[$this->page];
|
$this->subtitle = $this->menuitems[$this->page];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
$this->render_head();
|
$this->render_head();
|
||||||
$this->render_body();
|
$this->render_body();
|
||||||
@ -36,7 +36,7 @@ abstract class Page extends Responder {
|
|||||||
}
|
}
|
||||||
$this->render_foot();
|
$this->render_foot();
|
||||||
}
|
}
|
||||||
|
|
||||||
final private function render_head() {
|
final private function render_head() {
|
||||||
$headtitle = $this->title;
|
$headtitle = $this->title;
|
||||||
$pagetitle = $this->title;
|
$pagetitle = $this->title;
|
||||||
@ -83,7 +83,7 @@ abstract class Page extends Responder {
|
|||||||
'message' => $this->error),
|
'message' => $this->error),
|
||||||
$this->fragments['message']));
|
$this->fragments['message']));
|
||||||
}
|
}
|
||||||
|
|
||||||
final private function render_foot() {
|
final private function render_foot() {
|
||||||
print($this->template_parts['foot']);
|
print($this->template_parts['foot']);
|
||||||
}
|
}
|
||||||
@ -103,7 +103,7 @@ abstract class Page extends Responder {
|
|||||||
$replacements['has_notes'] = '*';
|
$replacements['has_notes'] = '*';
|
||||||
}
|
}
|
||||||
$userlink = replace(array('id' => $user->get_id(),
|
$userlink = replace(array('id' => $user->get_id(),
|
||||||
'name' => $user->get_displayname(),
|
'name' => $user->get_displayname($this->ldap),
|
||||||
'page' => 'users'),
|
'page' => 'users'),
|
||||||
$this->fragments['item_link']);
|
$this->fragments['item_link']);
|
||||||
$replacements['item_link'] = $userlink;
|
$replacements['item_link'] = $userlink;
|
||||||
@ -131,50 +131,75 @@ abstract class Page extends Responder {
|
|||||||
final protected function build_product_table($products) {
|
final protected function build_product_table($products) {
|
||||||
$rows = '';
|
$rows = '';
|
||||||
foreach($products as $product) {
|
foreach($products as $product) {
|
||||||
$prodlink = replace(array('id' => $product->get_id(),
|
$rows .= $this->build_product_row($product);
|
||||||
'name' => $product->get_name(),
|
|
||||||
'page' => 'products'),
|
|
||||||
$this->fragments['item_link']);
|
|
||||||
$note = 'Tillgänglig';
|
|
||||||
$status = $product->get_status();
|
|
||||||
switch($status) {
|
|
||||||
case 'discarded':
|
|
||||||
$discarded = format_date($product->get_discardtime());
|
|
||||||
$note = 'Skrotad '.$discarded;
|
|
||||||
break;
|
|
||||||
case 'service':
|
|
||||||
$service = $product->get_active_service();
|
|
||||||
$note = 'På service sedan '
|
|
||||||
.format_date($service->get_starttime());
|
|
||||||
break;
|
|
||||||
case 'on_loan':
|
|
||||||
case 'overdue':
|
|
||||||
$loan = $product->get_active_loan();
|
|
||||||
$user = $loan->get_user();
|
|
||||||
$replacements = array('name' => $user->get_displayname(),
|
|
||||||
'id' => $user->get_id(),
|
|
||||||
'page' => 'users');
|
|
||||||
$userlink = replace($replacements,
|
|
||||||
$this->fragments['item_link']);
|
|
||||||
$note = 'Utlånad till '.$userlink;
|
|
||||||
if($loan->is_overdue()) {
|
|
||||||
$note .= ', försenad';
|
|
||||||
} else {
|
|
||||||
$note .= ', slutdatum '
|
|
||||||
.format_date($loan->get_endtime());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
$rows .= replace(array('status' => $status,
|
|
||||||
'item_link' => $prodlink,
|
|
||||||
'serial' => $product->get_serial(),
|
|
||||||
'note' => $note),
|
|
||||||
$this->fragments['product_row']);
|
|
||||||
}
|
}
|
||||||
return replace(array('rows' => $rows),
|
return replace(array('rows' => $rows,
|
||||||
|
'type' => 'single'),
|
||||||
$this->fragments['product_table']);
|
$this->fragments['product_table']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final protected function build_product_row($product, $matches = null) {
|
||||||
|
$prodlink = replace(array('id' => $product->get_id(),
|
||||||
|
'name' => $product->get_name(),
|
||||||
|
'page' => 'products'),
|
||||||
|
$this->fragments['item_link']);
|
||||||
|
$note = 'Tillgänglig';
|
||||||
|
$status = $product->get_status();
|
||||||
|
switch($status) {
|
||||||
|
case 'discarded':
|
||||||
|
$discarded = format_date($product->get_discardtime());
|
||||||
|
$note = 'Skrotad '.$discarded;
|
||||||
|
break;
|
||||||
|
case 'service':
|
||||||
|
$service = $product->get_active_service();
|
||||||
|
$note = 'På service sedan '
|
||||||
|
.format_date($service->get_starttime());
|
||||||
|
break;
|
||||||
|
case 'on_loan':
|
||||||
|
case 'overdue':
|
||||||
|
$loan = $product->get_active_loan();
|
||||||
|
$user = $loan->get_user();
|
||||||
|
$replacements = array('name' => $user->get_displayname($this->ldap),
|
||||||
|
'id' => $user->get_id(),
|
||||||
|
'page' => 'users');
|
||||||
|
$userlink = replace($replacements,
|
||||||
|
$this->fragments['item_link']);
|
||||||
|
$note = 'Utlånad till '.$userlink;
|
||||||
|
if($loan->is_overdue()) {
|
||||||
|
$note .= ', försenad';
|
||||||
|
} else {
|
||||||
|
$note .= ', slutdatum '
|
||||||
|
.format_date($loan->get_endtime());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$out = replace(array('status' => $status,
|
||||||
|
'item_link' => $prodlink,
|
||||||
|
'serial' => $product->get_serial(),
|
||||||
|
'note' => $note),
|
||||||
|
$this->fragments['product_row']);
|
||||||
|
if($matches) {
|
||||||
|
$details = $this->build_product_details($product, $matches);
|
||||||
|
$out .= replace(array('status' => $status,
|
||||||
|
'details' => $details),
|
||||||
|
$this->fragments['product_detail_row']);
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function build_product_details($product, $matches) {
|
||||||
|
$out = '';
|
||||||
|
foreach($matches as $name => $value) {
|
||||||
|
if(is_array($value)) {
|
||||||
|
$value = implode(', ', $value);
|
||||||
|
}
|
||||||
|
$out .= replace(array('name' => $product->get_label($name),
|
||||||
|
'value' => $value),
|
||||||
|
$this->fragments['product_detail']);
|
||||||
|
}
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
final protected function build_user_loan_table($loans) {
|
final protected function build_user_loan_table($loans) {
|
||||||
$rows = '';
|
$rows = '';
|
||||||
foreach($loans as $loan) {
|
foreach($loans as $loan) {
|
||||||
@ -186,7 +211,7 @@ abstract class Page extends Responder {
|
|||||||
$status = $loan->get_status();
|
$status = $loan->get_status();
|
||||||
$note = '';
|
$note = '';
|
||||||
if($status !== 'inactive_loan') {
|
if($status !== 'inactive_loan') {
|
||||||
$extend = format_date(default_loan_end(time()));
|
$extend = format_date($loan->get_endtime());
|
||||||
$note = replace(array('id' => $product->get_id(),
|
$note = replace(array('id' => $product->get_id(),
|
||||||
'end_new' => $extend),
|
'end_new' => $extend),
|
||||||
$this->fragments['loan_extend_form']);
|
$this->fragments['loan_extend_form']);
|
||||||
@ -237,7 +262,7 @@ abstract class Page extends Responder {
|
|||||||
}
|
}
|
||||||
} else if($event instanceof Loan) {
|
} else if($event instanceof Loan) {
|
||||||
$user = $event->get_user();
|
$user = $event->get_user();
|
||||||
$userlink = replace(array('name' => $user->get_displayname(),
|
$userlink = replace(array('name' => $user->get_displayname($this->ldap),
|
||||||
'id' => $user->get_id(),
|
'id' => $user->get_id(),
|
||||||
'page' => 'users'),
|
'page' => 'users'),
|
||||||
$this->fragments['item_link']);
|
$this->fragments['item_link']);
|
||||||
@ -260,7 +285,8 @@ abstract class Page extends Responder {
|
|||||||
'note' => $note),
|
'note' => $note),
|
||||||
$this->fragments['product_row']);
|
$this->fragments['product_row']);
|
||||||
}
|
}
|
||||||
return replace(array('rows' => $rows),
|
return replace(array('rows' => $rows,
|
||||||
|
'type' => 'single'),
|
||||||
$this->fragments['product_table']);
|
$this->fragments['product_table']);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -68,6 +68,13 @@ class Product extends Entity {
|
|||||||
$this->update_fields();
|
$this->update_fields();
|
||||||
$this->update_info();
|
$this->update_info();
|
||||||
$this->update_tags();
|
$this->update_tags();
|
||||||
|
|
||||||
|
# Global variables are bad, but passing these email properties
|
||||||
|
# around everywhere would be worse
|
||||||
|
global $sender, $notify_discard, $email_subject_prefix;
|
||||||
|
$this->discard_email_address = $notify_discard;
|
||||||
|
$this->email_sender = $sender;
|
||||||
|
$this->email_subject_prefix = $email_subject_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update_fields() {
|
private function update_fields() {
|
||||||
@ -110,34 +117,108 @@ class Product extends Entity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function matches($terms, $matchAll=false) {
|
/*
|
||||||
$terms = $this->specify_search($terms, array('brand',
|
Return a list of field-value mappings containing all matching search terms.
|
||||||
'name',
|
*/
|
||||||
'serial',
|
public function matches($terms, $ldap) {
|
||||||
'invoice',
|
|
||||||
'status',
|
|
||||||
'tag'));
|
|
||||||
$matches = array();
|
$matches = array();
|
||||||
foreach($terms as $field => $values) {
|
|
||||||
if(property_exists($this, $field)) {
|
// Create a list mapping all basic fields to getters
|
||||||
if(match($values, $this->$field)) {
|
$fields = array('brand' => 'get_brand',
|
||||||
$matches[$field] = $this->$field;
|
'name' => 'get_name',
|
||||||
}
|
'invoice' => 'get_invoice',
|
||||||
} else if(array_key_exists($field, $this->get_info())) {
|
'serial' => 'get_serial',
|
||||||
if(match($values, $this->get_info()[$field])) {
|
'status' => 'get_status');
|
||||||
$matches[$field] = $this->get_info()[$field];
|
|
||||||
}
|
foreach($terms as $term) {
|
||||||
} else if($field == 'tag') {
|
$key = $term->get_key();
|
||||||
foreach($this->get_tags() as $tag) {
|
$matched = false;
|
||||||
if(match($values, $tag)) {
|
switch($key) {
|
||||||
$matches['tags'] = $this->get_tags();
|
case 'brand':
|
||||||
break;
|
case 'name':
|
||||||
|
case 'invoice':
|
||||||
|
case 'serial':
|
||||||
|
case 'status':
|
||||||
|
// If $key is a standard field, check against its value
|
||||||
|
$getter = $fields[$key];
|
||||||
|
$value = $this->$getter();
|
||||||
|
if(match($term, $value)) {
|
||||||
|
//Record a successful match
|
||||||
|
$matches[$key] = $value;
|
||||||
|
$matched = true;
|
||||||
}
|
}
|
||||||
}
|
break;
|
||||||
} else if($field == 'status') {
|
case 'tag':
|
||||||
if(match($values, $this->get_status())) {
|
// If $key is tag, iterate over the tags
|
||||||
$matches['status'] = $this->get_status();
|
$matched_tags = $this->match_tags($term);
|
||||||
}
|
if($matched_tags) {
|
||||||
|
// Record a successful match
|
||||||
|
$matched = true;
|
||||||
|
if(!isset($matches['tags'])) {
|
||||||
|
// This is the first list of matching tags
|
||||||
|
$matches['tags'] = $matched_tags;
|
||||||
|
} else {
|
||||||
|
// Merge these results with existing results
|
||||||
|
$matches['tags'] = array_unique(
|
||||||
|
array_merge($matches['tags'],
|
||||||
|
$matched_tags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'fritext':
|
||||||
|
// if $key is fritext:
|
||||||
|
// First check basic fields
|
||||||
|
foreach($fields as $field => $getter) {
|
||||||
|
$value = $this->$getter();
|
||||||
|
if(match($term, $value)) {
|
||||||
|
$matches[$field] = $value;
|
||||||
|
$matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then tags
|
||||||
|
$matched_tags = $this->match_tags($term);
|
||||||
|
if($matched_tags) {
|
||||||
|
$matched = true;
|
||||||
|
if(!isset($matches['tags'])) {
|
||||||
|
$matches['tags'] = $matched_tags;
|
||||||
|
} else {
|
||||||
|
$matches['tags'] = array_unique(
|
||||||
|
array_merge($matches['tags'],
|
||||||
|
$matched_tags));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Then custom fields
|
||||||
|
foreach($this->get_info() as $field => $value) {
|
||||||
|
if(match($term, $value)) {
|
||||||
|
//Record a successful match
|
||||||
|
$matches[$field] = $value;
|
||||||
|
$matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Handle custom fields
|
||||||
|
$info = $this->get_info();
|
||||||
|
if(isset($info[$key])) {
|
||||||
|
// If $key is a valid custom field on this product
|
||||||
|
$value = $info[$key];
|
||||||
|
if(match($term, $value)) {
|
||||||
|
//Record a successful match
|
||||||
|
$matches[$key] = $value;
|
||||||
|
$matched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// If a mandatory match failed, the entire search has failed
|
||||||
|
// and we return an empty result.
|
||||||
|
if($term->is_mandatory() && !$matched) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
// If a negative match succeeded, the entire search has failed
|
||||||
|
// and we return an empty result.
|
||||||
|
if($term->is_negative() && $matched) {
|
||||||
|
return array();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if($matchAll && array_diff_assoc($terms, $matches)) {
|
if($matchAll && array_diff_assoc($terms, $matches)) {
|
||||||
@ -146,6 +227,40 @@ class Product extends Entity {
|
|||||||
return $matches;
|
return $matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function match_tags($term) {
|
||||||
|
$tags = $this->get_tags();
|
||||||
|
$matches = array();
|
||||||
|
foreach($tags as $tag) {
|
||||||
|
if(match($term, $tag)) {
|
||||||
|
$matches[] = $tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_label($name) {
|
||||||
|
switch($name) {
|
||||||
|
case 'brand':
|
||||||
|
return 'Tillverkare';
|
||||||
|
break;
|
||||||
|
case 'name':
|
||||||
|
return 'Namn';
|
||||||
|
break;
|
||||||
|
case 'invoice':
|
||||||
|
return 'Fakturanummer';
|
||||||
|
break;
|
||||||
|
case 'serial':
|
||||||
|
return 'Serienummer';
|
||||||
|
break;
|
||||||
|
case 'tags':
|
||||||
|
return 'Taggar';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return ucfirst($name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function get_id() {
|
public function get_id() {
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
@ -167,9 +282,42 @@ class Product extends Entity {
|
|||||||
bind($update, 'ii', $now, $this->id);
|
bind($update, 'ii', $now, $this->id);
|
||||||
execute($update);
|
execute($update);
|
||||||
$this->discardtime = $now;
|
$this->discardtime = $now;
|
||||||
|
if($this->discard_email_address) {
|
||||||
|
$this->send_discard_email();
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function send_discard_email() {
|
||||||
|
$brand = $this->brand;
|
||||||
|
$name = $this->name;
|
||||||
|
$invoice = $this->invoice;
|
||||||
|
$serial = $this->serial;
|
||||||
|
$discardtime = format_date($this->discardtime);
|
||||||
|
|
||||||
|
$subject = $this->email_subject_prefix.$brand.' '.$name.' skrotad';
|
||||||
|
$message = <<<EOF
|
||||||
|
Hej!
|
||||||
|
|
||||||
|
Följande artikel har skrotats i Boka:
|
||||||
|
|
||||||
|
$brand $name, serienummer: $serial, fakturanummer: $invoice
|
||||||
|
|
||||||
|
EOF;
|
||||||
|
try {
|
||||||
|
mb_send_mail($this->discard_email_address,
|
||||||
|
$subject,
|
||||||
|
$message,
|
||||||
|
'From: '.$this->email_sender);
|
||||||
|
} catch(Exception $e) {
|
||||||
|
error_log($e->getMessage());
|
||||||
|
mb_send_mail($this->error,
|
||||||
|
"Kunde inte skicka mail",
|
||||||
|
"Mail kunde inte skickas till "
|
||||||
|
. $this->discard_email_address);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function toggle_service() {
|
public function toggle_service() {
|
||||||
$status = $this->get_status();
|
$status = $this->get_status();
|
||||||
$now = time();
|
$now = time();
|
||||||
|
@ -38,12 +38,12 @@ class ProductPage extends Page {
|
|||||||
$this->fragments['product_page']));
|
$this->fragments['product_page']));
|
||||||
break;
|
break;
|
||||||
case 'show':
|
case 'show':
|
||||||
print($this->build_product_details());
|
print($this->build_product_form());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function build_product_details() {
|
private function build_product_form() {
|
||||||
$info = '';
|
$info = '';
|
||||||
foreach($this->product->get_info() as $key => $value) {
|
foreach($this->product->get_info() as $key => $value) {
|
||||||
$info .= replace(array('name' => ucfirst($key),
|
$info .= replace(array('name' => ucfirst($key),
|
||||||
@ -67,21 +67,29 @@ class ProductPage extends Page {
|
|||||||
'tags' => $tags,
|
'tags' => $tags,
|
||||||
'info' => $info,
|
'info' => $info,
|
||||||
'label' => '',
|
'label' => '',
|
||||||
'hidden' => 'hidden',
|
'label_hidden' => 'hidden',
|
||||||
|
'checkout_hidden' => 'hidden',
|
||||||
|
'hidden' => '',
|
||||||
'service' => 'Starta service',
|
'service' => 'Starta service',
|
||||||
'history' => $history,
|
'history' => $history,
|
||||||
'attachments' => $attachments);
|
'attachments' => $attachments,
|
||||||
|
'end' => format_date(default_loan_end(time())));
|
||||||
if(class_exists('QRcode')) {
|
if(class_exists('QRcode')) {
|
||||||
$fields['label'] = replace($fields,
|
$fields['label'] = replace($fields,
|
||||||
$this->fragments['product_label']);
|
$this->fragments['product_label']);
|
||||||
}
|
}
|
||||||
if(!$this->product->get_discardtime()) {
|
if(!$this->product->get_discardtime()) {
|
||||||
$fields['hidden'] = '';
|
$fields['label_hidden'] = '';
|
||||||
if($this->product->get_status() == 'service') {
|
if($this->product->get_status() == 'service') {
|
||||||
$fields['service'] = 'Avsluta service';
|
$fields['service'] = 'Avsluta service';
|
||||||
}
|
}
|
||||||
|
if($this->product->get_status() == 'available') {
|
||||||
|
$fields['checkout_hidden'] = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return replace($fields, $this->fragments['product_details']);
|
$out = replace($fields, $this->fragments['product_form']);
|
||||||
|
$out .= replace($fields, $this->fragments['product_meta']);
|
||||||
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function build_history_table($history) {
|
private function build_history_table($history) {
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
<?php
|
<?php
|
||||||
abstract class Responder {
|
abstract class Responder {
|
||||||
protected $fragments = array();
|
protected $fragments = array();
|
||||||
|
protected $ldap = null;
|
||||||
|
|
||||||
public function __construct() {
|
public function __construct() {
|
||||||
$this->fragments = get_fragments('./html/fragments.html');
|
$this->fragments = get_fragments('./html/fragments.html');
|
||||||
|
$this->ldap = new Ldap();
|
||||||
}
|
}
|
||||||
|
|
||||||
final protected function escape_tags($tags) {
|
final protected function escape_tags($tags) {
|
||||||
|
@ -37,16 +37,33 @@ class SearchPage extends Page {
|
|||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function search($type, $terms) {
|
||||||
|
$matches = array();
|
||||||
|
foreach(get_items($type) as $item) {
|
||||||
|
if($result = $item->matches($terms, $this->ldap)) {
|
||||||
|
$matches[] = array($item, $result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $matches;
|
||||||
|
}
|
||||||
|
|
||||||
private function translate_terms($terms) {
|
private function translate_terms($terms) {
|
||||||
$matches = array();
|
$matches = array();
|
||||||
|
|
||||||
|
// If there is a q-query
|
||||||
|
// and it contains a : character
|
||||||
if(isset($terms['q']) && preg_match('/([^:]+):(.*)/',
|
if(isset($terms['q']) && preg_match('/([^:]+):(.*)/',
|
||||||
$terms['q'],
|
$terms['q'],
|
||||||
$matches)) {
|
$matches)) {
|
||||||
|
// remove the q key
|
||||||
unset($terms['q']);
|
unset($terms['q']);
|
||||||
|
// insert the term, using whatever came before
|
||||||
|
// the : as the key and whatever came after as the value
|
||||||
$terms[$matches[1]] = $matches[2];
|
$terms[$matches[1]] = $matches[2];
|
||||||
}
|
}
|
||||||
$translated = array();
|
$translated = array();
|
||||||
foreach($terms as $key => $value) {
|
// Translate all keys into a standard format
|
||||||
|
foreach($terms as $key => $values) {
|
||||||
$newkey = $key;
|
$newkey = $key;
|
||||||
switch($key) {
|
switch($key) {
|
||||||
case 'q':
|
case 'q':
|
||||||
@ -67,17 +84,38 @@ class SearchPage extends Page {
|
|||||||
$newkey = 'serial';
|
$newkey = 'serial';
|
||||||
break;
|
break;
|
||||||
case 'tagg':
|
case 'tagg':
|
||||||
|
case 'tags':
|
||||||
$newkey = 'tag';
|
$newkey = 'tag';
|
||||||
break;
|
break;
|
||||||
|
case 'anteckning':
|
||||||
|
$newkey = 'note';
|
||||||
|
break;
|
||||||
|
case 'e-post':
|
||||||
|
case 'epost':
|
||||||
|
case 'mail':
|
||||||
|
$newkey = 'email';
|
||||||
|
break;
|
||||||
case 'status':
|
case 'status':
|
||||||
$value = $this->translate_values($value);
|
// Translate all status values into a standard format
|
||||||
|
$values = $this->translate_values($values);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(!array_key_exists($newkey, $translated)) {
|
// Wrap the value in an array if it isn't one
|
||||||
$translated[$newkey] = $value;
|
if(!is_array($values)) {
|
||||||
} else {
|
$values = array($values);
|
||||||
$temp = $translated[$newkey];
|
}
|
||||||
$translated[$newkey] = array_merge((array)$temp, (array)$value);
|
// Make a SearchTerm object from each term
|
||||||
|
foreach($values as $value) {
|
||||||
|
// Check for flags
|
||||||
|
$flag = SearchTerm::OPTIONAL;
|
||||||
|
if(in_array($value[0], array(SearchTerm::MANDATORY,
|
||||||
|
SearchTerm::OPTIONAL,
|
||||||
|
SearchTerm::NEGATIVE))) {
|
||||||
|
$flag = $value[0];
|
||||||
|
$value = substr($value, 1);
|
||||||
|
}
|
||||||
|
// Collect the new SearchTerm
|
||||||
|
$translated[] = new SearchTerm($newkey, $value, $flag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return $translated;
|
return $translated;
|
||||||
@ -127,79 +165,96 @@ class SearchPage extends Page {
|
|||||||
}
|
}
|
||||||
return $translated;
|
return $translated;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function search($type, $terms) {
|
|
||||||
$items = get_items($type);
|
|
||||||
$out = array();
|
|
||||||
foreach($items as $item) {
|
|
||||||
$result = $item->matches($terms);
|
|
||||||
if($result) {
|
|
||||||
$out[] = array($item, $result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function render_body() {
|
protected function render_body() {
|
||||||
$hidden = 'hidden';
|
$hidden = 'hidden';
|
||||||
$terms = '';
|
$terms = '';
|
||||||
if($this->terms) {
|
if($this->terms) {
|
||||||
$hidden = '';
|
$hidden = '';
|
||||||
foreach($this->terms as $key => $value) {
|
foreach($this->terms as $term) {
|
||||||
if(!is_array($value)) {
|
$key = $term->get_key();
|
||||||
$value = array($value);
|
$flag = $term->get_flag();
|
||||||
}
|
$query = $term->get_query();
|
||||||
foreach($value as $item) {
|
$fullterm = ucfirst($key).": ".$flag.$query;
|
||||||
$terms .= replace(array('term' => ucfirst($key).": $item",
|
$terms .= replace(array('term' => $fullterm,
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $item),
|
'value' => $flag.$query),
|
||||||
$this->fragments['search_term']);
|
$this->fragments['search_term']);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$products = 'Inga artiklar hittade.';
|
$prod_table = 'Inga artiklar hittade.';
|
||||||
if($this->product_hits) {
|
if($this->product_hits) {
|
||||||
$products = '';
|
$products = '';
|
||||||
foreach($this->product_hits as $hit) {
|
foreach($this->product_hits as $hit) {
|
||||||
$products .= $this->render_product($hit[0], $hit[1]);
|
$products .= $this->build_product_row($hit[0], $hit[1]);
|
||||||
}
|
}
|
||||||
|
$prod_table = replace(array('rows' => $products,
|
||||||
|
'type' => 'double'),
|
||||||
|
$this->fragments['product_table']);
|
||||||
}
|
}
|
||||||
$users = 'Inga användare hittade.';
|
$user_table = 'Inga användare hittade.';
|
||||||
if($this->user_hits) {
|
if($this->user_hits) {
|
||||||
$users = '';
|
$users = array();
|
||||||
foreach($this->user_hits as $hit) {
|
foreach($this->user_hits as $hit) {
|
||||||
$users .= $this->render_user($hit[0], $hit[1]);
|
$users[] = $hit[0];
|
||||||
}
|
}
|
||||||
|
$user_table = $this->build_user_table($users);
|
||||||
}
|
}
|
||||||
|
|
||||||
print(replace(array('terms' => $terms,
|
print(replace(array('terms' => $terms,
|
||||||
'hidden' => $hidden,
|
'hidden' => $hidden,
|
||||||
'product_results' => $products,
|
'product_results' => $prod_table,
|
||||||
'user_results' => $users),
|
'user_results' => $user_table),
|
||||||
$this->fragments['search_form']));
|
$this->fragments['search_form']));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function render_product($product, $matches) {
|
class SearchTerm {
|
||||||
$link = replace(array('id' => $product->get_id(),
|
public const MANDATORY = '+';
|
||||||
'name' => $product->get_name(),
|
public const OPTIONAL = '~';
|
||||||
'page' => 'products'),
|
public const NEGATIVE = '-';
|
||||||
$this->fragments['item_link']);
|
|
||||||
|
|
||||||
$data = print_r($matches, true);
|
private $key;
|
||||||
|
private $query;
|
||||||
return $link . '<br/>'
|
private $flag;
|
||||||
. $data . '<br/>';
|
|
||||||
|
public function __construct($key, $query, $flag=SearchTerm::OPTIONAL) {
|
||||||
|
$this->key = $key;
|
||||||
|
$this->query = $query;
|
||||||
|
$this->flag = $flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function render_user($user, $matches) {
|
public function get_key() {
|
||||||
$link = replace(array('id' => $user->get_id(),
|
return $this->key;
|
||||||
'name' => $user->get_name(),
|
}
|
||||||
'page' => 'users'),
|
|
||||||
$this->fragments['item_link']);
|
|
||||||
|
|
||||||
$data = print_r($matches, true);
|
public function get_query() {
|
||||||
|
return $this->query;
|
||||||
return $link . '<br/>'
|
}
|
||||||
. $data . '<br/>';
|
|
||||||
|
public function get_flag() {
|
||||||
|
return $this->flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function is_optional() {
|
||||||
|
if($this->flag == SearchTerm::OPTIONAL) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function is_mandatory() {
|
||||||
|
if($this->flag == SearchTerm::MANDATORY) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function is_negative() {
|
||||||
|
if($this->flag == SearchTerm::NEGATIVE) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -3,8 +3,7 @@ class User extends Entity {
|
|||||||
private $id = 0;
|
private $id = 0;
|
||||||
private $name = '';
|
private $name = '';
|
||||||
private $notes = '';
|
private $notes = '';
|
||||||
private $ldap = null;
|
|
||||||
|
|
||||||
public static function create_user($name) {
|
public static function create_user($name) {
|
||||||
$ins_user = prepare('insert into `user`(`name`) values (?)');
|
$ins_user = prepare('insert into `user`(`name`) values (?)');
|
||||||
bind($ins_user, 's', $name);
|
bind($ins_user, 's', $name);
|
||||||
@ -34,9 +33,8 @@ class User extends Entity {
|
|||||||
}
|
}
|
||||||
$this->id = $id;
|
$this->id = $id;
|
||||||
$this->update_fields();
|
$this->update_fields();
|
||||||
$this->ldap = new Ldap();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function update_fields() {
|
private function update_fields() {
|
||||||
$get = prepare('select * from `user` where `id`=?');
|
$get = prepare('select * from `user` where `id`=?');
|
||||||
bind($get, 'i', $this->id);
|
bind($get, 'i', $this->id);
|
||||||
@ -47,51 +45,75 @@ class User extends Entity {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function matches($terms, $matchAll=false) {
|
public function matches($terms, $ldap) {
|
||||||
$terms = $this->specify_search($terms, array('name',
|
|
||||||
'email',
|
|
||||||
'notes'));
|
|
||||||
$matches = array();
|
$matches = array();
|
||||||
foreach($terms as $field => $values) {
|
foreach($terms as $term) {
|
||||||
switch($field) {
|
// Iterate over the terms
|
||||||
|
$matched = false;
|
||||||
|
$key = $term->get_key();
|
||||||
|
switch($key) {
|
||||||
case 'name':
|
case 'name':
|
||||||
if(match($values, $this->name)) {
|
// If the key is name, check username and displayname
|
||||||
$matches['name'] = $this->name;
|
$name = $this->get_name();
|
||||||
|
if(match($term, $name)) {
|
||||||
|
$matches['name'] = $name;
|
||||||
|
$matched = true;
|
||||||
}
|
}
|
||||||
if(match($values, $this->get_displayname())) {
|
$dname = $this->get_displayname($ldap);
|
||||||
$matches['displayname'] = $this->get_displayname();
|
if(match($term, $dname)) {
|
||||||
|
$matches['displayname'] = $dname;
|
||||||
|
$matched = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'note':
|
||||||
|
// If the key is note, check it.
|
||||||
|
$note = $this->get_note();
|
||||||
|
if($note && match($term, $note)) {
|
||||||
|
$matches['note'] = $note;
|
||||||
|
$matched = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'email':
|
case 'email':
|
||||||
if($this->get_email(false) && match($values,
|
$email = $this->get_email($ldap, false);
|
||||||
$this->get_email())) {
|
if($email && match($term, $email)) {
|
||||||
$matches['email'] = $this->get_email();
|
$matches['email'] = $email;
|
||||||
|
$matched = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'notes':
|
case 'fritext':
|
||||||
if(match($values, $this->notes)) {
|
//Check everything if the key is fritext
|
||||||
$matches['notes'] = $this->notes;
|
$name = $this->get_name();
|
||||||
|
if(match($term, $name)) {
|
||||||
|
$matches['name'] = $name;
|
||||||
|
$matched = true;
|
||||||
|
}
|
||||||
|
$dname = $this->get_displayname($ldap);
|
||||||
|
if(match($term, $dname)) {
|
||||||
|
$matches['displayname'] = $dname;
|
||||||
|
$matched = true;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
if($term->is_mandatory() && !$matched) {
|
||||||
if($matchAll && array_diff_assoc($terms, $matches)) {
|
return array();
|
||||||
return array();
|
}
|
||||||
|
if($term->is_negative() && $matched) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return $matches;
|
return $matches;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_displayname() {
|
public function get_displayname($ldap) {
|
||||||
try {
|
try {
|
||||||
return $this->ldap->get_user($this->name);
|
return $ldap->get_user($this->name);
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
return 'Ej i SUKAT';
|
return 'Ej i SUKAT';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_email($format = true) {
|
public function get_email($ldap, $format = true) {
|
||||||
try {
|
try {
|
||||||
return $this->ldap->get_user_email($this->name);
|
return $ldap->get_user_email($this->name);
|
||||||
} catch(Exception $e) {
|
} catch(Exception $e) {
|
||||||
if($format) {
|
if($format) {
|
||||||
return 'Mailadress saknas';
|
return 'Mailadress saknas';
|
||||||
@ -103,11 +125,11 @@ class User extends Entity {
|
|||||||
public function get_id() {
|
public function get_id() {
|
||||||
return $this->id;
|
return $this->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_name() {
|
public function get_name() {
|
||||||
return $this->name;
|
return $this->name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set_name($newname) {
|
public function set_name($newname) {
|
||||||
$update = prepare('update `user` set `name`=? where `id`=?');
|
$update = prepare('update `user` set `name`=? where `id`=?');
|
||||||
bind($update, 'si', $newname, $this->id);
|
bind($update, 'si', $newname, $this->id);
|
||||||
@ -119,7 +141,7 @@ class User extends Entity {
|
|||||||
public function get_notes() {
|
public function get_notes() {
|
||||||
return $this->notes;
|
return $this->notes;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function set_notes($newnotes) {
|
public function set_notes($newnotes) {
|
||||||
$update = prepare('update `user` set `notes`=? where `id`=?');
|
$update = prepare('update `user` set `notes`=? where `id`=?');
|
||||||
bind($update, 'si', $newnotes, $this->id);
|
bind($update, 'si', $newnotes, $this->id);
|
||||||
@ -129,7 +151,7 @@ class User extends Entity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get_loans($type = 'both') {
|
public function get_loans($type = 'both') {
|
||||||
$statement = "select `id` from `event`
|
$statement = "select `id` from `event`
|
||||||
left join `loan` on `event`.`id` = `loan`.`event`
|
left join `loan` on `event`.`id` = `loan`.`event`
|
||||||
where
|
where
|
||||||
`type`='loan' and `user`=?";
|
`type`='loan' and `user`=?";
|
||||||
@ -167,5 +189,15 @@ class User extends Entity {
|
|||||||
}
|
}
|
||||||
return $overdue;
|
return $overdue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function get_expiring_loans($end_date) {
|
||||||
|
$expiring = array();
|
||||||
|
foreach($this->get_loans('active') as $loan) {
|
||||||
|
if($loan->expires_before($end_date)) {
|
||||||
|
$expiring[] = $loan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $expiring;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -56,7 +56,7 @@ class UserPage extends Page {
|
|||||||
'inactive_loans' => $table_inactive,
|
'inactive_loans' => $table_inactive,
|
||||||
'id' => $this->user->get_id(),
|
'id' => $this->user->get_id(),
|
||||||
'name' => $this->user->get_name(),
|
'name' => $this->user->get_name(),
|
||||||
'displayname' => $this->user->get_displayname(),
|
'displayname' => $this->user->get_displayname($this->ldap),
|
||||||
'notes' => $this->user->get_notes()),
|
'notes' => $this->user->get_notes()),
|
||||||
$this->fragments['user_details']);
|
$this->fragments['user_details']);
|
||||||
}
|
}
|
||||||
|
@ -253,18 +253,23 @@ function suggest_content($fieldname) {
|
|||||||
return $out;
|
return $out;
|
||||||
}
|
}
|
||||||
|
|
||||||
function match($searchterms, $subject) {
|
function match($term, $subject) {
|
||||||
if(!is_array($searchterms)) {
|
if(fnmatch('*'.$term->get_query().'*', $subject, FNM_CASEFOLD)) {
|
||||||
$searchterms = array($searchterms);
|
return true;
|
||||||
}
|
|
||||||
foreach($searchterms as $term) {
|
|
||||||
if(fnmatch('*'.$term.'*', $subject, FNM_CASEFOLD)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function match_tags($searchterm, $tags) {
|
||||||
|
$found = array();
|
||||||
|
foreach($tags as $tag) {
|
||||||
|
if(fnmatch('*'.$tag.'*', $searchterm, FNM_CASEFOLD)) {
|
||||||
|
$found[] = $tag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $found;
|
||||||
|
}
|
||||||
|
|
||||||
function format_date($date) {
|
function format_date($date) {
|
||||||
if($date) {
|
if($date) {
|
||||||
return gmdate('Y-m-d', $date);
|
return gmdate('Y-m-d', $date);
|
||||||
|
27
script.js
27
script.js
@ -97,7 +97,7 @@ function getFragment(name, callback) {
|
|||||||
console.log(result);
|
console.log(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var data = new FormData()
|
var data = new FormData()
|
||||||
data.append('fragment', name)
|
data.append('fragment', name)
|
||||||
ajaxRequest('getfragment', data, unpack)
|
ajaxRequest('getfragment', data, unpack)
|
||||||
@ -483,6 +483,7 @@ function calendar(event) {
|
|||||||
if(!input.cal) {
|
if(!input.cal) {
|
||||||
var cal = new dhtmlXCalendarObject(input.id)
|
var cal = new dhtmlXCalendarObject(input.id)
|
||||||
cal.hideTime()
|
cal.hideTime()
|
||||||
|
cal.setDate(input.value)
|
||||||
input.cal = cal
|
input.cal = cal
|
||||||
cal.show()
|
cal.show()
|
||||||
}
|
}
|
||||||
@ -573,3 +574,27 @@ function showFile(event) {
|
|||||||
var filefield = event.currentTarget.parentNode.filename
|
var filefield = event.currentTarget.parentNode.filename
|
||||||
filefield.value = event.currentTarget.files[0].name
|
filefield.value = event.currentTarget.files[0].name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loanLength(event, length, unit) {
|
||||||
|
event.preventDefault()
|
||||||
|
var end = document.getElementById('end')
|
||||||
|
var enddate = new Date()
|
||||||
|
switch(unit) {
|
||||||
|
case 'day':
|
||||||
|
enddate.setDate(enddate.getDate() + length)
|
||||||
|
break
|
||||||
|
case 'year':
|
||||||
|
enddate.setFullYear(enddate.getFullYear() + length)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// javascript zero-indexes months because of course
|
||||||
|
var month = enddate.getMonth() + 1
|
||||||
|
if(month < 10) {
|
||||||
|
month = '0' + month
|
||||||
|
}
|
||||||
|
var day = enddate.getDate()
|
||||||
|
if(day < 10) {
|
||||||
|
day = '0' + day
|
||||||
|
}
|
||||||
|
end.value = enddate.getFullYear() + '-' + month + '-' + day
|
||||||
|
}
|
||||||
|
21
style.css
21
style.css
@ -1,3 +1,7 @@
|
|||||||
|
body {
|
||||||
|
font-size: 90%;
|
||||||
|
}
|
||||||
|
|
||||||
textarea {
|
textarea {
|
||||||
height: 80px;
|
height: 80px;
|
||||||
}
|
}
|
||||||
@ -104,10 +108,25 @@ tbody tr {
|
|||||||
background-color: #d7e0eb;
|
background-color: #d7e0eb;
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody tr:nth-child(odd) {
|
tbody.single tr:nth-child(odd) {
|
||||||
background-color: #ebf0f5;
|
background-color: #ebf0f5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tbody.double tr:is(:nth-child(4n+1), :nth-child(4n+2)) {
|
||||||
|
background-color: #ebf0f5;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody dl {
|
||||||
|
margin: 0;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 2fr 5fr;
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody dd {
|
||||||
|
margin: 0;
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
|
||||||
thead th, tfoot tr {
|
thead th, tfoot tr {
|
||||||
background-color: #c3d1e2;
|
background-color: #c3d1e2;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user