Several changes:

- The inventory page now shows status of seen products as of when they were registered,
   not as of now.
 - Renamed a placeholder in fragments.html to be more intuitive.
 - Added a type field to the event table in the database, so that complete events can
   be constructed without complex logic.
 - Refactored to support the above changes
This commit is contained in:
Erik Thuning 2019-07-24 14:09:31 +02:00
parent 763d1c6ba5
commit ef756e36b4
9 changed files with 172 additions and 62 deletions

@ -78,6 +78,7 @@ create table `user` (
create table `event` (
`id` bigint(20) not null auto_increment,
primary key(`id`),
`type` varchar(64),
`product` bigint(20) not null,
constraint `e_f_product`
foreign key(`product`) references `product`(`id`),
@ -123,7 +124,8 @@ create table `inventory_product` (
`product` bigint(20) not null,
constraint `i_f_product`
foreign key(`product`) references `product`(`id`),
unique `uniq_inventory_product`(`inventory`, `product`)
unique `uniq_inventory_product`(`inventory`, `product`),
`regtime` bigint(20) not null
) character set utf8mb4,
collate utf8mb4_unicode_ci;

@ -95,7 +95,7 @@
¤serial¤
</td>
<td>
¤availabl
¤not
</td>
</tr>

@ -5,7 +5,7 @@ class Event {
protected $starttime = 0;
protected $returntime = null;
protected static function create_event($product) {
protected static function create_event($product, $type) {
$status = $product->get_status();
if($status != 'available') {
$emsg = '';
@ -28,11 +28,18 @@ class Event {
}
throw new Exception($emsg);
}
switch($type) {
case 'loan':
case 'service':
break;
default:
throw new Excpetion("Invalid argument '$type'");
}
$now = time();
$insert = prepare('insert into
`event`(`product`, `starttime`)
values (?, ?)');
bind($insert, 'ii', $product->get_id(), $now);
$insert = prepare('insert into `event`
(`product`, `type`, `starttime`)
values (?, ?, ?)');
bind($insert, 'isi', $product->get_id(), $type, $now);
execute($insert);
$event_id = $insert->insert_id;
return new Event($event_id);

@ -15,12 +15,12 @@ class Inventory {
execute($start);
$invid = $start->insert_id;
$prodid = '';
$register = prepare('insert into
`inventory_product`(`inventory`, `product`)
values (?, ?)');
foreach(get_items('loan_active') as $loan) {
$prodid = $loan->get_product()->get_id();
bind($register, 'ii', $invid, $prodid);
$register = prepare('insert into `inventory_product`
(`inventory`, `product`, `regtime`)
values (?, ?, ?)');
foreach(get_items('event_active') as $event) {
$prodid = $event->get_product()->get_id();
bind($register, 'iii', $invid, $prodid, $now);
execute($register);
}
return new Inventory($invid);
@ -75,9 +75,10 @@ class Inventory {
}
public function add_product($product) {
$add = prepare('insert into `inventory_product`(`inventory`, `product`)
values (?, ?)');
bind($add, 'ii', $this->id, $product->get_id());
$add = prepare('insert into `inventory_product`
(`inventory`, `product`, `regtime`)
values (?, ?, ?)');
bind($add, 'iii', $this->id, $product->get_id(), time());
try {
execute($add);
} catch(Exception $e) {
@ -107,6 +108,21 @@ class Inventory {
return $out;
}
public function get_product_regtime($product) {
$invid = $this->id;
$prodid = $product->get_id();
$search = prepare('select `regtime` from `inventory_product`
where `inventory` = ? and `product` = ?');
bind($search, 'ii', $invid, $prodid);
execute($search);
$result = result_single($search);
if(!$result) {
$emsg = "Inventory $invid has no reference to product $prodid.";
throw new Exception($emsg);
}
return $result['regtime'];
}
public function get_unseen_products() {
$all = get_items('product');
$out = array();

@ -5,10 +5,12 @@ class Loan extends Event {
public static function create_loan($user, $product, $endtime) {
begin_trans();
$event = parent::create_event($product);
$event = parent::create_event($product, 'loan');
$event_id = $event->get_id();
$insert = prepare('insert into `loan`(`user`, `endtime`) values (?, ?)');
bind($insert, 'ii', $user->get_id(), strtotime($endtime . ' 13:00'));
$insert = prepare('insert into `loan`(`event`, `user`, `endtime`)
values (?, ?, ?)');
$endtime .= '13:00';
bind($insert, 'iii', $event_id, $user->get_id(), strtotime($endtime));
execute($insert);
commit_trans();
return new Loan($event_id);

@ -134,15 +134,16 @@ abstract class Page extends Responder {
'name' => $product->get_name(),
'page' => 'products'),
$this->fragments['item_link']);
$available = 'Tillgänglig';
$note = 'Tillgänglig';
$status = $product->get_status();
switch($status) {
case 'discarded':
$available = 'Skrotad '.$discarded;
$discarded = format_date($product->get_discardtime());
$note = 'Skrotad '.$discarded;
break;
case 'service':
$service = $product->get_active_service();
$available = 'På service sedan '
$note = 'På service sedan '
.format_date($service->get_starttime());
break;
case 'on_loan':
@ -153,18 +154,18 @@ abstract class Page extends Responder {
'id' => $user->get_id(),
'page' => 'users'),
$this->fragments['item_link']);
$available = 'Utlånad till '.$userlink;
$note = 'Utlånad till '.$userlink;
if($loan->is_overdue()) {
$available .= ', försenad';
$note .= ', försenad';
} else {
$available .= ', åter '.format_date($loan->get_endtime());
$note .= ', slutdatum '.format_date($loan->get_endtime());
}
break;
}
$rows .= replace(array('available' => $available,
$rows .= replace(array('status' => $status,
'item_link' => $prodlink,
'serial' => $product->get_serial(),
'status' => $status,
'item_link' => $prodlink),
'note' => $note,),
$this->fragments['product_row']);
}
return replace(array('rows' => $rows),
@ -240,6 +241,63 @@ abstract class Page extends Responder {
$this->fragments['history_table']);
}
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 = 'Skrotad '.format_date($discardtime);
} else {
$status = 'available';
}
} else if($event instanceof Service) {
$status = 'service';
$note = 'På service sedan '.format_date($event->get_starttime());
$returntime = $event->get_returntime();
if($returntime) {
$note .= ', åter den '.format_date($returntime);
}
} else if($event instanceof Loan) {
$user = $event->get_user();
$userlink = replace(array('name' => $user->get_displayname(),
'id' => $user->get_id(),
'page' => 'users'),
$this->fragments['item_link']);
$status = 'on_loan';
$note = 'Utlånad till '.$userlink;
$returntime = $event->get_returntime();
if($event->get_endtime() < $regtime) {
$status = 'overdue';
$note .= ', försenad';
} else {
$note .= ', slutdatum '.format_date($event->get_endtime());
}
if($returntime) {
$note .= ', återlämnad '.format_date($returntime);
}
}
$rows .= replace(array('status' => $status,
'item_link' => $prodlink,
'serial' => $product->get_serial(),
'note' => $note),
$this->fragments['product_row']);
}
return replace(array('rows' => $rows),
$this->fragments['product_table']);
}
final protected function build_inventory_details($inventory,
$interactive = true) {
$startdate = format_date($inventory->get_starttime());
@ -272,7 +330,7 @@ abstract class Page extends Responder {
$out .= replace(array('title' => 'Inventerade artiklar'),
$this->fragments['subtitle']);
if($seen) {
$out .= $this->build_product_table($seen);
$out .= $this->build_seen_table($seen, $inventory);
} else {
$out .= 'Inga artiklar inventerade.';
}

@ -148,10 +148,7 @@ class Product {
return $this->createtime;
}
public function get_discardtime($format = true) {
if($this->discardtime && $format) {
return gmdate('Y-m-d', $this->discardtime);
}
public function get_discardtime() {
return $this->discardtime;
}
@ -325,7 +322,7 @@ class Product {
}
public function get_status() {
if($this->get_discardtime(false)) {
if($this->get_discardtime()) {
return 'discarded';
}
if($this->get_active_service()) {
@ -341,6 +338,32 @@ class Product {
return 'on_loan';
}
public function get_historic_event($time) {
$search = prepare("select `id`,`type` from `event`
where `product` = ?
and `starttime` < ?
and ( `returntime` > ?
or `returntime` is null )");
bind($search, 'iii', $this->id, $time, $time);
execute($search);
$result = result_single($search);
if(!$result) {
return null;
}
$id = $result['id'];
$type = $result['type'];
switch($type) {
case 'service':
return new Service($id);
break;
case 'loan':
return new Loan($id);
break;
default:
throw new Exception("Invalid type '$type'");
}
}
public function get_active_loan() {
$find = prepare('select `id` from `event`
inner join `loan`
@ -357,23 +380,25 @@ class Product {
public function get_history() {
$out = array();
foreach(array('loan' => function($id) { return new Loan($id);},
'service' => function($id) { return new Service($id);})
as $type => $func) {
$find = prepare('select `id` from `event` '
."inner join `$type` "
."on `event`.`id` = `$type`.`event` "
.'where `product`=? order by `starttime` desc');
bind($find, 'i', $this->id);
execute($find);
$items = result_list($find);
foreach($items as $item) {
$out[] = $func($item['id']);
$find = prepare('select `id`,`type` from `event` '
.'where `product`=? order by `starttime` desc');
bind($find, 'i', $this->id);
execute($find);
$items = result_list($find);
foreach($items as $item) {
$id = $item['id'];
switch($item['type']) {
case 'service':
$out[] = new Service($id);
break;
case 'loan':
$out[] = new Loan($id);
break;
default:
$type = $item['type'];
throw new Exception("Invalid type '$type'");
}
}
usort($out, function($a, $b) {
return $a->get_starttime() < $b->get_starttime();
});
return $out;
}
}

@ -2,7 +2,7 @@
class Service extends Event {
public static function create_service($product) {
begin_trans();
$event = parent::create_event($product);
$event = parent::create_event($product, 'service');
$event_id = $event->get_id();
$insert = prepare('insert into `service`(`event`) values (?)');
bind($insert, 'i', $event_id);

@ -108,18 +108,18 @@ function get_ids($type) {
case 'product':
$append = 'where `discardtime` is null';
break;
case 'loan':
case 'product_discarded':
$type = 'product';
$append = 'where `discardtime` is not null';
break;
case 'event':
break;
case 'event_active':
$type = 'event';
$append = 'where `returntime` is null';
break;
case 'inventory':
break;
case 'product_discarded':
$append = 'where `discardtime` is not null';
$type = 'product';
break;
case 'loan_active':
$append = 'where `returntime` is null';
$type = 'loan';
break;
case 'inventory_old':
$append = 'where `endtime` is not null order by `id` desc';
$type = 'inventory';
@ -156,10 +156,10 @@ function get_items($type) {
return new Product($id);
};
break;
case 'loan':
case 'loan_active':
case 'event':
case 'event_active':
$construct = function($id) {
return new Loan($id);
return new Event($id);
};
break;
case 'inventory':