source: contrib/ProjectManager/inc/class.sopricelist.inc.php @ 3594

Revision 3594, 10.5 KB checked in by afernandes, 13 years ago (diff)

Ticket #1416 - Disponibilizado o módulo ProjectManager? para a comunidade

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * ProjectManager - Pricelist storage object
4 *
5 * @link http://www.egroupware.org
6 * @author Ralf Becker <RalfBecker-AT-outdoor-training.de>
7 * @package projectmanager
8 * @copyright (c) 2005 by Ralf Becker <RalfBecker-AT-outdoor-training.de>
9 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
10 * @version $Id: class.sopricelist.inc.php 23134 2006-12-27 11:08:15Z ralfbecker $
11 */
12
13include_once(PHPGW_INCLUDE_ROOT.'/etemplate/inc/class.so_sql.inc.php');
14
15/**
16 * Pricelist storage object of the projectmanager
17 *
18 * Tables: phpgw_pm_pricelist, phpgw_pm_prices
19 */
20class sopricelist extends so_sql
21{
22        /**
23         * @var string $prices_table table name of the prices table
24         */
25        var $prices_table = 'phpgw_pm_prices';
26        /**
27         * @var string $prices_join default join with the prices table
28         */
29        var $prices_join = 'JOIN phpgw_pm_prices p ON phpgw_pm_pricelist.pl_id=p.pl_id';
30        /**
31         * @var array $links_extracols extracolumns from the links table
32         */
33        var $prices_extracols = array('pm_id','pl_validsince','pl_price','pl_customertitle','pl_modifier','pl_modified','pl_billable');
34        /**
35         * @var int $pm_id project we work on or 0 for standard pricelist only
36         */
37        var $pm_id;
38
39        /**
40         * Constructor, calls the constructor of the extended class
41         *
42         * @param int $pm_id=0 pm_id of the project to use, default 0 (project independent / standard prices)
43         */
44        function sopricelist($pm_id=0)
45        {
46                $this->so_sql('projectmanager','phpgw_pm_pricelist');   // sets $this->table_name
47
48                $this->pm_id = (int) $pm_id;
49        }
50       
51        /**
52         * reads one pricelist-itme specified by $keys, reimplemented to use $this->pm_id, if no pm_id given
53         *
54         * @param array $keys array with keys in form internalName => value, may be a scalar value if only one key
55         * @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num"
56         * @param string/boolean $join=true default join with links-table or string as in so_sql
57         * @return array/boolean data if row could be retrived else False
58        */
59        function read($keys,$extra_cols='',$join=true)
60        {
61                if (!is_array($keys)) $keys = array('pl_id' => (int) $keys);
62
63                if ($join === true)     // add join with links-table and extra-columns
64                {
65                        // just pl_id would be ambigues
66                        $keys[] = $this->table_name.'.pl_id='.(int)$keys['pl_id'];
67                        unset($keys['pl_id']);
68                       
69                        if (isset($keys['pl_validsince']))
70                        {
71                                $keys[] = 'pl_validsince <= '.(int)$keys['pl_validsince'];
72                                unset($keys['pl_validsince']);
73                        }
74                        if (isset($keys['pm_id']))
75                        {
76                                $keys[] = $this->db->expression($this->prices_table,array('pm_id' => $keys['pm_id']));
77                                unset($keys['pm_id']);
78                        }
79                        $join = $this->prices_join;
80                       
81                        if (!$extra_cols) $extra_cols = $this->prices_extracols;
82                       
83                        // we use search as the join might return multiple columns, which we put in the prices and project_prices array
84                        if (!($prices = $this->search(false,false,'pm_id DESC,pl_validsince DESC',$extra_cols,'',false,'AND',false,$keys,$join)))
85                        {
86                                return false;
87                        }
88                        list(,$this->data) = each($prices);
89                        $this->data['prices'] = $this->data['project_prices'] = array();                       
90                       
91                        foreach($prices as $price)
92                        {
93                                if ($price['pm_id'])
94                                {
95                                        $this->data['project_prices'][] = $price;
96                                }
97                                else
98                                {
99                                        $this->data['prices'][] = $price;
100                                }
101                        }
102                        return $this->data;
103                }
104                return parent::read($keys,$extra_cols,$join);
105        }
106       
107        /**
108         * sql to define a priority depending on the relation-ship of the project the price was defined for to the given one
109         *
110         * The given project $pm_id has the highest priority, if $use_standard the standard-pricelist has priority 0
111         *
112         * @param int $pm_id=0 project to use, default $this->pm_id
113         * @param string $col='pm_id' column-name to use, default 'pm_id', can be changed to use a table-name/-alias too
114         * @param boolean $use_general=true should the general-pricelist be included too (pm_id=0)
115         * @return string sql with CASE WHEN
116         */
117        function sql_priority($pm_id=0,$col='pm_id',$use_general=true)
118        {
119                if (!$pm_id) $pm_id = $this->pm_id;
120               
121                $ancestors = array($pm_id);
122               
123                if (!($ancestors = $this->project->ancestors($pm_id,$ancestors)))
124                {
125                        echo "<p>sql_priority($pm_id,$col,$use_general) ancestory returnd false</p>\n";
126                        return false;
127                }
128                $sql = 'CASE '.$col;
129                foreach($ancestors as $n => $pm_id)
130                {
131                        $sql .= ' WHEN '.$pm_id.' THEN '.(count($ancestors)-$n);
132                }
133                if ($use_general)
134                {
135                        $sql .= ' WHEN 0 THEN 0';
136                }
137                $sql .= ' END';
138       
139                return $sql;
140        }
141
142        /**
143         * search elements, reimplemented to use $this->pm_id, if no pm_id given in criteria or filter and join with the prices table
144         *
145         * @param array/string $criteria array of key and data cols, OR a SQL query (content for WHERE), fully quoted (!)
146         * @param boolean $only_keys True returns only keys, False returns all cols
147         * @param string $order_by fieldnames + {ASC|DESC} separated by colons ','
148         * @param string/array $extra_cols string or array of strings to be added to the SELECT, eg. "count(*) as num"
149         * @param string $wildcard appended befor and after each criteria
150         * @param boolean $empty False=empty criteria are ignored in query, True=empty have to be empty in row
151         * @param string $op defaults to 'AND', can be set to 'OR' too, then criteria's are OR'ed together
152         * @param int/boolean $start if != false, return only maxmatch rows begining with start
153         * @param array $filter if set (!=null) col-data pairs, to be and-ed (!) into the query without wildcards
154         * @param string/boolean $join=true default join with prices-table or string as in so_sql
155         * @return array of matching rows (the row is an array of the cols) or False
156         */
157        function search($criteria,$only_keys=false,$order_by='pl_title',$extra_cols='',$wildcard='',$empty=False,$op='AND',$start=false,$filter=null,$join=true)
158        {
159                if ($join === true)     // add join with prices-table
160                {
161                        $join = $this->prices_join;
162                       
163                        if (isset($filter['pl_validsince']))
164                        {
165                                $filter[] = 'pl_validsince <= '.($validsince=(int)$filter['pl_validsince']);
166                                unset($filter['pl_validsince']);
167                        }
168                        else
169                        {
170                                $validsince = time();
171                        }
172                        if (!$extra_cols)
173                        {
174                                $extra_cols = $this->prices_extracols;
175                        }
176                        else
177                        {
178                                $extra_cols = array_merge($this->prices_extracols,
179                                        is_array($extra_cols) ? $extra_cols : explode(',',$extra_cols));
180                        }
181                        if (($no_general = isset($criteria['pm_id'])))
182                        {
183                                $pm_id = $criteria['pm_id'];
184                                unset($criteria['pm_id']);
185                        }
186                        else
187                        {
188                                $pm_id = isset($filter['pm_id']) ? $filter['pm_id'] : $this->pm_id;
189                                unset($filter['pm_id']);
190                        }
191                        if ($this->db->capabilities['sub_queries'])
192                        {
193                                $filter[] = "pl_validsince = (SELECT MAX(t.pl_validsince) FROM $this->prices_table t WHERE p.pl_id=t.pl_id AND p.pm_id=t.pm_id AND t.pl_validsince <= $validsince)";
194
195                                if (!$order_by) $order_by = 'pl_title';
196
197                                if ($pm_id)
198                                {
199                                        $filter[] = $this->sql_priority($pm_id,'p.pm_id').' = (select MAX('.$this->sql_priority($pm_id,'m.pm_id').
200                                                ") FROM $this->prices_table m WHERE m.pl_id=p.pl_id)";
201
202                                        if ($no_general) $filter[] = 'pm_id != 0 AND pl_billable IN (0,1)';
203                                }
204                                else
205                                {
206                                        $filter['pm_id'] = 0;
207                                }
208                        }
209                        else    // mysql 4.0 or less
210                        {
211                                // ToDo: avoid subqueries (eg. use a join) or do it manual inside php
212                                //echo "<p>Pricelist needs a DB capabal of subqueries (eg. MySQL 4.1+) !!!</p>\n";
213                                $filter['pm_id'] = $this->project->ancestors($this->pm_id,array(0,(int)$this->pm_id));
214                                $filter[] = 'pl_validsince <= '.$validsince;
215                        }
216                        $prices_filter = array();
217                        foreach($extra_cols as $col)
218                        {
219                                if (isset($filter[$col]))
220                                {
221                                        $prices_filter[$col] = $filter[$col];
222                                        unset($filter[$col]);
223                                }
224                        }
225                        if (count($prices_filter))
226                        {
227                                $filter[] = $this->db->expression($this->prices_table,$prices_filter);
228                        }
229                        // do we run a search
230                        if ($op == 'OR' && $wildcard == '%' && $criteria['pl_id'] && $criteria['pl_id'] == $criteria['pl_title'])
231                        {
232                                foreach(array('pl_customertitle','pl_price') as $col)
233                                {
234                                        $criteria[] = $col. ' LIKE '.$this->db->quote('%'.$criteria['pl_id'].'%');
235                                }
236                                unset($criteria['pl_id']);      // its ambigues
237                        }
238                }
239                // include sub-categories in the search
240                if ($filter['cat_id'])
241                {
242                        if (!is_object($GLOBALS['phpgw']->categories))
243                        {
244                                $GLOBALS['phpgw']->categories =& CreateObject('phpgwapi.categories');
245                        }
246                        $filter['cat_id'] = $GLOBALS['phpgw']->categories->return_all_children($filter['cat_id']);
247                }
248                return parent::search($criteria,$only_keys,$order_by,$extra_cols,$wildcard,$empty,$op,$start,$filter,$join);
249        }
250       
251        /**
252         * saves a single price
253         *
254         * @param array $price price-data
255         * @param boolean $touch_modified=true should the modififcation date and user be set
256         * @param int 0 on success, db::Errno otherwise
257         */
258        function save_price(&$price,$touch_modified=true)
259        {
260                //echo "<p>sopricelist::save_price(".print_r($price,true).",$touch_modified)</p>\n";
261                $price = $this->data2db($price);
262
263                if ($touch_modified)
264                {
265                        $price['pl_modified'] = time();
266                        $price['pl_modifier'] = $GLOBALS['phpgw_info']['user']['account_id'];
267                }
268                $this->db->insert($this->prices_table,$price,array(
269                        'pm_id' => $price['pm_id'],
270                        'pl_id' => $price['pl_id'],
271                        'pl_validsince' => $price['pl_validsince'],
272                ),__LINE__,__FILE__);
273               
274                $price = $this->db2data($price);
275
276                return $this->db->Errno;
277        }
278       
279        /**
280         * delete pricelist-entries and price(s) specified by keys pl_id, pm_id and/or pl_validsince
281         *
282         * If the last price of a pricelist-entry gets deleted, the pricelist entry is automatic deleted too!
283         *
284         * @param array/int $keys array with keys pm_id, pl_id and/or pl_validsince to delete or integer pm_id
285         * @return int number of deleted prices
286         */
287        function delete($keys)
288        {
289                //echo "<p>sopricelist::delete(".print_r($keys,true).",$touch_modified)</p>\n";
290                if (!is_array($keys) && (int) $keys) $keys = array('pm_id' => (int) $keys);
291               
292                $keys = $this->data2db($keys);  // adjust the validsince timestampt to server-time
293
294                $where = array();
295                foreach(array('pm_id','pl_id','pl_validsince') as $key)
296                {
297                        if (isset($keys[$key])) $where[$key] = $keys[$key];
298                }
299                if (!$where) return false;
300
301                $this->db->delete($this->prices_table,$where,__LINE__,__FILE__);
302                $deleted = $this->db->affected_rows();
303
304                // check for pricelist items with no prices and delete them too
305                $this->db->select($this->table_name,$this->table_name.'.pl_id',$this->prices_table.'.pl_id IS NULL',__LINE__,__FILE__,false,'',false,0,"LEFT JOIN $this->prices_table ON $this->table_name.pl_id=$this->prices_table.pl_id");
306                $pl_ids = array();
307                while($this->db->next_record())
308                {
309                        $pl_ids[] = $this->db->f(0);
310                }
311                if ($pl_ids)
312                {
313                        $this->db->delete($this->table_name,array('pl_id' => $pl_ids),__LINE__,__FILE__);
314                }
315                return $deleted;
316        }
317}
Note: See TracBrowser for help on using the repository browser.