source: spip-zone/_plugins_/Association/Associaspip/inc/association_comptabilite.php @ 63500

Last change on this file since 63500 was 63500, checked in by gildas.cotomale@…, 8 years ago

comme on ne peut plus modifier les opérations comptables validées il faut quand même le signaler dans les formulaires qui en dépendent

File size: 48.4 KB
Line 
1<?php
2/***************************************************************************
3 *  Associaspip, extension de SPIP pour gestion d'associations             *
4 *                                                                         *
5 *  Copyright (c) 2007 Bernard Blazin & Francois de Montlivault (V1)       *
6 *  Copyright (c) 2010-2011 Emmanuel Saint-James & Jeannot Lapin (V2)       *
7 *                                                                         *
8 *  Ce programme est un logiciel libre distribue sous licence GNU/GPL.     *
9 *  Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne.   *
10\***************************************************************************/
11
12if (!defined('_ECRIRE_INC_VERSION'))
13    return;
14
15// recupere dans la table de comptes et celle des destinations la liste des destinations associees a une operation
16// le parametre correspond a l'id_compte de l'operation dans spip_asso_compte (et spip_asso_destination)
17function association_liste_destinations_associees($id_compte)
18{
19    if (!$id_compte)
20        return '';
21    if ($destination_query = sql_select('spip_asso_destination_op.id_destination, spip_asso_destination_op.recette, spip_asso_destination_op.depense, spip_asso_destination.intitule', 'spip_asso_destination_op RIGHT JOIN spip_asso_destination ON spip_asso_destination.id_destination=spip_asso_destination_op.id_destination', "id_compte=$id_compte", '', 'spip_asso_destination.intitule')) {
22        $destination = array();
23        while ($destination_op = sql_fetch($destination_query)) {
24            /* soit recette soit depense est egal a 0, donc pour l'affichage du montant on se contente les additionner */
25            $destination[$destination_op[id_destination]] = $destination_op[recette]+$destination_op[depense];
26        }
27        if (count($destination)==0)
28            $destination = '';
29    } else {
30        $destination = '';
31    }
32    return $destination;
33}
34
35// retourne une liste d'option HTML de l'ensemble des destinations de la base, ordonee par intitule
36function association_toutes_destination_option_list()
37{
38    $liste_destination = '';
39    $sql = sql_select('id_destination,intitule', 'spip_asso_destination', '', '', 'intitule');
40    while ($destination_info = sql_fetch($sql)) {
41        $liste_destination .= '<option value="'. $destination_info['id_destination'] .'">'.$destination_info['intitule'].'</option>';
42    }
43    return $liste_destination;
44}
45
46// retourne dans un <div> le code HTML/javascript correspondant au selecteur de destinations dynamique
47// le premier parametre permet de donner un tableau de destinations deja selectionnees(ou '' si on ajoute une operation)
48// le second parametre (optionnel) permet de specifier si on veut associer une destination unique, par default on peut ventiler sur
49// plusieurs destinations
50// le troisieme parametre permet de regler une destination par defaut[contient l'id de la destination] - quand $destination est vide
51function association_editeur_destinations($destination, $unique='', $defaut='')
52{
53    // recupere la liste de toutes les destination dans un code HTML <option value="destination_id">destination</option>
54    $liste_destination = association_toutes_destination_option_list();
55    $res = '';
56    if ($liste_destination) {
57        $res = '<script type="text/javascript" src="'.find_in_path('javascript/jquery.destinations_form.js').'"></script>';
58        $res .= '<label for="destination">'
59            . _T('asso:destination') .'</label>'
60            . '<div id="divTxtDestination" class="formulaire_edition_destinations">';
61        $idIndex = 1;
62//      spip_log("liste de destinations : \n".print_r($destination,true)."\n---------",'associaspip');
63        if ($destination!='') { /* si on a une liste de destinations (on edite une operation) */
64            foreach ($destination as $destId => $destMontant) {
65                $liste_destination_selected = preg_replace('/(value="'.$destId.'")/', '$1 selected="selected"', $liste_destination);
66                $res .= '<div class="formo" id="row'.$idIndex.'"><ul>';
67                $res .= '<li class="editer_id_dest['.$idIndex.']">'
68                    . '<select name="id_dest['.$idIndex.']" id="id_dest['.$idIndex.']" >'
69                    . $liste_destination_selected
70                    . '</select></li>';
71                if ($unique==false) {
72                    $res .= '<li class="editer_montant_dest['.$idIndex.']"><input name="montant_dest['.$idIndex.']" value="'
73                        . association_nbrefr(association_recupere_montant($destMontant))
74                        . '" type="text" id="montant_dest['.$idIndex.']" /></li>'
75                        . '<button class="destButton" type="button" onClick="addFormField(); return false;">+</button>';
76                    if ($idIndex>1) {
77                        $res .= '<button class="destButton" type="button" onClick="removeFormField(\'#row'.$idIndex.'\'); return false;">-</button>';
78                    }
79                }
80                $res .= '<ul></div>';
81                $idIndex++;
82            }
83        } else {/* pas de destination deja definies pour cette operation */
84            if ($defaut!='') {
85                $liste_destination = preg_replace('/(value="'.$defaut.'")/', '$1 selected="selected"', $liste_destination);
86            }
87            $res .= '<div id="row1" class="formo"><ul><li class="editer_id_dest[1]"><select name="id_dest[1]" id="id_dest[1]" >'
88                . $liste_destination . '</select></li>';
89            if (!$unique) {
90                $res .= '<li class="editer_montant_dest[1]"><input name="montant_dest[1]" value="'
91                    .'" type="text" id="montant_dest[1]"/></li>'
92                    . '</ul><button class="destButton" type="button" onClick="addFormField(); return false;">+</button>';
93            }
94            $res .= '</div>';
95        }
96        if ($unique==false)
97            $res .= '<input type="hidden" id="idNextDestination" value="'.($idIndex+1).'">';
98        $res .= '</div>';
99    }
100    return $res;
101}
102
103/* Ajouter une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op */
104function association_ajouter_operation_comptable($date, $recette, $depense, $justification, $imputation, $journal, $id_journal)
105{
106    include_spip('base/association');
107    /* on passe par modifier_contenu pour que la modification soit envoyee aux plugins et que Champs Extras 2 la recupere */
108    include_spip('inc/modifier');
109    $id_compte = sql_insertq('spip_asso_comptes', array(
110        'date' => $date,
111        'imputation' => $imputation,
112        'recette' => $recette,
113        'depense' => $depense,
114        'journal' => $journal,
115        'id_journal' => $id_journal,
116        'justification' => $justification
117    ));
118    modifier_contenu('asso_compte', $id_compte, '', array());
119    if (!$imputation) { // On laisse passer ce qui est peut-etre une erreur, pour ceux qui ne definisse pas de plan comptable. Mais ce serait bien d'envoyer un message d'erreur au navigateur plutot que de le signaler seulement dans les log
120        spip_log("imputation manquante : id_compte=$id_compte, date=$date, recette=$recette, depense=$depense, journal=$journal, id_journal=$id_journal, justification=$justification",'associaspip');
121    }
122    if ($GLOBALS['association_metas']['destinations']=='on') { // Si on doit gerer les destinations
123        association_ajouter_destinations_comptables($id_compte, $recette, $depense);
124    }
125    return $id_compte;
126
127}
128
129/* modifier une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op */
130function association_modifier_operation_comptable($date, $recette, $depense, $justification, $imputation, $journal, $id_journal, $id_compte)
131{
132    $err = '';
133    include_spip('base/association');
134    if ( sql_countsel('spip_asso_comptes', "id_compte=$id_compte AND vu ") ) { // il ne faut pas modifier une operation verouillee !!!
135        spip_log("modification d'operation comptable : id_compte=$id_compte, date=$date, recette=$recette, depense=$depense, imputation=$imputation, journal=$journal, id_journal=$id_journal, justification=$justification",'associaspip');
136        return $err = _T('asso:operation_non_modifiable');
137    }
138    if ($GLOBALS['association_metas']['destinations']=='on') { // Si on doit gerer les destinations
139        $err = association_ajouter_destinations_comptables($id_compte, $recette, $depense);
140    }
141    $modifs = array(
142        'date' => $date,
143        'imputation' => $imputation,
144        'recette' => $recette,
145        'depense' => $depense,
146        'journal' => $journal,
147        'justification' => $justification)//,
148    );
149    if ($id_journal) { // si id_journal est null, ne pas le modifier afin de ne pas endommager l'entree dans la base en editant directement depuis le livre de comptes
150        $modifs['id_journal'] = $id_journal;
151    }
152    // on passe par modifier_contenu (et non sql_updateq) pour que la modification soit envoyee aux plugins et que Champs Extras 2 la recupere
153    include_spip('inc/modifier');
154    modifier_contenu(
155        'asso_compte',
156        $id_compte,
157        '',
158        $modifs
159    );
160    return $err;
161}
162
163/* Supprimer une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op ; cas 1 : usage direct de id_compte */
164function association_supprimer_operation_comptable1($id_compte, $securite=FALSE)
165{
166    include_spip('base/association');
167    /* recuperer les informations sur l'operation pour le fichier de log */
168    list($date, $recette, $depense, $imputation, $journal, $id_journal, $verrou) = sql_fetsel('date, recette, depense, imputation, journal, id_journal, vu', 'spip_asso_comptes', "id_compte=$id_compte");
169    if ( ($securite AND !$verrou) || !$securite ) { // operation non verouillee ou controle explicitement desactive...
170        /* on efface de la table destination_op toutes les entrees correspondant a cette operation  si on en trouve */
171        sql_delete('spip_asso_destination_op', "id_compte=$id_compte");
172        /* on logue quand meme */
173        spip_log("suppression d'operation comptable : id_compte=$id_compte, date=$date, recette=$recette, depense=$depense, imputation=$imputation, journal=$journal, id_journal=$id_journal, justification=...",'associaspip');
174    } else { // on ne supprime pas les ecritures validees/verouillees ; il faut annuler l'operation par une operation comptable inverse...
175        /*on cree l'operation opposee a celle a annuler ; mais ce n'est pas une annulation correcte au regard des numeros de comptes (imputation/journal)... */
176        $annulation = sql_insertq('spip_asso_comptes', array(
177            'date' => date('Y-m-d'),
178            'depense' => $recette,
179            'recette' => $depense,
180            'imputation' => _T('asso:compte_annulation_operation', array('numero'=>$id_compte,'date'=>$date) ),
181            'imputation' => $imputation, // pas forcement vrai, mais on fait au plus simples...
182            'journal' => $journal, // pas forcement vrai, mais on fait au plus simples...
183            'id_journal' => -$id_journal, // on garde la trace par rapport au module ayant cree l'operation
184            'vu' => 1, // cette operation n'est pas moifiable non plus...
185        ) );
186        /* on logue quand meme */
187        spip_log("annulation d'operation comptable : id_compte=$id_compte, date=$date, recette=$recette, depense=$depense, imputation=$imputation, journal=$journal, id_journal=$id_journal, justification=annule_par_op$annulation",'associaspip');
188    }
189    /* on efface enfin de la table comptes l'entree correspondant a cette operation */
190    sql_delete('spip_asso_comptes', "id_compte=$id_compte");
191}
192
193/* Supprimer une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op ; cas 2 : usage par les modules du couple imputation&id_journal */
194function association_supprimer_operation_comptable2($id_journal,$imputation)
195{
196    /* old-way: avant, on pouvait ne pas avoir d'imputation... du coup on prend le premier id_journal correspondant a n'importe quelle imputation!!! (avec cette methode il n'est pas surprenant de perdre des enregistrements...) */
197#    $association_imputation = charger_fonction('association_imputation', 'inc');
198#    $critere = (($critere_imputation = $association_imputation($pc_imputation))?' AND ':'') ."id_journal='$id_journal'";
199    /* new-way: maintenant on exige l'imputation ; et s'il n'y en a pas on prend le premier id_journal sans imputation ! c'est deja beaucoup moins problematique... */
200    $critere = "imputation='$imputation' AND id_journal='$id_journal'";
201    $id_compte = sql_getfetsel('id_compte', 'spip_asso_comptes', $critere);
202    association_supprimer_operation_comptable1($id_compte);
203    return $id_compte; // indique quelle operation a ete supprimee (0 si aucune --donc erreur dans les parametres ?)
204}
205
206/* Supprimer en masse des operations dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op */
207function association_supprimer_operations_comptables($critere)
208{
209    include_spip('base/association');
210    /* on recupere les id_comptes a supprimer */
211    $where = sql_in_select('id_compte', 'id_compte', 'spip_asso_comptes', $critere);
212    /* on efface de la table destination_op toutes les entrees correspondant a ces operations  si on en trouve */
213    sql_delete('spip_asso_destination_op', $where);
214    /* on logue quand meme */
215    $query_log = sql_select('id_compte, date, recette, depense, imputation, journal, id_journal', 'spip_asso_comptes', $where);
216    while ( list($id_compte, $date, $recette, $depense, $imputation, $journal, $id_journal) = fetch($query_log) ) {
217        spip_log("suppression d'operation comptable : id_compte=$id_compte, date=$date, recette=$recette, depense=$depense, imputation=$imputation, journal=$journal, id_journal=$id_journal ",'associaspip');
218    }
219    /* on efface enfin de la table comptes les entrees correspondant a ces operations */
220    sql_delete('spip_asso_comptes', $where); // $where ou $critere
221}
222
223/* fonction de verification des montants de destinations entres */
224/* le parametre d'entree est le montant total attendu, les montants des destinations sont recuperes */
225/* directement dans $_POST */
226function association_verifier_montant_destinations($montant_attendu)
227{
228    $err = '';
229    $toutesDestinations = _request('id_dest');
230    $toutesDestinationsMontants = _request('montant_dest');
231    /* on verifie que le montant des destinations correspond au montant global et qu'il n'y a pas deux fois la meme destination (uniquement si on a plusieurs destinations) */
232    $total_destination = 0;
233    $id_inserted = array();
234    if (count($toutesDestinations)>1) {
235        foreach ($toutesDestinations as $id => $id_destination) {
236            /* on verifie qu'on n'a pas deja insere une destination avec cette id */
237            if (!array_key_exists($id_destination,$id_inserted)) {
238                $id_inserted[$id_destination] = 0;
239            } else {
240                $err = _T('asso:erreur_destination_dupliquee');
241            }
242            $total_destination += association_recupere_montant($toutesDestinationsMontants[$id]); /* les montants sont dans un autre tableau aux meme cles */
243        }
244        /* on verifie que la somme des montants des destinations correspond au montant attendu */
245        if ($montant_attendu!=$total_destination) {
246            $err .= _T('asso:erreur_montant_destination');
247        }
248    } else { /* une seule destination, le montant peut ne pas avoir ete precise, dans ce cas pas de verif, c'est le montant attendu qui sera entre dans la base */
249        /* quand on a une seule destination, l'id dans les tableaux est forcement 1 par contruction de l'editeur */
250        if ($toutesDestinationsMontants[1]) {
251            $montant = association_recupere_montant($toutesDestinationsMontants[1]);
252            /* on verifie que le montant indique correspond au montant attendu */
253            if ($montant_attendu!=$montant) {
254                $err = _T('asso:erreur_montant_destination');
255            }
256        }
257    }
258    return $err;
259}
260
261/* fonction permettant d'ajouter/modifier les destinations comptables (presente dans $_POST) a une operation comptable */
262function association_ajouter_destinations_comptables($id_compte, $recette, $depense)
263{
264    include_spip('base/association');
265    /* on efface de la table destination_op toutes les entrees correspondant a cette operation  si on en trouve*/
266    sql_delete('spip_asso_destination_op', "id_compte=$id_compte");
267//    spip_log("DEL spip_asso_destination_op.id_compte=$id_compte",'associaspip');
268    if ($recette>0) {
269        $attribution_montant = 'recette';
270    } else {
271        $attribution_montant = 'depense';
272    }
273    $toutesDestinations = _request('id_dest');
274    $toutesDestinationsMontants = _request('montant_dest');
275//    spip_log("id_dest : \n".print_r($toutesDestinations, true), 'associaspip');
276//    spip_log("id_dest : \n".print_r($toutesDestinationsMontants, true), 'associaspip');
277    if (count($toutesDestinations)>1) {
278        foreach ($toutesDestinations as $id => $id_destination) {
279            $montant = association_recupere_montant($toutesDestinationsMontants[$id]);  /* le tableau des montants a des cles indentique a celui des id */
280            $id_dest_op = sql_insertq('spip_asso_destination_op', array(
281                'id_compte' => $id_compte,
282                'id_destination' => $id_destination,
283                $attribution_montant => $montant
284            ));
285//          spip_log("spip_asso_destination_op(id_dest_op,id_compte,id_destination,montant,attribution)=($id_dest_op,$id_compte,$id_destination,$montant,$attribution_montant)",'associaspip');
286        }
287    } else { /* une seule destination, le montant peut ne pas avoir ete precise, on entre directement le total recette+depense */
288        $id_dest_op = sql_insertq('spip_asso_destination_op', array(
289            'id_compte' => $id_compte,
290            'id_destination' => $toutesDestinations[1],
291            $attribution_montant => $depense+$recette
292        ));
293//      spip_log("spip_asso_destination_op(id_dest_op,id_compte,id_destination,recette,depense,attribution)=($id_dest_op,$id_compte,1,$recette,$depense,$attribution_montant)",'associaspip');
294    }
295}
296
297function inc_association_imputation_dist($nom, $table='')
298{
299    $champ = ($table ? ($table . '.') : '') . 'imputation';
300    return $champ . '=' . sql_quote($GLOBALS['association_metas'][$nom]);
301}
302
303/* valide le plan comptable: on doit avoir au moins deux classes de comptes differentes */
304/* le code du compte doit etre unique */
305/* le code du compte doit commencer par un chiffre egal a sa classe */
306function association_valider_plan_comptable()
307{
308    $classes = array();
309    $codes = array();
310    /* recupere le code et la classe de tous les comptes du plan comptable */
311    $query = sql_select('code, classe', 'spip_asso_plan');
312    while ($data = sql_fetch($query)) {
313        $classe = $data['classe'];
314        $code = $data['code'];
315        $classes[$classe] = 0; /* on comptes les classes differentes */
316        if(array_key_exists($code, $codes)) {
317            return false; /* on a deux fois le meme code */
318        } else {
319            $codes[$code] = 0;
320        }
321        /* on verifie que le code est bien de la forme chiffre-chiffre-caracteres alphanumeriques et que le premier digit correspond a la classe */
322        if ((!preg_match("/^[0-9]{2}\w*$/", $code)) || ($code[0]!=$classe))
323            return false;
324    }
325    if (count($classes)<2)
326        return false; /* on doit avoir au moins deux classes differentes */
327    return true;
328}
329
330/* retourne un tableau $code => $intitule trie sur $code et de classe $val */
331function association_liste_plan_comptable($val,$actives='') {
332    $res = array();
333    /* recupere le code et l'intitule de tous les comptes de classe $val */
334    $query = sql_select('code, intitule', 'spip_asso_plan', "classe='$val'".($actives?" AND active=$actives":''), '', 'code');
335    while ($data = sql_fetch($query)) {
336        $code = $data['code'];
337        $intitule = $data['intitule'];
338        $res[$code] = $intitule;
339    }
340    return $res;
341}
342
343/* si il existe un compte 58x on le retourne sinon on cree le compte 581 et on le retourne */
344function association_creer_compte_virement_interne() {
345    if ($GLOBALS['association_metas']['pc_intravirements']) // un code de virement interne est deja defini !
346        return $GLOBALS['association_metas']['pc_intravirements'];
347    $res = association_liste_plan_comptable($GLOBALS['association_metas']['classe_banques']); // on recupere tous les comptes de la classe "financier" (classe 5)
348    foreach($res as $code => $libelle) {
349        /* existe-t-il le compte 58x ? (nota : c'est la compta francaise...) */
350        if (substr($code,1,1)=='8') // il existe un code qui commence par 58...
351            return $code;
352    }
353    /* j'ai rien trouve, je cree le compte 581 */
354    $code = $GLOBALS['association_metas']['classe_banques'].'81';
355    $id_plan = sql_insertq('spip_asso_plan', array(
356        'code' => $code,
357        'intitule' => _T('asso:virement_interne'),
358        'classe' => $GLOBALS['association_metas']['classe_banques'],
359        'type_op' => 'multi',
360        'solde_anterieur' => '0',
361        'date_anterieure' => date('Y-m-d'),
362        'commentaire' => _T('asso:compte_cree_automatiquement'),
363        'active' => '0',
364        'maj' => date('Y-m-d')
365    ));
366    return $code;
367}
368
369/* on recupere les parametres de requete a passer aux fonctions */
370function association_passe_parametres_comptables($classes=array()) {
371    $params = array(); // initialisation de la liste
372    $params['exercice'] = intval(_request('exercice'));
373    if( !$params['exercice'] ) { // pas de "id_exercice" en parametre
374        $params['exercice'] = intval(sql_getfetsel('id_exercice', 'spip_asso_exercices', '', '', 'fin DESC')); // on recupere l'id_exercice dont la "date de fin" est "la plus grande", c'est a dire l'id de l'exercice le plus recent
375    }
376    $params['annee'] = intval(_request('annee'));
377    if( !$params['annee'] ) { // pas d'annee en parametre
378        $params['annee'] = date('Y'); // on prende l'annee actuelle
379    }
380    $params['destination'] = intval(_request('destination'));
381#    if( !$params['destination'] ) { // pas de destination
382#    }
383    $params['type'] = _request('type');
384    if ( !$classes ) { // pas en parametre, on prend dans la requete
385//      $params['classes'] = array_flip( explode(',', _request('classes')) );
386        $keys = explode(',', _request('classes'));
387        if ( count($keys) ) {
388            $vals = array_fill(0, count($keys) ,0);
389            $params['classes'] = array_combine($keys, $vals);
390        } else {
391            $params['classes'] = array();
392        }
393    } elseif ( is_array($classes) ) { // c'est a priori bon
394        $params['classes'] = $classes;
395    } else { // c'est un tableau de classe_comptable=>type_operations qui est requis !
396        $params['classes'] = $classes ? array( $classes=>0 ) : array() ;
397    }
398    $params['url'] = serialize($params); //!\ les cles numeriques peuvent poser probleme... <http://www.mail-archive.com/php-bugs@lists.php.net/msg100262.html> mais il semble qu'ici le souci vient de l'absence d'encodage lorsqu'on passe $var par URL...
399    return $params;
400}
401
402/* on recupere les soldes des differents comptes de la classe specifiee pour l'exercice specifie
403 * d'apres http://www.lacompta.ch/MITIC/theorie.php?ID=26 c'est le solde qui est recherche, et il corresponde bien a :
404 *  recettes-depenses=recettes pour les classes 6
405 *  depenses-recettes=depenses pour les classes 7
406 * */
407function association_calcul_soldes_comptes_classe($classe, $exercice=0, $destination=0, $direction='-1') {
408    $c_group = (($classe==$GLOBALS['association_metas']['classe_banques'])?'journal':'imputation');
409    $valeurs = (($direction)
410        ?
411        ( ($direction<0)
412            ?'SUM('.(($destination)?'a_d':'a_c').'.depense-'.(($destination)?'a_d':'a_c').'.recette) AS valeurs'
413            : 'SUM('.(($destination)?'a_d':'a_c').'.recette-'.(($destination)?'a_d':'a_c').'.depense) AS valeurs'
414        )
415        :
416        'SUM('.(($destination)?'a_d':'a_c').'.recette) AS recettes, SUM('.(($destination)?'a_d':'a_c').'.depense) as depenses, SUM('.(($destination)?'a_d':'a_c').'.recette-'.(($destination)?'a_d':'a_c').'.depense) AS soldes' );
417    $c_having = ($direction) ? 'valeurs>0' : ''; // on ne retiendra que les totaux non nuls...
418    if ( sql_countsel('spip_asso_plan','active=1') ) { // existence de comptes actifs
419        $p_join = " RIGHT JOIN spip_asso_plan AS a_p ON a_c.$c_group=a_p.code";
420        $p_select = ', a_p.code, a_p.intitule, a_p.classe';
421        $p_order = 'a_p.code'; // imputation ou journal
422#       $p_where = 'a_p.classe='.sql_quote($classe);
423        $p_having = 'a_p.classe='.sql_quote($classe); // ok : on agrege par code (indirectement) associe a une classe unique selectionnee ...
424    } else { // pas de comptes actifs ?!?
425        $p_join = $p_select = $p_where = $p_having = '';
426        $p_order = $c_group; // imputation ou journal
427    }
428    if ( $exercice ) { // exercice budgetaire personnalise
429        $exercice_data = sql_asso1ligne('exercice', $exercice);
430        $c_where = "a_c.date>='$exercice_data[debut]' AND a_c.date<='$exercice_data[fin]' ";
431    } elseif ( $annee ) { // exercice budgetaire par annee civile
432        $c_where = "DATE_FORMAT(a_c.date, '%Y')=$annee ";
433#    } elseif ( $classe==$GLOBALS['association_metas']['classe_banques'] ) { // encaisse
434#       $c_where = 'LEFT(a_c.imputation,1)<>'. sql_quote($GLOBALS['association_metas']['classe_contributions_volontaires']) .' AND a_c.date>=a_p.date_anterieure AND a_c.date<=NOW() ';
435    } else { // tout depuis le debut ?!?
436        $c_where = 'a_c.date<=NOW()'; // il faut mettre un test valide car la chaine peut etre precedee de "AND "...  limiter alors a aujourd'hui ?
437    }
438    $query = sql_select(
439        "$c_group, $valeurs ". ($destination ? ', a_d.id_destination' : '') .$p_select, // select
440        'spip_asso_comptes AS a_c '. ($destination ? 'LEFT JOIN spip_asso_destination_op AS a_d ON a_d.id_compte=a_c.id_compte ' : '') .$p_join, // from
441        ($destination ? "a_d.id_destination=$destination AND " : '') . ($p_where?"$p_where AND ":'')  .$c_where, // where
442        $c_group, // group by
443        $p_order, // order by
444        '', // limit
445        $c_having. (($c_having && $p_having)?' AND ':'') .$p_having // having
446    );
447    return $query;
448}
449
450/* on affiche les totaux (recettes et depenses) d'un exercice des differents comptes de la classe specifiee */
451function association_liste_totaux_comptes_classes($classes, $prefixe='', $direction='-1', $exercice=0, $destination=0) {
452    if( !is_array($classes) ) { // a priori une chaine ou un entier d'une unique classe
453        $liste_classes = array( $classes ) ; // transformer en tableau (puisqu'on va operer sur des tableaux);
454    } else { // c'est un tableau de plusieurs classes
455        $liste_classes = $classes;
456    }
457    $titre = $prefixe.'_'. ( ($direction) ? (($direction<0)?'depenses':'recettes') : 'soldes' );
458    echo "<table width='100%' class='asso_tablo' id='asso_tablo_$titre'>\n";
459    echo "<thead>\n<tr>";
460    echo '<th width="10">&nbsp;</td>';
461    echo '<th width="30">&nbsp;</td>';
462    echo '<th>'. _T("asso:$titre") .'</th>';
463    if ($direction) { // mode liste comptable : charge, produit, actifs, passifs
464        echo '<th width="80">&nbsp;</th>';
465    } else { // mode liste standard : contributions volontaires et autres
466        echo '<th width="80">'. _T("asso:$prefixe".'_recettes') .'</th>';
467        echo '<th width="80">'. _T("asso:$prefixe".'_depenses') .'</th>';
468        // echo '<th width="80">'. _T("asso:$prefixe".'_solde') .'</th>';
469    }
470    echo "</tr>\n</thead><tbody>";
471    $total_valeurs = $total_recettes = $total_depenses = 0;
472    $chapitre = '';
473    $i = 0;
474    foreach ( $liste_classes as $rang => $classe ) {
475        $query = association_calcul_soldes_comptes_classe($classe, $exercice, $destination, $direction );
476        while ($data = sql_fetch($query)) {
477            echo '<tr>';
478            $new_chapitre = substr($data['code'], 0, 2);
479            if ($chapitre!=$new_chapitre) {
480                echo '<td class="text">'. $new_chapitre . '</td>';
481                echo '<td colspan="3" class="text">'. ($GLOBALS['association_metas']['plan_comptable_prerenseigne']?association_plan_comptable_complet($new_chapitre):sql_getfetsel('intitule','spip_asso_plan',"code='$new_chapitre'")) .'</td>';
482                $chapitre = $new_chapitre;
483                echo "</tr>\n<tr>";
484            }
485#           if ( floatval($data['valeurs']) || floatval($data['recettes']) || floatval($data['depenses']) ) { // non-zero...
486                echo "<td>&nbsp;</td>";
487                echo '<td class="text">'. $data['code'] .'</td>';
488                echo '<td class="text">'. $data['intitule'] .'</td>';
489                if ($direction) { // mode liste comptable
490                    echo '<td class="decimal">'. association_nbrefr($data['valeurs']) .'</td>';
491                    $total_valeurs += $data['valeurs'];
492                } else { // mode liste standard
493                    echo '<td class="decimal">'. association_nbrefr($data['recettes']) .'</td>';
494                    $total_recettes += $data['recettes'];
495                    echo '<td class="decimal">'. association_nbrefr($data['depenses']) .'</td>';
496                    $total_depenses += $data['depenses'];
497                    //echo '<td class="decimal">'. association_nbrefr($data['soldes']) .'</td>';
498                    $total_valeurs += $data['soldes'];
499                }
500                echo "</tr>\n";
501#           }
502        }
503    }
504    echo "</tbody><tfoot>\n<tr>";
505    echo '<th colspan="2">&nbsp;</th>';
506    echo '<th class="text">'. _T("asso:$prefixe".'_total') .'</th>';
507    if ($direction) { // mode liste comptable
508        echo '<th class="decimal">'. association_nbrefr($total_valeurs) . '</th>';
509    } else { // mode liste standard
510        echo '<th class="decimal">'. association_nbrefr($total_recettes) . '</th>';
511        echo '<th class="decimal">'. association_nbrefr($total_depenses) . '</th>';
512        // echo '<th class="decimal">'. association_nbrefr($total_valeurs) . '</th>';
513    }
514    echo "</tr>\n</tfoot>\n</table>\n";
515    return $total_valeurs;
516}
517
518/* on affiche la difference entre les recettes et les depenses (passees en parametre) pour les classes d'un exercice */
519function association_liste_resultat_net($recettes, $depenses) {
520    echo "<table width='100%' class='asso_tablo' id='asso_tablo_bilan_solde'>\n";
521    echo "<thead>\n<tr>";
522    echo '<th width="10">&nbsp;</td>';
523    echo '<th width="30">&nbsp;</td>';
524    echo '<th>'. _T('asso:cpte_resultat_titre_resultat') .'</th>';
525    echo '<th width="80">&nbsp;</th>';
526    echo "</tr>\n</thead>";
527    echo "<tfoot>\n<tr>";
528    echo '<th colspan="2">&nbsp;</th>';
529    $res = $recettes-$depenses;
530    echo '<th class="text">'. (($res<0) ? _T('asso:cpte_resultat_perte') : _T('asso:cpte_resultat_benefice')) .'</th>';
531    echo '<th class="decimal">'. association_nbrefr(abs($res)) .'</th>';
532    echo "</tr></tfoot></table>";
533}
534
535// Brique commune aux classes d'exportation des etats comptables
536class ExportComptes_TXT {
537
538    var $exercice;
539    var $destination;
540    var $annee;
541    var $type;
542    var $classes;
543    var $out;
544
545    // constructeur (fonction d'initialisatio de la classe)
546    function __construct($var='') {
547        if ( !$var )
548            $tableau = association_passe_parametres_comptables();
549        elseif ( is_string($var) )
550            $tableau = unserialize(rawurldecode($var));
551        elseif ( is_array($var) )
552            $tableau = $var;
553        else
554            $tableau = array($var=>0);
555        $this->exercice = intval($tableau['exercice']);
556        $this->destination = intval($tableau['destination']);
557        $this->annee = intval($tableau['annee']);
558        $this->type = $tableau['type'];
559        if ( count($tableau['classes']) ) {
560            $this->classes = $tableau['classes'];
561        } else {
562            switch ($tableau['type']) {
563                case 'bilan' :
564                    $query = sql_select(
565                        'classe', // select
566                        'spip_asso_plan', // from
567                        sql_in('classe', array($GLOBALS['association_metas']['classe_charges'],$GLOBALS['association_metas']['classe_produits'],$GLOBALS['association_metas']['classe_contributions_volontaires']), 'NOT'), // where  not in
568                        'classe', // group by
569                        'classe' // order by
570                    );
571                    while ($data = sql_fetch($query)) {
572                        $this->classes[$data['classe']] = 0;
573                    }
574                    break;
575                case 'resultat' :
576                    $this->classes = array($GLOBALS['association_metas']['classe_charges']=>'-1', $GLOBALS['association_metas']['classe_produits']=>'+1', $GLOBALS['association_metas']['classe_contributions_volontaires']=>0);
577                    break;
578            }
579        }
580        $this->out = '';
581    }
582
583    // export texte de type tableau (lignes*colonnes) simple : CSV,CTX,HTML*SPIP,INI*,TSV,etc.
584    // de par la simplicite recherchee il n'y a pas de types ou autres : CSV et CTX dans une certaine mesure pouvant distinguer "nombres", "chaines alphanumeriques" et "chaine binaires encodees"
585    function exportLignesUniques($champsSeparateur, $lignesSeparateur, $echappements=array(), $champDebut='', $champFin='', $entete=true, $multi=false) {
586        if ($entete) {
587            $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), utf8_decode(html_entity_decode(_T('asso:entete_code')))) .$champFin.$champsSeparateur;
588            $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), utf8_decode(html_entity_decode(_T('asso:entete_intitule')))) .$champFin.$champsSeparateur;
589            if (!$multi) {
590                $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), utf8_decode(html_entity_decode(_T('asso:entete_montant')))) .$champFin.$lignesSeparateur;
591            } else {
592                $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), utf8_decode(html_entity_decode(_T('asso:entete_recette')))) .$champFin.$champsSeparateur;
593                $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), utf8_decode(html_entity_decode(_T('asso:entete_depense')))) .$champFin.$lignesSeparateur;
594            }
595        }
596        foreach ($this->classes as $laClasse=>$laDirection) {
597            $this->LignesSimplesCorps($nomClasse, $champsSeparateur, $lignesSeparateur, $echappements=array(), $champDebut='', $champFin='');
598            $query = association_calcul_soldes_comptes_classe($laClasse, $this->exercice, $this->destination, $multi?0:$laDirection);
599            $chapitre = '';
600            $i = 0;
601            while ($data = sql_fetch($query)) {
602                $new_chapitre = substr($data['code'], 0, 2);
603                if ($chapitre!=$new_chapitre) {
604                    $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), $new_chapitre) .$champFin.$champsSeparateur;
605                    $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), ($GLOBALS['association_metas']['plan_comptable_prerenseigne']?association_plan_comptable_complet($new_chapitre):sql_getfetsel('intitule','spip_asso_plan',"code='$new_chapitre'"))) .$champFin.$champsSeparateur;
606                    $this->out .= $champsSeparateur.' '.$champsSeparateur;
607                    $this->out .= $lignesSeparateur;
608                    $chapitre = $new_chapitre;
609                }
610                $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), $data['code']) .$champFin.$champsSeparateur;
611                $this->out .= $champDebut. str_replace(array_keys($echappements), array_values($echappements), $data['intitule']) .$champFin.$champsSeparateur;
612                if (!$multi) {
613                    $this->out .= $champDebut. ($laDirection?$data['valeurs']:$data['recettes']-$data['depenses']) .$champFin.$lignesSeparateur;
614                } else {
615                    $this->out .= $champDebut.$data['recettes'].$champFin.$champsSeparateur;
616                    $this->out .= $champDebut.$data['depenses'].$champFin.$lignesSeparateur;
617                }
618            }
619        }
620    }
621
622    // export texte de type s-expression / properties-list / balisage (conteneurs*conteneurs*donnees) simple : JSON, XML (utilisable avec ASN.1), YAML, etc.
623    // de par la simplicite recherchee il n'y a pas de types ou d'attributs : BSON, Bencode, JSON, pList, XML, etc.
624    function exportLignesMultiples($balises, $echappements=array(), $champDebut='', $champFin='', $indent="\t", $entetesPerso='', $multi=false) {
625        $this->out .= "$balises[compteresultat1]\n";
626        if (!$entetesPerso) {
627            $this->out .= "$indent$balises[entete1]\n";
628            $this->out .= "$indent$indent$balises[titre1] $champDebut". utf8_decode(html_entity_decode(_T('asso:cpte_resultat_titre_general'))) ."$champFin $balises[titre0]\n";
629            $this->out .= "$indent$indent$balises[nom1] $champDebut". $GLOBALS['association_metas']['nom'] ."$champFin $balises[nom0]\n";
630            $this->out .= "$indent$indent$balises[exercice1] $champDebut". sql_asso1champ('exercice', $this->exercice, 'intitule') ."$champFin $balises[exercice0]\n";
631            $this->out .= "$indent$balises[entete0]\n";
632        }
633        foreach ($this->classes as $laClasse=>$laDirection) {
634            $baliseClasse = $nomClasse.'1';
635            $this->out .= "$indent$balises[$baliseClasse]\n";
636            $query = association_calcul_soldes_comptes_classe($laClasse, $this->exercice, $this->destination, $laDirection);
637            $chapitre = '';
638            $i = 0;
639            while ($data = sql_fetch($query)) {
640                if ( !$laDirection ) {
641                    $valeurs = ($data['depenses']>0)?$data['depenses']:$data['recettes'];
642                } else {
643                    $valeurs = $data['valeurs'];
644                }
645                $new_chapitre = substr($data['code'], 0, 2);
646                if ($chapitre!=$new_chapitre) {
647                    if ($chapitre!='') {
648                        $this->out .= "$indent$indent$balises[chapitre0]\n";
649                    }
650                    $this->out .= "$indent$indent$balises[chapitre1]\n";
651                    $this->out .= "$indent$indent$indent$balises[code1] $champDebut". str_replace(array_keys($echappements), array_values($echappements), $new_chapitre) ."$champFin $balises[code0]\n";;
652                    $this->out .= "$indent$indent$indent$balises[libelle1] $champDebut". str_replace(array_keys($echappements), array_values($echappements), ($GLOBALS['association_metas']['plan_comptable_prerenseigne']?association_plan_comptable_complet($new_chapitre):sql_getfetsel('intitule','spip_asso_plan',"code='$new_chapitre'"))) ."$champFin $balises[libelle0]\n";
653                    $chapitre = $new_chapitre;
654                }
655                $this->out .= "$indent$indent$indent$balises[categorie1]\n";
656                $this->out .= "$indent$indent$indent$indent$balises[code1] $champDebut". str_replace(array_keys($echappements), array_values($echappements), $data['code']) ."$champFin $balises[code0]\n";
657                $this->out .= "$indent$indent$indent$indent$balises[intitule1] $champDebut". str_replace(array_keys($echappements), array_values($echappements), $data['intitule']) ."$champFin $balises[intitule0]\n";
658                if ( !$multi ) {
659                    $this->out .= "$indent$indent$indent$indent$balises[montant1] $champDebut".$valeurs."$champFin $balises[montant0]\n";
660                } else {
661                    $this->out .= "$indent$indent$indent$indent$balises[credit1] $champDebut".$data['recettes']."$champFin $balises[credit0]\n";
662                    $this->out .= "$indent$indent$indent$indent$balises[debit1] $champDebut".$data['depenses']."$champFin $balises[debit0]\n";
663                }
664                $this->out .= "$indent$indent$indent$balises[categorie0]\n";
665            }
666            if ($chapitre!='') {
667                $this->out .= "$indent$indent$balises[chapitre0]\n";
668            }
669            $baliseClasse = $nomClasse.'0';
670            $this->out .= "$indent$balises[$baliseClasse]\n";
671        }
672        $this->out .= "$balises[compteresultat0]\n";
673    }
674
675    // fichier texte final a afficher/telecharger
676    function leFichier($ext, $subtype='') {
677        $fichier = _DIR_RACINE.'/'._NOM_TEMPORAIRES_ACCESSIBLES.'compte_'. ($subtype?$subtype:$this->type) .'_'.$this->exercice.'_'.$this->destination.".$ext"; // on essaye de creer le fichier dans le cache local/ http://www.spip.net/fr_article4637.html
678        $f = fopen($fichier, 'w');
679        fputs($f, $this->out);
680                fclose($f);
681        header('Content-type: application/'.$ext);
682        header('Content-Disposition: attachment; filename="'.$fichier.'"');
683        readfile($fichier);
684    }
685
686}
687
688if (test_plugin_actif('FPDF')) {
689
690    define('FPDF_FONTPATH', 'font/');
691    include_spip('fpdf');
692    include_spip('inc/charsets');
693    include_spip('inc/association_plan_comptable');
694
695class ExportComptes_PDF extends FPDF {
696
697    // variables de parametres de mise en page
698    var $largeur = 210; // format A4
699    var $hauteur = 297; // format A4
700    var $marge_gauche = 10;
701    var $marge_droite = 10;
702    var $marge_haut = 10;
703    var $marge_bas = 10;
704    var $icone_h = 20;
705    var $icone_v = 20;
706    var $space_v = 2;
707    var $space_h = 2;
708
709    // variables de mise en page calculees
710    var $largeur_utile = 0; // largeur sans les marges droites et gauches
711    var $largeur_pour_titre = 0; // largeur utile sans icone
712
713    // position du curseur
714    var $xx = 0; // abscisse 1ere boite
715    var $yy = 0; // ordonnee 1ere boite
716
717    // variables de fonctionnement passees en parametre
718    var $annee;
719    var $exercice;
720    var $destination;
721
722    // Initialisations
723    function init($ids='') {
724        if ( !$ids )
725            $ids = association_passe_parametres_comptables();
726        // passer les parametres transmis aux variables de la classe
727        $this->annee = $ids['annee'];
728        $this->exercice = $ids['exercice'];
729        $this->destination = $ids['destination'];
730        // calculer les dimensions de mise en page
731        $this->largeur_utile = $this->largeur-$this->marge_gauche-$this->marge_droite;
732        $this->largeur_pour_titre = $this->largeur_utile-$this->icone_h-3*$this->space_h;
733        // initialiser les variables de mise en page
734        $this->xx = $this->marge_gauche;
735        $this->yy = $this->marge_haut;
736        // meta pour le fichier PDF
737        $this->SetAuthor('Marcel BOLLA');
738        $this->SetCreator('Associaspip & Fpdf');
739        $this->SetTitle('Module Comptabilite');
740        $this->SetSubject('Etats comptables');
741        // typo par defaut
742        $this->SetFont('Arial', '', 12);
743        // engager la page
744        $this->AddPage();
745    }
746
747    // Pied de pages : redefinition de FPDF::Footer() qui est automatiquement appele par FPDF::AddPage() et FPDF::Close() !
748    //@ http://www.id.uzh.ch/cl/zinfo/fpdf/doc/footer.htm
749    //!\ Adapter la marge basse (et la hauteur utile) des pages en consequence
750    function Footer() {
751        // Positionnement a 2 fois la marge du bas
752        $this->SetY(-2*$this->marge_bas);
753        // typo
754        $this->SetFont('Arial', 'I', 8); // police: Arial italique 8px
755        $this->SetTextColor(128); // Couleur du texte : gris-50.2% (fond blanc)
756        // Date et Numéro de page
757        $this->Cell(0, 10, html_entity_decode(_T('asso:cpte_export_pied_notice') .' -- '. affdate(date('Y-m-d')) .' -- '. _T('asso:cpte_export_page', array('numero'=>$this->PageNo()) )), 0, 0, 'C');
758    }
759
760    // Haut de pages : redefinition de FPDF qui est directement appele par FPDF::AddPage()
761    //@ http://www.id.uzh.ch/cl/zinfo/fpdf/doc/header.htm
762    //!\ Adapter la marge haute (et la hauteur utile) des pages en consequence
763    function Header() {
764        // nop
765    }
766
767    // cartouche au debut de la 1ere page (contrairement au Header ceci fait partir du contenu/flux et n'est pas repete sur toutes les pages, et peut accepter des parametres)
768    function association_cartouche_pdf($titre='') {
769        // Les coordonnees courantes
770        $xc = $this->xx+$this->space_h;
771        $yc = $this->yy+$this->space_v;
772        $this->SetDrawColor(128); // La couleur du trace : gris 50.2% (sur fond blanc)
773        // Le logo du site
774#       $chercher_logo = charger_fonction('chercher_logo', 'inc');
775#       $logo = $chercher_logo(0, 'id_site');
776        $logo = find_in_path('IMG/siteon0.jpg'); // Probleme FPDF et images non JPEG :-/ http://forum.virtuemart.net/index.php?topic=75616.0
777        if ($logo) {
778            include_spip('/inc/filtres_images_mini');
779            $this->Image(extraire_attribut(image_reduire($logo, $this->icone_h, $this->icone_v), 'src'), $xc, $yc, $this->icone_h);
780        }
781        // typo
782        $this->SetFont('Arial', 'B', 22); // police : Arial gras 22px
783        $this->SetFillColor(235); // Couleur du cadre, du fond du cadre : gris-92,2%
784        $this->SetTextColor(0); // Couleur du texte : noir
785        // Titre centre
786        $xc += $this->space_h+($logo?$this->icone_h:0);
787        $this->SetXY($xc, $yc);
788        $this->Cell($logo?($this->largeur_pour_titre):($this->largeur_pour_titre+$this->icone_h-$this->space_h), 12, html_entity_decode(_T("asso:$titre")), 0, 0, 'C', true);
789        $yc += 12;
790        $this->Ln($this->space_v); // Saut de ligne
791        $yc += $this->space_v;
792        // typo
793        $this->SetFont('Arial', '', 12); // police : Arial 12px
794        $this->SetFillColor(235); // Couleur de remplissage : gris-92.2%
795        // Sous titre Nom de l'association
796        $this->SetXY($xc, $yc);
797        $this->Cell($logo?$this->largeur_pour_titre:$this->largeur_pour_titre+$this->icone_h-$this->space_h, 6, utf8_decode(_T('asso:cpte_export_association', array('nom'=>$GLOBALS['association_metas']['nom']) )), 0, 0, 'C', true);
798        $yc += 6;
799        $this->Ln($this->space_v/2); // Saut de ligne
800        $yc += $this->space_v/2;
801        // typo
802        $this->SetFont('Arial', '', 12); // police : Arial 12px
803        $this->SetFillColor(235); // Couleur de fond : gris-92.2%
804        //Sous titre Intitule de l'exercice
805        $this->SetXY($xc, $yc);
806        $this->Cell($logo?$this->largeur_pour_titre:$this->largeur_pour_titre+$this->icone_h-$this->space_h, 6, utf8_decode(_T('asso:cpte_export_exercice', array('titre'=>sql_getfetsel('intitule','spip_asso_exercices', 'id_exercice='.$this->exercice) ) )), 0, 0, 'C', true);
807        $yc += 6;
808        $this->Ln($this->space_v); // Saut de ligne
809        $yc += $this->space_v;
810        $this->Rect($this->xx, $this->yy, $this->largeur_utile, $yc-$this->marge_haut); // Rectangle tout autour de l'entete
811        $this->yy = $yc; // on sauve la position du curseur dans la page
812    }
813
814    // Fichier final envoye
815    function File($titre='etat_comptes') {
816        $this->Output($titre.'_'.($this->exercice?$this->exercice:$this->annee).'_'.$this->destination.'.pdf', 'I');
817    }
818
819    // on affiche les totaux (recettes et depenses) d'un exercice des differents comptes de la classe specifiee
820    function association_liste_totaux_comptes_classes($classes, $prefixe='', $direction='-1', $exercice=0, $destination=0) {
821        if( !is_array($classes) ) { // a priori une chaine ou un entier d'une unique classe
822            $liste_classes = array( $classes ) ; // transformer en tableau (puisqu'on va operer sur des tableaux);
823        } else { // c'est un tableau de plusieurs classes
824            $liste_classes = $classes;
825        }
826        // Les coordonnees courantes
827        $xc = $this->xx+$this->space_h;
828        $y_orig = $this->yy+$this->space_v;
829        $yc = $y_orig+$this->space_v;
830        // typo
831        $this->SetFont('Arial', 'B', 14); // police: Arial gras 14px
832        $this->SetFillColor(235); // Couleursdu fond du cadre de titre : gris-92.2%
833        $this->SetTextColor(0); // Couleurs du texte du cadre de titre
834        // Titre centre
835        $titre = $prefixe.'_'. ( ($direction) ? (($direction<0)?'depenses':'recettes') : 'soldes' );
836        $this->SetXY($xc, $yc);
837        $this->Cell($this->largeur_utile, 10, html_entity_decode(_T("asso:$titre")), 0, 0, 'C');
838        $yc += 10;
839        $this->Ln($this->space_v); // Saut de ligne
840        $yc += $this->space_v;
841        // initialisation du calcul+affichage des comptes
842        $total_valeurs = $total_recettes = $total_depenses = 0;
843        $chapitre = '';
844        $i = 0;
845        foreach ( $liste_classes as $rang => $classe ) { // calcul+affichage par classe
846            $query = association_calcul_soldes_comptes_classe($classe, $this->exercice, $this->destination, $direction );
847            $this->SetFont('Arial', '', 12); // police : Arial 12px
848            while ($data = sql_fetch($query)) {
849                $this->SetXY($xc, $yc); // positionne le curseur
850                $new_chapitre = substr($data['code'], 0, 2);
851                if ($chapitre!=$new_chapitre) { // debut de categorie
852                    $this->SetFillColor(225); // Couleur de fond de la ligne : gris-92.2%
853                    $this->Cell(20, 6, utf8_decode($new_chapitre), 0, 0, 'L', true);
854                    $this->Cell(($this->largeur_utile)-(2*$this->space_h+20), 6, utf8_decode(($GLOBALS['association_metas']['plan_comptable_prerenseigne']?association_plan_comptable_complet($new_chapitre):sql_getfetsel('intitule','spip_asso_plan',"code='$new_chapitre'"))), 0, 0, 'L', true);
855                    $chapitre = $new_chapitre;
856                    $this->Ln(); // Saut de ligne
857                    $yc += 6;
858                }
859                $this->SetFillColor(245); // Couleur de fond du total : gris-96.1%
860                $this->SetXY($xc, $yc); // positionne le curseur
861#               if ( floatval($data['valeurs']) || floatval($data['recettes']) || floatval($data['depenses']) ) { // non-zero...
862                    $this->Cell(20, 6, utf8_decode($data['code']), 0, 0, 'R', true);
863                    $this->Cell(($this->largeur_utile)-(2*$this->space_h+50), 6, utf8_decode($data['intitule']), 0, 0, 'L', true);
864                    $this->Cell(30, 6, association_nbrefr($data['valeurs']), 0, 0, 'R', true);
865                    if ($direction) { // mode liste comptable
866                        $this->Cell(30, 6, association_nbrefr($data['valeurs']), 0, 0, 'R', true);
867                        $total_valeurs += $data['valeurs'];
868                    } else { // mode liste standard
869                        $this->Cell(30, 6, association_nbrefr($data['depenses']>0?$data['depenses']:$data['recettes']), 0, 0, 'R', true);
870                        $total_recettes += $data['recettes'];
871                        $total_depenses += $data['depenses'];
872                        $total_valeurs += $data['soldes'];
873                    }
874                    $this->Ln(); // Saut de ligne
875                    $yc += 6;
876#               }
877            }
878        }
879        $this->SetXY($xc, $yc); // positionne le curseur
880        $this->SetFillColor(215); // Couleur de fond : 84.3%
881        if ($direction) { // mode liste comptable : charge, produit, actifs, passifs
882            $this->Cell(($this->largeur_utile)-(2*$this->space_h+30), 6, html_entity_decode(_T("asso:$prefixe".'_total')), 1, 0, 'R', true);
883            $this->Cell(30, 6, association_nbrefr($total_valeurs), 1, 0, 'R', true);
884        } else { // mode liste standard : contributions volontaires et autres
885            $this->Cell(($this->largeur_utile)/2-(2*$this->space_h+30), 6, html_entity_decode(_T("asso:$prefixe".'_total_depenses')), 1, 0, 'R', true);
886            $this->Cell(30, 6, association_nbrefr($total_depenses), 1, 0, 'R', true);
887            $xc += ( $this->largeur_utile)/2;
888            $this->SetXY($xc, $yc); // positionne le curseur sur l'autre demi page
889            $this->Cell(($this->largeur_utile)/2-(2*$this->space_h+30), 6, html_entity_decode(_T("asso:$prefixe".'_total_recettes')), 1, 0, 'R', true);
890            $this->Cell(30, 6, association_nbrefr($total_recettes), 1, 0, 'R', true);
891        }
892        $yc += 6;
893        $this->Ln($this->space_v); // Saut de ligne
894        $yc += $this->space_v;
895        $this->Rect($this->xx, $y_orig, $this->largeur_utile, $yc-$y_orig); // Rectangle tout autour
896        $this->yy = $yc; // on sauve la position du curseur dans la page
897        return $total_valeurs;
898    }
899
900    // on affiche le resultat comptable net : benefice ou deficit
901    function association_liste_resultat_net($lesRecettes, $lesDepenses) {
902        // Les coordonnees courantes
903        $xc = $this->xx+$this->space_h;
904        $y_orig = $this->yy+$this->space_v;
905        $yc = $y_orig+$this->space_v;
906        // typo
907        $this->SetFont('Arial', 'B', 14); // police : Arial gras 14px
908        $this->SetFillColor(235); // Couleur du fond : gris-92.2%
909        $this->SetTextColor(0); // Couleur du texte : noir
910        // Titre centre
911        $this->SetXY($xc, $yc);
912        $this->Cell($this->largeur_utile, 10, html_entity_decode(_T('asso:cpte_resultat_titre_resultat')), 0, 0, 'C');
913        $yc += 10;
914        $this->Ln($this->space_v); // Saut de ligne
915        $yc += $this->space_v;
916        $this->SetFillColor(215); // Couleur de fond : gris-84.3%
917        $leSolde = $lesRecettes-$lesDepenses;
918        $this->SetXY($xc, $yc);
919        $this->Cell(($this->largeur_utile)-(2*$this->space_h+30), 6, html_entity_decode(_T('asso:cpte_resultat_'.($leSolde<0?'perte':'benefice'))), 1, 0, 'R', true);
920        $this->Cell(30, 6, association_nbrefr($leSolde), 1, 0, 'R', true);
921        $yc += 6;
922        $this->Ln($this->space_v); // Saut de ligne
923        $yc += $this->space_v;
924        $this->Rect($this->xx, $y_orig, $this->largeur_utile, $yc-$y_orig); // Rectangle tout autour
925        $this->yy = $yc; // on sauve la position du curseur dans la page
926    }
927
928} // fin classe
929
930} // fin if
931
932?>
Note: See TracBrowser for help on using the repository browser.