600 lines
19 KiB
PHP
600 lines
19 KiB
PHP
<?php
|
|
class Product extends Entity {
|
|
private $id = 0;
|
|
private $brand = '';
|
|
private $name = '';
|
|
private $invoice = '';
|
|
private $serial = '';
|
|
private $createtime = null;
|
|
private $discardtime = null;
|
|
private $info = array();
|
|
private $tags = array();
|
|
|
|
public static function create_product(
|
|
$brand,
|
|
$name,
|
|
$invoice,
|
|
$serial,
|
|
$info = array(),
|
|
$tags = array()
|
|
) {
|
|
$now = time();
|
|
begin_trans();
|
|
try {
|
|
$stmt = 'insert into `product`
|
|
(`brand`, `name`, `invoice`, `serial`, `createtime`)
|
|
values (?, ?, ?, ?, ?)';
|
|
$ins_prod = prepare($stmt);
|
|
bind($ins_prod, 'ssssi', $brand, $name, $invoice, $serial, $now);
|
|
execute($ins_prod);
|
|
$product = new Product($serial, 'serial');
|
|
foreach($info as $field => $value) {
|
|
$product->set_info($field, $value);
|
|
}
|
|
foreach($tags as $tag) {
|
|
$product->add_tag($tag);
|
|
}
|
|
commit_trans();
|
|
return $product;
|
|
} catch(Exception $e) {
|
|
revert_trans();
|
|
throw $e;
|
|
}
|
|
}
|
|
|
|
public static function compare($prod1, $prod2) {
|
|
return strcmp(strtolower($prod1->get_name()),
|
|
strtolower($prod2->get_name()));
|
|
}
|
|
|
|
public function __construct($clue, $type = 'id') {
|
|
parent::__construct();
|
|
$search = null;
|
|
switch($type) {
|
|
case 'id':
|
|
$search = prepare('select `id` from `product`
|
|
where `id`=?');
|
|
bind($search, 'i', $clue);
|
|
break;
|
|
case 'serial':
|
|
$search = prepare('select `id` from `product`
|
|
where `serial`=?');
|
|
bind($search, 's', $clue);
|
|
break;
|
|
default:
|
|
throw new Exception('Invalid type.');
|
|
}
|
|
execute($search);
|
|
$result = result_single($search);
|
|
if($result === null) {
|
|
throw new Exception('Product does not exist.');
|
|
}
|
|
$this->id = $result['id'];
|
|
$this->update_fields();
|
|
$this->update_info();
|
|
$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() {
|
|
$get = prepare('select * from `product` where `id`=?');
|
|
bind($get, 'i', $this->id);
|
|
execute($get);
|
|
$product = result_single($get);
|
|
$this->brand = $product['brand'];
|
|
$this->name = $product['name'];
|
|
$this->invoice = $product['invoice'];
|
|
$this->serial = $product['serial'];
|
|
$this->createtime = $product['createtime'];
|
|
$this->discardtime = $product['discardtime'];
|
|
return true;
|
|
}
|
|
|
|
private function update_info() {
|
|
$get = prepare('select * from `product_info`
|
|
where `product`=? order by `field`');
|
|
bind($get, 'i', $this->id);
|
|
execute($get);
|
|
foreach(result_list($get) as $row) {
|
|
$field = $row['field'];
|
|
$data = $row['data'];
|
|
$this->info[$field] = $data;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private function update_tags() {
|
|
$get = prepare('select * from `product_tag`
|
|
where `product`=? order by `tag`');
|
|
bind($get, 'i', $this->id);
|
|
execute($get);
|
|
$newtags = array();
|
|
foreach(result_list($get) as $row) {
|
|
$newtags[] = $row['tag'];
|
|
}
|
|
$this->tags = $newtags;
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
Return a list of field-value mappings containing all matching search terms.
|
|
*/
|
|
public function matches($terms, $ldap) {
|
|
$matches = array();
|
|
|
|
// Create a list mapping all basic fields to getters
|
|
$fields = array('brand' => 'get_brand',
|
|
'name' => 'get_name',
|
|
'invoice' => 'get_invoice',
|
|
'serial' => 'get_serial',
|
|
'status' => 'get_status');
|
|
|
|
foreach($terms as $term) {
|
|
$key = $term->get_key();
|
|
$matched = false;
|
|
switch($key) {
|
|
case 'brand':
|
|
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($term, $value)) {
|
|
//Record a successful match
|
|
$matches[$key] = $value;
|
|
$matched = true;
|
|
}
|
|
break;
|
|
case 'tag':
|
|
// If $key is tag, iterate over the tags
|
|
$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($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($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($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();
|
|
}
|
|
}
|
|
return $matches;
|
|
}
|
|
|
|
private function match_tags($term) {
|
|
$tags = $this->get_tags();
|
|
$matches = array();
|
|
foreach($tags as $tag) {
|
|
if(match_term($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() {
|
|
return $this->id;
|
|
}
|
|
|
|
public function get_createtime() {
|
|
return $this->createtime;
|
|
}
|
|
|
|
public function get_discardtime() {
|
|
return $this->discardtime;
|
|
}
|
|
|
|
public function discard() {
|
|
if($this->get_status() != 'available') {
|
|
return false;
|
|
}
|
|
$now = time();
|
|
$update = prepare('update `product` set `discardtime`=? where `id`=?');
|
|
bind($update, 'ii', $now, $this->id);
|
|
execute($update);
|
|
$this->discardtime = $now;
|
|
if($this->discard_email_address) {
|
|
$this->send_discard_email();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private function send_discard_email() {
|
|
$product_data = array('Märke' => $this->get_brand(),
|
|
'Namn' => $this->get_name(),
|
|
'Serienummer' => $this->get_serial(),
|
|
'Fakturanummer' => $this->get_invoice(),
|
|
);
|
|
$createtime = format_date($this->get_createtime());
|
|
$discardtime = format_date($this->get_discardtime());
|
|
|
|
$subject = $this->email_subject_prefix;
|
|
$subject .= $this->get_brand().' '.$this->get_name().' skrotad';
|
|
$message = <<<EOF
|
|
Hej!
|
|
|
|
Följande artikel har skrotats i Boka:
|
|
|
|
EOF;
|
|
foreach($product_data as $key => $value) {
|
|
$message .= "\n$key: $value";
|
|
}
|
|
foreach($this->get_info() as $key => $value) {
|
|
$uckey = ucfirst($key);
|
|
$message .= "\n$uckey: $value";
|
|
}
|
|
$message .= "\nTaggar: ".join(', ', $this->get_tags());
|
|
|
|
$message .= "\n\nHistorik:";
|
|
$message .= "\nSkrotad $discardtime";
|
|
foreach($this->get_history() as $item) {
|
|
$starttime = format_date($item->get_starttime());
|
|
$endtime = format_date($item->get_returntime());
|
|
$event = "Service";
|
|
if($item instanceof Loan) {
|
|
$user = $item->get_user();
|
|
$event = "Utlånad till ".$user->get_name();
|
|
}
|
|
$message .= "\n$event $starttime - $endtime";
|
|
}
|
|
$message .= "\nRegistrerad $createtime";
|
|
|
|
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() {
|
|
$status = $this->get_status();
|
|
$now = time();
|
|
$update = '';
|
|
if($status == 'service') {
|
|
return $this->get_active_service()->end();
|
|
} else if($status == 'available') {
|
|
Service::create_service($this);
|
|
return true;
|
|
}
|
|
$id = $this->get_id();
|
|
throw new Exception("The state ($status) of this product (id $id) "
|
|
."does not allow servicing.");
|
|
}
|
|
|
|
public function get_active_service() {
|
|
$find = prepare("select `id` from `event` where
|
|
`type`='service'
|
|
and `returntime` is null
|
|
and product=?");
|
|
bind($find, 'i', $this->id);
|
|
execute($find);
|
|
$result = result_single($find);
|
|
if($result === null) {
|
|
return null;
|
|
}
|
|
return new Service($result['id']);
|
|
}
|
|
|
|
public function get_brand() {
|
|
return $this->brand;
|
|
}
|
|
|
|
public function set_brand($newbrand) {
|
|
$update = prepare('update `product` set `brand`=? where `id`=?');
|
|
bind($update, 'si', $newbrand, $this->id);
|
|
execute($update);
|
|
$this->brand = $newbrand;
|
|
return true;
|
|
}
|
|
|
|
public function get_name() {
|
|
return $this->name;
|
|
}
|
|
|
|
public function set_name($newname) {
|
|
$update = prepare('update `product` set `name`=? where `id`=?');
|
|
bind($update, 'si', $newname, $this->id);
|
|
execute($update);
|
|
$this->name = $newname;
|
|
return true;
|
|
}
|
|
|
|
public function get_invoice() {
|
|
return $this->invoice;
|
|
}
|
|
|
|
public function set_invoice($newinvoice) {
|
|
$update = prepare('update `product` set `invoice`=? where `id`=?');
|
|
bind($update, 'si', $newinvoice, $this->id);
|
|
execute($update);
|
|
$this->invoice = $newinvoice;
|
|
return true;
|
|
}
|
|
|
|
public function get_serial() {
|
|
return $this->serial;
|
|
}
|
|
|
|
public function set_serial($newserial) {
|
|
$update = prepare('update `product` set `serial`=? where `id`=?');
|
|
bind($update, 'si', $newserial, $this->id);
|
|
execute($update);
|
|
$this->serial = $newserial;
|
|
return true;
|
|
}
|
|
|
|
public function get_info() {
|
|
return $this->info;
|
|
}
|
|
|
|
public function set_info($field, $value) {
|
|
if(!$value) {
|
|
return true;
|
|
}
|
|
$find = prepare('select * from `product_info`
|
|
where `product`=? and `field`=?');
|
|
bind($find, 'is', $this->id, $field);
|
|
execute($find);
|
|
if(result_single($find) === null) {
|
|
$update = prepare('insert into
|
|
`product_info`(`data`, `product`, `field`)
|
|
values (?, ?, ?)');
|
|
} else {
|
|
$update = prepare('update `product_info` set `data`=?
|
|
where `product`=? and `field`=?');
|
|
}
|
|
bind($update, 'sis', $value, $this->id, $field);
|
|
execute($update);
|
|
$this->update_info();
|
|
return true;
|
|
}
|
|
|
|
public function remove_info($field) {
|
|
$find = prepare('select * from `product_info`
|
|
where `product`=? and `field`=?');
|
|
bind($find, 'is', $this->id, $field);
|
|
execute($find);
|
|
if(result_single($find) === null) {
|
|
return true;
|
|
}
|
|
$update = prepare('delete from `product_info`
|
|
where `field`=? and `product`=?');
|
|
bind($update, 'si', $field, $this->id);
|
|
execute($update);
|
|
$this->update_info();
|
|
return true;
|
|
}
|
|
|
|
public function get_tags() {
|
|
return $this->tags;
|
|
}
|
|
|
|
public function add_tag($tag) {
|
|
if(!$tag) {
|
|
return true;
|
|
}
|
|
$find = prepare('select * from `product_tag`
|
|
where `product`=? and `tag`=?');
|
|
bind($find, 'is', $this->id, $tag);
|
|
execute($find);
|
|
if(result_single($find) === null) {
|
|
$update = prepare('insert into `product_tag`(`tag`, `product`)
|
|
values (?, ?)');
|
|
bind($update, 'si', $tag, $this->id);
|
|
execute($update);
|
|
$this->update_tags();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public function remove_tag($tag) {
|
|
$find = prepare('select * from `product_tag`
|
|
where `product`=? and `tag`=?');
|
|
bind($find, 'is', $this->id, $tag);
|
|
execute($find);
|
|
if(result_single($find) === null) {
|
|
return true;
|
|
}
|
|
$update = prepare('delete from `product_tag`
|
|
where `tag`=? and `product`=?');
|
|
bind($update, 'si', $tag, $this->id);
|
|
execute($update);
|
|
$this->update_tags();
|
|
return true;
|
|
}
|
|
|
|
public function get_status() {
|
|
if($this->get_discardtime()) {
|
|
return 'discarded';
|
|
}
|
|
if($this->get_active_service()) {
|
|
return 'service';
|
|
}
|
|
$loan = $this->get_active_loan();
|
|
if(!$loan) {
|
|
return 'available';
|
|
}
|
|
if($loan->is_overdue()) {
|
|
return 'overdue';
|
|
}
|
|
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`
|
|
where `type`='loan'
|
|
and `returntime` is null
|
|
and product=?");
|
|
bind($find, 'i', $this->id);
|
|
execute($find);
|
|
$result = result_single($find);
|
|
if($result === null) {
|
|
return null;
|
|
}
|
|
return new Loan($result['id']);
|
|
}
|
|
|
|
public function get_history() {
|
|
$out = array();
|
|
$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'");
|
|
}
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
public function get_attachments() {
|
|
$out = array();
|
|
$find = prepare('select `id` from `attachment`
|
|
where `product`=? and `deletetime` is NULL
|
|
order by `uploadtime` asc');
|
|
bind($find, 'i', $this->id);
|
|
execute($find);
|
|
$items = result_list($find);
|
|
foreach($items as $item) {
|
|
$out[] = new Attachment($item['id']);
|
|
}
|
|
return $out;
|
|
}
|
|
}
|
|
?>
|