
Loans are no longer displayed as a unified table, but instead each loan gets a "card" that contains the relevant data for the loan. This has had a fairly major html/css re-work as a side effect. Most views are now structured with two div-based columns so as to avoid the large blank areas that pure grid can lead to when elements are very different in height.
369 lines
14 KiB
PHP
369 lines
14 KiB
PHP
<?php
|
|
abstract class Page extends Responder {
|
|
protected abstract function render_body();
|
|
|
|
protected $page = 'checkout';
|
|
protected $title = '';
|
|
protected $subtitle = '';
|
|
protected $error = null;
|
|
protected $menuitems = array();
|
|
private $template_parts = array();
|
|
|
|
public function __construct() {
|
|
global $language, $name;
|
|
parent::__construct();
|
|
|
|
$this->title = $name;
|
|
$this->menuitems = array('checkout' => i18n('Check out'),
|
|
'return' => i18n('Return'),
|
|
'products' => i18n('Products'),
|
|
'new' => i18n('New product'),
|
|
'users' => i18n('Borrowers'),
|
|
'inventory' => i18n('Inventory'),
|
|
'history' => i18n('History'),
|
|
'search' => i18n('Search'));
|
|
$this->template_parts = get_fragments("./html/$language/base.html");
|
|
|
|
if(isset($_GET['page'])) {
|
|
$this->page = $_GET['page'];
|
|
}
|
|
if(isset($this->menuitems[$this->page])) {
|
|
$this->subtitle = $this->menuitems[$this->page];
|
|
}
|
|
}
|
|
|
|
public function render() {
|
|
$this->render_head();
|
|
$this->render_body();
|
|
if($this->error) {
|
|
$this->render_error();
|
|
}
|
|
$this->render_foot();
|
|
}
|
|
|
|
private function render_head() {
|
|
$headtitle = $this->title;
|
|
$pagetitle = $this->title;
|
|
if($this->subtitle) {
|
|
$headtitle .= ' - '. $this->subtitle;
|
|
$pagetitle = $this->subtitle;
|
|
}
|
|
$query = '';
|
|
if(isset($_GET['q'])) {
|
|
$query = $_GET['q'];
|
|
}
|
|
print(replace(
|
|
array('title' => $headtitle,
|
|
'menu' => $this->build_menu(),
|
|
'query'=> $query),
|
|
$this->template_parts['head']
|
|
));
|
|
print(replace(array('title' => $pagetitle),
|
|
$this->fragments['title']));
|
|
}
|
|
|
|
private function build_menu() {
|
|
$menu = '';
|
|
foreach($this->menuitems as $page => $title) {
|
|
$align = 'left';
|
|
$active = '';
|
|
if($this->page == $page) {
|
|
$active = 'active';
|
|
}
|
|
if($page == 'search') {
|
|
$align = 'right';
|
|
}
|
|
$menu .= replace(array('title' => $title,
|
|
'page' => $page,
|
|
'align' => $align,
|
|
'active' => $active),
|
|
$this->template_parts['menuitem']);
|
|
}
|
|
return $menu;
|
|
}
|
|
|
|
private function render_error() {
|
|
print(replace(array('type' => 'error',
|
|
'message' => $this->error),
|
|
$this->fragments['message']));
|
|
}
|
|
|
|
private function render_foot() {
|
|
print($this->template_parts['foot']);
|
|
}
|
|
|
|
final protected function build_user_table($users) {
|
|
$rows = '';
|
|
foreach($users as $user) {
|
|
$replacements = array('name' => '',
|
|
'loan' => '',
|
|
'has_notes' => '',
|
|
'notes' => '',
|
|
'item_link' => '');
|
|
$replacements['name'] = $user->get_name();
|
|
$notes = $user->get_notes();
|
|
if($notes) {
|
|
$replacements['notes'] = $notes;
|
|
$replacements['has_notes'] = '*';
|
|
}
|
|
$userlink = replace(array('id' => $user->get_id(),
|
|
'name' => $user->get_displayname($this->ldap),
|
|
'page' => 'users'),
|
|
$this->fragments['item_link']);
|
|
$replacements['item_link'] = $userlink;
|
|
$loans = $user->get_loans('active');
|
|
$loan_str = '';
|
|
$count = count($loans);
|
|
switch($count) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
$product = $loans[0]->get_product();
|
|
$loan_str = $product->get_name();
|
|
break;
|
|
default:
|
|
$loan_str = i18n('{count} products', $count);
|
|
break;
|
|
}
|
|
$replacements['loan'] = $loan_str;
|
|
$rows .= replace($replacements, $this->fragments['user_row']);
|
|
}
|
|
return replace(array('rows' => $rows),
|
|
$this->fragments['user_table']);
|
|
}
|
|
|
|
final protected function build_loan_preset_buttons() {
|
|
global $loan_length_presets;
|
|
$buttons = '';
|
|
foreach($loan_length_presets as $preset) {
|
|
[$count, $type] = explode(' ', $preset);
|
|
$buttons .= replace(array('count' => $count,
|
|
'type' => $type,
|
|
'description' => $count." ".i18n($type)),
|
|
$this->fragments['loan_preset_button']);
|
|
}
|
|
return $buttons;
|
|
}
|
|
|
|
final protected function build_product_table($products) {
|
|
usort($products, ['Product', 'compare']);
|
|
|
|
$rows = '';
|
|
foreach($products as $product) {
|
|
$rows .= $this->build_product_row($product);
|
|
}
|
|
return replace(array('rows' => $rows,
|
|
'type' => 'single'),
|
|
$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 = i18n('Available');
|
|
$status = $product->get_status();
|
|
switch($status) {
|
|
case 'discarded':
|
|
$discarded = format_date($product->get_discardtime());
|
|
$note = i18n('Discarded on {date}', $discarded);
|
|
break;
|
|
case 'service':
|
|
$service = $product->get_active_service();
|
|
$note = i18n('Being serviced since {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 = i18n('Borrowed by {user} {loan}', $userlink, $loan);
|
|
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_match_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_match']);
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
final protected function build_user_loan_table($loans) {
|
|
$rows = '';
|
|
foreach($loans as $loan) {
|
|
$product = $loan->get_product();
|
|
$prodlink = replace(array('id' => $product->get_id(),
|
|
'name' => $product->get_name(),
|
|
'page' => 'products'),
|
|
$this->fragments['item_link']);
|
|
$status = $loan->get_status();
|
|
$initiator = $loan->get_initiator();
|
|
$initiator_name = i18n('Unknown');
|
|
if($initiator) {
|
|
$initiator_name = replace(
|
|
array('id' => $initiator->get_id(),
|
|
'name' => $initiator->get_name(),
|
|
'page' => 'users'),
|
|
$this->fragments['item_link']);
|
|
}
|
|
$notes = $loan->get_notes();
|
|
$hidden = 'hidden';
|
|
if($notes) {
|
|
$hidden = '';
|
|
}
|
|
$misc = '';
|
|
if($status !== 'inactive_loan') {
|
|
$extend = format_date($loan->get_endtime());
|
|
$misc = replace(array('id' => $product->get_id(),
|
|
'end_new' => $extend),
|
|
$this->fragments['loan_extend_form']);
|
|
}
|
|
$start = $loan->get_starttime();
|
|
$end = $loan->get_returntime();
|
|
if(!$end) {
|
|
$end = $loan->get_endtime();
|
|
}
|
|
$rows .= replace(array('status' => $status,
|
|
'name' => $prodlink,
|
|
'serial' => $product->get_serial(),
|
|
'start_date' => format_date($start),
|
|
'end_date' => format_date($end),
|
|
'initiator' => $initiator_name,
|
|
'hidden' => $hidden,
|
|
'notes' => $notes,
|
|
'misc' => $misc),
|
|
$this->fragments['user_loan_card']);
|
|
}
|
|
return $rows;
|
|
}
|
|
|
|
final protected function build_seen_table($products, $inventory) {
|
|
$rows = '';
|
|
foreach($products as $product) {
|
|
$prodid = $product->get_id();
|
|
$prodlink = replace(array('id' => $prodid,
|
|
'name' => $product->get_name(),
|
|
'page' => 'products'),
|
|
$this->fragments['item_link']);
|
|
$regtime = $inventory->get_product_regtime($product);
|
|
$event = $product->get_historic_event($regtime);
|
|
$status = '';
|
|
$note = '';
|
|
if(!$event) {
|
|
$discardtime = $product->get_discardtime();
|
|
if($discardtime && $discardtime < $regtime) {
|
|
$status = 'discarded';
|
|
$note = i18n('Discarded on {date}',
|
|
format_date($discardtime));
|
|
} else {
|
|
$status = 'available';
|
|
}
|
|
} else if($event instanceof Service) {
|
|
$status = 'service';
|
|
$starttime = $event->get_starttime();
|
|
$returntime = $event->get_returntime();
|
|
$note = i18n('Being serviced since {date}', $starttime);
|
|
if($returntime) {
|
|
$note = i18n("Serviced between {start} and {end}",
|
|
$starttime,
|
|
$returntime);
|
|
}
|
|
} else if($event instanceof Loan) {
|
|
$user = $event->get_user();
|
|
$userlink = replace(
|
|
array('name' => $user->get_displayname($this->ldap),
|
|
'id' => $user->get_id(),
|
|
'page' => 'users'),
|
|
$this->fragments['item_link']);
|
|
$status = 'on_loan';
|
|
$note = i18n('Borrowed by {user} {loan} {inventorytime}',
|
|
$userlink,
|
|
$event,
|
|
$regtime);
|
|
if($event->get_endtime() < $regtime) {
|
|
$status = 'overdue';
|
|
}
|
|
}
|
|
$rows .= replace(array('status' => $status,
|
|
'item_link' => $prodlink,
|
|
'serial' => $product->get_serial(),
|
|
'note' => $note),
|
|
$this->fragments['product_row']);
|
|
}
|
|
return replace(array('rows' => $rows,
|
|
'type' => 'single'),
|
|
$this->fragments['product_table']);
|
|
|
|
}
|
|
|
|
final protected function build_inventory_details($inventory,
|
|
$interactive = true) {
|
|
$startdate = format_date($inventory->get_starttime());
|
|
$seen = $inventory->get_seen_products();
|
|
$unseen = array();
|
|
if($interactive) {
|
|
$all_products = get_items('product');
|
|
$total_count = count($all_products);
|
|
foreach($all_products as $product) {
|
|
if(!in_array($product, $seen)) {
|
|
$unseen[] = $product;
|
|
}
|
|
}
|
|
usort($unseen, ['Product', 'compare']);
|
|
} else {
|
|
$unseen = $inventory->get_unseen_products();
|
|
$total_count = count($unseen) + count($seen);
|
|
}
|
|
$missing = i18n('Missing products');
|
|
$hidden = 'hidden';
|
|
if($interactive) {
|
|
$missing = i18n('Remaining products');
|
|
$hidden = '';
|
|
}
|
|
$unseen_table = i18n('No products are missing.');
|
|
if($unseen) {
|
|
$unseen_table = $this->build_product_table($unseen);
|
|
}
|
|
$seen_table = i18n('No products registered');
|
|
if($seen) {
|
|
$seen_table = $this->build_seen_table($seen, $inventory);
|
|
}
|
|
return replace(array('start_date' => $startdate,
|
|
'total_count' => $total_count,
|
|
'seen_count' => count($seen),
|
|
'hide' => $hidden,
|
|
'unseen_title' => $missing,
|
|
'unseen' => $unseen_table,
|
|
'seen' => $seen_table),
|
|
$this->fragments['inventory_do']);
|
|
}
|
|
}
|
|
?>
|