noalyss Version-9
NOALYSS : serveur de comptabilité et ERP (2002)
Loading...
Searching...
No Matches
impress.class.php
Go to the documentation of this file.
1<?php
2
3/*
4 * This file is part of NOALYSS.
5 *
6 * NOALYSS is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * NOALYSS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with NOALYSS; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21// Copyright Author Dany De Bontridder danydb@aevalys.eu
22/* !
23 * \file
24 * \brief contains function for the parsing and computing formulae. Test are in scenario/test_parse_formula.php
25 */
26
27/**
28 * @class Impress
29 * @brief contains function for the parsing and computing formulae . Test are in scenario/test_parse_formula.php
30 */
32{
33 //!< string pattern to use
34 const STR_PATTERN="([\[\{]{1,2}[[:alnum:]]*%*(-[c,d,s,S]){0,1}[\]\}]{1,2})";
35
36 /* !
37 *
38 * \brief Purpose Parse a formula
39 *
40 * \param $p_cn connexion
41 * \param $p_label
42 * \param $p_formula
43 * \param $p_eval true if we eval here otherwise the function returns
44 * a string which must be evaluated
45 \param $p_type_date : type of the date 0 for accountant period or 1
46 * for calendar
47 * \return array key [ desc , montant ]
48 *
49 *
50 */
51
52 static function parse_formula($p_cn, $p_label, $p_formula, $p_start, $p_end, $p_eval=true, $p_type_date=0, $p_sql="")
53 {
54 global $g_user;
55 if (Impress::check_formula($p_formula)==false)
56 {
57 if ($p_eval==true)
58 return array('desc'=>$p_label.' Erreur Formule!',
59 'montant'=>0);
60 else
61 return $p_formula;
62 }
63 // Bug
64 // with PHP8 if ('periode'==0 ) echo "hello"; else echo 'different' ; => different
65 // with PHP7 if ('periode'==0 ) echo "hello"; else echo 'different' ; => hello
66
67 if ($p_type_date==0)
68 {
69 $cond=sql_filter_per($p_cn, $p_start, $p_end, 'p_id', 'j_tech_per');
70 $cond_anc= "and ".transform_sql_filter_per($cond);
71 }
72 elseif ($p_type_date == 1) {
73 $cond="( j_date >= to_date('$p_start','DD.MM.YYYY') and j_date <= to_date('$p_end','DD.MM.YYYY'))";
74 $cond_anc="and ( oa_date >= to_date('$p_start','DD.MM.YYYY') and oa_date <= to_date('$p_end','DD.MM.YYYY'))";
75 } else {
76 throw new Exception("impress72 invalid type_date [ {$p_type_date} ] ");
77 }
78
79 // ------------------- for accounting , analytic or card-------------------------------------
80 if ( DEBUGNOALYSS > 1)
81 {
82 tracedebug("impress.debug.log", "$p_formula ", 'parse_formula-71 $formula to parse' );
83 tracedebug("impress.debug.log", "$p_label ", 'parse_formula-72 $p_label' );
84 tracedebug("impress.debug.log", $p_start,'parse_formula-73 $p_start' );
85 tracedebug("impress.debug.log", $p_end,'parse_formula-74 $p_end ' );
86 tracedebug("impress.debug.log", $p_type_date,'parse_formula-75 $p_type_date' );
87 tracedebug("impress.debug.log", $p_sql,'parse_formula-76 $p_sql' );
88 tracedebug("impress.debug.log", $cond ,'parse_formula-77 $cond SQL accountancy' );
89 tracedebug("impress.debug.log", $cond_anc,'parse_formula-78 $cond_anc SQL Analytic Acc' );
90 }
91 while (preg_match_all(Impress::STR_PATTERN, $p_formula, $e)==true)
92 {
93 $x=$e[0];
94 foreach ($x as $line)
95 {
96
97 // If there is a FROM clause we must recompute
98 // the time cond
99
100 if ($p_type_date==0&&preg_match("/FROM=[0-9]+\.[0-9]+/", $p_formula, $afrom)==1)
101 {
102 $from=noalyss_str_replace('FROM=','',$afrom[0]);
104 $cond_anc=" and ".transform_sql_filter_per($cond);
105 // We remove FROM out of the p_formula
106 $p_formula=substr_replace($p_formula, "", strpos($p_formula, "FROM"));
107 }
108 if ($p_type_date==1&&preg_match("/FROM=[0-9]+\.[0-9]+/", $p_formula, $afrom)==1)
109 {
110 // We remove FROM out of the p_formula
111 $p_formula=substr_replace($p_formula, "", strpos($p_formula, "FROM"));
112 }
113 $amount=\Impress::compute_amount($p_cn,$line,$cond." ".$p_sql,$cond_anc." ".$p_sql);
114
115
116 $p_formula=noalyss_str_replace($x[0],"(". $amount.")", $p_formula);
117 }
118 }
119
120 // $p_eval is true then we eval and returns result
121 if ($p_eval==true)
122 {
123 /* -------------------------------------
124 * Protect againt division by zero
125 */
126 $p_formula=remove_divide_zero($p_formula);
127 $p_formula="\$result=".$p_formula.";";
128 try {
129 eval("$p_formula");
130 } catch(Exception $e) {
131 return array("desc"=>"erreur","montant"=>'0');
132 }
133 while (preg_match("/\[([0-9]+)(-[Tt]*)\]/", trim($p_label), $e)==1)
134 {
135 $nom="!!".$e[1]."!!";
137 {
138 $nom=$p_cn->get_value("SELECT pcm_lib AS acct_name FROM tmp_pcmn WHERE pcm_val::text LIKE $1||'%' ORDER BY pcm_val ASC LIMIT 1",
139 array($e[1]));
140 if ($nom)
141 {
142 if ($e[2]=='-T')
143 $nom=strtoupper($nom);
144 if ($e[2]=='-t')
145 $nom=strtolower($nom);
146 }
147 }
148 $p_label=noalyss_str_replace($e[0], $nom, $p_label);
149 }
150
151 $aret=array('desc'=>$p_label,
152 'montant'=>$result);
153 return $aret;
154 }
155 else
156 {
157 // $p_eval is false we returns only the string
158 return $p_formula;
159 }
160 }
161
162 /* !
163 * \brief Check if formula doesn't contain
164 * php injection
165 * \param string
166 *
167 * \return true if the formula is good otherwise false
168 */
169
170 static function check_formula($p_string)
171 {
172 // the preg_match gets too complex if we want to add a test
173 // for parenthesis, math function...
174 // So I prefer remove them before testing
175
176
177
178 $p_string=noalyss_str_replace("round", "", $p_string);
179 $p_string=noalyss_str_replace("abs", "", $p_string);
180 $p_string=noalyss_str_replace("(", "", $p_string);
181 $p_string=noalyss_str_replace(")", "", $p_string);
182 // for the inline test like $a=(cond)?value:other;
183 $p_string=noalyss_str_replace("?", "+", $p_string);
184 $p_string=noalyss_str_replace(":", "+", $p_string);
185 $p_string=noalyss_str_replace(">=", "+", $p_string);
186 $p_string=noalyss_str_replace("<=", "+", $p_string);
187 $p_string=noalyss_str_replace(">", "+", $p_string);
188 $p_string=noalyss_str_replace("<", "+", $p_string);
189 // eat Space + comma
190 $p_string=noalyss_str_replace(" ", "", $p_string);
191 $p_string=noalyss_str_replace(",", "", $p_string);
192 // Remove D/C/S
193 $p_string=noalyss_str_replace("-c", "", $p_string);
194 $p_string=noalyss_str_replace("-d", "", $p_string);
195 $p_string=noalyss_str_replace("-s", "", $p_string);
196 $p_string=noalyss_str_replace("-S", "", $p_string);
197 // Remove T,t
198 $p_string=noalyss_str_replace("-t", "", $p_string);
199
200 // analytic accountancy (between {} )
201 $p_string=preg_replace("/\{\{[[:alnum:]]*\}\}/", "", $p_string);
202
203 // card (between {} )
204 $p_string=preg_replace("/\{[[:alnum:]]*\}/", "", $p_string);
205
206 // remove date
207 $p_string=preg_replace("/FROM*=*[0-9]+/", "", $p_string);
208 // remove comment
209 $p_string=preg_replace("/#.*/", "", $p_string);
210 // remove php variable $C=
211 $p_string=preg_replace('/\$[a-z]*[A-Z]*[0-9]*[A-Z]*[a-z]*/', "", $p_string);
212 $p_string=preg_replace('/=/', "", $p_string);
213
214 // remove account
215 $p_string=preg_replace("/\[[0-9]*[A-Z]*%*\]/", "", $p_string);
216
217 $p_string=preg_replace("/\+|-|\/|\*/", "", $p_string);
218 $p_string=preg_replace("/[0-9]*\.*[0-9]/", "", $p_string);
219
220 //************************************************************************************************************
221 // If the string is empty then formula should be good
222 //
223 //************************************************************************************************************
224 if ($p_string=='')
225 {
226 return true;
227 }
228 else
229 {
230 return false;
231 }
232 }
233
234 /**
235 * with the handle of a successull query, echo each row into CSV and
236 * send it directly
237 * @param type $array of data
238 * @param type $aheader double array, each item of the array contains
239 * a key type (num) and a key title
240 */
241 static function array_to_csv($array, $aheader, $p_filename)
242 {
243 $file_csv=new Noalyss_Csv($p_filename);
244 for ($i=0; $i<count($aheader); $i++)
245 {
246 $file_csv->add($aheader[$i]['title']);
247 }
248 $file_csv->write();
249
250 // fetch all the rows
251 for ($i=0; $i<count($array); $i++)
252 {
253 $row=$array[$i];
254 $e=0;
255 // for each rows, for each value
256 foreach ($array[$i] as $key=> $value)
257 {
258 if ($e>count($aheader))
259 continue;
260
261 if (isset($aheader[$e]['type']))
262 {
263 switch ($aheader[$e]['type'])
264 {
265 case 'num':
266 $file_csv->add($value, "number");
267 break;
268 default:
269 $file_csv->add($value);
270 }
271 }
272 else
273 {
274 $file_csv->add($value);
275 }
276 $e++;
277 }
278 $file_csv->write();
279 }
280 }
281
282 /**
283 * return what to consider
284 * - "deb" for the total of the debit ,
285 * - "cred" for total of credit,
286 * - "signed" for tot. debit - tot. credit
287 * - "cdsigned" for tot.credit - tot.debit
288 * - "all" is the balance of accounting in absolute value
289 *
290 * @param string $p_formula
291 * @return "all", "deb","cred","signed" or "cdsigned"
292 */
293 static function find_computing_mode($p_formula)
294 {
295 if (strpos($p_formula, '-d')!=0)
296 {
297 return 'deb';
298 }
299 elseif (strpos($p_formula, '-c')!=0)
300 {
301 return 'cred';
302 }
303 elseif (strpos($p_formula, '-s')!=0)
304 {
305 return 'signed';
306 }
307 elseif (strpos($p_formula, '-S')!=0)
308 {
309 return 'cdsigned';
310 }
311 return 'all';
312 }
313 /**
314 * @brief make the condition SQL for filtering on the period
315 * @param \DatabaseCore $p_cn
316 * @param int $p_from periode id
317 * @param int $p_end until periode id
318 * @throws Exception
319 */
320 static public function compute_periode($p_cn, $p_from,$p_end)
321 {
322 // There is a FROM clause
323 // then we must modify the cond for the periode
324
325
326 // Get the periode
327 /* ! \note special value for the clause FROM=00.0000, we take the first day of the exercice of $p_end
328 for France (MY_REPORT==N), the first day of the folder
329 */
330 if ($p_from=='00.0000')
331 {
332 $current_exercice=$p_cn->get_value('select p_exercice from parm_periode where p_id=$1',
333 [$p_end]);
334 if ( $current_exercice=="") {
335 throw new Execution(_('CP329'));
336 }
337 $first_day=$p_cn->get_value("select to_char(min(p_start),'DD.MM.YYYY') as p_start from parm_periode where p_exercice=$1",
339 $last_day=$p_cn->get_value("select to_char(p_end,'DD.MM.YYYY') from parm_periode where p_id=$1",[$p_end]);
340 // retrieve the first month of this periode
341 if (empty($first_day))
342 throw new Exception('Pas de limite à cette période', 1);
343 global $g_parameter;
344
345 if ( $g_parameter->MY_REPORT == 'N') $first_day='01.01.1900';
346
347 $cond=sql_filter_per($p_cn, $first_day, $last_day, 'date', 'j_tech_per');
348 }
349 else
350 {
351 $oPeriode=new Periode($p_cn);
352 try
353 {
354 $pfrom=$oPeriode->find_periode('01.'.$p_from);
355 $cond=sql_filter_per($p_cn, $pfrom, $p_end, 'p_id', 'j_tech_per');
356 }
357 catch (Exception $exp)
358 {
359 /* if none periode is found
360 then we take the first periode of the year
361 */
362
363 $first_day=$p_cn->get_value("select to_char(min(p_start),'DD.MM.YYYY') as p_start from parm_periode");
364 $last_day=$p_cn->get_value("select to_char(p_end,'DD.MM.YYYY') from parm_periode where p_id=$1",[$p_end]);
365 // retrieve the first month of this periode
366 if (empty($first_day))
367 throw new Exception('Pas de limite à cette période', 1);
368 $cond=sql_filter_per($p_cn, $first_day, $last_day, 'date', 'j_tech_per');
369 }
370 }
371 return $cond;
372 }
373 /**
374 * @brief compute the amount of the accounting ,analytic accounting or a card, the SQL condition
375 * from sql_filter_per must be transformed for ANALYTIC ACCOUNT
376 * @see sql_filter_per
377 * @param DatabaseCore $p_cn
378 * @param string $p_expression part of a formula
379 * @param string $p_cond_sql SQL cond for accountancy
380 * @param string $p_cond_sql SQL cond for analytic accountancy
381 */
382 static function compute_amount($p_cn, $p_expression, $p_cond_sql,$p_cond_anc_sql)
383 {
384 if ( DEBUGNOALYSS > 1)
385 {
386 tracedebug("impress.debug.log", "$p_expression", '$p_expression' );
387 tracedebug("impress.debug.log", "$p_cond_sql", '$p_cond_sql' );
388 }
389 $compute=\Impress::find_computing_mode($p_expression);
390 // remove char for the mode
391 $p_expression=noalyss_str_replace("-d", "", $p_expression);
392 $p_expression=noalyss_str_replace("-c", "", $p_expression);
393 $p_expression=noalyss_str_replace("-s", "", $p_expression);
394 $p_expression=noalyss_str_replace("-S", "", $p_expression);
395 // we have an account
396 if (preg_match("/\[.*\]/", $p_expression)) {
397 $p_expression=noalyss_str_replace("[", "", $p_expression);
398 $p_expression=noalyss_str_replace("]", "", $p_expression);
399 $P=new Acc_Account_Ledger($p_cn, $p_expression);
400 $detail=$P->get_solde_detail($p_cond_sql);
401 } elseif (preg_match("/\{\{.*\}\}/", $p_expression))
402 {
403 $p_expression=noalyss_str_replace("{", "", $p_expression);
404 $p_expression=noalyss_str_replace("}", "", $p_expression);
405 $anc_account= new Anc_Account($p_cn);
406 $anc_account->load_by_code($p_expression);
407
408 if ( DEBUGNOALYSS > 1)
409 {
410 tracedebug("impress.debug.log", $p_expression, 'code analytic account');
411 tracedebug("impress.debug.log", $p_cond_anc_sql, 'condition SQL ');
412 }
413 /// Transform the $p_cond_sql , it comes from sql_filter_per
414 // and looks like j_tech_per in (select p_id from parm_periode where
415
416 $detail=$anc_account->get_balance($p_cond_anc_sql);
417
418 } elseif (preg_match("/\{.*\}/", $p_expression))
419 { // we have a card
420 // remove useless char
421 $p_expression=noalyss_str_replace("{", "", $p_expression);
422 $p_expression=noalyss_str_replace("}", "", $p_expression);
423 $fiche=new Fiche($p_cn);
424 if ( DEBUGNOALYSS > 1)
425 {
426 tracedebug("impress.debug.log", "$p_expression", 'search_card qcode =');
427 }
428 $fiche->get_by_qcode(strtoupper(trim($p_expression)));
429 $detail=$fiche->get_solde_detail($p_cond_sql);
430 } else {
431 throw new \Exception ("Impress::compute_amount383.".
432 " Unknown expression \$p_expression [$p_expression]".
433 " \$p_cond_sql $p_cond_sql");
434 }
435
436
437
438
439 // Get sum of account
440
441 switch ($compute)
442 {
443 case "all":
444 $res=$detail['solde'];
445 break;
446 case 'deb':
447 $res=$detail['debit'];
448 break;
449 case 'cred':
450 $res=$detail['credit'];
451 break;
452 case 'signed':
453 $res=bcsub($detail['debit'], $detail['credit'], 4);
454 break;
455 case 'cdsigned':
456 $res=bcsub($detail['credit'], $detail['debit'], 4);
457 break;
458 }
459 return $res;
460 }
461
462}
sql_filter_per($p_cn, $p_from, $p_to, $p_form='p_id', $p_field='jr_tech_per')
Create the condition to filter on the j_tech_per thanks a from and to date.
noalyss_str_replace($search, $replace, $string)
remove_divide_zero($p_formula)
When it is needed to eval a formula , this function prevent the divide by zero.
global $g_parameter
global $g_user
if no group available , then stop
$from
_("actif, passif,charge,...")
Manage the account from the table jrn, jrnx or tmp_pcmn.
Analytic account ; get the balance.
define Class fiche and fiche def, those class are using class attribut. When adding or modifing new c...
contains function for the parsing and computing formulae .
static find_computing_mode($p_formula)
return what to consider
static compute_periode($p_cn, $p_from, $p_end)
make the condition SQL for filtering on the period
static array_to_csv($array, $aheader, $p_filename)
with the handle of a successull query, echo each row into CSV and send it directly
static compute_amount($p_cn, $p_expression, $p_cond_sql, $p_cond_anc_sql)
compute the amount of the accounting ,analytic accounting or a card, the SQL condition from sql_filte...
const STR_PATTERN
< string pattern to use
static check_formula($p_string)
static parse_formula($p_cn, $p_label, $p_formula, $p_start, $p_end, $p_eval=true, $p_type_date=0, $p_sql="")
Manage the CSV : manage files and write CSV record.
$oPeriode
Definition do.php:156
if( $delta< 0) elseif( $delta==0)