class_acc_ledger.php

Go to the documentation of this file.
00001 <?php
00002 
00003 /*
00004  *   This file is part of PhpCompta.
00005  *
00006  *   PhpCompta is free software; you can redistribute it and/or modify
00007  *   it under the terms of the GNU General Public License as published by
00008  *   the Free Software Foundation; either version 2 of the License, or
00009  *   (at your option) any later version.
00010  *
00011  *   PhpCompta is distributed in the hope that it will be useful,
00012  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *   GNU General Public License for more details.
00015  *
00016  *   You should have received a copy of the GNU General Public License
00017  *   along with PhpCompta; if not, write to the Free Software
00018  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  */
00020 /* $Revision: 5028 $ */
00021 // Copyright Author Dany De Bontridder ddebontridder@yahoo.fr
00022 require_once("class_iselect.php");
00023 require_once("class_icard.php");
00024 require_once("class_ispan.php");
00025 require_once("class_ihidden.php");
00026 require_once("class_idate.php");
00027 require_once("class_itext.php");
00028 require_once("class_icheckbox.php");
00029 require_once('class_iperiod.php');
00030 require_once('class_fiche.php');
00031 require_once('class_user.php');
00032 require_once ('class_dossier.php');
00033 require_once ('class_anc_operation.php');
00034 require_once ('class_acc_operation.php');
00035 require_once ('class_acc_account_ledger.php');
00036 require_once ('class_pre_op_advanced.php');
00037 require_once ('class_acc_reconciliation.php');
00038 require_once ('class_periode.php');
00039 require_once ('class_gestion_purchase.php');
00040 require_once ('class_acc_account.php');
00041 require_once('ac_common.php');
00042 require_once('class_inum.php');
00043 require_once('class_lettering.php');
00044 require_once 'class_sort_table.php';
00045 require_once 'class_jrn_def_sql.php';
00046 require_once 'class_acc_payment.php';
00047 /* !\file
00048  * \brief Class for jrn,  class acc_ledger for manipulating the ledger
00049  */
00050 
00051 /* !\brief Class for jrn,  class acc_ledger for manipulating the ledger
00052  *
00053  */
00054 
00055 class Acc_Ledger extends jrn_def_sql
00056 {
00057 
00058         var $id;   /* !< jrn_def.jrn_def_id */
00059         var $name;   /* !< jrn_def.jrn_def_name */
00060         var $db;   /* !< database connextion */
00061         var $row;   /* !< row of the ledger */
00062         var $type;   /* !< type of the ledger ACH ODS FIN
00063           VEN or GL */
00064         var $nb;   /* !< default number of rows by
00065           default 10 */
00066 
00067         /**
00068          * @param $p_cn database connexion
00069          * @param $p_id jrn.jrn_def_id
00070          */
00071         function __construct($p_cn, $p_id)
00072         {
00073                 $this->id = $p_id;
00074                 $this->name = &$this->jrn_def_name;
00075                 $this->jrn_def_id = &$this->id;
00076                 $this->db = $p_cn;
00077                 $this->row = null;
00078                 $this->nb = 10;
00079         }
00080 
00081         function get_last_pj()
00082         {
00083                 if ($this->db->exist_sequence("s_jrn_pj" . $this->id))
00084                 {
00085                         $ret = $this->db->get_array("select last_value,is_called from s_jrn_pj" . $this->id);
00086                         $last = $ret[0]['last_value'];
00087                         /* !
00088                          * \note  With PSQL sequence , the last_value column is 1 when before   AND after the first call, to make the difference between them
00089                          * I have to check whether the sequence has been already called or not */
00090                         if ($ret[0]['is_called'] == 'f')
00091                                 $last--;
00092                         return $last;
00093                 }
00094                 else
00095                         $this->db->create_sequence("s_jrn_pj" . $this->id);
00096                 return 0;
00097         }
00098 
00099         /* !
00100          * \brief Return the type of a ledger (ACH,VEN,ODS or FIN) or GL
00101          *
00102          */
00103 
00104         function get_type()
00105         {
00106                 if ($this->id == 0)
00107                 {
00108                         $this->name = " Tous les journaux";
00109                         $this->type = "GL";
00110                         return "GL";
00111                 }
00112 
00113                 $Res = $this->db->exec_sql("select jrn_def_type from " .
00114                                 " jrn_def where jrn_def_id=" .
00115                                 $this->id);
00116                 $Max = Database::num_row($Res);
00117                 if ($Max == 0)
00118                         return null;
00119                 $ret = Database::fetch_array($Res, 0);
00120                 $this->type = $ret['jrn_def_type'];
00121                 return $ret['jrn_def_type'];
00122         }
00123 
00124         /**
00125          * let you delete a operation
00126          * @note by cascade it will delete also in
00127          * - jrnx
00128          * - stock
00129          * - quant_purchase
00130          * - quant_fin
00131          * - quant_sold
00132          * - operation_analytique
00133          * - letter
00134          * - reconciliation
00135          * @bug the attached document is not deleted
00136          */
00137         function delete()
00138         {
00139                 if ($this->id == 0)
00140                         return;
00141                 $grpt_id = $this->db->get_value('select jr_grpt_id from jrn where jr_id=$1', array($this->jr_id));
00142                 if ($this->db->count() == 0)
00143                         return;
00144                 $this->db->exec_sql('delete from jrnx where j_grpt=$1', array($grpt_id));
00145                 $this->db->exec_sql('delete from jrn where jr_id=$1', array($this->jr_id));
00146         }
00147 
00148         /**
00149          * Display warning contained in an array
00150          * @return string with error message
00151          */
00152         function display_warning($pa_msg, $p_warning)
00153         {
00154                 $str = '<p class="notice"> ' . $p_warning;
00155                 $str.="<ol class=\"notice\">";
00156                 for ($i = 0; $i < count($pa_msg); $i++)
00157                 {
00158                         $str.="<li>" . $pa_msg[$i] . "</li>";
00159                 }
00160                 $str.='</ol>';
00161                 $str.='</p>';
00162                 return $str;
00163         }
00164 
00165         /**
00166          * reverse the operation by creating the opposite one,
00167          * the result is to avoid it
00168          * it must be done in
00169          * - jrn
00170          * - jrnx
00171          * - quant_fin
00172          * - quant_sold
00173          * - quant_purchase
00174          * - stock
00175          * - ANC
00176          * @param $p_date is the date of the reversed op
00177          * @exception if date is invalid or other prob
00178          * @note automatically create a reconciliation between operation
00179          * You must set the ledger_id $this->jrn_def_id
00180          */
00181         function reverse($p_date)
00182         {
00183                 global $g_user;
00184                 try
00185                 {
00186                         $this->db->start();
00187                         if (!isset($this->jr_id) || $this->jr_id == '')
00188                                 throw new Exception("this->jr_id is not set ou opération inconnue");
00189 
00190                         /* check if the date is valid */
00191                         if (isDate($p_date) == null)
00192                                 throw new Exception(_('Date invalide') . $p_date);
00193 
00194                         // if the operation is in a closed or centralized period
00195                         // the operation is voided thanks the opposite operation
00196                         $grp_new = $this->db->get_next_seq('s_grpt');
00197                         $seq = $this->db->get_next_seq("s_jrn");
00198                         $p_internal = $this->compute_internal_code($seq);
00199                         $this->jr_grpt_id = $this->db->get_value('select jr_grpt_id from jrn where jr_id=$1', array($this->jr_id));
00200                         if ($this->db->count() == 0)
00201                                 throw new Exception(_("Cette opération n'existe pas"));
00202                         $this->jr_internal = $this->db->get_value('select jr_internal from jrn where jr_id=$1', array($this->jr_id));
00203                         if ($this->db->count() == 0 || trim($this->jr_internal) == '')
00204                                 throw new Exception(_("Cette opération n'existe pas"));
00205 
00206                         /* find the periode thanks the date */
00207                         $per = new Periode($this->db);
00208                         $per->jrn_def_id = $this->id;
00209                         $per->find_periode($p_date);
00210 
00211                         if ($per->is_open() == 0)
00212                                 throw new Exception(_('PERIODE FERMEE'));
00213 
00214 
00215 
00216 
00217 
00218                         // Mark the operation invalid into the ledger
00219                         // to avoid to nullify twice the same op.
00220                         $sql = "update jrn set jr_comment='Annule : '||jr_comment where jr_id=$1";
00221                         $Res = $this->db->exec_sql($sql, array($this->jr_id));
00222 
00223                         // Check return code
00224                         if ($Res == false)
00225                                 throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00226 
00227                         //////////////////////////////////////////////////
00228                         // Reverse in jrnx* tables
00229                         //////////////////////////////////////////////////
00230                         $a_jid = $this->db->get_array("select j_id,j_debit from jrnx where j_grpt=$1", array($this->jr_grpt_id));
00231                         for ($l = 0; $l < count($a_jid); $l++)
00232                         {
00233                                 $row = $a_jid[$l]['j_id'];
00234                                 // Make also the change into jrnx
00235                                 $sql = "insert into jrnx (
00236                   j_date,j_montant,j_poste,j_grpt,
00237                   j_jrn_def,j_debit,j_text,j_internal,j_tech_user,j_tech_per,j_qcode
00238                   ) select to_date($1,'DD.MM.YYYY'),j_montant,j_poste,$2,
00239                   j_jrn_def,not (j_debit),j_text,$3,$4,$5,
00240                   j_qcode
00241                   from
00242                   jrnx
00243                   where   j_id=$6 returning j_id";
00244                                 $Res = $this->db->exec_sql($sql, array($p_date, $grp_new, $p_internal, $g_user->id, $per->p_id, $row));
00245                                 // Check return code
00246                                 if ($Res == false)
00247                                         throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00248                                 $aj_id = $this->db->fetch(0);
00249                                 $j_id = $aj_id['j_id'];
00250 
00251                                 /* automatic lettering */
00252                                 $let = new Lettering($this->db);
00253                                 $let->insert_couple($j_id, $row);
00254 
00255                                 // reverse in QUANT_SOLD
00256                                 $Res = $this->db->exec_sql("INSERT INTO quant_sold(
00257                                      qs_internal, qs_fiche, qs_quantite, qs_price, qs_vat,
00258                                      qs_vat_code, qs_client, qs_valid, j_id)
00259                                      SELECT $1, qs_fiche, qs_quantite*(-1), qs_price*(-1), qs_vat*(-1),
00260                                      qs_vat_code, qs_client, qs_valid, $2
00261                                      FROM quant_sold where j_id=$3", array($p_internal, $j_id, $row));
00262 
00263                                 if ($Res == false)
00264                                         throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00265                                 $Res = $this->db->exec_sql("INSERT INTO quant_purchase(
00266                                      qp_internal, j_id, qp_fiche, qp_quantite, qp_price, qp_vat,
00267                                      qp_vat_code, qp_nd_amount, qp_nd_tva, qp_nd_tva_recup, qp_supplier,
00268                                      qp_valid, qp_dep_priv)
00269                                      SELECT  $1, $2, qp_fiche, qp_quantite*(-1), qp_price*(-1), qp_vat*(-1),
00270                                      qp_vat_code, qp_nd_amount*(-1), qp_nd_tva*(-1), qp_nd_tva_recup*(-1), qp_supplier,
00271                                      qp_valid, qp_dep_priv*(-1)
00272                                      FROM quant_purchase where j_id=$3", array($p_internal, $j_id, $row));
00273 
00274                                 if ($Res == false)
00275                                         throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00276                         }
00277                         $sql = "insert into jrn (
00278               jr_id,
00279               jr_def_id,
00280               jr_montant,
00281               jr_comment,
00282               jr_date,
00283               jr_grpt_id,
00284               jr_internal
00285               ,jr_tech_per, jr_valid
00286               )
00287               select $1,jr_def_id,jr_montant,'Annulation '||jr_comment,
00288               to_date($2,'DD.MM.YYYY'),$3,$4,
00289               $5, true
00290               from
00291               jrn
00292               where   jr_id=$6";
00293                                 $Res = $this->db->exec_sql($sql, array($seq, $p_date, $grp_new, $p_internal, $per->p_id, $this->jr_id));
00294                                 // Check return code
00295                                 if ($Res == false)
00296                                         throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00297                         // reverse in QUANT_FIN table
00298                         $Res = $this->db->exec_sql("  INSERT INTO quant_fin(
00299                                  qf_bank,  qf_other, qf_amount,jr_id)
00300                                  SELECT  qf_bank,  qf_other, qf_amount*(-1),$1
00301                                  FROM quant_fin where jr_id=$2", array($seq, $this->jr_id));
00302                         if ($Res == false)
00303                                 throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00304 
00305                         // Add a "concerned operation to bound these op.together
00306                         //
00307         $rec = new Acc_Reconciliation($this->db);
00308                         $rec->set_jr_id($seq);
00309                         $rec->insert($this->jr_id);
00310 
00311                         // Check return code
00312                         if ($Res == false)
00313                         {
00314                                 throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00315                         }
00316 
00317 
00318 
00319                         // the table stock must updated
00320                         // also in the stock table
00321                         $sql = "delete from stock_goods where sg_id = any ( select sg_id
00322              from stock_goods natural join jrnx  where j_grpt=" . $this->jr_grpt_id . ")";
00323                         $Res = $this->db->exec_sql($sql);
00324                         if ($Res == false)
00325                                 throw (new Exception(__FILE__ . __LINE__ . "sql a echoue [ $sql ]"));
00326                 }
00327                 catch (Exception $e)
00328                 {
00329                         $this->db->rollback();
00330                         throw $e;
00331                 }
00332         }
00333 
00334         /* !
00335          * \brief Return the name of a ledger
00336          *
00337          */
00338 
00339         function get_name()
00340         {
00341                 if ($this->id == 0)
00342                 {
00343                         $this->name = " Grand Livre ";
00344                         return $this->name;
00345                 }
00346 
00347                 $Res = $this->db->exec_sql("select jrn_def_name from " .
00348                                 " jrn_def where jrn_def_id=$1", array($this->id));
00349                 $Max = Database::num_row($Res);
00350                 if ($Max == 0)
00351                         return null;
00352                 $ret = Database::fetch_array($Res, 0);
00353                 $this->name = $ret['jrn_def_name'];
00354                 return $ret['jrn_def_name'];
00355         }
00356 
00357         /* ! \function  get_row
00358          * \brief  Get The data
00359          *
00360          *
00361          * \param p_from from periode
00362          * \param p_to to periode
00363          * \param p_limit starting line
00364          * \param p_offset number of lines
00365          * \return Array with the asked data
00366          *
00367          */
00368 
00369         function get_row($p_from, $p_to, $p_limit = -1, $p_offset = -1)
00370         {
00371                 global $g_user;
00372                 $periode = sql_filter_per($this->db, $p_from, $p_to, 'p_id', 'jr_tech_per');
00373 
00374                 $cond_limite = ($p_limit != -1) ? " limit " . $p_limit . " offset " . $p_offset : "";
00375                 // retrieve the type
00376                 $this->get_type();
00377                 // Grand livre == 0
00378                 if ($this->id != 0)
00379                 {
00380                         $Res = $this->db->exec_sql("select jr_id,j_id,j_id as int_j_id,to_char(j_date,'DD.MM.YYYY') as j_date,
00381                                      jr_internal,
00382                                      case j_debit when 't' then j_montant::text else '   ' end as deb_montant,
00383                                      case j_debit when 'f' then j_montant::text else '   ' end as cred_montant,
00384                                      j_debit as debit,j_poste as poste,jr_montant , " .
00385                                         "case when j_text='' or j_text is null then pcm_lib else j_text end as description,j_grpt as grp,
00386                                      jr_comment||' ('||jr_internal||')'  as jr_comment,
00387                                      jr_pj_number,
00388                                      j_qcode,
00389                                      jr_rapt as oc, j_tech_per as periode
00390                                      from jrnx left join jrn on " .
00391                                         "jr_grpt_id=j_grpt " .
00392                                         " left join tmp_pcmn on pcm_val=j_poste " .
00393                                         " where j_jrn_def=" . $this->id .
00394                                         " and " . $periode . " order by j_date::date asc,substring(jr_pj_number,'\\\\d+$')::numeric asc,j_grpt,j_debit desc " .
00395                                         $cond_limite);
00396                 }
00397                 else
00398                 {
00399                         $Res = $this->db->exec_sql("select jr_id,j_id,j_id as int_j_id,to_char(j_date,'DD.MM.YYYY') as j_date,
00400                                      jr_internal,
00401                                      case j_debit when 't' then j_montant::text else '   ' end as deb_montant,
00402                                      case j_debit when 'f' then j_montant::text else '   ' end as cred_montant,
00403                                      j_debit as debit,j_poste as poste," .
00404                                         "case when j_text='' or j_text is null then pcm_lib else j_text end as description,j_grpt as grp,
00405                                      jr_comment||' ('||jr_internal||')' as jr_comment,
00406                                      jr_pj_number,
00407                                      jr_montant,
00408                                      j_qcode,
00409                                      jr_rapt as oc, j_tech_per as periode from jrnx left join jrn on " .
00410                                         "jr_grpt_id=j_grpt left join tmp_pcmn on pcm_val=j_poste
00411                                                                                  join jrn_def on (jr_def_id=jrn_def_id)
00412                                                                                  where " .
00413                                         $g_user->get_ledger_sql() . " and " .
00414                                         "  " . $periode . " order by j_date::date,substring(jr_pj_number,'\\\\d+$') asc,j_grpt,j_debit desc   " .
00415                                         $cond_limite);
00416                 }
00417 
00418 
00419                 $array = array();
00420                 $Max = Database::num_row($Res);
00421                 if ($Max == 0)
00422                         return null;
00423                 $case = "";
00424                 $tot_deb = 0;
00425                 $tot_cred = 0;
00426                 $row = Database::fetch_all($Res);
00427                 for ($i = 0; $i < $Max; $i++)
00428                 {
00429                         $fiche = new Fiche($this->db);
00430                         $line = $row[$i];
00431                         $mont_deb = ($line['deb_montant'] != 0) ? sprintf("% 8.2f", $line['deb_montant']) : "";
00432                         $mont_cred = ($line['cred_montant'] != 0) ? sprintf("% 8.2f", $line['cred_montant']) : "";
00433                         $jr_montant = ($line['jr_montant'] != 0) ? sprintf("% 8.2f", $line['jr_montant']) : "";
00434                         $tot_deb+=$line['deb_montant'];
00435                         $tot_cred+=$line['cred_montant'];
00436                         $tot_op = $line['jr_montant'];
00437 
00438                         /* Check first if there is a quickcode */
00439                         if (strlen(trim($line['description'])) == 0 && strlen(trim($line['j_qcode'])) != 0)
00440                         {
00441                                 if ($fiche->get_by_qcode($line['j_qcode'], false) == 0)
00442                                 {
00443                                         $line['description'] = $fiche->strAttribut(ATTR_DEF_NAME);
00444                                 }
00445                         }
00446                         if ($case != $line['grp'])
00447                         {
00448                                 $case = $line['grp'];
00449                                 // for financial, we show if the amount is or not in negative
00450                                 if ($this->type == 'FIN')
00451                                 {
00452                                         $amount = $this->db->get_value('select qf_amount from quant_fin where jr_id=$1', array($line['jr_id']));
00453                                         /*  if nothing is found */
00454                                         if ($this->db->count() == 0)
00455                                                 $tot_op = $jr_montant;
00456                                         else if ($amount < 0)
00457                                         {
00458                                                 $tot_op = $amount;
00459                                         }
00460                                 }
00461                                 $array[] = array(
00462                                         'jr_id' => $line['jr_id'],
00463                                         'int_j_id' => $line['int_j_id'],
00464                                         'j_id' => $line['j_id'],
00465                                         'j_date' => $line['j_date'],
00466                                         'internal' => $line['jr_internal'],
00467                                         'deb_montant' => '',
00468                                         'cred_montant' => ' ',
00469                                         'description' => '<b><i>' . h($line['jr_comment']) . ' [' . $tot_op . '] </i></b>',
00470                                         'poste' => $line['oc'],
00471                                         'qcode' => $line['j_qcode'],
00472                                         'periode' => $line['periode'],
00473                                         'jr_pj_number' => $line ['jr_pj_number']);
00474 
00475                                 $array[] = array(
00476                                         'jr_id' => '',
00477                                         'int_j_id' => $line['int_j_id'],
00478                                         'j_id' => '',
00479                                         'j_date' => '',
00480                                         'internal' => '',
00481                                         'deb_montant' => $mont_deb,
00482                                         'cred_montant' => $mont_cred,
00483                                         'description' => $line['description'],
00484                                         'poste' => $line['poste'],
00485                                         'qcode' => $line['j_qcode'],
00486                                         'periode' => $line['periode'],
00487                                         'jr_pj_number' => ''
00488                                 );
00489                         }
00490                         else
00491                         {
00492                                 $array[] = array(
00493                                         'jr_id' => $line['jr_id'],
00494                                         'int_j_id' => $line['int_j_id'],
00495                                         'j_id' => '',
00496                                         'j_date' => '',
00497                                         'internal' => '',
00498                                         'deb_montant' => $mont_deb,
00499                                         'cred_montant' => $mont_cred,
00500                                         'description' => $line['description'],
00501                                         'poste' => $line['poste'],
00502                                         'qcode' => $line['j_qcode'],
00503                                         'periode' => $line['periode'],
00504                                         'jr_pj_number' => '');
00505                         }
00506                 }
00507                 $this->row = $array;
00508                 $a = array($array, $tot_deb, $tot_cred);
00509                 return $a;
00510         }
00511 
00512         /* ! \brief  Get simplified row from ledger
00513          *
00514          * \param from periode
00515          * \param to periode
00516          * \param p_limit starting line
00517          * \param p_offset number of lines
00518          * \param trunc if data must be truncated (pdf export)
00519          *
00520          * \return an Array with the asked data
00521          */
00522 
00523         function get_rowSimple($p_from, $p_to, $trunc = 0, $p_limit = -1, $p_offset = -1)
00524         {
00525                 global $g_user;
00526                 // Grand-livre : id= 0
00527                 //---
00528                 $jrn = ($this->id == 0 ) ? "and " . $g_user->get_ledger_sql() : "and jrn_def_id = " . $this->id;
00529 
00530                 $periode = sql_filter_per($this->db, $p_from, $p_to, 'p_id', 'jr_tech_per');
00531 
00532                 $cond_limite = ($p_limit != -1) ? " limit " . $p_limit . " offset " . $p_offset : "";
00533                 //---
00534                 $sql = "
00535              SELECT jrn.jr_id as jr_id ,
00536              jrn.jr_id as num ,
00537              jrn.jr_def_id as jr_def_id,
00538              jrn.jr_montant as montant,
00539              substr(jrn.jr_comment,1,35) as comment,
00540              to_char(jrn.jr_date,'DD-MM-YYYY') as date,
00541              jr_pj_number,
00542              jr_internal,
00543              jrn.jr_grpt_id as grpt_id,
00544              jrn.jr_pj_name as pj,
00545              jrn_def_type,
00546              jrn.jr_tech_per
00547              FROM jrn join jrn_def on (jrn_def_id=jr_def_id)
00548              WHERE $periode $jrn order by jr_date $cond_limite";
00549 
00550                 $Res = $this->db->exec_sql($sql);
00551                 $Max = Database::num_row($Res);
00552                 if ($Max == 0)
00553                 {
00554                         return null;
00555                 }
00556                 $type = $this->get_type();
00557                 // for type ACH and Ven we take more info
00558                 if ($type == 'ACH' || $type == 'VEN')
00559                 {
00560                         $a_ParmCode = $this->db->get_array('select p_code,p_value from parm_code');
00561                         $a_TVA = $this->db->get_array('select tva_id,tva_label,tva_poste
00562                                         from tva_rate where tva_rate != 0 order by tva_id');
00563                         for ($i = 0; $i < $Max; $i++)
00564                         {
00565                                 $array[$i] = Database::fetch_array($Res, $i);
00566                                 $p = $this->get_detail($array[$i], $type, $trunc, $a_TVA, $a_ParmCode);
00567                                 if ($array[$i]['dep_priv'] != 0.0)
00568                                 {
00569                                         $array[$i]['comment'].="(priv. " . $array[$i]['dep_priv'] . ")";
00570                                 }
00571                         }
00572                 }
00573                 else
00574                 {
00575                         $array = Database::fetch_all($Res);
00576                 }
00577 
00578                 return $array;
00579         }
00580 
00581 // end function get_rowSimple
00582 
00583         /* !\brief guess what  the next pj should be
00584          */
00585 
00586         function guess_pj()
00587         {
00588                 $prop = $this->get_propertie();
00589                 $pj_pref = $prop["jrn_def_pj_pref"];
00590                 $pj_seq = $this->get_last_pj() + 1;
00591                 return $pj_pref . $pj_seq;
00592         }
00593 
00594         /* !\brief Show all the operation
00595          * \param $sql is the sql stmt, normally created by build_search_sql
00596          * \param $offset the offset
00597          * \param $p_paid if we want to see info about payment
00598           \code
00599           // Example
00600           // Build the sql
00601           list($sql,$where)=$Ledger->build_search_sql($_GET);
00602           // Count nb of line
00603           $max_line=$this->db->count_sql($sql);
00604 
00605           $step=$_SESSION['g_pagesize'];
00606           $page=(isset($_GET['offset']))?$_GET['page']:1;
00607           $offset=(isset($_GET['offset']))?$_GET['offset']:0;
00608           // create the nav. bar
00609           $bar=navigation_bar($offset,$max_line,$step,$page);
00610           // show a part
00611           list($count,$html)= $Ledger->list_operation($sql,$offset,0);
00612           echo $html;
00613           // show nav bar
00614           echo $bar;
00615 
00616           \endcode
00617          * \see build_search_sql
00618          * \see display_search_form
00619          * \see search_form
00620 
00621          * \return HTML string
00622          */
00623 
00624         public function list_operation_to_reconcile($sql)
00625         {
00626                 global $g_parameter, $g_user;
00627                 $gDossier = dossier::id();
00628                 $limit = " LIMIT 25";
00629                 // Sort
00630                 // Count
00631                 $count = $this->db->count_sql($sql);
00632                 // Add the limit
00633                 $sql.=" order by jr_date asc " . $limit;
00634 
00635                 // Execute SQL stmt
00636                 $Res = $this->db->exec_sql($sql);
00637 
00638                 //starting from here we can refactor, so that instead of returning the generated HTML,
00639                 //this function returns a tree structure.
00640 
00641                 $r = "";
00642 
00643 
00644                 $Max = Database::num_row($Res);
00645 
00646                 if ($Max == 0)
00647                         return array(0, _("Aucun enregistrement trouvé"));
00648 
00649                 $r.='<table class="result">';
00650 
00651 
00652                 $r.="<tr >";
00653                 $r.="<th>Selection</th>";
00654                 $r.="<th>Internal</th>";
00655 
00656                 if ($this->type == 'ALL')
00657                 {
00658                         $r.=th('Journal');
00659                 }
00660 
00661                 $r.='<th>Date</th>';
00662                 $r.='<th>Pièce</td>';
00663                 $r.=th('tiers');
00664                 $r.='<th>Description</th>';
00665                 $r.=th('Notes', ' style="width:15%"');
00666                 $r.='<th>Montant</th>';
00667                 $r.="<th>" . _('Op. Concernée') . "</th>";
00668                 $r.="</tr>";
00669                 // Total Amount
00670                 $tot = 0.0;
00671                 $gDossier = dossier::id();
00672                 $str_dossier = Dossier::id();
00673                 for ($i = 0; $i < $Max; $i++)
00674                 {
00675 
00676 
00677                         $row = Database::fetch_array($Res, $i);
00678 
00679                         if ($i % 2 == 0)
00680                                 $tr = '<TR class="odd">';
00681                         else
00682                                 $tr = '<TR class="even">';
00683                         $r.=$tr;
00684                         // Radiobox
00685                         //
00686 
00687                         $r.='<td><INPUT TYPE="CHECKBOX" name="jr_concerned' . $row['jr_id'] . '" ID="jr_concerned' . $row['jr_id'] . '"> </td>';
00688                         //internal code
00689                         // button  modify
00690                         $r.="<TD>";
00691                         // If url contains
00692                         //
00693 
00694             $href = basename($_SERVER['PHP_SELF']);
00695 
00696 
00697                         $r.=sprintf('<A class="detail" style="text-decoration:underline" HREF="javascript:modifyOperation(\'%s\',\'%s\')" >%s </A>', $row['jr_id'], $gDossier, $row['jr_internal']);
00698                         $r.="</TD>";
00699                         if ($this->type == 'ALL')
00700                                 $r.=td($row['jrn_def_name']);
00701                         // date
00702                         $r.="<TD>";
00703                         $r.=$row['str_jr_date'];
00704                         $r.="</TD>";
00705 
00706                         // pj
00707                         $r.="<TD>";
00708                         $r.=$row['jr_pj_number'];
00709                         $r.="</TD>";
00710 
00711                         // Tiers
00712                         $other = ($row['quick_code'] != '') ? '[' . $row['quick_code'] . '] ' . $row['name'] . ' ' . $row['first_name'] : '';
00713                         $r.=td($other);
00714                         // comment
00715                         $r.="<TD>";
00716                         $tmp_jr_comment = h($row['jr_comment']);
00717                         $r.=$tmp_jr_comment;
00718                         $r.="</TD>";
00719                         $r.=td(h($row['n_text']), ' style="font-size:6"');
00720                         // Amount
00721                         // If the ledger is financial :
00722                         // the credit must be negative and written in red
00723                         $positive = 0;
00724 
00725                         // Check ledger type :
00726                         if ($row['jrn_def_type'] == 'FIN')
00727                         {
00728                                 $positive = $this->db->get_value("select qf_amount from quant_fin where jr_id=$1", array($row['jr_id']));
00729                                 if ($this->db->count() != 0)
00730                                         $positive = ($positive < 0) ? 1 : 0;
00731                         }
00732                         $r.="<TD align=\"right\">";
00733 
00734                         $r.=( $positive != 0 ) ? "<font color=\"red\">  - " . nbm($row['jr_montant']) . "</font>" : nbm($row['jr_montant']);
00735                         $r.="</TD>";
00736 
00737 
00738 
00739                         // Rapprochement
00740                         $rec = new Acc_Reconciliation($this->db);
00741                         $rec->set_jr_id($row['jr_id']);
00742                         $a = $rec->get();
00743                         $r.="<TD>";
00744                         if ($a != null)
00745                         {
00746 
00747                                 foreach ($a as $key => $element)
00748                                 {
00749                                         $operation = new Acc_Operation($this->db);
00750                                         $operation->jr_id = $element;
00751                                         $l_amount = $this->db->get_value("select jr_montant from jrn " .
00752                                                         " where jr_id=$element");
00753                                         $r.= "<A class=\"detail\" HREF=\"javascript:modifyOperation('" . $element . "'," . $gDossier . ")\" > " . $operation->get_internal() . "[" . nbm($l_amount) . "]</A>";
00754                                 }//for
00755                         }// if ( $a != null ) {
00756                         $r.="</TD>";
00757 
00758                         if ($row['jr_valid'] == 'f')
00759                         {
00760                                 $r.="<TD> Op&eacute;ration annul&eacute;e</TD>";
00761                         }
00762                         // end row
00763                         $r.="</tr>";
00764                 }
00765                 $r.='</table>';
00766                 return array($count, $r);
00767         }
00768 
00769         /* !\brief Show all the operation
00770          * \param $sql is the sql stmt, normally created by build_search_sql
00771          * \param $offset the offset
00772          * \param $p_paid if we want to see info about payment
00773           \code
00774           // Example
00775           // Build the sql
00776           list($sql,$where)=$Ledger->build_search_sql($_GET);
00777           // Count nb of line
00778           $max_line=$cn->count_sql($sql);
00779 
00780           $step=$_SESSION['g_pagesize'];
00781           $page=(isset($_GET['offset']))?$_GET['page']:1;
00782           $offset=(isset($_GET['offset']))?$_GET['offset']:0;
00783           // create the nav. bar
00784           $bar=navigation_bar($offset,$max_line,$step,$page);
00785           // show a part
00786           list($count,$html)= $Ledger->list_operation($sql,$offset,0);
00787           echo $html;
00788           // show nav bar
00789           echo $bar;
00790 
00791           \endcode
00792          * \see build_search_sql
00793          * \see display_search_form
00794          * \see search_form
00795 
00796          * \return HTML string
00797          */
00798 
00799         public function list_operation($sql, $offset, $p_paid = 0)
00800         {
00801                 global $g_parameter, $g_user;
00802                 $table = new Sort_Table();
00803                 $gDossier = dossier::id();
00804                 $amount_paid = 0.0;
00805                 $amount_unpaid = 0.0;
00806                 $limit = ($_SESSION['g_pagesize'] != -1) ? " LIMIT " . $_SESSION['g_pagesize'] : "";
00807                 $offset = ($_SESSION['g_pagesize'] != -1) ? " OFFSET " . Database::escape_string($offset) : "";
00808                 $order = "  order by jr_date_order asc,jr_internal asc";
00809                 // Sort
00810                 $url = "?" . CleanUrl();
00811                 $str_dossier = dossier::get();
00812                 $table->add("Date", $url, 'order by jr_date asc,substring(jr_pj_number,\'\\\d+$\')::numeric asc', 'order by  jr_date desc,substring(jr_pj_number,\'\\\d+$\')::numeric desc', "da", "dd");
00813                 $table->add('Echeance', $url, " order by  jr_ech asc", " order by  jr_ech desc", 'ea', 'ed');
00814                 $table->add('PJ', $url, ' order by  substring(jr_pj_number,\'\\\d+$\')::numeric asc ', ' order by  substring(jr_pj_number,\'\\\d+$\')::numeric desc ', "pja", "pjd");
00815                 $table->add('Tiers', $url, " order by  name asc", " order by  name desc", 'na', 'nd');
00816                 $table->add('Montant', $url, " order by jr_montant asc", " order by jr_montant desc", "ma", "md");
00817                 $table->add("Description", $url, "order by jr_comment asc", "order by jr_comment desc", "ca", "cd");
00818 
00819                 $ord = (!isset($_GET['ord'])) ? 'da' : $_GET['ord'];
00820                 $order = $table->get_sql_order($ord);
00821 
00822                 // Count
00823                 $count = $this->db->count_sql($sql);
00824                 // Add the limit
00825                 $sql.=$order . $limit . $offset;
00826                 // Execute SQL stmt
00827                 $Res = $this->db->exec_sql($sql);
00828 
00829                 //starting from here we can refactor, so that instead of returning the generated HTML,
00830                 //this function returns a tree structure.
00831 
00832                 $r = "";
00833 
00834 
00835                 $Max = Database::num_row($Res);
00836 
00837                 if ($Max == 0)
00838                         return array(0, _("Aucun enregistrement trouvé"));
00839 
00840                 $r.='<table class="result">';
00841 
00842 
00843                 $r.="<tr >";
00844                 $r.="<th>Internal</th>";
00845                 if ($this->type == 'ALL')
00846                 {
00847                         $r.=th('Journal');
00848                 }
00849                 $r.='<th>' . $table->get_header(0) . '</th>';
00850                 $r.='<th>' . $table->get_header(1) . '</td>';
00851                 $r.='<th>' . $table->get_header(2) . '</th>';
00852                 $r.='<th>' . $table->get_header(3) . '</th>';
00853                 $r.='<th>' . $table->get_header(5) . '</th>';
00854                 $r.=th('Notes', ' style="width:15%"');
00855                 $r.='<th>' . $table->get_header(4) . '</th>';
00856                 // if $p_paid is not equal to 0 then we have a paid column
00857                 if ($p_paid != 0)
00858                 {
00859                         $r.="<th> " . _('Payé') . "</th>";
00860                 }
00861                 $r.="<th>" . _('Op. Concernée') . "</th>";
00862                 $r.="<th>" . _('Document') . "</th>";
00863                 $r.="</tr>";
00864                 // Total Amount
00865                 $tot = 0.0;
00866                 $gDossier = dossier::id();
00867                 for ($i = 0; $i < $Max; $i++)
00868                 {
00869 
00870 
00871                         $row = Database::fetch_array($Res, $i);
00872 
00873                         if ($i % 2 == 0)
00874                                 $tr = '<TR class="odd">';
00875                         else
00876                                 $tr = '<TR class="even">';
00877                         $r.=$tr;
00878                         //internal code
00879                         // button  modify
00880                         $r.="<TD>";
00881                         // If url contains
00882                         //
00883 
00884             $href = basename($_SERVER['PHP_SELF']);
00885 
00886 
00887                         $r.=sprintf('<A class="detail" style="text-decoration:underline" HREF="javascript:modifyOperation(\'%s\',\'%s\')" >%s </A>', $row['jr_id'], $gDossier, $row['jr_internal']);
00888                         $r.="</TD>";
00889                         if ($this->type == 'ALL')
00890                                 $r.=td($row['jrn_def_name']);
00891                         // date
00892                         $r.="<TD>";
00893                         $r.=smaller_date($row['str_jr_date']);
00894                         $r.="</TD>";
00895                         // echeance
00896                         $r.="<TD>";
00897                         $r.=smaller_date($row['str_jr_ech']);
00898                         $r.="</TD>";
00899 
00900                         // pj
00901                         $r.="<TD>";
00902                         $r.=$row['jr_pj_number'];
00903                         $r.="</TD>";
00904 
00905                         // Tiers
00906                         $other = ($row['quick_code'] != '') ? '[' . $row['quick_code'] . '] ' . $row['name'] . ' ' . $row['first_name'] : '';
00907                         $r.=td($other);
00908                         // comment
00909                         $r.="<TD>";
00910                         $tmp_jr_comment = h($row['jr_comment']);
00911                         $r.=$tmp_jr_comment;
00912                         $r.="</TD>";
00913                         $r.=td(h($row['n_text']), ' style="font-size:6"');
00914                         // Amount
00915                         // If the ledger is financial :
00916                         // the credit must be negative and written in red
00917                         $positive = 0;
00918 
00919                         // Check ledger type :
00920                         if ($row['jrn_def_type'] == 'FIN')
00921                         {
00922                                 $positive = $this->db->get_value("select qf_amount from quant_fin where jr_id=$1", array($row['jr_id']));
00923                                 if ($this->db->count() != 0)
00924                                         $positive = ($positive < 0) ? 1 : 0;
00925                         }
00926                         $r.="<TD align=\"right\">";
00927 
00928                         $tot = ($positive != 0) ? $tot - $row['jr_montant'] : $tot + $row['jr_montant'];
00929                         //STAN $positive always == 0
00930                         $r.=( $positive != 0 ) ? "<font color=\"red\">  - " . nbm($row['jr_montant']) . "</font>" : nbm($row['jr_montant']);
00931                         $r.="</TD>";
00932 
00933 
00934                         // Show the paid column if p_paid is not null
00935                         if ($p_paid != 0)
00936                         {
00937                                 $w = new ICheckBox();
00938                                 $w->name = "rd_paid" . $row['jr_id'];
00939                                 $w->selected = ($row['jr_rapt'] == 'paid') ? true : false;
00940                                 // if p_paid == 2 then readonly
00941                                 $w->readonly = ( $p_paid == 2) ? true : false;
00942                                 $h = new IHidden();
00943                                 $h->name = "set_jr_id" . $row['jr_id'];
00944                                 $r.='<TD>' . $w->input() . $h->input() . '</TD>';
00945                                 if ($row['jr_rapt'] == 'paid')
00946                                         $amount_paid+=$row['jr_montant'];
00947                                 else
00948                                         $amount_unpaid+=$row['jr_montant'];
00949                         }
00950 
00951                         // Rapprochement
00952                         $rec = new Acc_Reconciliation($this->db);
00953                         $rec->set_jr_id($row['jr_id']);
00954                         $a = $rec->get();
00955                         $r.="<TD>";
00956                         if ($a != null)
00957                         {
00958 
00959                                 foreach ($a as $key => $element)
00960                                 {
00961                                         $operation = new Acc_Operation($this->db);
00962                                         $operation->jr_id = $element;
00963                                         $l_amount = $this->db->get_value("select jr_montant from jrn " .
00964                                                         " where jr_id=$element");
00965                                         $r.= "<A class=\"detail\" HREF=\"javascript:modifyOperation('" . $element . "'," . $gDossier . ")\" > " . $operation->get_internal() . "[" . nbm($l_amount) . "]</A>";
00966                                 }//for
00967                         }// if ( $a != null ) {
00968                         $r.="</TD>";
00969 
00970                         if ($row['jr_valid'] == 'f')
00971                         {
00972                                 $r.="<TD> Op&eacute;ration annul&eacute;e</TD>";
00973                         }
00974                         else
00975                         {
00976 
00977                         } // else
00978                         //document
00979                         if ($row['jr_pj_name'] != "")
00980                         {
00981                                 $image = '<IMG SRC="image/insert_table.gif" title="' . $row['jr_pj_name'] . '" border="0">';
00982                                 $r.="<TD>" . sprintf('<A class="detail" HREF="show_pj.php?jrn=%s&jr_grpt_id=%s&%s">%s</A>', $row['jrn_def_id'], $row['jr_grpt_id'], $str_dossier, $image)
00983                                                 . "</TD>";
00984                         }
00985                         else
00986                                 $r.="<TD></TD>";
00987 
00988                         // end row
00989                         $r.="</tr>";
00990                 }
00991                 $amount_paid = round($amount_paid, 4);
00992                 $amount_unpaid = round($amount_unpaid, 4);
00993                 $tot = round($tot, 4);
00994                 $r.="<TR>";
00995                 $r.='<TD COLSPAN="5">Total</TD>';
00996                 $r.='<TD ALIGN="RIGHT">' . nbm($tot) . "</TD>";
00997                 $r.="</tr>";
00998                 if ($p_paid != 0)
00999                 {
01000                         $r.="<TR>";
01001                         $r.='<TD COLSPAN="5">Pay&eacute;</TD>';
01002                         $r.='<TD ALIGN="RIGHT">' . nbm($amount_paid) . "</TD>";
01003                         $r.="</tr>";
01004                         $r.="<TR>";
01005                         $r.='<TD COLSPAN="5">Non pay&eacute;</TD>';
01006                         $r.='<TD ALIGN="RIGHT">' . nbm($amount_unpaid) . "</TD>";
01007                         $r.="</tr>";
01008                 }
01009                 $r.="</table>";
01010 
01011                 return array($count, $r);
01012         }
01013 
01014         /* !
01015          * \brief get_detail gives the detail of row
01016          * this array must contains at least the field
01017          *       <ul>
01018          *       <li> montant</li>
01019          *       <li> grpt_id
01020          *       </ul>
01021          * the following field will be added
01022          *       <ul>
01023          *       <li> HTVA
01024          *       <li> TVAC
01025          *       <li> TVA array with
01026          *          <ul>
01027          *          <li> field 0 idx
01028          *          <li> array containing tva_id,tva_label and tva_amount
01029          *          </ul>
01030          *       </ul>
01031          *
01032          * \param p_array the structure is set in get_rowSimple, this array is
01033          *        modified,
01034          * \param $trunc if the data must be truncated, usefull for pdf export
01035          * \param p_jrn_type is the type of the ledger (ACH or VEN)
01036          * \param $a_TVA TVA Array (default null)
01037          * \param $a_ParmCode Array (default null)
01038          * \return p_array
01039          */
01040 
01041         function get_detail(&$p_array, $p_jrn_type, $trunc = 0, $a_TVA = null, $a_ParmCode = null)
01042         {
01043                 if ($a_TVA == null)
01044                 {
01045                         //Load TVA array
01046                         $a_TVA = $this->db->get_array('select tva_id,tva_label,tva_poste
01047                                         from tva_rate where tva_rate != 0 order by tva_id');
01048                 }
01049                 if ($a_ParmCode == null)
01050                 {
01051                         //Load Parm_code
01052                         $a_ParmCode = $this->db->get_array('select p_code,p_value from parm_code');
01053                 }
01054                 // init
01055                 $p_array['client'] = "";
01056                 $p_array['TVAC'] = 0;
01057                 $p_array['TVA'] = array();
01058                 $p_array['AMOUNT_TVA'] = 0.0;
01059                 $p_array['dep_priv'] = 0;
01060                 $dep_priv = 0.0;
01061                 //
01062                 // Retrieve data from jrnx
01063                 $sql = "select j_id,j_poste,j_montant, j_debit,j_qcode from jrnx where " .
01064                                 " j_grpt=" . $p_array['grpt_id'];
01065                 $Res2 = $this->db->exec_sql($sql);
01066                 $data_jrnx = Database::fetch_all($Res2);
01067                 $c = 0;
01068 
01069                 // Parse data from jrnx and fill diff. field
01070                 foreach ($data_jrnx as $code)
01071                 {
01072                         $idx_tva = 0;
01073                         $poste = new Acc_Account_Ledger($this->db, $code['j_poste']);
01074 
01075                         // if card retrieve name if the account is not a VAT account
01076                         if (strlen(trim($code['j_qcode'])) != 0 && $poste->isTva() == 0)
01077                         {
01078                                 $fiche = new Fiche($this->db);
01079                                 $fiche->get_by_qcode(trim($code['j_qcode']), false);
01080                                 $fiche_def_id = $fiche->get_fiche_def_ref_id();
01081                                 // Customer or supplier
01082                                 if ($fiche_def_id == FICHE_TYPE_CLIENT ||
01083                                                 $fiche_def_id == FICHE_TYPE_FOURNISSEUR)
01084                                 {
01085                                         $p_array['TVAC'] = $code['j_montant'];
01086 
01087                                         $p_array['client'] = ($trunc == 0) ? $fiche->getName() : mb_substr($fiche->getName(), 0, 20);
01088                                         $p_array['reversed'] = false;
01089                                         if ($fiche_def_id == FICHE_TYPE_CLIENT && $code['j_debit'] == 'f')
01090                                         {
01091                                                 $p_array['reversed'] = true;
01092                                                 $p_array['TVAC']*=-1;
01093                                         }
01094                                         if ($fiche_def_id == FICHE_TYPE_FOURNISSEUR && $code['j_debit'] == 't')
01095                                         {
01096                                                 $p_array['reversed'] = true;
01097                                                 $p_array['TVAC']*=-1;
01098                                         }
01099                                 }
01100                                 else
01101                                 {
01102                                         // if we use the ledger ven / ach for others card than supplier and customer
01103                                         if ($fiche_def_id != FICHE_TYPE_VENTE &&
01104                                                         $fiche_def_id != FICHE_TYPE_ACH_MAR &&
01105                                                         $fiche_def_id != FICHE_TYPE_ACH_SER)
01106                                         {
01107                                                 $p_array['TVAC'] = $code['j_montant'];
01108 
01109                                                 $p_array['client'] = ($trunc == 0) ? $fiche->getName() : mb_substr($fiche->getName(), 0, 20);
01110                                                 $p_array['reversed'] = false;
01111                                                 if ($p_jrn_type == 'ACH' && $code['j_debit'] == 't')
01112                                                 {
01113                                                         $p_array['reversed'] = true;
01114                                                         $p_array['TVAC']*=-1;
01115                                                 }
01116                                                 if ($p_jrn_type == 'VEN' && $code['j_debit'] == 'f')
01117                                                 {
01118                                                         $p_array['reversed'] = true;
01119                                                         $p_array['TVAC']*=-1;
01120                                                 }
01121                                         }
01122                                 }
01123                         }
01124                         // if TVA, load amount, tva id and rate in array
01125                         foreach ($a_TVA as $line_tva)
01126                         {
01127                                 list($tva_deb, $tva_cred) = explode(',', $line_tva['tva_poste']);
01128                                 if ($code['j_poste'] == $tva_deb ||
01129                                                 $code['j_poste'] == $tva_cred)
01130                                 {
01131 
01132                                         // For the reversed operation
01133                                         if ($p_jrn_type == 'ACH' && $code['j_debit'] == 'f')
01134                                         {
01135                                                 $code['j_montant'] = -1 * $code['j_montant'];
01136                                         }
01137                                         if ($p_jrn_type == 'VEN' && $code['j_debit'] == 't')
01138                                         {
01139                                                 $code['j_montant'] = -1 * $code['j_montant'];
01140                                         }
01141 
01142                                         $p_array['AMOUNT_TVA']+=$code['j_montant'];
01143 
01144                                         $p_array['TVA'][$c] = array($idx_tva, array($line_tva['tva_id'], $line_tva['tva_label'], $code['j_montant']));
01145                                         $c++;
01146 
01147                                         $idx_tva++;
01148                                 }
01149                         }
01150 
01151                         // isDNA
01152                         // If operation is reversed then  amount are negatif
01153                         /* if ND */
01154                         if ($p_array['jrn_def_type'] == 'ACH')
01155                         {
01156                                 $purchase = new Gestion_Purchase($this->db);
01157                                 $purchase->search_by_jid($code['j_id']);
01158                                 $purchase->load();
01159                                 $dep_priv+=$purchase->qp_dep_priv;
01160                                 $p_array['dep_priv'] = $dep_priv;
01161                         }
01162                 }
01163                 $p_array['TVAC'] = sprintf('% 10.2f', $p_array['TVAC'] - $dep_priv);
01164                 $p_array['HTVA'] = sprintf('% 10.2f', $p_array['TVAC'] - $p_array['AMOUNT_TVA']);
01165                 $r = "";
01166                 $a_tva_amount = array();
01167                 // inline TVA (used for the PDF)
01168                 foreach ($p_array['TVA'] as $linetva)
01169                 {
01170                         foreach ($a_TVA as $tva)
01171                         {
01172                                 if ($tva['tva_id'] == $linetva[1][0])
01173                                 {
01174                                         $a = $tva['tva_id'];
01175                                         $a_tva_amount[$a] = $linetva[1][2];
01176                                 }
01177                         }
01178                 }
01179                 foreach ($a_TVA as $line_tva)
01180                 {
01181                         $a = $line_tva['tva_id'];
01182                         if (isset($a_tva_amount[$a]))
01183                         {
01184                                 $tmp = sprintf("% 10.2f", $a_tva_amount[$a]);
01185                                 $r.="$tmp";
01186                         }
01187                         else
01188                                 $r.=sprintf("% 10.2f", 0);
01189                 }
01190                 $p_array['TVA_INLINE'] = $r;
01191 
01192                 return $p_array;
01193         }
01194 
01195 // retrieve data from jrnx
01196         /* !
01197          * \brief  Get the properties of a journal
01198          *
01199          * \return an array containing properties
01200          *
01201          */
01202 
01203         function get_propertie()
01204         {
01205                 if ($this->id == 0)
01206                         return;
01207 
01208                 $Res = $this->db->exec_sql("select jrn_Def_id,jrn_def_name,jrn_def_class_deb,jrn_def_class_cred,jrn_def_type,
01209                                  jrn_deb_max_line,jrn_cred_max_line,jrn_def_ech,jrn_def_ech_lib,jrn_def_code,
01210                                  jrn_def_fiche_deb,jrn_def_fiche_cred,jrn_def_pj_pref
01211                                  from jrn_Def
01212                                  where jrn_def_id=$1", array($this->id));
01213                 $Count = Database::num_row($Res);
01214                 if ($Count == 0)
01215                 {
01216                         echo '<DIV="redcontent"><H2 class="error">' . _('Parametres journaux non trouves') . '</H2> </DIV>';
01217                         return null;
01218                 }
01219                 return Database::fetch_array($Res, 0);
01220         }
01221 
01222         /* ! \function GetDefLine
01223          * \brief Get the number of lines of a journal
01224          * \param $p_cred deb or cred
01225          *
01226          * \return an integer
01227          */
01228 
01229         function GetDefLine()
01230         {
01231                 $sql_cred = 'jrn_deb_max_line';
01232                 $sql = "select jrn_deb_max_line as value from jrn_def where jrn_def_id=$1";
01233                 $r = $this->db->exec_sql($sql, array($this->id));
01234                 $Res = Database::fetch_all($r);
01235                 if (sizeof($Res) == 0)
01236                         return 1;
01237                 return $Res[0]['value'];
01238         }
01239 
01240         /* !\brief get the saldo of a ledger for a specific period
01241          * \param $p_from start period
01242          * \param $p_to end period
01243          */
01244 
01245         function get_solde($p_from, $p_to)
01246         {
01247                 $ledger = "";
01248                 if ($this->id != 0)
01249                 {
01250                         $ledger = " and j_jrn_def = " . $this->id;
01251                 }
01252 
01253                 $periode = sql_filter_per($this->db, $p_from, $p_to, 'p_id', 'j_tech_per');
01254                 $sql = 'select j_montant as montant,j_debit as deb from jrnx where '
01255                                 . $periode . $ledger;
01256 
01257                 $ret = $this->db->exec_sql($sql);
01258                 $array = Database::fetch_all($ret);
01259                 $deb = 0.0;
01260                 $cred = 0.0;
01261                 foreach ($array as $line)
01262                 {
01263 
01264                         if ($line['deb'] == 't')
01265                                 $deb+=$line['montant'];
01266                         else
01267                                 $cred+=$line['montant'];
01268                 }
01269                 $response = array($deb, $cred);
01270                 return $response;
01271         }
01272 
01273         /* !
01274          * \brief Show a select list   of the ledgers you can access in
01275          * writing, reading or simply accessing.
01276          * \param $p_type = ALL or the type of the ledger (ACH,VEN,FIN,ODS)
01277          * \param $p_access =3 for READ and WRITE, 2 for write and 1 for readonly
01278          * \return     object HtmlInput select
01279          */
01280 
01281         function select_ledger($p_type = "ALL", $p_access = 3)
01282         {
01283                 global $g_user;
01284                 $array = $g_user->get_ledger($p_type, $p_access);
01285 
01286                 if ($array == null)
01287                         return null;
01288                 $idx = 0;
01289                 $ret = array();
01290 
01291                 foreach ($array as $value)
01292                 {
01293                         $ret[$idx]['value'] = $value['jrn_def_id'];
01294                         $ret[$idx]['label'] = h($value['jrn_def_name']);
01295                         $idx++;
01296                 }
01297 
01298                 $select = new ISelect();
01299                 $select->name = 'p_jrn';
01300                 $select->value = $ret;
01301                 $select->selected = $this->id;
01302                 return $select;
01303         }
01304 
01305         /* !
01306          * \brief retrieve the jrn_def_fiche and return them into a array
01307          *        index deb, cred
01308          * \param
01309          * \param
01310          * \param
01311          *
01312          *
01313          * \return return an array ('deb'=> ,'cred'=>)
01314          */
01315 
01316         function get_fiche_def()
01317         {
01318                 $sql = "select jrn_def_fiche_deb as deb,jrn_def_fiche_cred as cred " .
01319                                 " from jrn_def where " .
01320                                 " jrn_def_id = $1 ";
01321 
01322                 $r = $this->db->exec_sql($sql, array($this->id));
01323 
01324                 $res = Database::fetch_all($r);
01325                 if (empty($res))
01326                         return null;
01327 
01328                 return $res[0];
01329         }
01330 
01331         /* !
01332          * \brief retrieve the jrn_def_class_deb and return it
01333          *
01334          *
01335          * \return return an string
01336          */
01337 
01338         function get_class_def()
01339         {
01340                 $sql = "select jrn_def_class_deb  " .
01341                                 " from jrn_def where " .
01342                                 " jrn_def_id = $1";
01343 
01344                 $r = $this->db->exec_sql($sql, array($this->id));
01345 
01346                 $res = Database::fetch_all($r);
01347 
01348                 if (empty($res))
01349                         return null;
01350 
01351                 return $res[0];
01352         }
01353 
01354         /* !
01355          * \brief show the result of the array to confirm
01356          * before inserting
01357          * \param $p_array array from the form
01358          * \return string
01359          */
01360 
01361         function confirm($p_array, $p_readonly = false)
01362         {
01363                 global $g_parameter;
01364                 $msg = array();
01365                 if (!$p_readonly)
01366                         $msg = $this->verify($p_array);
01367                 $this->id = $p_array['p_jrn'];
01368                 if (empty($p_array))
01369                         return 'Aucun r&eacute;sultat';
01370                 $anc = null;
01371                 extract($p_array);
01372                 $lPeriode = new Periode($this->db);
01373                 if ($this->check_periode() == true)
01374                 {
01375                         $lPeriode->p_id = $period;
01376                 }
01377                 else
01378                 {
01379                         $lPeriode->find_periode($e_date);
01380                 }
01381                 $total_deb = 0;
01382                 $total_cred = 0;
01383                 bcscale(2);
01384 
01385                 $ret = "";
01386                 if (!empty($msg))
01387                 {
01388                         $ret.=$this->display_warning($msg, "Attention : il vaut mieux utiliser les fiches que les postes comptables pour");
01389                 }
01390                 $ret.="<table >";
01391                 $ret.="<tr><td>" . _('Date') . " : </td><td>$e_date</td></tr>";
01392                 /* display periode */
01393                 $date_limit = $lPeriode->get_date_limit();
01394                 $ret.='<tr> ' . td(_('Période Comptable')) . td($date_limit['p_start'] . '-' . $date_limit['p_end']) . '</tr>';
01395                 $ret.="<tr><td>" . _('Libellé') . " </td><td>" . h($desc) . "</td></tr>";
01396                 $ret.="<tr><td>" . _('PJ Num') . " </td><td>" . h($e_pj) . "</td></tr>";
01397                 $ret.='</table>';
01398                 $ret.="<table class=\"result\">";
01399                 $ret.="<tr>";
01400                 $ret.="<th>" . _('Quick Code ou ');
01401                 $ret.=_("Poste") . " </th>";
01402                 $ret.="<th style=\"text-align:left\"> " . _("Libellé") . " </th>";
01403                 $ret.="<th style=\"text-align:right\">" . _("Débit") . "</th>";
01404                 $ret.="<th style=\"text-align:right\">" . _("Crédit") . "</th>";
01405                 /* if we use the AC */
01406                 if ($g_parameter->MY_ANALYTIC != 'nu')
01407                 {
01408                         $anc = new Anc_Plan($this->db);
01409                         $a_anc = $anc->get_list();
01410                         $x = count($a_anc);
01411                         /* set the width of the col */
01412                         $ret.='<th colspan="' . $x . '" style="width:auto;text-align:center" >' . _('Compt. Analytique') . '</th>';
01413 
01414                         /* add hidden variables pa[] to hold the value of pa_id */
01415                         $ret.=Anc_Plan::hidden($a_anc);
01416                 }
01417                 $ret.="</tr>";
01418 
01419                 $ret.=HtmlInput::hidden('e_date', $e_date);
01420                 $ret.=HtmlInput::hidden('desc', $desc);
01421                 $ret.=HtmlInput::hidden('period', $lPeriode->p_id);
01422                 $ret.=HtmlInput::hidden('e_pj', $e_pj);
01423                 $ret.=HtmlInput::hidden('e_pj_suggest', $e_pj_suggest);
01424                 $mt = microtime(true);
01425                 $ret.=HtmlInput::hidden('mt', $mt);
01426                 // For predefined operation
01427                 $ret.=HtmlInput::hidden('e_comm', $desc);
01428                 $ret.=HtmlInput::hidden('jrn_type', $this->get_type());
01429                 $ret.=HtmlInput::hidden('p_jrn', $this->id);
01430                 $ret.=HtmlInput::hidden('nb_item', $nb_item);
01431                 if ($this->with_concerned == true)
01432                 {
01433                         $ret.=HtmlInput::hidden('jrn_concerned', $jrn_concerned);
01434                 }
01435                 $ret.=dossier::hidden();
01436                 $count = 0;
01437                 for ($i = 0; $i < $nb_item; $i++)
01438                 {
01439                         if ($p_readonly == true)
01440                         {
01441                                 if (!isset(${'qc_' . $i}))
01442                                         ${'qc_' . $i} = '';
01443                                 if (!isset(${'poste' . $i}))
01444                                         ${'poste' . $i} = '';
01445                                 if (!isset(${'amount' . $i}))
01446                                         ${'amount' . $i} = '';
01447                         }
01448                         $ret.="<tr>";
01449                         if (trim(${'qc_' . $i}) != "")
01450                         {
01451                                 $oqc = new Fiche($this->db);
01452                                 $oqc->get_by_qcode(${'qc_' . $i}, false);
01453                                 $strPoste = $oqc->strAttribut(ATTR_DEF_ACCOUNT);
01454                                 $ret.="<td>" .
01455                                                 ${'qc_' . $i} . ' - ' .
01456                                                 $oqc->strAttribut(ATTR_DEF_NAME) . HtmlInput::hidden('qc_' . $i, ${'qc_' . $i}) .
01457                                                 '</td>';
01458                         }
01459 
01460                         if (trim(${'qc_' . $i}) == "" && trim(${'poste' . $i}) != "")
01461                         {
01462                                 $oposte = new Acc_Account_Ledger($this->db, ${'poste' . $i});
01463                                 $strPoste = $oposte->id;
01464                                 $ret.="<td>" . h(${"poste" . $i} . " - " .
01465                                                                 $oposte->get_name()) . HtmlInput::hidden('poste' . $i, ${'poste' . $i}) .
01466                                                 '</td>';
01467                         }
01468 
01469                         if (trim(${'qc_' . $i}) == "" && trim(${'poste' . $i}) == "")
01470                                 continue;
01471                         $ret.="<td>" . h(${"ld" . $i}) . HtmlInput::hidden('ld' . $i, ${'ld' . $i}) . "</td>";
01472                         if (isset(${"ck$i"}))
01473                         {
01474                                 $ret.="<td class=\"num\">" . nbm(${"amount" . $i}) . HtmlInput::hidden('amount' . $i, ${'amount' . $i}) . "</td>" . td("");
01475                                 $total_deb = bcadd($total_deb, ${'amount' . $i});
01476                         }
01477                         else
01478                         {
01479                                 $ret.=td("") . "<td class=\"num\">" . nbm(${"amount" . $i}) . HtmlInput::hidden('amount' . $i, ${'amount' . $i}) . "</td>";
01480                                 $total_cred = bcadd($total_cred, ${"amount" . $i});
01481                         }
01482                         $ret.="<td>";
01483                         $ret.=(isset(${"ck$i"})) ? HtmlInput::hidden('ck' . $i, ${'ck' . $i}) : "";
01484                         $ret.="</td>";
01485                         // CA
01486 
01487                         if ($g_parameter->MY_ANALYTIC != 'nu') // use of AA
01488                         {
01489                                 if (preg_match("/^[6,7]+/", $strPoste) == 1)
01490                                 {
01491                                         // show form
01492                                         $op = new Anc_Operation($this->db);
01493                                         $null = ($g_parameter->MY_ANALYTIC == 'op') ? 1 : 0;
01494                                         $p_array['pa_id'] = $a_anc;
01495                                         /* op is the operation it contains either a sequence or a jrnx.j_id */
01496                                         $ret.=HtmlInput::hidden('op[]=', $i);
01497 
01498                                         $ret.='<td style="text-align:center">';
01499                                         $read = ($p_readonly == true) ? 0 : 1;
01500                                         $ret.=$op->display_form_plan($p_array, $null, $read, $count, round(${'amount' . $i}, 2));
01501                                         $ret.='</td>';
01502                                         $count++;
01503                                 }
01504                         }
01505 
01506 
01507 
01508                         $ret.="</tr>";
01509                 }
01510                 $ret.=tr(td('') . td(_('Totaux')) . td($total_deb, 'class="num"') . td($total_cred, 'class="num"'), 'class="footer"');
01511                 $ret.="</table>";
01512                 if ($g_parameter->MY_ANALYTIC != 'nu' && $p_readonly == false)
01513                         $ret.='<input type="button" class="button" value="' . _('verifie Imputation Analytique') . '" onClick="verify_ca(\'\');">';
01514                 return $ret;
01515         }
01516 
01517         /* !
01518          * \brief Show the form to encode your operation
01519          * \param $p_array if you correct or use a predef operation (default = null)
01520          * \param $p_readonly 1 for readonly 0 for writable (default 0)
01521          *
01522          * \return a string containing the form
01523          */
01524 
01525         function input($p_array = null, $p_readonly = 0)
01526         {
01527                 global $g_parameter, $g_user;
01528 
01529                 if ($p_readonly == 1)
01530                         return $this->confirm($p_array);
01531 
01532                 if ($p_array != null)
01533                         extract($p_array);
01534                 $add_js = "";
01535                 if ($g_parameter->MY_PJ_SUGGEST == 'Y')
01536                 {
01537                         $add_js = "update_pj();";
01538                 }
01539                 $add_js.='get_last_date();';
01540 
01541                 $ret = "";
01542                 if ($g_user->check_action(FICADD) == 1)
01543                 {
01544                         /* Add button */
01545                         $f_add_button = new IButton('add_card');
01546                         $f_add_button->label = _('Créer une nouvelle fiche');
01547                         $f_add_button->set_attribute('ipopup', 'ipop_newcard');
01548                         $f_add_button->set_attribute('jrn', $this->id);
01549                         $f_add_button->javascript = " this.jrn=\$('p_jrn').value;select_card_type(this);";
01550                         $f_add_button->input();
01551                 }
01552                 $wLedger = $this->select_ledger('ODS', 2);
01553                 if ($wLedger == null)
01554                         exit(_('Pas de journal disponible'));
01555                 $wLedger->javascript = "onChange='update_name();update_predef(\"ods\",\"t\");$add_js'";
01556                 $label = " Journal " . HtmlInput::infobulle(2);
01557 
01558                 $ret.=$label . $wLedger->input();
01559 
01560 
01561                 // Load the javascript
01562                 //
01563         $ret.="<table>";
01564                 $ret.= '<tr ><td colspan="2" style="width:auto">';
01565                 $wDate = new IDate('e_date');
01566                 $wDate->readonly = $p_readonly;
01567                 $e_date = (isset($e_date) && trim($e_date) != '') ? $e_date : '';
01568                 $wDate->value = $e_date;
01569 
01570                 $ret.=_("Date") . ' : ' . $wDate->input();
01571                 $ret.= '</td>';
01572                 /* insert periode if needed */
01573                 // Periode
01574                 //--
01575                 if ($this->check_periode() == true)
01576                 {
01577                         $l_user_per = $g_user->get_periode();
01578                         $def = (isset($periode)) ? $periode : $l_user_per;
01579 
01580                         $period = new IPeriod("period");
01581                         $period->user = $g_user;
01582                         $period->cn = $this->db;
01583                         $period->value = $def;
01584                         $period->type = OPEN;
01585                         try
01586                         {
01587                                 $l_form_per = $period->input();
01588                         }
01589                         catch (Exception $e)
01590                         {
01591                                 if ($e->getCode() == 1)
01592                                 {
01593                                         echo _("Aucune période ouverte");
01594                                         exit();
01595                                 }
01596                         }
01597                         $label = HtmlInput::infobulle(3);
01598                         $f_periode = _("Période comptable") . " $label " . $l_form_per;
01599                         $ret.=td($f_periode);
01600                 }
01601                 $wPJ = new IText('e_pj');
01602                 $wPJ->readonly = false;
01603                 $wPJ->size = 10;
01604 
01605                 /* suggest PJ ? */
01606                 $default_pj = '';
01607                 if ($g_parameter->MY_PJ_SUGGEST == 'Y')
01608                 {
01609                         $default_pj = $this->guess_pj();
01610                 }
01611                 $wPJ->value = (isset($e_pj)) ? $e_pj : $default_pj;
01612                 $ret.= '</tr>';
01613                 $ret.='<tr >';
01614                 $ret.='<td colspan="2" style="width:auto"> ' . _('Pièce') . ' : ' . $wPJ->input();
01615                 $ret.=HtmlInput::hidden('e_pj_suggest', $default_pj);
01616                 $ret.= '</tr>';
01617                 $ret.= '</td>';
01618 
01619                 $ret.= '<tr>';
01620                 $ret.='<td colspan="2" style="width:auto">';
01621                 $ret.=_('Libellé');
01622                 $wDescription = new IText('desc');
01623                 $wDescription->readonly = $p_readonly;
01624                 $wDescription->size = "50";
01625                 $wDescription->value = (isset($desc)) ? $desc : '';
01626 
01627                 $ret.=$wDescription->input();
01628                 $ret.= '</td>';
01629                 $ret.='</tr>';
01630 
01631                 $ret.= '</table>';
01632                 $nb_row = (isset($nb_item) ) ? $nb_item : $this->nb;
01633 
01634                 $ret.=HtmlInput::hidden('nb_item', $nb_row);
01635                 $ret.=dossier::hidden();
01636 
01637                 $ret.=dossier::hidden();
01638 
01639                 $ret.=HtmlInput::hidden('jrn_type', $this->get_type());
01640                 $info = HtmlInput::infobulle(0);
01641                 $info_poste = HtmlInput::infobulle(9);
01642                 if ($g_user->check_action(FICADD) == 1)
01643                         $ret.=$f_add_button->input();
01644                 $ret.='<table id="quick_item" style="width:100%">';
01645                 $ret.='<tr>' .
01646                                 '<th style="text-align:left">Quickcode' . $info . '</th>' .
01647                                 '<th style="text-align:left">' . _('Poste') . $info_poste . '</th>' .
01648                                 '<th style="text-align:left">' . _('Libellé') . '</th>' .
01649                                 '<th style="text-align:left">' . _('Montant') . '</th>' .
01650                                 '<th style="text-align:left">' . _('Débit') . '</th>' .
01651                                 '</tr>';
01652 
01653 
01654                 for ($i = 0; $i < $nb_row; $i++)
01655                 {
01656                         // Quick Code
01657                         $quick_code = new ICard('qc_' . $i);
01658                         $quick_code->set_dblclick("fill_ipopcard(this);");
01659                         $quick_code->set_attribute('ipopup', 'ipopcard');
01660 
01661                         // name of the field to update with the name of the card
01662                         $quick_code->set_attribute('label', "ld" . $i);
01663                         $quick_code->set_attribute('jrn', $this->id);
01664 
01665                         // name of the field to update with the name of the card
01666                         $quick_code->set_attribute('typecard', 'filter');
01667 
01668                         // Add the callback function to filter the card on the jrn
01669                         $quick_code->set_callback('filter_card');
01670                         $quick_code->set_function('fill_data');
01671                         $quick_code->javascript = sprintf(' onchange="fill_data_onchange(\'%s\');" ', $quick_code->name);
01672 
01673                         $quick_code->jrn = $this->id;
01674                         $quick_code->value = (isset(${'qc_' . $i})) ? ${'qc_' . $i} : "";
01675                         $quick_code->readonly = $p_readonly;
01676 
01677                         $label = '';
01678                         if ($quick_code->value != '')
01679                         {
01680                                 $Fiche = new Fiche($this->db);
01681                                 $Fiche->get_by_qcode($quick_code->value);
01682                                 $label = $Fiche->strAttribut(ATTR_DEF_NAME);
01683                         }
01684 
01685 
01686                         // Account
01687                         $poste = new IPoste();
01688                         $poste->name = 'poste' . $i;
01689                         $poste->set_attribute('jrn', $this->id);
01690                         $poste->set_attribute('ipopup', 'ipop_account');
01691                         $poste->set_attribute('label', 'ld' . $i);
01692                         $poste->set_attribute('account', 'poste' . $i);
01693                         $poste->set_attribute('dossier', Dossier::id());
01694 
01695                         $poste->value = (isset(${'poste' . $i})) ? ${"poste" . $i} : ''
01696                         ;
01697                         $poste->dbl_click_history();
01698 
01699                         $poste->readonly = $p_readonly;
01700 
01701                         if ($poste->value != '')
01702                         {
01703                                 $Poste = new Acc_Account($this->db);
01704                                 $Poste->set_parameter('value', $poste->value);
01705                                 $label = $Poste->get_lib();
01706                         }
01707 
01708                         // Description of the line
01709                         $line_desc = new IText();
01710                         $line_desc->name = 'ld' . $i;
01711                         $line_desc->size = 30;
01712                         $line_desc->value = (isset(${"ld" . $i})) ? ${"ld" . $i} :
01713                                         $label;
01714 
01715                         // Amount
01716                         $amount = new INum();
01717                         $amount->size = 10;
01718                         $amount->name = 'amount' . $i;
01719                         $amount->value = (isset(${'amount' . $i})) ? ${"amount" . $i} : ''
01720                         ;
01721                         $amount->readonly = $p_readonly;
01722                         $amount->javascript = ' onChange="format_number(this);checkTotalDirect()"';
01723                         // D/C
01724                         $deb = new ICheckBox();
01725                         $deb->name = 'ck' . $i;
01726                         $deb->selected = (isset(${'ck' . $i})) ? true : false;
01727                         $deb->readonly = $p_readonly;
01728                         $deb->javascript = ' onChange="checkTotalDirect()"';
01729 
01730                         $ret.='<tr>';
01731                         $ret.='<td>' . $quick_code->input() . $quick_code->search() . '</td>';
01732                         $ret.='<td>' . $poste->input() .
01733                                         '<script> document.getElementById(\'poste' . $i . '\').onblur=function(){ if (trim(this.value) !=\'\') {document.getElementById(\'qc_' . $i . '\').value="";}}</script>' .
01734                                         '</td>';
01735                         $ret.='<td>' . $line_desc->input() . '</td>';
01736                         $ret.='<td>' . $amount->input() . '</td>';
01737                         $ret.='<td>' . $deb->input() . '</td>';
01738                         $ret.='</tr>';
01739                         // If readonly == 1 then show CA
01740                 }
01741                 $ret.='</table>';
01742                 if (isset($this->with_concerned) && $this->with_concerned == true)
01743                 {
01744                         $oRapt = new Acc_Reconciliation($this->db);
01745                         $w = $oRapt->widget();
01746                         $w->name = 'jrn_concerned';
01747                         $w->value = (isset($jrn_concerned)) ? $jrn_concerned : "";
01748                         $ret.="R&eacute;conciliation/rapprochements : " . $w->input();
01749                 }
01750                 return $ret;
01751         }
01752 
01753         /* !\brief
01754          * check if the current ledger is closed
01755          * \return 1 for yes, otherwise 0
01756          * \see Periode::is_closed
01757          */
01758 
01759         function is_closed($p_periode)
01760         {
01761                 $per = new Periode($this->db);
01762                 $per->set_jrn($this->id);
01763                 $per->set_periode($p_periode);
01764                 $ret = $per->is_closed();
01765                 return $ret;
01766         }
01767 
01768         /* !
01769          * \brief verify that the operation can be saved
01770          * \param $p_array array of data same layout that the $_POST from show_form
01771          *
01772          *
01773          * \throw  the getcode  value is 1 incorrect balance,  2 date
01774          * invalid, 3 invalid amount,  4 the card is not in the range of
01775          * permitted card, 5 not in the user's period, 6 closed period
01776          *
01777          */
01778 
01779         function verify($p_array)
01780         {
01781                 extract($p_array);
01782                 global $g_user;
01783                 $tot_cred = 0;
01784                 $tot_deb = 0;
01785                 $msg = array();
01786 
01787                 /* check if we can write into this ledger */
01788                 if ($g_user->check_jrn($p_jrn) != 'W')
01789                         throw new Exception(_('Accès interdit'), 20);
01790 
01791                 /* check for a double reload */
01792                 if (isset($mt) && $this->db->count_sql('select jr_mt from jrn where jr_mt=$1', array($mt)) != 0)
01793                         throw new Exception('Double Encodage', 5);
01794 
01795                 // Check the periode and the date
01796                 if (isDate($e_date) == null)
01797                 {
01798                         throw new Exception('Date invalide', 2);
01799                 }
01800                 $periode = new Periode($this->db);
01801                 /* find the periode  if we have enabled the check_periode */
01802                 if ($this->check_periode() == false)
01803                 {
01804                         $periode->find_periode($e_date);
01805                 }
01806                 else
01807                 {
01808                         $periode->p_id = $period;
01809                         list ($min, $max) = $periode->get_date_limit();
01810                         if (cmpDate($e_date, $min) < 0 ||
01811                                         cmpDate($e_date, $max) > 0)
01812                                 throw new Exception(_('Date et periode ne correspondent pas'), 6);
01813                 }
01814 
01815 
01816 
01817                 // Periode ferme
01818                 if ($this->is_closed($periode->p_id) == 1)
01819                 {
01820                         throw new Exception('Periode fermee', 6);
01821                 }
01822                 /* check if we are using the strict mode */
01823                 if ($this->check_strict() == true)
01824                 {
01825                         /* if we use the strict mode, we get the date of the last
01826                           operation */
01827                         $last_date = $this->get_last_date();
01828                         if ($last_date != null && cmpDate($e_date, $last_date) < 0)
01829                                 throw new Exception(_('Vous utilisez le mode strict la dernière operation est la date du ')
01830                                                 . $last_date . ' ' . _('vous ne pouvez pas encoder à une date antérieure'), 15);
01831                 }
01832 
01833                 for ($i = 0; $i < $nb_item; $i++)
01834                 {
01835                         $err = 0;
01836 
01837                         // Check the balance
01838                         if (!isset(${'amount' . $i}))
01839                                 continue;
01840 
01841                         $amount = round(${'amount' . $i}, 2);
01842                         $tot_deb+=(isset(${'ck' . $i})) ? $amount : 0;
01843                         $tot_cred+=(!isset(${'ck' . $i})) ? $amount : 0;
01844 
01845                         // Check if the card is permitted
01846                         if (isset(${'qc_' . $i}) && trim(${'qc_' . $i}) != "")
01847                         {
01848                                 $f = new Fiche($this->db);
01849                                 $f->quick_code = ${'qc_' . $i};
01850                                 if ($f->belong_ledger($p_jrn) < 0)
01851                                         throw new Exception("La fiche quick_code = " .
01852                                                         $f->quick_code . " n\'est pas dans ce journal", 4);
01853                                 if (strlen(trim(${'qc_' . $i})) != 0 && isNumber(${'amount' . $i}) == 0)
01854                                         throw new Exception('Montant invalide', 3);
01855 
01856                                 $strPoste = $f->strAttribut(ATTR_DEF_ACCOUNT);
01857                                 if ($strPoste == '')
01858                                         throw new Exception(sprintf(_("La fiche %s n'a pas de poste comptable"), ${"qc_" . $i}));
01859 
01860                                 $p = new Acc_Account_Ledger($this->db, $strPoste);
01861                                 if ($p->do_exist() == 0)
01862                                         throw new Exception(_('Poste Inexistant pour la fiche [' . ${'qc_' . $i} . ']'), 4);
01863                         }
01864 
01865                         // Check if the account is permitted
01866                         if (isset(${'poste' . $i}) && strlen(trim(${'poste' . $i})) != 0)
01867                         {
01868                                 $p = new Acc_Account_Ledger($this->db, ${'poste' . $i});
01869                                 if ($p->belong_ledger($p_jrn) < 0)
01870                                         throw new Exception(_("Le poste") . " " . $p->id . " " . _("n'est pas dans ce journal"), 5);
01871                                 if (strlen(trim(${'poste' . $i})) != 0 && isNumber(${'amount' . $i}) == 0)
01872                                         throw new Exception(_('Poste invalide [' . ${'poste' . $i} . ']'), 3);
01873                                 if ($p->do_exist() == 0)
01874                                         throw new Exception(_('Poste Inexistant [' . ${'poste' . $i} . ']'), 4);
01875                                 $card_id = $p->find_card();
01876                                 if (!empty($card_id))
01877                                 {
01878                                         $str_msg = " Le poste " . $p->id . " appartient à " . count($card_id) . " fiche(s) dont :";
01879                                         $max = (count($card_id) > MAX_COMPTE_CARD) ? MAX_COMPTE_CARD : count($card_id);
01880                                         for ($x = 0; $x < $max; $x++)
01881                                         {
01882                                                 $card = new Fiche($this->db, $card_id[$x]['f_id']);
01883                                                 $str_msg.=HtmlInput::card_detail($card->strAttribut(ATTR_DEF_QUICKCODE), $card->strAttribut(ATTR_DEF_NAME), 'style="color:red;display:inline;text-decoration:underline"');
01884                                                 $str_msg.=" ";
01885                                         }
01886                                         $msg[] = $str_msg;
01887                                 }
01888                         }
01889                 }
01890                 $tot_deb = round($tot_deb, 4);
01891                 $tot_cred = round($tot_cred, 4);
01892                 if ($tot_deb != $tot_cred)
01893                 {
01894                         throw new Exception(_("Balance incorrecte ") . " debit = $tot_deb credit=$tot_cred ", 1);
01895                 }
01896 
01897                 return $msg;
01898         }
01899 
01900         /* !
01901          * \brief compute the internal code of the saved operation and set the $this->jr_internal to
01902          *  the computed value
01903          *
01904          * \param $p_grpt id in jr_grpt_
01905          *
01906          * \return string internal_code
01907          *      -
01908          *
01909          */
01910 
01911         function compute_internal_code($p_grpt)
01912         {
01913                 if ($this->id == 0)
01914                         return;
01915                 $num = $this->db->get_next_seq('s_internal');
01916                 $atype = $this->get_propertie();
01917                 $type = substr($atype['jrn_def_code'], 0, 1);
01918                 $internal_code = sprintf("%s%06X", $type, $num);
01919                 $this->jr_internal = $internal_code;
01920                 return $internal_code;
01921         }
01922 
01923         /* !
01924          * \brief save the operation into the jrnx,jrn, ,
01925          *  CA and pre_def
01926          * \param $p_array
01927          *
01928          * \return array with [0] = false if failed otherwise true, [1] error
01929          * code
01930          */
01931 
01932         function save($p_array = null)
01933         {
01934                 if ($p_array == null)
01935                         throw new Exception('save cannot use a empty array');
01936                 global $g_parameter;
01937                 extract($p_array);
01938                 try
01939                 {
01940                         $msg = $this->verify($p_array);
01941                         if (!empty($msg))
01942                         {
01943                                 echo $this->display_warning($msg, "Attention : il vaut mieux utiliser les fiches que les postes comptables pour");
01944                         }
01945                         $this->db->start();
01946 
01947                         $seq = $this->db->get_next_seq('s_grpt');
01948                         $internal = $this->compute_internal_code($seq);
01949 
01950                         $group = $this->db->get_next_seq("s_oa_group");
01951                         $tot_amount = 0;
01952                         $tot_deb = 0;
01953                         $tot_cred = 0;
01954                         $oPeriode = new Periode($this->db);
01955                         $check_periode = $this->check_periode();
01956                         if ($check_periode == false)
01957                         {
01958                                 $oPeriode->find_periode($e_date);
01959                         }
01960                         else
01961                         {
01962                                 $oPeriode->id = $period;
01963                         }
01964 
01965                         $count = 0;
01966                         for ($i = 0; $i < $nb_item; $i++)
01967                         {
01968                                 if (!isset(${'qc_' . $i}) && !isset(${'poste' . $i}))
01969                                         continue;
01970                                 $acc_op = new Acc_Operation($this->db);
01971                                 $quick_code = "";
01972                                 // First we save the jrnx
01973                                 if (isset(${'qc_' . $i}))
01974                                 {
01975                                         $qc = new Fiche($this->db);
01976                                         $qc->get_by_qcode(${'qc_' . $i}, false);
01977                                         $sposte = $qc->strAttribut(ATTR_DEF_ACCOUNT);
01978                                         /*  if there are 2 accounts take following the deb or cred */
01979                                         if (strpos($sposte, ',') != 0)
01980                                         {
01981                                                 $array = explode(",", $sposte);
01982                                                 $poste = (isset(${'ck' . $i})) ? $array[0] : $array[1];
01983                                         }
01984                                         else
01985                                         {
01986                                                 $poste = $sposte;
01987                                                 if ($poste == '')
01988                                                         throw new Exception(sprintf(_("La fiche %s n'a pas de poste comptable"), ${"qc_" . $i}));
01989                                         }
01990                                         $quick_code = ${'qc_' . $i};
01991                                 }
01992                                 else
01993                                 {
01994                                         $poste = ${'poste' . $i};
01995                                 }
01996 
01997                                 $acc_op->date = $e_date;
01998                                 // compute the periode is do not check it
01999                                 if ($check_periode == false)
02000                                         $acc_op->periode = $oPeriode->p_id;
02001                                 $acc_op->desc = null;
02002                                 if (strlen(trim(${'ld' . $i})) != 0)
02003                                         $acc_op->desc = ${'ld' . $i};
02004                                 $acc_op->amount = round(${'amount' . $i}, 2);
02005                                 $acc_op->grpt = $seq;
02006                                 $acc_op->poste = $poste;
02007                                 $acc_op->jrn = $this->id;
02008                                 $acc_op->type = (isset(${'ck' . $i})) ? 'd' : 'c';
02009                                 $acc_op->qcode = $quick_code;
02010                                 $j_id = $acc_op->insert_jrnx();
02011                                 $tot_amount+=round($acc_op->amount, 2);
02012                                 $tot_deb+=($acc_op->type == 'd') ? $acc_op->amount : 0;
02013                                 $tot_cred+=($acc_op->type == 'c') ? $acc_op->amount : 0;
02014                                 if ($g_parameter->MY_ANALYTIC != "nu")
02015                                 {
02016                                         if (preg_match("/^[6,7]+/", $poste) == 1)
02017                                         {
02018 
02019                                                 // for each item, insert into operation_analytique */
02020                                                 $op = new Anc_Operation($this->db);
02021                                                 $op->oa_group = $group;
02022                                                 $op->j_id = $j_id;
02023                                                 $op->oa_date = $e_date;
02024                                                 $op->oa_debit = ($acc_op->type == 'd' ) ? 't' : 'f';
02025                                                 $op->oa_description = $desc;
02026                                                 $op->save_form_plan($p_array, $count, $j_id);
02027                                                 $count++;
02028                                         }
02029                                 }
02030                         }// loop for each item
02031                         $acc_end = new Acc_Operation($this->db);
02032                         $acc_end->amount = $tot_deb;
02033                         if ($check_periode == false)
02034                                 $acc_end->periode = $oPeriode->p_id;
02035                         $acc_end->date = $e_date;
02036                         $acc_end->desc = $desc;
02037                         $acc_end->grpt = $seq;
02038                         $acc_end->jrn = $this->id;
02039                         $acc_end->mt = $mt;
02040                         $jr_id = $acc_end->insert_jrn();
02041                         $this->jr_id = $jr_id;
02042                         if ($jr_id == false)
02043                                 throw new Exception('Balance incorrecte');
02044                         $acc_end->pj = $e_pj;
02045 
02046                         /* if e_suggest != e_pj then do not increment sequence */
02047                         if (strcmp($e_pj, $e_pj_suggest) == 0 && strlen(trim($e_pj)) != 0)
02048                         {
02049                                 $this->inc_seq_pj();
02050                         }
02051 
02052                         $this->pj = $acc_end->set_pj();
02053 
02054                         $this->db->exec_sql("update jrn set jr_internal='" . $internal . "' where " .
02055                                         " jr_grpt_id = " . $seq);
02056                         $this->internal = $internal;
02057                         // Save now the predef op
02058                         //------------------------
02059                         if (isset($opd_save))
02060                         {
02061                                 $opd = new Pre_Op_Advanced($this->db);
02062                                 $opd->get_post();
02063                                 $opd->save();
02064                         }
02065 
02066                         if (isset($this->with_concerned) && $this->with_concerned == true)
02067                         {
02068                                 $orap = new acc_reconciliation($this->db);
02069                                 $orap->jr_id = $jr_id;
02070 
02071                                 $orap->insert($jrn_concerned);
02072                         }
02073                 }
02074                 catch (Exception $a)
02075                 {
02076                         throw $a;
02077                 }
02078                 catch (Exception $e)
02079                 {
02080                         $this->db->rollback();
02081                         echo 'OPERATION ANNULEE ';
02082                         echo '<hr>';
02083                         echo __FILE__ . __LINE__ . $e->getMessage();
02084                         exit();
02085                 }
02086                 $this->db->commit();
02087                 return true;
02088         }
02089 
02090         /* !
02091          * \brief get all the data from request and build the object
02092          */
02093 
02094         function get_request()
02095         {
02096                 $this->id = $_REQUEST['p_jrn'];
02097         }
02098 
02099         /* !
02100          * \brief retrieve the next number for this type of ledger
02101          * \param p_cn connx
02102          * \param p_type ledger type
02103          *
02104          * \return the number
02105          *
02106          *
02107          */
02108 
02109         static function next_number($p_cn, $p_type)
02110         {
02111 
02112                 $Ret = $p_cn->count_sql("select * from jrn_def where jrn_def_type='" . $p_type . "'");
02113                 return $Ret + 1;
02114         }
02115 
02116         /* !\brief get the first ledger
02117          * \param the type
02118          * \return the j_id
02119          */
02120 
02121         public function get_first($p_type, $p_access = 3)
02122         {
02123                 global $g_user;
02124                 $all = $g_user->get_ledger($p_type, $p_access);
02125                 return $all[0];
02126         }
02127 
02128         /* !\brief Update the paiment  in the list of operation
02129          * \param $p_array is normally $_GET
02130          */
02131 
02132         function update_paid($p_array)
02133         {
02134                 // reset all the paid flag because the checkbox is post only
02135                 // when checked
02136                 foreach ($p_array as $name => $paid)
02137                 {
02138                         list($ad) = sscanf($name, "set_jr_id%d");
02139                         if ($ad == null)
02140                                 continue;
02141                         $sql = "update jrn set jr_rapt='' where jr_id=$ad";
02142                         $Res = $this->db->exec_sql($sql);
02143                 }
02144                 // set a paid flag for the checked box
02145                 foreach ($p_array as $name => $paid)
02146                 {
02147                         list ($id) = sscanf($name, "rd_paid%d");
02148                         if ($id == null)
02149                                 continue;
02150 
02151                         $sql = "update jrn set jr_rapt='paid' where jr_id=$id";
02152                         $Res = $this->db->exec_sql($sql);
02153                 }
02154         }
02155 
02156         function update_internal_code($p_internal)
02157         {
02158                 if (!isset($this->grpt_id))
02159                         exit('ERREUR ' . __FILE__ . ":" . __LINE__);
02160                 $Res = $this->db->exec_sql("update jrn set jr_internal='" . $p_internal . "' where " .
02161                                 " jr_grpt_id = " . $this->grpt_id);
02162         }
02163 
02164         /* !\brief retrieve all the card for this type of ledger, make them
02165          * into a string separated by comma
02166          * \param none
02167          * \return all the card or null is nothing is found
02168          */
02169 
02170         function get_all_fiche_def()
02171         {
02172                 $sql = "select jrn_def_fiche_deb as deb,jrn_def_fiche_cred as cred " .
02173                                 " from jrn_def where " .
02174                                 " jrn_def_id = $1 ";
02175 
02176                 $r = $this->db->exec_sql($sql, array($this->id));
02177 
02178                 $res = Database::fetch_all($r);
02179                 if (empty($res))
02180                         return null;
02181                 $card = "";
02182                 $comma = '';
02183                 foreach ($res as $item)
02184                 {
02185                         if (strlen(trim($item['deb'])) != 0)
02186                         {
02187                                 $card.=$comma . $item['deb'];
02188                                 $comma = ',';
02189                         }
02190                         if (strlen(trim($item['cred'])) != '')
02191                         {
02192                                 $card.=$comma . $item['cred'];
02193                                 $comma = ',';
02194                         }
02195                 }
02196 
02197                 return $card;
02198         }
02199 
02200         /* !\brief get the saldo of an exercice, used for the opening of a folder
02201          * \param $p_exercice is the exercice we want
02202          * \return an array
02203          * index =
02204          * - solde (debit > 0 ; credit < 0)
02205          * - j_poste
02206          * - j_qcode
02207          */
02208 
02209         function get_saldo_exercice($p_exercice)
02210         {
02211                 $sql = "select sum(a.montant) as solde, j_poste, j_qcode
02212              from
02213              (select j_id, case when j_debit='t' then j_montant
02214              else j_montant * (-1) end  as montant
02215              from jrnx) as a
02216              join jrnx using (j_id)
02217              join parm_periode on (j_tech_per = p_id )
02218              where
02219              p_exercice=$1
02220              and j_poste::text not like '7%'
02221              and j_poste::text not like '6%'
02222              group by j_poste,j_qcode
02223              having (sum(a.montant) != 0 )";
02224                 $res = $this->db->get_array($sql, array($p_exercice));
02225                 return $res;
02226         }
02227 
02228         /* !
02229          * \brief Check if a Dossier is using the strict mode or not
02230          * \return true if we are using the strict_mode
02231          */
02232 
02233         function check_strict()
02234         {
02235                 global $g_parameter;
02236                 if ($g_parameter->MY_STRICT == 'Y')
02237                         return true;
02238                 if ($g_parameter->MY_STRICT == 'N')
02239                         return false;
02240                 exit("Valeur invalid " . __FILE__ . ':' . __LINE__);
02241         }
02242 
02243         /* !
02244          * \brief Check if a Dossier is using the check on the periode, if true than the user has to enter the date
02245          * and the periode, it is a security check
02246          * \return true if we are using the double encoding (date+periode)
02247          */
02248 
02249         function check_periode()
02250         {
02251                 global $g_parameter;
02252                 if ($g_parameter->MY_CHECK_PERIODE == 'Y')
02253                         return true;
02254                 if ($g_parameter->MY_CHECK_PERIODE == 'N')
02255                         return false;
02256                 exit("Valeur invalid " . __FILE__ . ':' . __LINE__);
02257         }
02258 
02259         /* !\brief get the date of the last operation
02260          */
02261 
02262         function get_last_date()
02263         {
02264                 if ($this->id == 0)
02265                         throw new Exception(__FILE__ . ":" . __LINE__ . "Journal incorrect ");
02266                 $sql = "select to_char(max(jr_date),'DD.MM.YYYY') from jrn where jr_def_id=$1";
02267                 $date = $this->db->get_value($sql, array($this->id));
02268                 return $date;
02269         }
02270 
02271         /* !\brief retrieve the jr_id thanks the internal code, do not change
02272          * anything to the current object
02273          * \param the internal code
02274          * \return the jr_id or 0 if not found
02275          */
02276 
02277         function get_id($p_internal)
02278         {
02279                 $sql = 'select jr_id from jrn where jr_internal=$1';
02280                 $value = $this->db->get_value($sql, array($p_internal));
02281                 if ($value == '')
02282                         $value = 0;
02283                 return $value;
02284         }
02285 
02286         /* !\brief create the invoice and saved it as attachment to the
02287          * operation,
02288          * \param $internal is the internal code
02289          * \param $p_array is normally the $_POST
02290          * \return a string
02291          */
02292 
02293         function create_document($internal, $p_array)
02294         {
02295                 extract($p_array);
02296                 $doc = new Document($this->db);
02297                 $doc->f_id = $e_client;
02298                 $doc->md_id = $gen_doc;
02299                 $doc->ag_id = 0;
02300                 $doc->Generate($p_array);
02301                 // Move the document to the jrn
02302                 $doc->MoveDocumentPj($internal);
02303                 // Update the comment with invoice number, if the comment is empty
02304                 if (!isset($e_comm) || strlen(trim($e_comm)) == 0)
02305                 {
02306                         $sql = "update jrn set jr_comment=' document " . $doc->d_number . "' where jr_internal='$internal'";
02307                         $this->db->exec_sql($sql);
02308                 }
02309                 return h($doc->d_name . ' (' . $doc->d_filename . ')');
02310         }
02311 
02312         /* !\brief check if the payment method is valid
02313          * \param $e_mp is the value and $e_mp_qcode is the quickcode
02314          * \return nothing throw an Exception
02315          */
02316 
02317         public function check_payment($e_mp, $e_mp_qcode)
02318         {
02319                 /*   Check if the "paid by" is empty, */
02320                 if ($e_mp != 0)
02321                 {
02322                         /* the paid by is not empty then check if valid */
02323                         $empl = new Fiche($this->db);
02324                         $empl->get_by_qcode($e_mp_qcode);
02325                         if ($empl->empty_attribute(ATTR_DEF_ACCOUNT) == true)
02326                         {
02327                                 throw new Exception('Celui qui paie n\' a pas de poste comptable', 20);
02328                         }
02329                         /* get the account and explode if necessary */
02330                         $sposte = $empl->strAttribut(ATTR_DEF_ACCOUNT);
02331                         // if 2 accounts, take only the debit one for customer
02332                         if (strpos($sposte, ',') != 0)
02333                         {
02334                                 $array = explode(',', $sposte);
02335                                 $poste_val = $array[0];
02336                         }
02337                         else
02338                         {
02339                                 $poste_val = $sposte;
02340                         }
02341                         $poste = new Acc_Account_Ledger($this->db, $poste_val);
02342                         if ($poste->load() == false)
02343                         {
02344                                 throw new Exception('Pour la fiche' . $empl->quick_code . '  le poste comptable [' . $poste->id . 'n\'existe pas', 9);
02345                         }
02346                 }
02347         }
02348 
02349         /* !\brief increment the sequence for the pj */
02350 
02351         function inc_seq_pj()
02352         {
02353                 $sql = "select nextval('s_jrn_pj" . $this->id . "')";
02354                 $this->db->exec_sql($sql);
02355         }
02356 
02357         /* !@brief return a HTML string with the form for the search
02358          * @param $p_type if the type of ledger possible values=ALL,VEN,ACH,ODS,FIN
02359          * @param $all_type_ledger
02360          *       values :
02361          *         - 1 means all the ledger of this type
02362          *         - 0 No have the "Tous les journaux" availables
02363          * @param $div is the div (for reconciliation)
02364          * @return a HTML String without the tag FORM or DIV
02365          *
02366          * @see build_search_sql
02367          * @see display_search_form
02368          * @see list_operation
02369          */
02370 
02371         function search_form($p_type, $all_type_ledger = 1, $div = "")
02372         {
02373                 global $g_user;
02374                 $r = '';
02375                 /* security : filter ledger on user */
02376                 $filter_ledger = $g_user->get_ledger($p_type, 3);
02377 
02378                 $selected = (isset($_REQUEST['r_jrn' . $div])) ? $_REQUEST['r_jrn' . $div] : null;
02379                 $f_ledger = HtmlInput::select_ledger($filter_ledger, $selected, $div);
02380 
02381                 /* widget for date_start */
02382                 $f_date_start = new IDate('date_start');
02383                 /* all periode or only the selected one */
02384                 if (isset($_REQUEST['date_start']))
02385                 {
02386                         $f_date_start->value = $_REQUEST['date_start'];
02387                 }
02388                 else
02389                 {
02390                         $period = $g_user->get_periode();
02391                         $per = new Periode($this->db, $period);
02392                         $exercice = $per->get_exercice();
02393                         list($per_start, $per_end) = $per->get_limit($exercice);
02394                         $f_date_start->value = $per_start->first_day();
02395                         $date_end = $per_end->last_day();
02396                 }
02397 
02398                 /* widget for date_end */
02399                 $f_date_end = new IDate('date_end');
02400                 /* all date or only the selected one */
02401                 if (isset($_REQUEST['date_end']))
02402                 {
02403                         $f_date_end->value = $_REQUEST['date_end'];
02404                 }
02405                 else
02406                 {
02407                         $f_date_end->value = $date_end;
02408                 }
02409 
02410                 /* widget for desc */
02411                 $f_descript = new IText('desc');
02412                 $f_descript->size = 40;
02413                 if (isset($_REQUEST['desc']))
02414                 {
02415                         $f_descript->value = $_REQUEST['desc'];
02416                 }
02417 
02418                 /* widget for amount */
02419                 $f_amount_min = new INum('amount_min');
02420                 $f_amount_min->value = (isset($_REQUEST['amount_min'])) ? abs($_REQUEST['amount_min']) : 0;
02421                 $f_amount_max = new INum('amount_max');
02422                 $f_amount_max->value = (isset($_REQUEST['amount_max'])) ? abs($_REQUEST['amount_max']) : 0;
02423 
02424                 /* input quick code */
02425                 $f_qcode = new ICard('qcode' . $div);
02426 
02427                 $f_qcode->set_attribute('typecard', 'all');
02428                 /*        $f_qcode->set_attribute('p_jrn','0');
02429 
02430                   $f_qcode->set_callback('filter_card');
02431                  */
02432                 $f_qcode->set_dblclick("fill_ipopcard(this);");
02433                 // Add the callback function to filter the card on the jrn
02434                 //$f_qcode->set_callback('filter_card');
02435                 $f_qcode->set_function('fill_data');
02436                 $f_qcode->javascript = sprintf(' onchange="fill_data_onchange(%s);" ', $f_qcode->name);
02437                 $f_qcode->value = (isset($_REQUEST['qcode' . $div])) ? $_REQUEST['qcode' . $div] : '';
02438 
02439                 /*        $f_txt_qcode=new IText('qcode');
02440                   $f_txt_qcode->value=(isset($_REQUEST['qcode']))?$_REQUEST['qcode']:'';
02441                  */
02442 
02443                 /* input poste comptable */
02444                 $f_accounting = new IPoste('accounting');
02445                 $f_accounting->value = (isset($_REQUEST['accounting'])) ? $_REQUEST['accounting'] : '';
02446                 if ($this->id == -1)
02447                         $jrn = 0;
02448                 else
02449                         $jrn = $this->id;
02450                 $f_accounting->set_attribute('jrn', $jrn);
02451                 $f_accounting->set_attribute('ipopup', 'ipop_account');
02452                 $f_accounting->set_attribute('label', 'ld');
02453                 $f_accounting->set_attribute('account', 'accounting');
02454                 $info = HtmlInput::infobulle(13);
02455 
02456                 $f_paid = new ICheckbox('unpaid');
02457                 $f_paid->selected = (isset($_REQUEST['unpaid'])) ? true : false;
02458 
02459                 $r.=dossier::hidden();
02460                 $r.=HtmlInput::hidden('ledger_type', $this->type);
02461                 $r.=HtmlInput::hidden('ac', $_REQUEST['ac']);
02462                 ob_start();
02463                 require_once('template/ledger_search.php');
02464                 $r.=ob_get_contents();
02465                 ob_clean();
02466                 return $r;
02467         }
02468 
02469         /* !\brief this function will create a sql stmt to use to create the list for
02470          * the ledger,
02471          * \param $p_array is usually the $_GET,
02472          * \param $p_order the order of the row
02473          * \param $p_where is the sql condition if not null then the $p_array will not be used
02474          * \note the p_action will be used to filter the ledger but gl means ALL
02475          * struct array $p_array
02476           \verbatim
02477           (
02478           [gDossier] => 13
02479           [p_jrn] => -1
02480           [date_start] =>
02481           [date_end] =>
02482           [amount_min] => 0
02483           [amount_max] => 0
02484           [desc] =>
02485           [search] => Rechercher
02486           [p_action] => ven
02487           [sa] => l
02488           )
02489           \endverbatim
02490          * \return an array with a valid sql statement, an the where clause => array[sql] array[where]
02491          * \see list_operation
02492          * \see display_search_form
02493          * \see search_form
02494          */
02495 
02496         public function build_search_sql($p_array, $p_order = "", $p_where = "")
02497         {
02498                 $sql = "select jr_id    ,
02499              jr_montant,
02500              substr(jr_comment,1,60) as jr_comment,
02501              to_char(jr_ech,'DD.MM.YYYY') as str_jr_ech,
02502              to_char(jr_date,'DD.MM.YYYY') as str_jr_date,
02503              jr_date as jr_date_order,
02504              jr_grpt_id,
02505              jr_rapt,
02506              jr_internal,
02507              jrn_def_id,
02508              jrn_def_name,
02509              jrn_def_ech,
02510              jrn_def_type,
02511              jr_valid,
02512              jr_tech_per,
02513              jr_pj_name,
02514              p_closed,
02515              jr_pj_number,
02516              n_text,
02517              case
02518              when jrn_def_type='VEN' then
02519                  (select ad_value from fiche_detail where ad_id=1
02520                  and f_id=(select max(qs_client) from quant_sold join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02521             when jrn_def_type = 'ACH' then
02522                 (select ad_value from fiche_detail where ad_id=1
02523                 and f_id=(select max(qp_supplier) from quant_purchase join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02524             when jrn_def_type = 'FIN' then
02525                 (select ad_value from fiche_detail where ad_id=1
02526                 and f_id=(select qf_other from quant_fin where quant_fin.jr_id=x.jr_id))
02527             end as name,
02528            case
02529              when jrn_def_type='VEB' then (select ad_value from fiche_detail where ad_id=32 and f_id=(select max(qs_client) from quant_sold join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02530             when jrn_def_type = 'ACH' then (select ad_value from fiche_detail where ad_id=32 and f_id=(select max(qp_supplier) from quant_purchase join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02531             when jrn_def_type = 'FIN' then (select ad_value from fiche_detail where ad_id=32 and f_id=(select qf_other from quant_fin where quant_fin.jr_id=x.jr_id))
02532             end as first_name,
02533             case
02534              when jrn_def_type='VEN' then (select ad_value from fiche_detail where ad_id=23 and f_id=(select max(qs_client) from quant_sold join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02535             when jrn_def_type = 'ACH' then (select ad_value from fiche_detail where ad_id=23 and f_id=(select max(qp_supplier) from quant_purchase join jrnx using (j_id) join jrn as e on (e.jr_grpt_id=j_grpt) where e.jr_id=x.jr_id))
02536             when jrn_def_type = 'FIN' then (select ad_value from fiche_detail where ad_id=23 and f_id=(select qf_other from quant_fin where quant_fin.jr_id=x.jr_id))
02537             end as quick_code
02538 
02539 
02540              from
02541              jrn as X left join jrn_note using(jr_id)
02542              join jrn_def on jrn_def_id=jr_def_id
02543              join parm_periode on p_id=jr_tech_per";
02544 
02545                 if (!empty($p_array))
02546                         extract($p_array);
02547 
02548                 $r_jrn = (isset($r_jrn)) ? $r_jrn : -1;
02549 
02550                 /* if no variable are set then give them a default
02551                  * value */
02552                 if ($p_array == null || empty($p_array) || !isset($amount_min))
02553                 {
02554                         $amount_min = 0;
02555                         $amount_max = 0;
02556 
02557                         $desc = '';
02558                         $qcode = (isset($qcode)) ? $qcode : "";
02559                         if (isset($qcodesearch_op))
02560                                 $qcode = $qcodesearch_op;
02561                         $accounting = (isset($accounting)) ? $accounting : "";
02562                         $periode = new Periode($this->db);
02563                         $g_user = new User($this->db);
02564                         $p_id = $g_user->get_periode();
02565                         if ($p_id != null)
02566                         {
02567                                 list($date_start, $date_end) = $periode->get_date_limit($p_id);
02568                         }
02569                 }
02570 
02571                 /* if p_jrn : 0 if means all ledgers, if -1 means all ledger of this
02572                  *  type otherwise only one ledger */
02573                 $fil_ledger = '';
02574                 $fil_amount = '';
02575                 $fil_date = '';
02576                 $fil_desc = '';
02577                 $fil_sec = '';
02578                 $fil_qcode = '';
02579                 $fil_account = '';
02580                 $fil_paid = '';
02581 
02582                 $and = '';
02583                 $g_user = new User($this->db);
02584                 $p_action = $ledger_type;
02585                 if ($p_action == '')
02586                         $p_action = 'ALL';
02587                 if ($r_jrn == -1)
02588                 {
02589 
02590                         /* from compta.php the p_action is quick_writing instead of ODS  */
02591                         if ($p_action == 'quick_writing')
02592                                 $p_action = 'ODS';
02593 
02594 
02595                         $fil_ledger = $g_user->get_ledger_sql($p_action, 3);
02596                         $and = ' and ';
02597                 }
02598                 else
02599                 {
02600 
02601                         if ($p_action == 'quick_writing')
02602                                 $p_action = 'ODS';
02603 
02604                         $aLedger = $g_user->get_ledger($p_action, 3);
02605                         $fil_ledger = '';
02606                         $sp = '';
02607                         for ($i = 0; $i < count($aLedger); $i++)
02608                         {
02609                                 if (isset($r_jrn[$i]))
02610                                 {
02611                                         $fil_ledger.=$sp . $aLedger[$i]['jrn_def_id'];
02612                                         $sp = ',';
02613                                 }
02614                         }
02615                         $fil_ledger = ' jrn_def_id in (' . $fil_ledger . ')';
02616                         $and = ' and ';
02617 
02618                         /* no ledger selected */
02619                         if ($sp == '')
02620                         {
02621                                 $fil_ledger = '';
02622                                 $and = '';
02623                         }
02624                 }
02625 
02626                 /* format the number */
02627                 $amount_min = abs(toNumber($amount_min));
02628                 $amount_max = abs(toNumber($amount_max));
02629                 if ($amount_min > 0 && isNumber($amount_min))
02630                 {
02631                         $fil_amount = $and . ' jr_montant >=' . $amount_min;
02632                         $and = ' and ';
02633                 }
02634                 if ($amount_max > 0 && isNumber($amount_max))
02635                 {
02636                         $fil_amount.=$and . ' jr_montant <=' . $amount_max;
02637                         $and = ' and ';
02638                 }
02639                 /* -------------------------------------------------------------------------- *
02640                  * if both amount are the same then we need to search into the detail
02641                  * and we reset the fil_amount
02642                  * -------------------------------------------------------------------------- */
02643                 if (isNumber($amount_min) &&
02644                                 isNumber($amount_max) &&
02645                                 $amount_min > 0 &&
02646                                 bccomp($amount_min, $amount_max, 2) == 0)
02647                 {
02648                         $fil_amount = $and . 'jr_grpt_id in  ( select distinct j_grpt from jrnx where j_montant = ' . $amount_min . ')';
02649                         $and = " and ";
02650                 }
02651                 // date
02652                 if (isset($date_start) && isDate($date_start) != null)
02653                 {
02654                         $fil_date = $and . " jr_date >= to_date('" . $date_start . "','DD.MM.YYYY')";
02655                         $and = " and ";
02656                 }
02657                 if (isset($date_end) && isDate($date_end) != null)
02658                 {
02659                         $fil_date.=$and . " jr_date <= to_date('" . $date_end . "','DD.MM.YYYY')";
02660                         $and = " and ";
02661                 }
02662                 // comment
02663                 if (isset($desc) && $desc != null)
02664                 {
02665                         $desc = sql_string($desc);
02666                         $fil_desc = $and . " ( upper(jr_comment) like upper('%" . $desc . "%') or upper(jr_pj_number) like upper('%" . $desc . "%') " .
02667                                         " or upper(jr_internal)  like upper('%" . $desc . "%')
02668                           or jr_grpt_id in (select j_grpt from jrnx where j_text ~* '" . $desc . "'))";
02669                         $and = " and ";
02670                 }
02671                 //    Poste
02672                 if (isset($accounting) && $accounting != null)
02673                 {
02674                         $fil_account = $and . "  jr_grpt_id in (select j_grpt
02675                          from jrnx where j_poste::text like '" . sql_string($accounting) . "%' )  ";
02676                         $and = " and ";
02677                 }
02678                 // Quick Code
02679                 if (isset($qcodesearch_op))
02680                         $qcode = $qcodesearch_op;
02681                 if (isset($qcode) && $qcode != null)
02682                 {
02683                         $fil_qcode = $and . "  jr_grpt_id in ( select j_grpt from
02684                        jrnx where trim(j_qcode) = upper(trim('" . sql_string($qcode) . "')))";
02685                         $and = " and ";
02686                 }
02687 
02688                 // Only the unpaid
02689                 if (isset($unpaid))
02690                 {
02691                         $fil_paid = $and . SQL_LIST_UNPAID_INVOICE;
02692                         $and = " and ";
02693                 }
02694 
02695                 $g_user = new User(new Database());
02696                 $g_user->Check();
02697                 $g_user->check_dossier(dossier::id());
02698 
02699                 if ($g_user->admin == 0 && $g_user->is_local_admin() == 0)
02700                 {
02701                         $fil_sec = $and . " jr_def_id in ( select uj_jrn_id " .
02702                                         " from user_sec_jrn where " .
02703                                         " uj_login='" . $_SESSION['g_user'] . "'" .
02704                                         " and uj_priv in ('R','W'))";
02705                 }
02706                 $where = $fil_ledger . $fil_amount . $fil_date . $fil_desc . $fil_sec . $fil_amount . $fil_qcode . $fil_paid . $fil_account;
02707                 $sql.=" where " . $where;
02708                 return array($sql, $where);
02709         }
02710 
02711         /* !\brief return a html string with the search_form
02712          * \return a HTML string with the FORM
02713          * \see build_search_sql
02714          * \see search_form
02715          * \see list_operation
02716          */
02717 
02718         function display_search_form()
02719         {
02720                 $r = '';
02721                 $type = $this->type;
02722 
02723                 if ($type == "")
02724                         $type = 'ALL';
02725                 $r.='<div id="search_form" style="display:none">';
02726                 $r.=HtmlInput::anchor_hide('Fermer', '$(\'search_form\').style.display=\'none\';');
02727                 $r.=h2info('Recherche');
02728                 $r.='<FORM METHOD="GET">';
02729                 $r.=$this->search_form($type);
02730                 $r.=HtmlInput::submit('search', _('Rechercher'));
02731                 $r.=HtmlInput::hidden('ac', $_REQUEST['ac']);
02732 
02733                 /*  when called from commercial.php some hidden values are needed */
02734                 if (isset($_REQUEST['sa']))
02735                         $r.= HtmlInput::hidden("sa", $_REQUEST['sa']);
02736                 if (isset($_REQUEST['sb']))
02737                         $r.= HtmlInput::hidden("sb", $_REQUEST['sb']);
02738                 if (isset($_REQUEST['sc']))
02739                         $r.= HtmlInput::hidden("sc", $_REQUEST['sc']);
02740                 if (isset($_REQUEST['f_id']))
02741                         $r.=HtmlInput::hidden("f_id", $_REQUEST['f_id']);
02742                 $r.=HtmlInput::button_anchor('Fermer', 'javascript:void(0)', 'fsearch_form', 'onclick="$(\'search_form\').style.display=\'none\';"');
02743 
02744                 $r.='</FORM>';
02745 
02746                 $r.='</div>';
02747                 $button = new IButton('tfs');
02748                 $button->label = _("Filtrer");
02749                 $button->javascript = "toggleHideShow('search_form','tfs');";
02750 
02751                 $r.=$button->input();
02752                 $r.='<hr>';
02753                 return $r;
02754         }
02755 
02756         /* !\brief return the last p_limit operation into an array
02757          * \param $p_limit is the max of operation to return
02758          * \return $p_array of Follow_Up object
02759          */
02760 
02761         function get_last($p_limit)
02762         {
02763                 global $g_user;
02764                 $filter_ledger = $g_user->get_ledger_sql('ALL', 3);
02765                 $filter_ledger = str_replace('jrn_def_id', 'jr_def_id', $filter_ledger);
02766                 $sql = "
02767                         select jr_id,jr_pj_number,jr_date,to_char(jr_date,'DD.MM.YYYY') as jr_date_fmt,jr_montant, jr_comment,jr_internal,jrn_def_code
02768                         from jrn
02769                         join jrn_def on (jrn_def_id=jr_def_id)
02770                          where $filter_ledger
02771                         order by jr_date desc limit $p_limit";
02772                 $array = $this->db->get_array($sql);
02773                 return $array;
02774         }
02775 
02776         /**
02777          * @brief retreive the jr_grpt_id from a ledger
02778          * @param $p_what the column to seek
02779          *    possible values are
02780          *   - internal
02781          * @param $p_value the value of the col.
02782          */
02783         function search_group($p_what, $p_value)
02784         {
02785                 switch ($p_what)
02786                 {
02787                         case 'internal':
02788                                 return $this->db->get_value('select jr_grpt_id from jrn where jr_internal=$1', array($p_value));
02789                 }
02790         }
02791 
02792         /**
02793          * @brief retrieve operation from  jrn
02794          * @param $p_from periode (id)
02795          * @param $p_to periode (id)
02796          * @return an array
02797          */
02798         function get_operation($p_from, $p_to)
02799         {
02800                 global $g_user;
02801                 $jrn = ($this->id == 0) ? 'and ' . $g_user->get_ledger_sql() : ' and jr_def_id = ' . $this->id;
02802                 $sql = "select jr_id as id ,jr_internal as internal, " .
02803                                 "jr_pj_number as pj,jr_grpt_id," .
02804                                 " to_char(jr_date,'DDMMYY') as date_fmt, " .
02805                                 " jr_comment as comment, jr_montant as montant ," .
02806                                 " jr_grpt_id,jr_def_id" .
02807                                 " from jrn join jrn_def on (jr_def_id=jrn_def_id) where  " .
02808                                 " jr_date >= (select p_start from parm_periode where p_id = $1)
02809                                  and  jr_date <= (select p_end from parm_periode where p_id  = $2)" .
02810                                 '  ' . $jrn . ' order by jr_date,substring(jr_pj_number,\'\\\d+$\')::numeric asc';
02811                 $ret = $this->db->get_array($sql, array($p_from, $p_to));
02812                 return $ret;
02813         }
02814 
02815         /**
02816          * @brief return the used VAT code with a rate > 0
02817          * @return an array of tva_id,tva_label,tva_poste
02818          */
02819         public function existing_vat()
02820         {
02821                 if ($this->type == 'ACH')
02822                 {
02823                         $array = $this->db->get_array("select tva_id,tva_label,tva_poste from tva_rate where tva_rate != 0.0000 " .
02824                                         " and  exists (select qp_vat_code from quant_purchase
02825                                         where  qp_vat_code=tva_id and  exists (select j_id from jrnx where j_jrn_def = $1)) order by tva_id", array($this->id));
02826                 }
02827                 if ($this->type == 'VEN')
02828                 {
02829                         $array = $this->db->get_array("select tva_id,tva_label,tva_poste from tva_rate where tva_rate != 0.0000 " .
02830                                         " and  exists (select qs_vat_code from quant_sold
02831                                         where  qs_vat_code=tva_id and  exists (select j_id from jrnx where j_jrn_def = $1)) order by tva_id", array($this->id));
02832                 }
02833                 return $array;
02834         }
02835 
02836         /**
02837          * @brief get the amount of vat for a given jr_grpt_id from the table
02838          * quant_purchase
02839          * @param the jr_grpt_id
02840          * @return array price=htva, [1] =  vat,
02841          * @note
02842          * @see
02843           @code
02844           array
02845           'price' => string '91.3500' (length=7)
02846           'vat' => string '0.0000' (length=6)
02847           'priv' => string '0.0000' (length=6)
02848           'tva_nd_recup' => string '0.0000' (length=6)
02849 
02850           @endcode
02851          */
02852         function get_other_amount($p_jr_id)
02853         {
02854                 if ($this->type == 'ACH')
02855                 {
02856                         $array = $this->db->get_array('select sum(qp_price) as price,sum(qp_vat) as vat ' .
02857                                         ',sum(qp_dep_priv) as priv' .
02858                                         ',sum(qp_nd_tva_recup)+sum(qp_nd_tva) as tva_nd' .
02859                                         '  from quant_purchase join jrnx using(j_id)
02860                                         where  j_grpt=$1 ', array($p_jr_id));
02861                         $ret = $array[0];
02862                 }
02863                 if ($this->type == 'VEN')
02864                 {
02865                         $array = $this->db->get_array('select sum(qs_price) as price,sum(qs_vat) as vat ' .
02866                                         ',0 as priv' .
02867                                         ',0 as tva_nd' .
02868                                         '  from quant_sold join jrnx using(j_id)
02869                                         where  j_grpt=$1 ', array($p_jr_id));
02870                         $ret = $array[0];
02871                 }
02872                 return $ret;
02873         }
02874 
02875         /**
02876          * @brief get the amount of vat for a given jr_grpt_id from the table
02877          * quant_purchase
02878          * @param the jr_grpt_id
02879          * @return array of sum_vat, tva_label
02880          * @note
02881          * @see
02882           @code
02883 
02884           @endcode
02885          */
02886         function vat_operation($p_jr_id)
02887         {
02888                 if ($this->type == 'ACH')
02889                 {
02890                         $array = $this->db->get_array('select coalesce(sum(qp_vat),0) as sum_vat,tva_id
02891                                         from quant_purchase as p right join tva_rate on (qp_vat_code=tva_id)  join jrnx using(j_id)
02892                                         where tva_rate !=0.0 and j_grpt=$1 group by tva_id', array($p_jr_id));
02893                 }
02894                 if ($this->type == 'VEN')
02895                 {
02896                         $array = $this->db->get_array('select coalesce(sum(qs_vat),0) as sum_vat,tva_id
02897                                         from quant_sold as p right join tva_rate on (qs_vat_code=tva_id)  join jrnx using(j_id)
02898                                         where tva_rate !=0.0 and j_grpt=$1 group by tva_id', array($p_jr_id));
02899                 }
02900                 return $array;
02901         }
02902 
02903         /**
02904          * @brief retrieve amount of previous periode
02905          * @param $p_to frmo the start of the exercise until $p_to
02906          * @return $array with vat, price,other_amount
02907          * @note
02908          * @see
02909           @code
02910           array
02911           'price' => string '446.1900' (length=8)
02912           'vat' => string '21.7600' (length=7)
02913           'priv' => string '0.0000' (length=6)
02914           'tva_nd_recup' => string '0.0000' (length=6)
02915           'tva' =>
02916           array
02917           0 =>
02918           array
02919           'sum_vat' => string '13.7200' (length=7)
02920           'tva_id' => string '1' (length=1)
02921           1 =>
02922           array
02923           'sum_vat' => string '8.0400' (length=6)
02924           'tva_id' => string '3' (length=1)
02925           2 =>
02926           array
02927           'sum_vat' => string '0.0000' (length=6)
02928           'tva_id' => string '4' (length=1)
02929 
02930           @endcode
02931          */
02932         function previous_amount($p_to)
02933         {
02934                 /* get the first periode of exercise */
02935                 $periode = new Periode($this->db, $p_to);
02936                 $exercise = $periode->get_exercice();
02937                 list ($min, $max) = $periode->get_limit($exercise);
02938                 // min periode
02939                 if ($this->type == 'ACH')
02940                 {
02941                         /*  get all amount exclude vat */
02942                         $sql = "select coalesce(sum(qp_price),0) as price" .
02943                                         " ,coalesce(sum(qp_vat),0) as vat " .
02944                                         ',coalesce(sum(qp_dep_priv),0) as priv' .
02945                                         ',coalesce(sum(qp_nd_tva_recup),0)+coalesce(sum(qp_nd_tva),0) as tva_nd' .
02946                                         '  from quant_purchase join jrnx using(j_id) ' .
02947                                         ' where j_tech_per >= $1 and j_tech_per < $2';
02948                         $array = $this->db->get_array($sql, array($min->p_id, $p_to));
02949 
02950                         $ret = $array[0];
02951                         /* retrieve all vat code */
02952                         $array = $this->db->get_array('select coalesce(sum(qp_vat),0) as sum_vat,tva_id
02953                                         from quant_purchase as p right join tva_rate on (qp_vat_code=tva_id)  join jrnx using(j_id)
02954                                         where tva_rate !=0 and j_tech_per >= $1 and j_tech_per < $2 group by tva_id', array($min->p_id, $p_to));
02955                         $ret['tva'] = $array;
02956                 }
02957                 if ($this->type == 'VEN')
02958                 {
02959                         /*  get all amount exclude vat */
02960                         $sql = "select coalesce(sum(qs_price),0) as price" .
02961                                         " ,coalesce(sum(qs_vat),0) as vat " .
02962                                         ',0 as priv' .
02963                                         ',0 as tva_nd' .
02964                                         '  from quant_sold join jrnx using(j_id) ' .
02965                                         ' where j_tech_per >= $1 and j_tech_per < $2';
02966                         $array = $this->db->get_array($sql, array($min->p_id, $p_to));
02967                         $ret = $array[0];
02968                         /* retrieve all vat code */
02969                         $array = $this->db->get_array('select coalesce(sum(qs_vat),0) as sum_vat,tva_id
02970                                         from quant_sold as p right join tva_rate on (qs_vat_code=tva_id)  join jrnx using(j_id)
02971                                         where tva_rate !=0 and j_tech_per >= $1 and j_tech_per < $2 group by tva_id', array($min->p_id, $p_to));
02972                         $ret['tva'] = $array;
02973                 }
02974                 return $ret;
02975         }
02976 
02977         ////////////////////////////////////////////////////////////////////////////////
02978         // TEST MODULE
02979         ////////////////////////////////////////////////////////////////////////////////
02980         /* !
02981          * \brief this function is intended to test this class
02982          */
02983         static function test_me($pCase = '')
02984         {
02985                 if ($pCase == '')
02986                 {
02987                         echo Acc_Reconciliation::$javascript;
02988                         html_page_start();
02989                         $cn = new Database(dossier::id());
02990                         $_SESSION['g_user'] = 'phpcompta';
02991                         $_SESSION['g_pass'] = 'phpcompta';
02992 
02993                         $id = (isset($_REQUEST['p_jrn'])) ? $_REQUEST['p_jrn'] : -1;
02994                         $a = new Acc_Ledger($cn, $id);
02995                         $a->with_concerned = true;
02996                         // Vide
02997                         echo '<FORM method="post">';
02998                         echo $a->select_ledger()->input();
02999                         echo HtmlInput::submit('go', 'Test it');
03000                         echo '</form>';
03001                         if (isset($_POST['go']))
03002                         {
03003                                 echo "Ok ";
03004                                 echo '<form method="post">';
03005                                 echo $a->show_form();
03006                                 echo HtmlInput::submit('post_id', 'Try me');
03007                                 echo '</form>';
03008                                 // Show the predef operation
03009                                 // Don't forget the p_jrn
03010                                 echo '<form>';
03011                                 echo dossier::hidden();
03012                                 echo '<input type="hidden" value="' . $id . '" name="p_jrn">';
03013                                 $op = new Pre_operation($cn);
03014                                 $op->p_jrn = $id;
03015                                 $op->od_direct = 't';
03016                                 if ($op->count() != 0)
03017                                 {
03018                                         echo HtmlInput::submit('use_opd', 'Utilisez une opération pr&eacute;d&eacute;finie');
03019                                         echo $op->show_button();
03020                                 }
03021                                 echo '</form>';
03022                                 exit();
03023                         }
03024 
03025                         if (isset($_POST['post_id']))
03026                         {
03027 
03028                                 echo '<form method="post">';
03029                                 echo $a->show_form($_POST, 1);
03030                                 echo HtmlInput::button('add', 'Ajout d\'une ligne', 'onClick="quick_writing_add_row()"');
03031                                 echo HtmlInput::submit('save_it', "Sauver");
03032                                 echo '</form>';
03033                                 exit();
03034                         }
03035                         if (isset($_POST['save_it']))
03036                         {
03037                                 print 'saving';
03038                                 $array = $_POST;
03039                                 $array['save_opd'] = 1;
03040                                 try
03041                                 {
03042                                         $a->save($array);
03043                                 }
03044                                 catch (Exception $e)
03045                                 {
03046                                         alert($e->getMessage());
03047                                         echo '<form method="post">';
03048 
03049                                         echo $a->show_form($_POST);
03050                                         echo HtmlInput::submit('post_id', 'Try me');
03051                                         echo '</form>';
03052                                 }
03053                                 exit();
03054                         }
03055                         // The GET at the end because automatically repost when you don't
03056                         // specify the url in the METHOD field
03057                         if (isset($_GET['use_opd']))
03058                         {
03059                                 $op = new Pre_op_advanced($cn);
03060                                 $op->set_od_id($_REQUEST['pre_def']);
03061                                 //$op->p_jrn=$id;
03062 
03063                                 $p_post = $op->compute_array();
03064 
03065                                 echo '<FORM method="post">';
03066 
03067                                 echo $a->show_form($p_post);
03068                                 echo HtmlInput::submit('post_id', 'Use predefined operation');
03069                                 echo '</form>';
03070                                 exit();
03071                         }
03072                 }// if case = ''
03073                 ///////////////////////////////////////////////////////////////////////////
03074                 // search
03075                 if ($pCase == 'search')
03076                 {
03077                         html_page_start();
03078                         $cn = new Database(dossier::id());
03079                         $ledger = new Acc_Ledger($cn, 0);
03080                         $_SESSION['g_user'] = 'phpcompta';
03081                         $_SESSION['g_pass'] = 'phpcompta';
03082                         echo $ledger->search_form('ALL');
03083                 }
03084                 ///////////////////////////////////////////////////////////////////////////
03085                 // reverse
03086                 // Give yourself the var and check in your tables
03087                 ///////////////////////////////////////////////////////////////////////////
03088                 if ($pCase == 'reverse')
03089                 {
03090                         $cn = new Database(dossier::id());
03091                         $jr_internal = 'OD-01-272';
03092                         try
03093                         {
03094                                 $cn->start();
03095                                 $jrn_def_id = $cn->get_value('select jr_def_id from jrn where jr_internal=$1', array($jr_internal));
03096                                 $ledger = new Acc_Ledger($cn, $jrn_def_id);
03097                                 $ledger->jr_id = $cn->get_value('select jr_id from jrn where jr_internal=$1', array($jr_internal));
03098 
03099                                 echo "Ouvrez le fichier " . __FILE__ . " à la ligne " . __LINE__ . " pour changer jr_internal et vérifier le résultat de l'extourne";
03100 
03101                                 $ledger->reverse('01.07.2010');
03102                         }
03103                         catch (Exception $e)
03104                         {
03105                                 $cn->rollback();
03106                                 var_dump($e);
03107                         }
03108                         $cn->commit();
03109                 }
03110         }
03111 
03112         /**
03113          * create an array of the existing cat, to be used in a checkbox form
03114          *
03115          */
03116         static function array_cat()
03117         {
03118                 $r = array(
03119                         array('cat' => 'VEN', 'name' => 'Journaux de vente'),
03120                         array('cat' => 'ACH', 'name' => 'Journaux d\'achat'),
03121                         array('cat' => 'FIN', 'name' => 'Journaux Financier'),
03122                         array('cat' => 'ODS', 'name' => 'Journaux d\'Opérations diverses')
03123                 );
03124                 return $r;
03125         }
03126 
03127         /**
03128          * Retrieve the third : supplier for purchase, customer for sale, bank for fin,
03129          * @param $p_jrn_type type of the ledger FIN, VEN ACH or ODS
03130          */
03131         function get_tiers($p_jrn_type, $jr_id)
03132         {
03133                 if ($p_jrn_type == 'ODS')
03134                         return ' ';
03135                 $tiers = '';
03136                 switch ($p_jrn_type)
03137                 {
03138                         case 'VEN':
03139                                 $tiers = $this->db->get_value('select max(qs_client) from quant_sold join jrnx using (j_id) join jrn on (jr_grpt_id=j_grpt) where jrn.jr_id=$1', array($jr_id));
03140                                 break;
03141                         case 'ACH':
03142                                 $tiers = $this->db->get_value('select max(qp_supplier) from quant_purchase join jrnx using (j_id) join jrn on (jr_grpt_id=j_grpt) where jrn.jr_id=$1', array($jr_id));
03143 
03144                                 break;
03145                         case 'FIN':
03146                                 $tiers = $this->db->get_value('select qf_other from quant_fin where jr_id=$1', array($jr_id));
03147                                 break;
03148                 }
03149                 if ($this->db->count() == 0)
03150                         return '';
03151                 $name = $this->db->get_value('select ad_value from fiche_detail where ad_id=1 and f_id=$1', array($tiers));
03152                 $first_name = $this->db->get_value('select ad_value from fiche_detail where ad_id=32 and f_id=$1', array($tiers));
03153                 return $name . ' ' . $first_name;
03154         }
03155 
03156         /**
03157          * @brief listing of all ledgers
03158          * @return HTML string
03159          */
03160         function listing()
03161         {
03162                 $str_dossier = dossier::get();
03163                 $base_url = "?" . dossier::get() . "&ac=" . $_REQUEST['ac'];
03164 
03165                 $r = "";
03166                 $r.='<TABLE>';
03167                 $r.='<TR><TD class="mtitle"><A class="mtitle" HREF="' . $base_url . '&sa=add">' . _('Création') . ' </A></TD></TR>';
03168                 $ret = $this->db->exec_sql("select jrn_def_id,jrn_def_name,
03169                        jrn_def_class_deb,jrn_def_class_cred,jrn_type_id,jrn_desc
03170                        from jrn_def join jrn_type on jrn_def_type=jrn_type_id order by jrn_def_name");
03171                 $Max = Database::num_row($ret);
03172 
03173 
03174                 for ($i = 0; $i < $Max; $i++)
03175                 {
03176                         $l_line = Database::fetch_array($ret, $i);
03177                         $url = $base_url . "&sa=detail&p_jrn=" . $l_line['jrn_def_id'];
03178                         $r.=sprintf('<TR><TD class="mtitle"><A class="mtitle" HREF="%s">%s</A></TD></TR>', $url, h($l_line['jrn_def_name']));
03179                 }
03180                 $r.= "</TABLE>";
03181                 return $r;
03182         }
03183 
03184         /**
03185          * display detail of a ledger
03186          *
03187          */
03188         function display_ledger()
03189         {
03190                 if ($this->load() == -1)
03191                 {
03192                         throw new Exception(_("Journal n'existe pas"), -1);
03193                 }
03194                 $type = $this->jrn_def_type;
03195                 $name = $this->jrn_def_name;
03196                 $code = $this->jrn_def_code;
03197 
03198                 /* widget for searching an account */
03199                 $wSearch = new IPoste();
03200                 $wSearch->set_attribute('ipopup', 'ipop_account');
03201                 $wSearch->set_attribute('account', 'p_jrn_class_deb');
03202                 $wSearch->set_attribute('no_overwrite', '1');
03203                 $wSearch->set_attribute('noquery', '1');
03204                 $wSearch->table = 3;
03205                 $wSearch->name = "p_jrn_class_deb";
03206                 $wSearch->size = 20;
03207                 $wSearch->value = $this->jrn_def_class_deb;
03208                 $search = $wSearch->input();
03209 
03210                 $wPjPref = new IText();
03211                 $wPjPref->name = 'jrn_def_pj_pref';
03212                 $wPjPref->value = $this->jrn_def_pj_pref;
03213                 $pj_pref = $wPjPref->input();
03214 
03215                 $wPjSeq = new INum();
03216                 $wPjSeq->value = 0;
03217                 $wPjSeq->name = 'jrn_def_pj_seq';
03218                 $pj_seq = $wPjSeq->input();
03219                 $last_seq = $this->get_last_pj();
03220                 $name = $this->jrn_def_name;
03221 
03222                 $hidden = HtmlInput::hidden('p_jrn', $this->id);
03223                 $hidden.= HtmlInput::hidden('sa', 'detail');
03224                 $hidden.= dossier::hidden();
03225                 $hidden.=HtmlInput::hidden('p_jrn_deb_max_line', 10);
03226                 $hidden.=HtmlInput::hidden('p_ech_lib', 'echeance');
03227                 $hidden.=HtmlInput::hidden('p_jrn_type', $type);
03228 
03229                 /* Load the card */
03230                 $card = $this->get_fiche_def();
03231                 $rdeb = explode(',', $card['deb']);
03232                 $rcred = explode(',', $card['cred']);
03233                 /* Numbering (only FIN) */
03234                 $num_op = new ICheckBox('numb_operation');
03235                 if ($this->jrn_def_num_op == 1)
03236                         $num_op->selected = true;
03237                 /* bank card */
03238                 $qcode_bank = '';
03239                 if ($type == 'FIN')
03240                 {
03241                         $f_id = $this->jrn_def_bank;
03242                         if (isNumber($f_id) == 1)
03243                         {
03244                                 $fBank = new Fiche($this->db, $f_id);
03245                                 $qcode_bank = $fBank->get_quick_code();
03246                         }
03247                 }
03248                 $new = false;
03249                 $cn = $this->db;
03250                 echo $hidden;
03251                 require_once('template/param_jrn.php');
03252         }
03253 
03254         /**
03255          * Verify before update
03256          *
03257          * @param type $array
03258          *   'p_jrn' => string '3' (length=1)
03259           'sa' => string 'detail' (length=6)
03260           'gDossier' => string '82' (length=2)
03261           'p_jrn_deb_max_line' => string '10' (length=2)
03262           'p_ech_lib' => string 'echeance' (length=8)
03263           'p_jrn_type' => string 'ACH' (length=3)
03264           'p_jrn_name' => string 'Achat' (length=5)
03265           'jrn_def_pj_pref' => string 'ACH' (length=3)
03266           'jrn_def_pj_seq' => string '0' (length=1)
03267           'FICHECRED' =>
03268           array
03269           0 => string '4' (length=1)
03270           'FICHEDEB' =>
03271           array
03272           0 => string '7' (length=1)
03273           1 => string '5' (length=1)
03274           2 => string '13' (length=2)
03275           'update' => string 'Sauve' (length=5
03276          * @exception is throw is test are not valid
03277          */
03278         function verify_ledger($array)
03279         {
03280                 extract($array);
03281                 try
03282                 {
03283                         if (isNumber($p_jrn) == 0)
03284                                 throw new Exception("Id invalide");
03285                         if (isNumber($p_jrn_deb_max_line) == 0)
03286                                 throw new Exception("Nombre de ligne incorrect");
03287                         if (trim($p_jrn_name) == "")
03288                                 throw new Exception("Nom de journal invalide");
03289                         if ($this->db->get_value("select count(*) from jrn_def where jrn_def_name=$1 and jrn_Def_id<>$2", array($p_jrn_name, $p_jrn)) > 0)
03290                                 throw new Exception("Un journal avec ce nom existe déjà");
03291                         if ($p_jrn_type == 'FIN')
03292                         {
03293                                 $a = new Fiche($this->db);
03294                                 $result = $a->get_by_qcode(trim(strtoupper($_POST['bank'])), false);
03295                                 if ($result == 1)
03296                                         throw new Exception("Aucun compte en banque n'est donné");
03297                         }
03298                 }
03299                 catch (Exception $e)
03300                 {
03301                         throw $e;
03302                 }
03303         }
03304 
03305         /**
03306          * update a ledger
03307          * @param type $array  normally post
03308          * @see verify_ledger
03309          */
03310         function update($array = '')
03311         {
03312                 if ($array == null)
03313                         throw new Exception('save cannot use a empty array');
03314 
03315                 extract($array);
03316                 $this->jrn_def_id = $p_jrn;
03317                 $this->jrn_def_name = $p_jrn_name;
03318                 $this->jrn_def_ech_lib = $p_ech_lib;
03319                 $this->jrn_def_max_line_deb = $p_jrn_deb_max_line;
03320                 $this->jrn_def_type = $p_jrn_type;
03321                 $this->jrn_def_pj_pref = $jrn_def_pj_pref;
03322                 $this->jrn_def_fiche_deb = (isset($FICHEDEB)) ? join($FICHEDEB, ',') : "";
03323                 switch ($this->jrn_def_type)
03324                 {
03325                         case 'ACH':
03326                         case 'VEN':
03327                                 $this->jrn_def_fiche_cred = (isset($FICHECRED)) ? join($FICHECRED, ',') : '';
03328                                 break;
03329                         case 'ODS':
03330                                 $this->jrn_def_class_deb = $p_jrn_class_deb;
03331                                 break;
03332                         case 'FIN':
03333                                 $a = new Fiche($this->db);
03334                                 $result = $a->get_by_qcode(trim(strtoupper($_POST['bank'])), false);
03335                                 $bank = $a->id;
03336                                 $this->jrn_def_bank = $bank;
03337                                 if ($result == -1)
03338                                         throw new Exception("Aucun compte en banque n'est donné");
03339                                 $this->jrn_def_num_op = (isset($numb_operation)) ? 1 : 0;
03340                                 break;
03341                 }
03342 
03343                 parent::update();
03344                 //Reset sequence if needed
03345                 if ($jrn_def_pj_seq != 0)
03346                 {
03347                         $Res = $this->db->alter_seq("s_jrn_pj" . $p_jrn, $jrn_def_pj_seq);
03348                 }
03349         }
03350 
03351         function input_paid($nofieldset = 0)
03352         {
03353                 $r = '';
03354                 if ($nofieldset == 0)
03355                 {
03356                         $r.='<fieldset id="payment"> ';
03357                 }
03358                 $r.='<legend> ' . _('Payé par') . ' </legend>';
03359                 $mp = new Acc_Payment($this->db);
03360                 $mp->set_parameter('ledger_source', $this->id);
03361                 $r.=$mp->select();
03362                 if ($nofieldset == 0)
03363                         $r.='</fieldset>';
03364                 return $r;
03365         }
03366 
03367         /**
03368          * display screen to enter a new ledger
03369          */
03370         function input_new()
03371         {
03372                 $wSearch = new IPoste();
03373                 $wSearch->table = 3;
03374                 $wSearch->set_attribute('ipopup', 'ipop_account');
03375                 $wSearch->set_attribute('account', 'p_jrn_class_deb');
03376                 $wSearch->set_attribute('no_overwrite', '1');
03377                 $wSearch->set_attribute('noquery', '1');
03378 
03379                 $wSearch->name = "p_jrn_class_deb";
03380                 $wSearch->size = 20;
03381 
03382                 $search = $wSearch->input();
03383 
03384                 /* construct all the hidden */
03385                 $hidden = HtmlInput::hidden('p_jrn', -1);
03386                 $hidden.= HtmlInput::hidden('p_action', 'jrn');
03387                 $hidden.= HtmlInput::hidden('sa', 'add');
03388                 $hidden.= dossier::hidden();
03389                 $hidden.=HtmlInput::hidden('p_jrn_deb_max_line', 10);
03390                 $hidden.=HtmlInput::hidden('p_ech_lib', 'echeance');
03391 
03392                 /* properties of the ledger */
03393                 $name = "";
03394                 $code = "";
03395                 $wType = new ISelect();
03396                 $wType->value = $this->db->make_array('select jrn_type_id,jrn_desc from jrn_type');
03397                 $wType->name = "p_jrn_type";
03398                 $type = $wType->input();
03399                 $rcred = $rdeb = array();
03400                 $wPjPref = new IText();
03401                 $wPjPref->name = 'jrn_def_pj_pref';
03402                 $pj_pref = $wPjPref->input();
03403                 $pj_seq = '';
03404                 $last_seq = 0;
03405                 $new = true;
03406                 /* bank card */
03407                 $qcode_bank = '';
03408                 /* Numbering (only FIN) */
03409                 $num_op = new ICheckBox('numb_operation');
03410                 echo dossier::hidden();
03411                 echo HtmlInput::hidden('ac', $_REQUEST['ac']);
03412                 echo HtmlInput::hidden('p_jrn', -1);
03413                 echo HtmlInput::hidden('sa', 'add');
03414 
03415                 $cn = $this->db;
03416 
03417                 require_once('template/param_jrn.php');
03418         }
03419 
03420         /**
03421          * Insert a new ledger
03422          * @param type $array normally $_POST
03423          * @see verify_ledger
03424          */
03425         function save_new($array)
03426         {
03427                 $this->load();
03428                 extract($array);
03429                 $this->jrn_def_id = -1;
03430                 $this->jrn_def_name = $p_jrn_name;
03431                 $this->jrn_def_ech_lib = $p_ech_lib;
03432                 $this->jrn_def_max_line_deb = $p_jrn_deb_max_line;
03433                 $this->jrn_def_type = $p_jrn_type;
03434                 $this->jrn_def_pj_pref = $jrn_def_pj_pref;
03435                 $this->jrn_def_fiche_deb = (isset($FICHEDEB)) ? join($FICHEDEB, ',') : "";
03436                 $this->jrn_def_code = sprintf("%s%02d", trim(substr($this->jrn_def_type, 0, 1)), Acc_Ledger::next_number($this->db, $this->jrn_def_type));
03437 
03438                 switch ($this->jrn_def_type)
03439                 {
03440                         case 'ACH':
03441                         case 'VEN':
03442                                 $this->jrn_def_fiche_cred = (isset($FICHECRED)) ? join($FICHECRED, ',') : '';
03443 
03444                                 break;
03445                         case 'ODS':
03446                                 $this->jrn_def_class_deb = $p_jrn_class_deb;
03447                                 break;
03448                         case 'FIN':
03449                                 $a = new Fiche($this->db);
03450                                 $result = $a->get_by_qcode(trim(strtoupper($_POST['bank'])), false);
03451                                 $bank = $a->id;
03452                                 $this->jrn_def_bank = $bank;
03453                                 if ($result == -1)
03454                                         throw new Exception("Aucun compte en banque n'est donné");
03455                                 $this->jrn_def_num_op = (isset($numb_operation)) ? 1 : 0;
03456                                 break;
03457                 }
03458 
03459                 parent::insert();
03460         }
03461 
03462         /**
03463          * delete a ledger IF is not already used
03464          * @exeption : cannot delete
03465          */
03466         function delete_ledger()
03467         {
03468                 try
03469                 {
03470                         if ($this->db->get_value("select count(jr_id) from jrn where jr_def_id=$1", array($this->jrn_def_id)) > 0)
03471                                 throw new Exception("Impossible d'effacer un journal qui contient des opérations");
03472                         parent::delete();
03473                 }
03474                 catch (Exception $e)
03475                 {
03476                         throw $e;
03477                 }
03478         }
03479 
03480 }