/** * @file * @brief class for Ledger's history, list of operation for MISC, FIN, ACH and VEN * */ /** * @brief manage the list of operation when we need several ledger with a different * type or from Misceleaneous ledger * @include acc_ledger_historyTest.php */ class Acc_Ledger_History_Generic extends Acc_Ledger_History { private $data; //!< array of rows /** * Constructor * @param Database $cn * @param type $pa_ledger * @param type $p_from * @param type $p_to * @param type $p_mode * @example acc_ledger_historyTest.php */ function __construct(Database $cn, $pa_ledger, $p_from, $p_to, $p_mode) { parent::__construct($cn, $pa_ledger, $p_from, $p_to, $p_mode); $this->data=[]; } /** * @brief get_detail gives the detail of row * this array must contains at least the field * * the following field will be added * * * @paramp_array the structure is set in get_rowSimple, this array is * modified, @verbatim jrn.jr_id as jr_id , jrn.jr_id as num , jrn.jr_def_id as jr_def_id, jrn.jr_montant as montant, substr(jrn.jr_comment,1,35) as comment, to_char(jrn.jr_date,'DD-MM-YYYY') as date, to_char(jrn.jr_date_paid,'DD-MM-YYYY') as date_paid, jr_pj_number, jr_internal, jrn.jr_grpt_id as grpt_id, jrn.jr_pj_name as pj, jrn_def_type, jrn.jr_tech_per @endverbatim * * @param $trunc if the data must be truncated, usefull for pdf export * @paramp_jrn_type is the type of the ledger (ACH or VEN) * @param $a_TVA TVA Array (default null) * @param $a_ParmCode Array (default null) * * @todo useless since only 2 modes are supported : oneline and extended (accounting writing) but * can be used for ledger before 2007 * \return p_array */ function get_detail(&$p_array, $p_jrn_type, $trunc=0, $a_TVA=null, $a_ParmCode=null) { bcscale(2); if ($a_TVA==null) { //Load TVA array $a_TVA=$this->db->get_array('select tva_id,tva_label,tva_poste from tva_rate where tva_rate != 0 order by tva_rate,tva_label,tva_id'); } if ($a_ParmCode==null) { //Load Parm_code $a_ParmCode=$this->db->get_array('select p_code,p_value from parm_code'); } // init $p_array['client']=""; $p_array['TVAC']=0; $p_array['HTVA']=0; $p_array['TVA']=array(); $p_array['AMOUNT_TVA']=0.0; $p_array['dep_priv']=0; $p_array['dna']=0; $p_array['tva_dna']=0; $p_array['tva_np']=0; $dep_priv=0.0; // if using the QUANT_* tables then get there the needed info // if ($this->use_quant_table($p_array['grpt_id'], $p_array['jrn_def_type']) ==TRUE) { // Initialize amount for VAT $nb_tva=count($a_TVA); for ($i=0; $i<$nb_tva; $i++) { $p_array['TVA'][$i]=array($i, array( $a_TVA[$i]['tva_id'], $a_TVA[$i]['tva_label'], 0) ); } switch ($p_array['jrn_def_type']) { case "ACH": $sql="select sum(coalesce(qp_price,0)) as htva, sum(coalesce(qp_vat)) as vat, sum(coalesce(qp_nd_tva)) as nd_tva, sum(coalesce(qp_nd_tva_recup)) as nd_tva_recup, sum(coalesce(qp_dep_priv)) as dep_priv, qp_vat_code as tva_code, qp_supplier as fiche_id, qp_vat_sided as tva_sided from quant_purchase where qp_internal=$1 group by qp_supplier,qp_vat_code,qp_vat_sided "; break; case "VEN": $sql="select sum(coalesce(qs_price,0)) as htva, sum(coalesce(qs_vat)) as vat, sum(0) as nd_tva, sum(0) as nd_tva_recup, sum(0) as dep_priv, qs_vat_code as tva_code, qs_client as fiche_id, qs_vat_sided as tva_sided from quant_sold where qs_internal=$1 group by qs_client,qs_vat_code,qs_vat_sided "; break; default: break; } $a_detail=$this->db->get_array($sql, array($p_array['jr_internal'])); $nb_detail=count($a_detail); for ($x=0; $x<$nb_detail; $x++) { $p_array['HTVA']=bcadd($p_array['HTVA'], $a_detail[$x]['htva']); $p_array['tva_dna']=bcadd($p_array['tva_dna'], $a_detail[$x]['nd_tva_recup']); $p_array['tva_dna']=bcadd($p_array['tva_dna'], $a_detail[$x]['nd_tva']); $p_array['TVAC']=bcadd($p_array['TVAC'], $a_detail[$x]['htva']); if ($a_detail[$x]['tva_sided']==0) $p_array['TVAC']=bcadd($p_array['TVAC'], $a_detail[$x]['vat']); $p_array['TVAC']=bcadd($p_array['TVAC'], $a_detail[$x]['nd_tva']); $p_array['TVAC']=bcadd($p_array['TVAC'], $a_detail[$x]['nd_tva_recup']); $p_array['dep_priv']=bcadd($p_array['dep_priv'], $a_detail[$x]['dep_priv']); $xdx=$a_detail[$x]['tva_code']; // $p_array['TVA'][$xdx]=bcadd($p_array['TVA'][$xdx],$a_detail[$x]['vat']); //--- Put VAT in the right place in the array $a_TVA $nb_tva=count($a_TVA); for ($j=0; $j<$nb_tva; $j++) { if ($xdx==$p_array['TVA'][$j][1][0]) { $p_array['TVA'][$j][1][2]=bcadd($p_array['TVA'][$j][1][2], $a_detail[$x]['vat']); } } } $fiche=new Fiche($this->db, $a_detail[0]['fiche_id']); $p_array['client']=($trunc==0)?$fiche->getName():mb_substr($fiche->getName(), 0, 20); return $p_array; } // // Retrieve data from jrnx // Order is important for TVA autoreversed $sql="select j_id,j_poste,j_montant, j_debit,j_qcode from jrnx where ". " j_grpt=$1 order by 1 desc"; $Res2=$this->db->exec_sql($sql, array($p_array['grpt_id'])); $data_jrnx=Database::fetch_all($Res2); $c=0; // Parse data from jrnx and fill diff. field foreach ($data_jrnx as $code) { $idx_tva=0; $poste=new Acc_Account_Ledger($this->db, $code['j_poste']); // if card retrieve name if the account is not a VAT account if (strlen(trim($code['j_qcode']))!=0&&$poste->isTva()==0) { $fiche=new Fiche($this->db); $fiche->get_by_qcode(trim($code['j_qcode']), false); $fiche_def_id=$fiche->get_fiche_def_ref_id(); // Customer or supplier if ($fiche_def_id==FICHE_TYPE_CLIENT|| $fiche_def_id==FICHE_TYPE_FOURNISSEUR||$fiche_def_id==FICHE_TYPE_ADM_TAX) { $p_array['TVAC']=$code['j_montant']; $p_array['client']=($trunc==0)?$fiche->getName():mb_substr($fiche->getName(), 0, 20); $p_array['reversed']=false; if ($fiche_def_id==FICHE_TYPE_CLIENT&&$code['j_debit']=='f') { $p_array['reversed']=true; $p_array['TVAC']*=-1; } if ($fiche_def_id==FICHE_TYPE_ADM_TAX&&$code['j_debit']=='f') { $p_array['reversed']=true; $p_array['TVAC']*=-1; } if ($fiche_def_id==FICHE_TYPE_FOURNISSEUR&&$code['j_debit']=='t') { $p_array['reversed']=true; $p_array['TVAC']*=-1; } } else { // if we use the ledger ven / ach for others card than supplier and customer if ($fiche_def_id!=FICHE_TYPE_VENTE&& $fiche_def_id!=FICHE_TYPE_ACH_MAR&& $fiche_def_id!=FICHE_TYPE_ACH_SER&& $fiche_def_id!=FICHE_TYPE_ACH_MAT ) { $p_array['TVAC']=$code['j_montant']; $p_array['client']=($trunc==0)?$fiche->getName():mb_substr($fiche->getName(), 0, 20); $p_array['reversed']=false; if ($p_jrn_type=='ACH'&&$code['j_debit']=='t') { $p_array['reversed']=true; $p_array['TVAC']*=-1; } if ($p_jrn_type=='VEN'&&$code['j_debit']=='f') { $p_array['reversed']=true; $p_array['TVAC']*=-1; } } } } // if TVA, load amount, tva id and rate in array foreach ($a_TVA as $line_tva) { list($tva_deb, $tva_cred)=explode(',', $line_tva['tva_poste']); if ($code['j_poste']==$tva_deb|| $code['j_poste']==$tva_cred) { // For the reversed operation if ($p_jrn_type=='ACH'&&$code['j_debit']=='f') { $code['j_montant']=-1*$code['j_montant']; } if ($p_jrn_type=='VEN'&&$code['j_debit']=='t') { $code['j_montant']=-1*$code['j_montant']; } $p_array['AMOUNT_TVA']+=$code['j_montant']; $p_array['TVA'][$c]=array($idx_tva, array($line_tva['tva_id'], $line_tva['tva_label'], $code['j_montant'])); $c++; $idx_tva++; } } // isDNA // If operation is reversed then amount are negatif /* if ND */ if ($p_array['jrn_def_type']=='ACH') { $purchase=new Gestion_Purchase($this->db); $purchase->search_by_jid($code['j_id']); $purchase->load(); $dep_priv+=$purchase->qp_dep_priv; $p_array['dep_priv']=$dep_priv; $p_array['dna']=bcadd($p_array['dna'], $purchase->qp_nd_amount); $p_array['tva_dna']=bcadd($p_array['tva_dna'], bcadd($purchase->qp_nd_tva, $purchase->qp_nd_tva_recup)); $p_array['tva_np']=bcadd($purchase->qp_vat_sided, $p_array['tva_np']); } if ($p_array['jrn_def_type']=='VEN') { $sold=new gestion_sold($this->db); $sold->search_by_jid($code['j_id']); $sold->load(); $p_array['tva_np']=bcadd($sold->qs_vat_sided, $p_array['tva_np']); } } $p_array['TVAC']=sprintf('% 10.2f', $p_array['TVAC']); $p_array['HTVA']=sprintf('% 10.2f', $p_array['TVAC']-$p_array['AMOUNT_TVA']-$p_array['tva_dna']); $r=""; $a_tva_amount=array(); // inline TVA (used for the PDF) foreach ($p_array['TVA'] as $linetva) { foreach ($a_TVA as $tva) { if ($tva['tva_id']==$linetva[1][0]) { $a=$tva['tva_id']; $a_tva_amount[$a]=$linetva[1][2]; } } } foreach ($a_TVA as $line_tva) { $a=$line_tva['tva_id']; if (isset($a_tva_amount[$a])) { $tmp=sprintf("% 10.2f", $a_tva_amount[$a]); $r.="$tmp"; } else $r.=sprintf("% 10.2f", 0); } $p_array['TVA_INLINE']=$r; return $p_array; } /** * @brief depending on the mode will call the right function * - export_oneline_html for one line (mode=L) * - export_accounting_html for accounting (mode=A,D,E) */ function export_html() { switch ($this->m_mode) { case "E": $this->export_accounting_html(); break; case "D": $this->export_accounting_html(); break; case "L": $this->export_oneline_html(); break; case "A": $this->export_accounting_html(); break; default: break; } } /** * @brief Get simplified row from ledger * * @param p_from periode * @param p_to periode * @param p_limit starting line * @param p_offset number of lines * @param trunc if data must be truncated (pdf export) * @todo Prévoir aussi les journaux sans tables quant < 2007 * @return numbe of rows found */ function get_rowSimple($trunc=0, $p_limit=-1, $p_offset=-1) { global $g_user; $jrn=" jrn_def_id in (".join($this->ma_ledger, ",").")"; $periode=sql_filter_per($this->db, $this->m_from, $this->m_to, 'p_id', 'jr_tech_per'); $cond_limite=($p_limit!=-1)?" limit ".$p_limit." offset ".$p_offset:""; //--- $sql=" SELECT jrn.jr_id as jr_id , jrn.jr_id as num , jrn.jr_def_id as jr_def_id, jrn.jr_montant as montant, substr(jrn.jr_comment,1,35) as comment, to_char(jrn.jr_date,'DD-MM-YYYY') as date, to_char(jrn.jr_date_paid,'DD-MM-YYYY') as date_paid, jr_pj_number, jr_internal, jrn.jr_grpt_id as grpt_id, jrn.jr_pj_name as pj, jrn_def_type, jrn.jr_tech_per FROM jrn join jrn_def on (jrn_def_id=jr_def_id) WHERE $periode and $jrn order by jr_date,substring(jrn.jr_pj_number,'[0-9]+$')::numeric asc $cond_limite"; $Res=$this->db->exec_sql($sql); $Max=Database::num_row($Res); if ($Max==0) { return 0; } // @todo Pas nécessaire puisqu'on ne traite que les journaux d'opération diverses, // Il faudrait p-e prévoir un système pour les journaux avant 2007 qui n'utilisaient // pas les tables quant // // $type=$this->get_type(); // // for type ACH and Ven we take more info // if ($type=='ACH'||$type=='VEN') // { // $a_ParmCode=$this->db->get_array('select p_code,p_value from parm_code'); // $a_TVA=$this->db->get_array('select tva_id,tva_label,tva_poste // from tva_rate where tva_rate != 0 order by tva_rate,tva_label,tva_id '); // for ($i=0; $i<$Max; $i++) // { // $array[$i]=Database::fetch_array($Res, $i); // $p=$this->get_detail($array[$i], $type, $trunc, $a_TVA, // $a_ParmCode); // if ($array[$i]['dep_priv']!=0.0) // { // $array[$i]['comment'].="(priv. ".$array[$i]['dep_priv'].")"; // } // } // } // else // { $array=Database::fetch_all($Res); // } $this->data=$array; return $Max; } /** * @brief set $this->data with the array of rows * * * @param p_limit starting line * @param p_offset number of lines * @returns nb of rows found * */ function get_row($p_limit=-1, $p_offset=-1) { global $g_user; $periode=sql_filter_per($this->db, $this->m_from, $this->m_to, 'p_id', 'jr_tech_per'); $cond_limite=($p_limit!=-1)?" limit ".$p_limit." offset ".$p_offset:""; $ledger_list=join($this->ma_ledger, ","); // Grand livre == 0 $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, jr_internal, case j_debit when 't' then j_montant::text else ' ' end as deb_montant, case j_debit when 'f' then j_montant::text else ' ' end as cred_montant, j_debit as debit,j_poste as poste,j_qcode,jr_montant , ". "case when j_text='' or j_text is null then pcm_lib else j_text end as description,j_grpt as grp, jr_comment||' ('||jr_internal||')' as jr_comment, jr_pj_number, j_qcode, jrn_def_type, jr_rapt as oc, j_tech_per as periode, j_id from jrnx left join jrn on jr_grpt_id=j_grpt left join tmp_pcmn on pcm_val=j_poste join jrn_def on (jrn_def_id=jr_def_id) where j_jrn_def in (".$ledger_list.") and ".$periode." order by j_date::date asc,substring(jr_pj_number,'[0-9]+$')::numeric asc,j_grpt,j_debit desc ". $cond_limite); $array=array(); $Max=Database::num_row($Res); if ($Max==0) return 0; $case=""; $tot_deb=0; $tot_cred=0; $row=Database::fetch_all($Res); bcscale(2); for ($i=0; $i<$Max; $i++) { $line=$row[$i]; $tot_deb=bcadd($tot_deb, $line['deb_montant']); $tot_cred=bcadd($tot_cred, $line['cred_montant']); $tot_op=$line['jr_montant']; /* Check first if there is a quickcode */ if (strlen(trim($line['description']))==0&&strlen(trim($line['j_qcode'])) !=0) { $fiche=new Fiche($this->db); if ($fiche->get_by_qcode($line['j_qcode'], false)==0) { $line['description']=$fiche->strAttribut(ATTR_DEF_NAME); } } if ($case!=$line['grp']) { $case=$line['grp']; // for financial, we show if the amount is or not in negative if ($line['jrn_def_type']=='FIN') { $amount=$this->db->get_value('select qf_amount from quant_fin where jr_id=$1', array($line['jr_id'])); /* if nothing is found */ if ($this->db->count()==0) $tot_op=$line['jr_montant']; else if ($amount<0) { $tot_op=$amount; } } $array[]=array( 'jr_id'=>$line['jr_id'], 'int_j_id'=>$line['int_j_id'], 'j_id'=>$line['j_id'], 'j_date'=>$line['j_date'], 'internal'=>$line['jr_internal'], 'deb_montant'=>'', 'cred_montant'=>' ', 'description'=>''.h($line['jr_comment']).' ['.$tot_op.'] ', 'poste'=>$line['oc'], 'j_qcode'=>$line['j_qcode'], 'periode'=>$line['periode'], 'jr_pj_number'=>$line ['jr_pj_number'], "ledger_type"=>$line['jrn_def_type']); $array[]=array( 'jr_id'=>'', 'int_j_id'=>$line['int_j_id'], 'j_id'=>'', 'j_date'=>'', 'internal'=>'', 'deb_montant'=>$line['deb_montant'], 'cred_montant'=>$line['cred_montant'], 'description'=>$line['description'], 'poste'=>$line['poste'], 'j_qcode'=>$line['j_qcode'], 'periode'=>$line['periode'], 'jr_pj_number'=>'', "ledger_type"=>$line['jrn_def_type'] ); } else { $array[]=array( 'jr_id'=>$line['jr_id'], 'int_j_id'=>$line['int_j_id'], 'j_id'=>'', 'j_date'=>'', 'internal'=>'', 'deb_montant'=>$line['deb_montant'], 'cred_montant'=>$line['cred_montant'], 'description'=>$line['description'], 'poste'=>$line['poste'], 'j_qcode'=>$line['j_qcode'], 'periode'=>$line['periode'], 'jr_pj_number'=>'', "ledger_type"=>$line['jrn_def_type']); } } $this->data=array($array, $tot_deb, $tot_cred); return $Max; } /** * display in html the detail the list of operation */ public function export_detail_html() { $this->export_accounting_html(); } /** * display in html with extended detail the list of operation */ public function export_extended_html() { $this->export_accounting_html(); } /** * display in html the accounting of the list of operations */ public function export_accounting_html() { $this->get_row(); echo ''; // detailled printing //--- foreach ($this->data[0] as $op) { $class=""; if ($op['j_date']!='') { $class="odd"; } echo ""; echo ""; echo ""; if ($op['internal']!='') echo ""; else echo td(); echo "". "". "". "". ""; }// end loop echo "
".$op['j_date']."".$op['jr_pj_number']."".HtmlInput::detail_op($op['jr_id'], $op['internal'])."".$op['poste']."".$op['description']."".nbm($op['deb_montant'])."".nbm($op['cred_montant'])."
"; // show the saldo //@todo use
  • instead of
    echo _("solde débiteur:").$this->data[1]."
    "; echo _("solde créditeur:").$this->data[2]; } /** * @brief list operation on one line per operation */ public function export_oneline_html() { $this->get_rowSimple(); echo ''; echo "". th(_("Date")). th(_("n° pièce")). th(_("internal")). th(_("Tiers")). th(_("Commentaire")). th(_("Total opération")). ""; // set a filter for the FIN $i=0; $tot_amount=0; bcscale(2); foreach ($this->data as $line) { $i++; $class=($i%2==0)?' class="even" ':' class="odd" '; echo ""; echo ""; echo ""; echo ""; $tiers=$this->get_tiers($line['jrn_def_type'], $line['jr_id']); echo td($tiers); echo ""; // echo ""; // If the ledger is financial : // the credit must be negative and written in red // Get the jrn type if ($line['jrn_def_type']=='FIN') { $positive=$this->db->get_value("select qf_amount from quant_fin where jr_id=$1", array($line['jr_id'])); if ($this->db->count()==0) $positive=1; else $positive=($positive>0)?1:0; echo ""; if ($positive==1) { $tot_amount=bcadd($tot_amount, $line['montant']); } else { $tot_amount=bcsub($tot_amount, $line['montant']); } } else { echo ""; $tot_amount=bcadd($tot_amount, $line['montant']); } echo ""; } echo ''; echo ''; echo td().td().td().td(); echo ''; echo ''; echo "
    ".$line['date']."".h($line['jr_pj_number'])."".HtmlInput::detail_op($line['jr_id'], $line['jr_internal'])."".h($line['comment'])."".$line['pj'].""; echo ( $positive==0 )?" - ".nbm($line['montant'])."":nbm($line['montant']); echo "".nbm($line['montant'])."
    '._('Totaux').''.nbm($tot_amount).'
    "; } /** * To get data * @return array of rows */ function get_data() { return $this->data; } /** * export CSV */ function export_csv() { $export=new Noalyss_Csv(_('journal')); $export->send_header(); $this->get_row(); $title=array(); $title[]=_("operation"); $title[]=_("N° Pièce"); $title[]=_("Interne"); $title[]=_("Date"); $title[]=_("Poste"); $title[]=_("QuickCode"); $title[]=_("Libellé"); $title[]=_("Débit"); $title[]=_("Crédit"); $export->write_header($title); if (count($this->data)==0) exit; $old_id=""; /** * @todo add table headers */ foreach ($this->data[0] as $idx=>$op) { // should clean description : remove tag and '; char $desc=$op['description']; $desc=str_replace("", "", $desc); $desc=str_replace("", "", $desc); $desc=str_replace("", "", $desc); $desc=str_replace("", "", $desc); if ($op['j_id']!="") $old_id=$op['j_id']; $export->add($old_id, "text"); $export->add($op['jr_pj_number']); $export->add($op['internal']); $export->add($op['j_date']); $export->add($op['poste']); $export->add($op['j_qcode']); $export->add($desc); $export->add($op['deb_montant'], "number"); $export->add($op['cred_montant'], "number"); $export->write(); } } }