Activated strict SQL mode, minor SQL injection fix, fixed _vl() debug helper.
[fa-stable.git] / includes / db / class.reflines_db.inc
1 <?php
2 /**********************************************************************
3     Copyright (C) FrontAccounting, LLC.
4         Released under the terms of the GNU General Public License, GPL, 
5         as published by the Free Software Foundation, either version 3 
6         of the License, or (at your option) any later version.
7     This program is distributed in the hope that it will be useful,
8     but WITHOUT ANY WARRANTY; without even the implied warranty of
9     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
10     See the License here <http://www.gnu.org/licenses/gpl-3.0.html>.
11 ***********************************************************************/
12 include_once 'class.data_set.inc';
13
14 /**
15 *       Reference lines.
16 *
17 **/
18
19 class reflines_db extends data_set {
20         function __construct()
21         {
22                 $this->set_validator('prefix:ui:_check_prefix', _("This prefix conflicts with another one already defined. Prefix have to be unambigous."));
23                 $this->set_validator('prefix:ui:_check_template', _("Invalid template format."));
24                 $this->set_validator('trans_type:ui:required', _("Transaction type cannot be empty."));
25                 $this->set_validator('pattern:ui:required', _("Next reference cannot be empty."));
26                 parent::__construct('reflines', 
27                         array('trans_type', 'prefix', 'description', 'default', 'pattern', 'id', 'inactive'), 
28                         'id');
29         }
30
31         /*
32                 Prefix cannot be ambigous.
33         */
34         function _check_prefix($data, $dummy_opt, $key)
35         {
36                 $cond = "`id`<>".db_escape($key)." AND `trans_type`=".db_escape($data['trans_type']);
37                 if ($data['prefix'] === '')
38                         $cond .= " AND `prefix`='".$data['prefix']."'";
39                 else
40                         $cond .= "AND ((LOCATE('".$data['prefix']."', CONCAT(`prefix`,`pattern`))=1 OR (`prefix`<>'' AND LOCATE(`prefix`, '".$data['prefix'].$data['pattern']."')=1)))";
41
42                 return db_num_rows($this->get_all($cond)) == 0;
43         }
44
45         function _check_template($data, $dummy_opt, $key)
46         {
47                 global $refline_options, $refline_placeholders;
48
49                 if (strpbrk($data['prefix'], '{}') !== false)
50                         return $this->error(_("You cannot use placeholders in refline prefix."));
51
52                 if (substr_count($data['pattern'], '{') != substr_count($data['pattern'], '}'))
53                         return $this->error(_("Curly brackets does not balance."));
54
55                 if (preg_match_all('/\{([^\}]*)\}/', $data['pattern'], $match)) // placeholders defind in template
56                 {
57                         $numph = 0;
58                         foreach($match[1] as $ph) {
59                                 if (is_numeric($ph))
60                                         $numph++;
61                                 elseif (!isset($refline_placeholders[$ph]) || !@in_array($refline_placeholders[$ph], $refline_options[$data['trans_type']])) {
62                                         $allowed = array();
63                                         foreach($refline_placeholders as $id => $dt)
64                                                  if (in_array($dt, $refline_options[$data['trans_type']]))
65                                                         $allowed[] = $id;
66
67                                         return $this->error(sprintf(_("Invalid placeholder '%s'. Placeholders allowed for this transaction type are: %s."),
68                                                 $ph, implode(',', $allowed)));
69                                 }
70                         }
71
72                         if ($numph !== 1)
73                                 return $this->error(_("Missing numeric placeholder. If you want to use template based references, you have to define numeric placeholder too."));
74                 }
75                 return true;
76         }
77
78         function is_used($prefix, $trans_type)
79         {
80
81                 $sql = "SELECT *
82                         FROM (SELECT r.* FROM ".TB_PREF."refs r 
83                                 LEFT JOIN ".TB_PREF."voided as v
84                                         ON r.id=v.id AND r.type=v.type
85                                 WHERE r.type=".db_escape($trans_type)." AND ISNULL(v.id)
86                                 ) ref
87                         LEFT JOIN ".TB_PREF."reflines line ON ref.type=line.trans_type AND substr(ref.reference,1, LENGTH(line.prefix))= line.prefix AND line.prefix<>''
88                         WHERE ".($prefix == '' ? "ISNULL(prefix)" : "prefix=".db_escape($prefix));
89
90                 $res = db_query($sql, "cannot check reference line");
91
92                 return db_num_rows($res);
93         }
94
95         function delete_check($ref_id)
96         {
97                 $rec = $this->get($ref_id);
98                 if ($rec['default'])
99                         return $this->error(_("Reference line which is default for any transaction type cannot be deleted."));
100
101                 if ($this->is_used($rec['prefix'], $rec['trans_type']))
102                         return $this->error(_("Reference line cannot be deleted because it is already in use."));
103
104                 return true;
105         }
106
107         function _set_as_default($id, $type)
108         {
109                 $sql  = "UPDATE ".TB_PREF."reflines SET `default`=(`id`=".db_escape($id).")
110                          WHERE `trans_type`=".db_escape($type);
111                 return db_query($sql, "cannot update default refline");
112         }
113
114         function insert($data)
115         {
116                 if (!parent::insert($data))
117                         return false;
118                 if (@$data['default'])
119                         return $this->_set_as_default(db_insert_id(), $data['trans_type']);
120                 return true;
121         }
122
123         function update($key, $data)
124         {
125                 if (!parent::update($key, $data))
126                         return false;
127                 if (@$data['default'])
128                         return $this->_set_as_default($key , $data['trans_type']);
129                 return true;
130         }
131
132         function get_default($type)
133         {
134                 $sql = "SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)." AND `default`";
135                 $result = db_query($sql, "cannot retreive default refline for trnasaction type $type");
136                 return db_fetch($result);
137         }
138
139         function count($type, $all=false)
140         {
141                 $sql = "SELECT count(*) FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type);
142
143                 if (!$all)
144                         $sql .= " AND !inactive";
145                 $result = db_query($sql, "cannot retreive refline count for transaction type $type");
146                 $rec = db_fetch($result);
147                 return $rec ? $rec[0] : 0;
148         }
149
150         /*
151                 Recognize refline by reference prefix
152         */
153         function find_refline_id($reference, $type, $fallback=true)
154         {
155                 $sql = "SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)
156                         ." AND CHAR_LENGTH(`prefix`) AND LEFT(".db_escape($reference).", CHAR_LENGTH(`prefix`)) = `prefix`";
157                 if ($fallback)  // if not found return refline with empty prefix
158                         $sql .= " UNION SELECT * FROM ".TB_PREF."reflines WHERE trans_type=".db_escape($type)." AND `prefix`=''";
159                 $ret = db_query($sql, "cannot check reference line id");
160                 $line = db_fetch($ret);
161
162                 if (!$fallback && (db_num_rows($fallback) != 1))        // more than one record means ambigous reference line
163                         return null;
164
165                 return $line ? $line['id'] : null;
166         }
167
168         function save_next($type, $reference, $line=null)
169         {
170             $sql = "UPDATE ".TB_PREF."reflines SET pattern=SUBSTRING(" . db_escape(trim($reference)) .", LENGTH(`prefix`)+1)"
171                 . " WHERE trans_type = ".db_escape($type)." AND ";
172
173                 if (isset($line))
174                         $sql .= "`id`=".db_escape($line);
175                 else
176                         $sql .= "`default`";
177
178                 return db_query($sql, "The next transaction ref for $type could not be updated");
179         }
180 }