[ Index ] |
|
Code source de eGroupWare 1.2.106-2 |
1 <?php 2 /**************************************************************************\ 3 * eGroupWare - ProjectManager - Pricelist buisness object * 4 * http://www.egroupware.org * 5 * Written and (c) 2005 by Ralf Becker <RalfBecker@outdoor-training.de> * 6 * -------------------------------------------- * 7 * This program is free software; you can redistribute it and/or modify it * 8 * under the terms of the GNU General Public License as published by the * 9 * Free Software Foundation; either version 2 of the License, or (at your * 10 * option) any later version. * 11 \**************************************************************************/ 12 13 /* $Id: class.bopricelist.inc.php 23135 2006-12-27 11:12:45Z ralfbecker $ */ 14 15 include_once (EGW_INCLUDE_ROOT.'/projectmanager/inc/class.sopricelist.inc.php'); 16 17 /** 18 * Pricelist buisness object of the projectmanager 19 * 20 * @package projectmanager 21 * @author RalfBecker-AT-outdoor-training.de 22 * @copyright (c) 2005 by RalfBecker-AT-outdoor-training.de 23 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License 24 */ 25 class bopricelist extends sopricelist 26 { 27 /** 28 * @var array $timestamps timestaps that need to be adjusted to user-time on reading or saving 29 */ 30 var $timestamps = array( 31 'pl_modified','pl_validsince', 32 ); 33 /** 34 * @var int $tz_offset_s offset in secconds between user and server-time, 35 * it need to be add to a server-time to get the user-time or substracted from a user-time to get the server-time 36 */ 37 var $tz_offset_s; 38 /** 39 * @var int $now actual USER time 40 */ 41 var $now; 42 43 /** 44 * Constructor, calls the constructor of the extended class 45 * 46 * @param int $pm_id=0 pm_id of the project to use, default 0 (project independent / standard prices) 47 */ 48 function bopricelist($pm_id=0) 49 { 50 $this->sopricelist($pm_id); 51 52 if (!is_object($GLOBALS['egw']->datetime)) 53 { 54 $GLOBALS['egw']->datetime =& CreateObject('phpgwapi.datetime'); 55 } 56 $this->tz_offset_s = $GLOBALS['egw']->datetime->tz_offset; 57 $this->now = time() + $this->tz_offset_s; 58 59 if (!is_object($GLOBALS['boprojectmanager'])) 60 { 61 CreateObject('projectmanager.boprojectmanager',$pm_id); 62 } 63 $this->project =& $GLOBALS['boprojectmanager']; 64 } 65 66 /** 67 * saves the content of data to the db, also checks acl and deletes not longer set prices! 68 * 69 * @param array $keys=null if given $keys are copied to data before saveing => allows a save as 70 * @return int/boolean 0 on success, true on missing acl-rights and errno != 0 else 71 */ 72 function save($keys=null) 73 { 74 if (is_array($keys) && count($keys)) $this->data_merge($keys); 75 76 if ((int)$this->debug >= 2) 77 { 78 echo "<p>sopricelist::save(".print_r($keys,true).") data="; 79 _debug_array($this->data); 80 } 81 if ($this->data['pl_id']) 82 { 83 $backup =& $this->data; // would get overwritten by read 84 unset($this->data); 85 $old = $this->read(array( 86 'pl_id' => $backup['pl_id'], 87 'pm_id' => $backup['pm_id'] ? array($backup['pm_id'],0) : 0 88 )); 89 $this->data =& $backup; 90 unset($backup); 91 } 92 $need_general = count($old['prices']) > 0 || count($this->data['prices']) > 0; 93 if (!($pricelist_need_save = !$this->data['pl_id'])) 94 { 95 $this->data['cat_id'] = (int) $this->data['cat_id']; 96 foreach($this->db_cols as $col => $data) 97 { 98 if (!$old || $this->data[$col] != $old[$col]) 99 { 100 $pricelist_need_save = true; 101 break; 102 } 103 } 104 } 105 if ($pricelist_need_save) 106 { 107 // check acl 108 if (!$this->check_acl(EGW_ACL_EDIT,$need_general ? 0 : $this->data['pm_id'])) 109 { 110 return lang('permission denied !!!').' need_general='.(int)$need_general; 111 } 112 if (($err = parent::save($this->data))) 113 { 114 return $err; 115 } 116 } 117 $prices = array(); 118 foreach($this->data['prices'] as $key => $nul) 119 { 120 $price =& $this->data['prices'][$key]; 121 $price['pm_id'] = 0; 122 $price['pl_billable'] = $price['pl_customertitle'] = null; 123 if (count($this->data['prices']) == 1) $price['pl_validsince'] = 0; // no date for first price 124 $prices[] =& $price; 125 } 126 foreach($this->data['project_prices'] as $key => $nul) 127 { 128 $price =& $this->data['project_prices'][$key]; 129 foreach(array('pm_id','pl_billable','pl_customertitle') as $key) 130 { 131 if (!isset($price[$key])) $price[$key] = $this->data[$key]; 132 } 133 if (count($this->data['project_prices']) == 1) $price['pl_validsince'] = 0; // no date for first price 134 $prices[] =& $price; 135 } 136 137 // index prices in old by pm_id and date (!) of validsince 138 $old_prices = array(); 139 if ($old) 140 { 141 foreach(array_merge($old['prices'],$old['project_prices']) as $old_price) 142 { 143 $old_prices[(int)$old_price['pm_id']][date('Y-m-d',(int)$old_price['pl_validsince'])] = $old_price; 144 } 145 } 146 foreach($prices as $key => $nul) 147 { 148 $price =& $prices[$key]; 149 if (!isset($price['pl_id'])) $price['pl_id'] = $this->data['pl_id']; 150 $old_price = $old_prices[(int)$price['pm_id']][date('Y-m-d',(int)$price['pl_validsince'])]; 151 if (!$this->prices_equal($price,$old_price)) 152 { 153 // price needs saving, checking acl now 154 if (!$this->check_acl(EGW_ACL_EDIT,$price['pm_id'])) 155 { 156 return lang('permission denied !!!').' check_acl(EGW_ACL_EDIT(pm_id='.(int)$price[pm_id].')'; 157 } 158 // maintain time of old price, to not create doublets with different times by users operating in different TZ's 159 if ($old_price) $price['pl_validsince'] = $old_price['pl_validsince']; 160 161 if (($err = parent::save_price($price))) 162 { 163 return $err; 164 } 165 } 166 unset($old_prices[(int)$price['pm_id']][date('Y-m-d',(int)$old_price['pl_validsince'])]); 167 } 168 // check if there are old prices not longer set ==> delete them 169 foreach($old_prices as $pm_id => $prices) 170 { 171 foreach($prices as $price) 172 { 173 if (!$this->check_acl(EGW_ACL_DELETE,$price['pm_id'])) 174 { 175 return lang('permission denied !!!').' check_acl(EGW_ACL_DELETE(pm_id='.(int)$price[pm_id].')'; 176 } 177 if (!parent::delete($price)) 178 { 179 return lang('Error: deleting price !!!'); 180 } 181 } 182 } 183 return 0; 184 } 185 186 /** 187 * search elements, reimplemented to use $this->pm_id, if no pm_id given in criteria or filter and join with the prices table 188 * 189 * @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!) 190 * @param boolean $only_keys True returns only keys, False returns all cols 191 * @param string $order_by fieldnames + {ASC|DESC} separated by colons ',' 192 * @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num" 193 * @param string $wildcard appended befor and after each criteria 194 * @param boolean $empty False=empty criteria are ignored in query, True=empty have to be empty in row 195 * @param string $op defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together 196 * @param int/boolean $start if != false, return only maxmatch rows begining with start 197 * @param array $filter if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards 198 * @param string/boolean $join=true default join with prices-table or string as in so_sql 199 * @return array of matching rows (the row is an array of the cols) or False 200 */ 201 function search($criteria,$only_keys=false,$order_by='',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join=true) 202 { 203 if (!$this->check_acl(EGW_ACL_READ,(int)($criteria['pm_id'] ? $criteria['pm_id'] : $this->pm_id))) 204 { 205 return false; 206 } 207 return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join); 208 } 209 210 /** 211 * return priceslist of a given project (only bookable or billable price, no general pricelist) 212 * 213 * @param int $pm_id project 214 * @return array/boolean array with pl_id => pl_unit: pl_tiltle (pl_price) pairs or false on error (eg. no ACL) 215 */ 216 function pricelist($pm_id) 217 { 218 //echo "<p>bopricelist::pricelist($pm_id)</p>\n"; 219 if (!($prices =& $this->search(array('pm_id' => $pm_id)))) 220 { 221 return false; 222 } 223 $options = array(); 224 foreach($prices as $price) 225 { 226 $options[$price['pl_id']] = $price['pl_unit'].' '.$price['pl_title'].' ('.$price['pl_price'].')'; 227 } 228 return $options; 229 } 230 231 /** 232 * reads one pricelist-itme specified by $keys, reimplemented to use $this->pm_id, if no pm_id given 233 * 234 * @param array $keys array with keys in form internalName => value, may be a scalar value if only one key 235 * @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num" 236 * @param string/boolean $join=true default join with links-table or string as in so_sql 237 * @return array/boolean data if row could be retrived else False 238 */ 239 function read($keys,$extra_cols='',$join=true) 240 { 241 // check if we have the requested access to all given pricelists 242 foreach(!is_array($keys) || !isset($keys['pm_id']) ? array($this->pm_id) : 243 (is_array($keys['pm_id']) ? $keys['pm_id'] : array($keys['pm_id'])) as $pm_id) 244 { 245 if (!$this->check_acl(EGW_ACL_READ,(int)$pm_id)) return false; 246 } 247 return parent::read($keys,$extra_cols,$join); 248 } 249 250 /** 251 * delete pricelist-entries and price(s) specified by keys pl_id, pm_id and/or pl_validsince 252 * 253 * If the last price of a pricelist-entry gets deleted, the pricelist entry is automatic deleted too! 254 * 255 * @param array/int $keys array with keys pm_id, pl_id and/or pl_validsince to delete or integer pm_id 256 * @return int/boolean number of deleted prices or false if permission denied 257 */ 258 function delete($keys) 259 { 260 if (!$this->check_acl(EGW_ACL_EDIT,(int)(is_array($keys) ? $keys['pm_id'] : $keys))) 261 { 262 return false; 263 } 264 return parent::delete($keys); 265 } 266 267 /** 268 * checks if the user has sufficent rights for a certain action 269 * 270 * For project-spez. prices/data you need a EGW_ACL_BUDGET right of the project for read or 271 * EGW_ACL_EDIT_BUDGET for write or delete. 272 * For general pricelist data you need atm. no extra read rights, but is_admin to write/delete. 273 * 274 * @param int $required EGW_ACL_{READ|WRITE|DELETE} 275 * @param int $pm_id=0 project-id for project-spez. prices/data to check, default 0 = general pricelist 276 * @param array/int $data=null data/id of pricelist-entry, default null = use $this->data ($pm_id is ignored) 277 * @return boolean true if the user has the rights, false otherwise 278 */ 279 function check_acl($required,$pm_id=0,$data=null) 280 { 281 /* not used atm. 282 if (is_null($data)) 283 { 284 $data =& $this->data; 285 } 286 elseif (!is_array($data)) 287 { 288 if ((int) $data) 289 { 290 $backup = $this->data; 291 $data = $this->read(array('pm_id'=>(int)$pm_id,'pl_id' => (int)$data)); 292 $this->data = $backup; 293 } 294 else 295 { 296 return false; 297 } 298 } 299 */ 300 if (!$pm_id) 301 { 302 return $required == EGW_ACL_READ || $this->project->is_admin; 303 } 304 return $this->project->check_acl($required == EGW_ACL_READ ? EGW_ACL_BUDGET : EGW_ACL_EDIT_BUDGET,$pm_id); 305 } 306 307 /** 308 * Compares two prices to check if they are equal 309 * 310 * The compared fields depend on the price being project-specific or not 311 * 312 * @param array $price 313 * @param array $price2 314 * @return boolean true if the two prices are identical, false otherwise or if they are no arrays! 315 */ 316 function prices_equal($price,$price2) 317 { 318 if (!is_array($price) || !is_array($price2)) return false; 319 320 $to_compare = array('pl_id','pm_id','pl_price','pl_validsince','pl_modified','pl_modifier'); 321 322 if ($price['pm_id']) 323 { 324 $to_compare[] = 'pl_customertitle'; 325 $to_compare[] = 'pl_billable'; 326 } 327 $equal = true; 328 foreach($to_compare as $key) 329 { 330 switch($key) 331 { 332 case 'pm_id': 333 $equal = (int) $price['pm_id'] == (int) $price2['pm_id']; 334 break; 335 case 'pl_validsince': 336 $equal = date('Y-m-d',(int)$price['pl_validsince']) == date('Y-m-d',(int)$price2['pl_validsince']); 337 break; 338 default: 339 $equal = $price[$key] == $price2[$key]; 340 break; 341 } 342 if (!$equal) break; 343 } 344 if ((int)$this->debug >= 3) echo "<p>bopricelist::prices_equal(".print_r($price,true).','.print_r($price2,true).') = '.($equal ? 'true' : "differ in $key: {$price[$key]} != {$price2[$key]}")."</p>\n"; 345 346 return $equal; 347 } 348 349 /** 350 * changes the data from the db-format to your work-format 351 * 352 * reimplemented to adjust the timezone of the timestamps (adding $this->tz_offset_s to get user-time) 353 * Please note, we do NOT call the method of the parent or so_sql !!! 354 * 355 * @param array $data if given works on that array and returns result, else works on internal data-array 356 * @return array with changed data 357 */ 358 function db2data($data=null) 359 { 360 if (!is_array($data)) 361 { 362 $data = &$this->data; 363 } 364 foreach($this->timestamps as $name) 365 { 366 if (isset($data[$name]) && $data[$name]) $data[$name] += $this->tz_offset_s; 367 } 368 return $data; 369 } 370 371 /** 372 * changes the data from your work-format to the db-format 373 * 374 * reimplemented to adjust the timezone of the timestamps (subtraction $this->tz_offset_s to get server-time) 375 * Please note, we do NOT call the method of the parent or so_sql !!! 376 * 377 * @param array $data if given works on that array and returns result, else works on internal data-array 378 * @return array with changed data 379 */ 380 function data2db($data=null) 381 { 382 if ($intern = !is_array($data)) 383 { 384 $data = &$this->data; 385 } 386 foreach($this->timestamps as $name) 387 { 388 if (isset($data[$name]) && $data[$name]) $data[$name] -= $this->tz_offset_s; 389 } 390 return $data; 391 } 392 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 17:20:01 2007 | par Balluche grâce à PHPXref 0.7 |