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

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

export des états comptables : correction du bug provoqué par l'abscence de FPDF

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