From ef756e36b4af0fc50ba8d18bc8057b8a10458b89 Mon Sep 17 00:00:00 2001 From: Erik Thuning <boooink@gmail.com> Date: Wed, 24 Jul 2019 14:09:31 +0200 Subject: [PATCH] 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 --- database.sql | 4 ++- html/fragments.html | 2 +- include/Event.php | 17 +++++++--- include/Inventory.php | 34 ++++++++++++++----- include/Loan.php | 8 +++-- include/Page.php | 78 +++++++++++++++++++++++++++++++++++++------ include/Product.php | 65 +++++++++++++++++++++++++----------- include/Service.php | 2 +- include/functions.php | 24 ++++++------- 9 files changed, 172 insertions(+), 62 deletions(-) diff --git a/database.sql b/database.sql index 0f4b552..7f5b3e7 100644 --- a/database.sql +++ b/database.sql @@ -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; diff --git a/html/fragments.html b/html/fragments.html index 0f00766..165bb68 100644 --- a/html/fragments.html +++ b/html/fragments.html @@ -95,7 +95,7 @@ ¤serial¤ </td> <td> - ¤available¤ + ¤note¤ </td> </tr> diff --git a/include/Event.php b/include/Event.php index a697270..865a5d3 100644 --- a/include/Event.php +++ b/include/Event.php @@ -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); diff --git a/include/Inventory.php b/include/Inventory.php index 4efa501..86e743d 100644 --- a/include/Inventory.php +++ b/include/Inventory.php @@ -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(); diff --git a/include/Loan.php b/include/Loan.php index 3165de7..9bf38c8 100644 --- a/include/Loan.php +++ b/include/Loan.php @@ -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); diff --git a/include/Page.php b/include/Page.php index 3995c62..466fb8f 100644 --- a/include/Page.php +++ b/include/Page.php @@ -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.'; } diff --git a/include/Product.php b/include/Product.php index 7ae1072..ea7faa9 100644 --- a/include/Product.php +++ b/include/Product.php @@ -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; } } diff --git a/include/Service.php b/include/Service.php index 79f274a..b854319 100644 --- a/include/Service.php +++ b/include/Service.php @@ -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); diff --git a/include/functions.php b/include/functions.php index a3479c7..16f6d17 100644 --- a/include/functions.php +++ b/include/functions.php @@ -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':