Plugins  LAST
 All Data Structures Files Functions Variables Pages
class_impacc_csv.php
Go to the documentation of this file.
1 <?php
2 
3 /*
4  * Copyright (C) 2016 Dany De Bontridder <dany@alchimerys.be>
5  *
6  * This program 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 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 require_once 'class_impacc_csv_bank.php';
22 require_once 'class_impacc_csv_sale.php';
23 require_once 'class_impacc_csv_purchase.php';
24 require_once 'class_impacc_csv_misc_operation.php';
25 require_once 'class_impacc_tool.php';
26 require_once DIR_IMPORT_ACCOUNT."/database/class_impacc_import_detail_sql.php";
27 
28 ///Used by all Import CSV Operation , contains the setting (delimiter,thousand ...)
30 {
31 
32  var $detail; //!< Object Impacc_Import_csv_SQL
33  var $errcode; //!< Array of error code will be recorded in import_detail.id_message
34 
35  function __construct()
36  {
37  $cn=Dossier::connect();
38  $this->detail=new Impacc_Import_csv_SQL($cn);
39  $this->detail->s_delimiter="2";
40  $this->detail->s_surround='"';
41  $this->detail->jrn_def_id=3;
42  $this->detail->s_encoding="utf-8";
43  $this->detail->s_decimal='1';
44  $this->detail->s_thousand='0';
45  $this->detail->s_date_format=1;
46  $this->errcode=array(
47  "CK_FORMAT_DATE"=>_("Format de date incorrect"),
48  "CK_PERIODE_CLOSED"=>_("Période non trouvée"),
49  "CK_INVALID_PERIODE"=>_("Période non trouvée"),
50  "CK_INVALID_AMOUNT"=>_("Montant invalide"),
51  "CK_INVALID_ACCOUNTING"=>_("Poste comptable ou Fiche non existante"),
52  "CK_TVA_INVALID"=>_("Code TVA Invalide"),
53  "CK_CARD_LEDGER"=>_("Fiche non disponible pour journal"),
54  "CK_BALANCE"=>_("Balance incorrecte"),
55  "CK_ERROR_DEBIT"=>_("Erreur D/C")
56  );
57  }
58 
59  /// Display a form to upload a CSV file with operation
60  function input_format()
61  {
63  $in_delimiter=new ISelect('in_delimiter');
64  $in_delimiter->value=$aseparator;
65  $in_delimiter->selected=$this->detail->s_delimiter;
66  $in_delimiter->size=1;
67 
68  $in_surround=new IText('in_surround', $this->detail->s_surround);
69  $in_surround->size=1;
70 
71  $ledger=new Acc_Ledger($cn, $this->detail->jrn_def_id);
72  $in_ledger=$ledger->select_ledger('ALL', 3);
73  $in_ledger->name='in_ledger';
74 
75  $in_encoding=new ISelect('in_encoding');
76  $in_encoding->value=array(
77  array('value'=>"utf-8", 'label'=>_('Unicode')),
78  array('value'=>"latin1", 'label'=>_('Latin'))
79  );
80  $in_encoding->selected=$this->detail->s_encoding;
81 
82  $in_decimal=new ISelect('in_decimal');
83  $in_decimal->value=$adecimal;
84  $in_decimal->selected=$this->detail->s_decimal;
85  $in_decimal->size=1;
86 
87  $in_thousand=new ISelect('in_thousand');
88  $in_thousand->selected=$this->detail->s_thousand;
89  $in_thousand->value=$athousand;
90  $in_thousand->size=1;
91 
92  $in_date_format=new ISelect("in_date_format");
93  $in_date_format->value=$aformat_date;
94  $in_date_format->selected=$this->detail->s_date_format;
95 
96  require_once DIR_IMPORT_ACCOUNT.'/template/upload_operation.php';
97  }
98 
99  function set_import($p_file_id)
100  {
101  $this->detail->import_id=$p_file_id;
102  }
103 
104  //---------------------------------------------------------------------
105  ///Get value from post , fill up the Impacc_Import_csv_SQL object
106  //---------------------------------------------------------------------
107 
108  function set_setting()
109  {
110  $this->detail->s_delimiter=HtmlInput::default_value_post("in_delimiter",
111  "");
112  $this->detail->s_surround=HtmlInput::default_value_post("in_surround",
113  "");
114  $this->detail->jrn_def_id=HtmlInput::default_value_post("in_ledger", "");
115  $this->detail->s_encoding=HtmlInput::default_value_post("in_encoding",
116  " ");
117  $this->detail->s_decimal=HtmlInput::default_value_post("in_decimal", "");
118  $this->detail->s_thousand=HtmlInput::default_value_post("in_thousand",
119  "");
120  $this->detail->s_date_format=HtmlInput::default_value_post("in_date_format",
121  4);
122  }
123 
124  function check_setting()
125  {
126 // Check if valid
127 // 1 sep for thousand and decimal MUST be different
128  if ($this->detail->s_thousand==$this->detail->s_decimal)
129  throw new Exception(_("Séparateur de décimal et milliers doivent être différent"));
130 //2 encoding and delimiter can not be empty
131 //3 ledger must be writable for user
132 //4 Check Date format
133  }
134 
135  /// Check that upload file is correct
136  function check(Impacc_File $p_file)
137  {
138  global $aformat_date;
139 
140  $this->load_import($p_file->impid);
141  $cn=Dossier::connect();
142  $ledger=new Acc_Ledger($cn, $this->detail->jrn_def_id);
143  $ledger_type=$ledger->get_type();
144 
145  // connect to DB
146  $cn=Dossier::connect();
147 
148  // load all rows where status != -1
149  $t1=new Impacc_Import_detail_SQL($cn);
150  $array=$t1->collect_objects(" where import_id = $1 and coalesce(id_status,0) <> -1 ",
151  array($p_file->impid));
152  // for each row check
153  $nb_array=count($array);
154  $date_format=$aformat_date[$this->detail->s_date_format-1]['format'];
155  $date_format_sql=$aformat_date[$this->detail->s_date_format-1]['label'];
156 
157  for ($i=0; $i<$nb_array; $i++)
158  {
159  $and=($array[$i]->id_message=="")?"":",";
160  $array[$i]->id_status=0;
161  if (trim($array[$i]->id_code_group)=="")
162  {
163  $array[$i]->id_status=-1;
164  $array[$i]->id_message .= $and."CK_CODE_GROUP";
165  $and=",";
166  }
167  //------------------------------------
168  //Check date format
169  //------------------------------------
170  $test=DateTime::createFromFormat($date_format, $array[$i]->id_date);
171  if ($test==false)
172  {
173  $array[$i]->id_status=-1;
174  $array[$i]->id_message .= $and."CK_FORMAT_DATE";
175  $and=",";
176  }
177  else
178  {
179  $array[$i]->id_date_conv=$test->format('d.m.Y');
180  $array[$i]->id_date_format_conv=$test->format('Ymd');
181  // Check if date exist and in a open periode
182  $sql=sprintf("select p_id from parm_periode where p_start <= to_date($1,'%s') and p_end >= to_date($1,'%s') ",
183  $date_format_sql, $date_format_sql);
184  $periode_id=$cn->get_value($sql, array($array[$i]->id_date));
185  if ($cn->size()==0)
186  {
187  $array[$i]->id_message.=$and."CK_INVALID_PERIODE";
188  $and=",";
189  }
190  else
191  // Check that this periode is open for this ledger
192  {
193  $per=new Periode($cn, $periode_id);
194  $per->jrn_def_id=$this->detail->jrn_def_id;
195  if ($per->is_open()==0)
196  {
197  $array[$i]->id_message.=$and."CK_PERIODE_CLOSED";
198  $and=",";
199  }
200  }
201  }
202  //----------------------------------------------------------------
203  // Check that first id_acc does exist , for ODS it could be an
204  // accounting, the card must be accessible for the ledger
205  //----------------------------------------------------------------
206  $card=Impacc_Verify::check_card($array[$i]->id_acc);
207  if ($ledger_type=='ODS'&&$card==false)
208  {
209  // For ODS it could be an accounting
210  $poste=new Acc_Account_Ledger($cn, $array[$i]->id_acc);
211  if ($poste->do_exist()==0)
212  {
213  $array[$i]->id_message.=$and."CK_INVALID_ACCOUNTING";
214  $and=",";
215  }
216  }
217  if ($ledger_type!='ODS'&&$card==false)
218  {
219  $array[$i]->id_message.=$and."CK_INVALID_ACCOUNTING";
220  $and=",";
221  }
222  // If card is valid check if belong to ledger
223  if ($card instanceof Fiche)
224  {
225  if ($card->belong_ledger($this->detail->jrn_def_id)!=1)
226  {
227  $array[$i]->id_message.=$and."CK_CARD_LEDGER";
228  $and=",";
229  }
230  }
231  //---------------------------------------------------------------
232  // Check amount
233  // --------------------------------------------------------------
234 
235  $array[$i]->id_amount_novat_conv=Impacc_Tool::convert_amount($array[$i]->id_amount_novat,
236  $this->detail->s_thousand, $this->detail->s_decimal);
237  if (isNumber($array[$i]->id_amount_novat_conv)==0)
238  {
239  $array[$i]->id_message.=$and."CK_INVALID_AMOUNT";
240  $and=",";
241  }
242 
243  //----------------------------------------------------------------
244  // Test for specific filter
245  //----------------------------------------------------------------
246  switch ($ledger_type)
247  {
248  case 'ACH':
249  //-----------------
250  ///- Check Service
251  //-----------------
252  $card=Impacc_Verify::check_card($array[$i]->id_acc_second);
253  if ($card==false)
254  {
255  $array[$i]->id_message=$and."CK_INVALID_ACCOUNTING";
256  $and=",";
257  }
258  if ($card instanceof Fiche&&$card->belong_ledger($this->detail->jrn_def_id)!=1)
259  {
260  $array[$i]->id_message.=$and."CK_CARD_LEDGER";
261  $and=",";
262  }
264  $this->detail->s_thousand, $this->detail->s_decimal);
265  break;
266  case 'VEN':
267  //-----------------
268  ///- Check Service
269  //-----------------
270  $card=Impacc_Verify::check_card($array[$i]->id_acc_second);
271  if ($card==false)
272  {
273  $array[$i]->id_message=$and."CK_INVALID_ACCOUNTING";
274  $and=",";
275  }
276  if ($card instanceof Fiche&&$card->belong_ledger($this->detail->jrn_def_id)!=1)
277  {
278  $array[$i]->id_message.=$and."CK_CARD_LEDGER";
279  $and=",";
280  }
282  $this->detail->s_thousand, $this->detail->s_decimal);
283  break;
284  case 'ODS':
285  // Check that colonne id_debit is C or D
286  if ($array[$i]->id_debit!="D"&&$array[$i]->id_debit!="C")
287  {
288  $array[$i]->id_message.=$and."CK_ERROR_DEBIT";
289  $and=",";
290  }
291  break;
292  case 'FIN':
293 
294  break;
295  default :
296  throw new Exception(_('type journal inconnu'));
297  }
298  // update status
299  $array[$i]->update();
300  }
301  if ($ledger_type=="ODS")
302  {
303  // Check that D == C for each group
304  $array=$cn->get_array("
305 with deb as (
306  select sum(coalesce(id_amount_novat_conv::numeric,0)) as sum_debit,
307  id_code_group
308  from
309  impacc.import_detail
310  where
311  import_id = $1
312  and id_debit='D'
313  group by id_code_group
314 ) ,cred as (
315  select sum(coalesce(id_amount_novat_conv::numeric,0)) as sum_credit,
316  id_code_group
317  from
318  impacc.import_detail
319  where
320  import_id = $1 and
321  id_debit='C'
322  group by id_code_group)
323  select id_code_group,sum_debit-sum_credit
324  from
325  deb join cred using(id_code_group)
326  where
327  sum_debit <> sum_credit
328  ", array($p_file->impid));
329  $nb_array=count($array);
330  for ($e=0; $e<$nb_array; $e++)
331  {
332  $cn->exec_sql("update impacc.import_detail set id_message = id_message||',CK_BALANCE' where id_code_group=$1 ",
333  array($array[$e]['id_code_group']));
334  }
335  }
336  }
337 
338  ///Save the Impacc_Import_csv_SQL object into db
339  function save_setting()
340  {
341  $this->detail->save();
342  }
343 
344  /// Thank the import_file.id we find the corresponding record from import_csv
345  /// and we load id
346  //! \param $p_import_id is impacc.import_file.id
347  function load_import($p_import_id)
348  {
349  try
350  {
351  $cn=Dossier::connect();
352  $id=$cn->get_value('select id from impacc.import_csv where import_id=$1',
353  array($p_import_id));
354  $this->detail=new Impacc_Import_csv_SQL($cn, $id);
355  $this->detail->load();
356  }
357  catch (Exception $e)
358  {
359  echo $e->getMessage();
360  }
361  }
362 
363  /// Create the right object for the import id
364  /// and throw and exception if the ledger type can not be found
365  //\param $p_import_id is the import_file.id
366  function make_csv_class($p_import_id)
367  {
368  $this->load_import($p_import_id);
369  $cn=Dossier::connect();
370  $ledger=new Acc_Ledger($cn, $this->detail->jrn_def_id);
371 
372  switch ($ledger->get_type())
373  {
374  case 'ACH':
376  break;
377  case 'VEN':
378  $obj=new Impacc_Csv_Sale();
379  break;
380  case 'ODS':
382  break;
383  case 'FIN':
384  $obj=new Impacc_Csv_Bank();
385  break;
386  default :
387  throw new Exception(_('type journal inconnu'));
388  }
389  $obj->errcode=$this->errcode;
390  return $obj;
391  }
392 
393  /// Record the given csv file into impacc.import_detail ,
394  /// depending of the ledger type a different filter is used to import rows
395  //! \param $p_file is an Impacc_File , use to open the temporary file
396  function record(Impacc_File $p_file)
397  {
398  try
399  {
400  $csv_class=$this->make_csv_class($p_file->impid);
401  $csv_class->record($this, $p_file);
402  }
403  catch (Exception $ex)
404  {
405  error_log($ex->getTraceAsString());
406  echo _("Echec dans record")." ".$ex->getMessage();
407  throw $ex;
408  }
409  }
410 
411  /// Display result from the table import_detail for CSV import
412  //!\param $importfile is an Impacc_File object
413  function result(Impacc_File $importfile)
414  {
415  try
416  {
417  $csv_class=$this->make_csv_class($importfile->impid);
418  }
419  catch (Exception $ex)
420  {
421  error_log($ex->getTraceAsString());
422  echo _("Echec dans result");
423  throw $ex;
424  }
425  $cn=Dossier::connect();
426  $display=new Impacc_Import_detail_SQL($cn);
427  $ret=$display->seek(" where import_id = $1 order by id",
428  array($importfile->impid));
429  $nb=Database::num_row($ret);
430  require DIR_IMPORT_ACCOUNT."/template/operation_result.php";
431  }
432 
433  /// Transfer the operation to the right ledger
434  function transfer()
435  {
436  $cn=Dossier::connect();
437  try
438  {
439  ///- Create the right object
440  $csv_class=$this->make_csv_class($this->detail->import_id);
441 
442  ///- Create the ledger object
443  $ledger=Impacc_Tool::ledger_factory($this->detail->jrn_def_id);
444 
445  ///- Load only the correct group (all the rows in the group must be valid)
446  $sql="
447  with rejected as ( SELECT distinct id_code_group
448  FROM impacc.import_detail a
449  where
450  import_id=$1
451  and (id_status != 0 or trim(COALESCE(id_message,'')) !='')
452  )
453  select distinct id_code_group ,id_date_format_conv, import_id
454  from
455  impacc.import_detail
456  where
457  import_id=$1
458  and id_code_group not in (select coalesce(id_code_group,'') from rejected)
459 
460  order by id_date_format_conv asc
461  ";
462 
463  $array=$cn->get_array($sql, array($this->detail->import_id));
464  ///- Call the function insert from a child classs
465  $csv_class->insert($array, $ledger);
466  }
467  catch (Exception $ex)
468  {
469  error_log($ex->getTraceAsString());
470  echo _("Echec dans transfer")." ".$ex->getMessage();
471  throw $ex;
472  }
473  }
474 
475 }
$errcode
Array of error code will be recorded in import_detail.id_message.
global $aformat_date
$ret
static convert_amount($p_amount, $p_thousand, $p_decimal)
convert_amount($array[$i]->id_amount_novat,$this->detail->s_thousand,$this->s_decimal); ...
set_import($p_file_id)
global $aseparator
result(Impacc_File $importfile)
Display result from the table import_detail for CSV import.
Used by all Import CSV Operation , contains the setting (delimiter,thousand ...)
if(isset($_POST['remove'])) $array
record(Impacc_File $p_file)
Record the given csv file into impacc.import_detail , depending of the ledger type a different filter...
make_csv_class($p_import_id)
Create the right object for the import id and throw and exception if the ledger type can not be found...
transfer()
Transfer the operation to the right ledger.
global $adecimal
check(Impacc_File $p_file)
Check that upload file is correct.
save_setting()
Save the Impacc_Import_csv_SQL object into db.
switch($sep_field->selected) $date_format
retrieve the format
static check(Impacc_Import_detail_SQL $row, $p_format_date, $p_thousand, $p_decimal)
Check if Data are valid for one row.
static ledger_factory($p_jrn_def_id)
Factory pattern to get a ledger of the right type based on $p_jrn_def_id which is the id of the table...
global $athousand
$sql
Filter for the Financial format.
For Ledger of style SALE.
load_import($p_import_id)
Thank the import_file.id we find the corresponding record from import_csv and we load id...
For Ledger of style SALE.
input_format()
Display a form to upload a CSV file with operation.
global $cn
set_setting()
Get value from post , fill up the Impacc_Import_csv_SQL object.
$detail
Object Impacc_Import_csv_SQL.
static check_card($p_account)
Check that a card exist and use a valid accounting.