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

Last change on this file since 53976 was 53976, checked in by marcel@…, 9 years ago

barre de saisie rapide : Dépense, Recette, Virement et Contibution Solidaire avec positionnement des comptes correspondants.

File size: 13.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")) return;
13
14// recupere dans la table de comptes et celle des destinations la liste des destinations associees a une operation
15// le parametre correspond a l'id_compte de l'operation dans spip_asso_compte (et spip_asso_destination)
16function association_liste_destinations_associees($id_compte)
17{
18        if (!$id_compte) return '';
19
20        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'))
21        {
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) $destination = '';
28        }
29        else
30        {
31                $destination='';
32        }
33
34        return $destination;
35}
36
37// retourne une liste d'option HTML de l'ensemble des destinations de la base, ordonee par intitule
38function association_toutes_destination_option_list()
39{
40        $liste_destination = '';
41        $sql = sql_select('id_destination,intitule', 'spip_asso_destination', "", "", "intitule");
42        while ($destination_info = sql_fetch($sql)) {
43                $id_destination = $destination_info['id_destination'];
44                $liste_destination .= "<option value='$id_destination'>".$destination_info['intitule'].'</option>';
45        }
46        return $liste_destination;
47}
48
49// retourne dans un <div> le code HTML/javascript correspondant au selecteur de destinations dynamique
50// le premier parametre permet de donner un tableau de destinations deja selectionnees(ou '' si on ajoute une operation)
51// le second parametre (optionnel) permet de specifier si on veut associer une destination unique, par default on peut ventiler sur
52// plusieurs destinations
53// le troisieme parametre permet de regler une destination par defaut[contient l'id de la destination] - quand $destination est vide
54function association_editeur_destinations($destination, $unique='', $defaut='')
55{
56        // recupere la liste de toutes les destination dans un code HTML <option value="destination_id">destination</option>
57        $liste_destination = association_toutes_destination_option_list();
58
59        $res = '';
60       
61        if ($liste_destination) {
62                $res = "<script type='text/javascript' src='".find_in_path("javascript/jquery.destinations_form.js")."'></script>";
63                $res .= '<label for="destination"><strong>'
64                . _T('asso:destination')
65                . '</strong></label>'
66                . '<div id="divTxtDestination" class="formulaire_edition_destinations">';
67
68                $idIndex=1;
69                if ($destination != '') { /* si on a une liste de destinations (on edite une operation) */
70                        foreach ($destination as $destId => $destMontant) {                                             
71                                $liste_destination_selected = preg_replace('/(value=\''.$destId.'\')/', '$1 selected="selected"', $liste_destination);
72                                $res .= '<div class="formo" id="row'.$idIndex.'">';
73                                $res .= '<li class="editer_id_dest['.$idIndex.']">'
74                                . '<select name="id_dest['.$idIndex.']" id="id_dest['.$idIndex.']" >'
75                                . $liste_destination_selected
76                                . '</select></li>';
77                                if ($unique==false) {
78                                        $res .= '<li class="editer_montant_dest['.$idIndex.']"><input name="montant_dest['.$idIndex.']" value="'
79                                        . association_nbrefr(association_recupere_montant($destMontant))
80                                        . '" type="text" id="montant_dest['.$idIndex.']" /></li>'
81                                        . "<button class='destButton' type='button' onClick='addFormField(); return false;'>+</button>";
82                                        if ($idIndex>1) {
83                                                $res .= "<button class='destButton' type='button' onClick='removeFormField(\"#row".$idIndex."\"); return false;'>-</button>";
84                                        }
85                                }
86                                $res .= '</div>';
87                                $idIndex++;
88                        }
89                }
90                else {/* pas de destination deja definies pour cette operation */
91                        if ($defaut!='') {
92                                $liste_destination = preg_replace('/(value=\''.$defaut.'\')/', '$1 selected="selected"', $liste_destination);
93                        }
94                        $res .= '<div id="row1" class="formo"><li class="editer_id_dest[1]"><select name="id_dest[1]" id="id_dest[1]" >'
95                        . $liste_destination
96                        . '</select></li>';
97                        if (!$unique) {
98                                $res .= '<li class="editer_montant_dest[1]"><input name="montant_dest[1]" value="'
99                                . ''
100                                . '" type="text" id="montant_dest[1]"/></li>'
101                                . "<button class='destButton' type='button' onClick='addFormField(); return false;'>+</button>";
102                        }
103                        $res .= '</div>';
104                }
105
106                if ($unique==false) $res .= '<input type="hidden" id="idNextDestination" value="'.($idIndex+1).'">';
107                $res .= '</div>';
108        }
109        return $res;
110}
111
112/* Ajouter une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op */
113function association_ajouter_operation_comptable($date, $recette, $depense, $justification, $imputation, $journal, $id_journal)
114{
115        include_spip('base/association');               
116
117        $id_compte = sql_insertq('spip_asso_comptes', array(
118                    'date' => $date,
119                    'imputation' => $imputation,
120                    'recette' => $recette,
121                    'depense' => $depense,
122                    'journal' => $journal,
123                    'id_journal' => $id_journal,
124                    'justification' => $justification));
125
126        // on laisse passer ce qui est peut-etre une erreur,
127        // pour ceux qui ne definisse pas de plan comptable.
128        // Mais ce serait bien d'envoyer un message d'erreur au navigateur
129        // plutot que de le signaler seulement dans les log
130        if (!$imputation) {
131                spip_log("imputation manquante dans $id_compte, $date, $recette, $depense, $justification, $journal, $id_journal");
132        }
133        /* Si on doit gerer les destinations */
134        if ($GLOBALS['association_metas']['destinations']=="on")
135        {
136                association_ajouter_destinations_comptables($id_compte, $recette, $depense);
137        }
138
139        return $id_compte;
140
141}
142
143/* modifier une operation dans spip_asso_comptes ainsi que si necessaire dans spip_asso_destination_op */
144function association_modifier_operation_comptable($date, $recette, $depense, $justification, $imputation, $journal, $id_journal, $id_compte)
145{
146        include_spip('base/association');               
147
148        /* Si on doit gerer les destinations */
149        if ($GLOBALS['association_metas']['destinations']=="on")
150        {
151                $err = association_ajouter_destinations_comptables($id_compte, $recette, $depense);
152        }
153
154        // 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
155        if ($id_journal) {
156                sql_updateq('spip_asso_comptes', array(
157                            'date' => $date,
158                            'imputation' => $imputation,
159                            'recette' => $recette,
160                            'depense' => $depense,
161                            'journal' => $journal,
162                            'id_journal' => $id_journal,
163                            'justification' => $justification),
164                            "id_compte=$id_compte");
165        } else {
166                sql_updateq('spip_asso_comptes', array(
167                            'date' => $date,
168                            'imputation' => $imputation,
169                            'recette' => $recette,
170                            'depense' => $depense,
171                            'journal' => $journal,
172                            'justification' => $justification),
173                            "id_compte=$id_compte");
174
175        }
176
177        return $err;
178}
179
180/* fonction de verification des montants de destinations entres */
181/* le parametre d'entree est le montant total attendu, les montants des destinations sont recuperes */
182/* directement dans $_POST */
183function association_verifier_montant_destinations($montant_attendu)
184{
185        $err = '';
186
187        $toutesDestinations = _request('id_dest');
188        $toutesDestinationsMontants = _request('montant_dest');
189
190        /* 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) */
191        $total_destination = 0;
192        $id_inserted = array();
193
194        if (count($toutesDestinations) > 1) {
195                foreach ($toutesDestinations as $id => $id_destination)
196                {               
197                        /* on verifie qu'on n'a pas deja insere une destination avec cette id */
198                        if (!array_key_exists($id_destination,$id_inserted)) {
199                                $id_inserted[$id_destination]=0;
200                        }
201                        else {
202                                $err = _T('asso:erreur_destination_dupliquee');
203                        }
204
205                        $total_destination += association_recupere_montant($toutesDestinationsMontants[$id]); /* les montants sont dans un autre tableau aux meme cles */
206                }
207       
208                /* on verifie que la somme des montants des destinations correspond au montant attendu */
209                if ($montant_attendu != $total_destination) {
210                        $err .= _T('asso:erreur_montant_destination');
211                }
212
213        } 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 */
214                /* quand on a une seule destination, l'id dans les tableaux est forcement 1 par contruction de l'editeur */
215                if ($toutesDestinationsMontants[1]) {
216                        $montant = association_recupere_montant($toutesDestinationsMontants[1]);
217                        /* on verifie que le montant indique correspond au montant attendu */
218                        if ($montant_attendu != $montant) {
219                                $err = _T('asso:erreur_montant_destination');
220                        }
221                }
222        }
223        return $err;
224}
225
226/* fonction permettant d'ajouter/modifier les destinations comptables (presente dans $_POST) a une operation comptable */
227function association_ajouter_destinations_comptables($id_compte, $recette, $depense)
228{
229        include_spip('base/association');
230
231        /* on efface de la table destination_op toutes les entrees correspondant a cette operation  si on en trouve*/
232        sql_delete("spip_asso_destination_op", "id_compte=$id_compte");
233
234        if ($recette>0) {
235                $attribution_montant = "recette";
236        }
237        else {
238                $attribution_montant = "depense";
239        }
240
241        $toutesDestinations = _request('id_dest');
242        $toutesDestinationsMontants = _request('montant_dest');
243
244        if (count($toutesDestinations) > 1) {
245                foreach ($toutesDestinations as $id => $id_destination) {
246                        $montant = association_recupere_montant($toutesDestinationsMontants[$id]);      /* le tableau des montants a des cles indentique a celui des id */
247                        sql_insertq('spip_asso_destination_op', array(
248                            'id_compte' => $id_compte,
249                            'id_destination' => $id_destination,
250                            $attribution_montant => $montant));
251                }
252        } else { /* une seule destination, le montant peut ne pas avoir ete precise, on entre directement le total recette+depense */
253                sql_insertq('spip_asso_destination_op', array(
254                    'id_compte' => $id_compte,
255                    'id_destination' => $toutesDestinations[1],
256                    $attribution_montant => $depense+$recette));
257        }
258}
259
260function inc_association_imputation_dist($nom, $table='')
261{
262        $champ = ($table ? ($table . '.') : '') . 'imputation';
263        return $champ . '=' . sql_quote($GLOBALS['association_metas'][$nom]);
264}
265
266/* valide le plan comptable: on doit avoir au moins deux classes de comptes differentes */
267/* le code du compte doit etre unique */
268/* le code du compte doit commencer par un chiffre egal a sa classe */
269function association_valider_plan_comptable()
270{
271        $classes = array();
272        $codes = array();
273        /* recupere le code et la classe de tous les comptes du plan comptable */
274        $query = sql_select("code, classe", "spip_asso_plan");
275        while ($data = sql_fetch($query)) {
276                $classe = $data['classe'];
277                $code = $data['code'];
278                $classes[$classe] = 0; /* on comptes les classes differentes */
279                if(array_key_exists($code, $codes)) {
280                        return false; /* on a deux fois le meme code */
281                } else {
282                        $codes[$code] = 0;
283                }
284                /* on verifie que le code est bien de la forme chiffre-chiffre-caracteres alphanumeriques et que le premier digit correspond a la classe */
285                if ((!preg_match("/^[0-9]{2}\w*$/", $code)) || ($code[0] != $classe)) return false;
286        }
287        if (count($classes)<2) return false; /* on doit avoir au moins deux classes differentes */
288
289        return true;
290}
291/* retourne un tableau $code => $intitule trie sur $code et de classe $val */
292function association_liste_plan_comptable($val) {
293        $res = array();
294        /* recupere le code et l'intitule de tous les comptes de classe $val */
295        $query = sql_select("code, intitule", "spip_asso_plan", "classe='".$val."'", "", "code");
296        while ($data = sql_fetch($query)) {
297                $code = $data['code'];
298                $intitule = $data['intitule'];
299                $res[$code] = $intitule;
300        }
301        return $res;
302}
303
304/* si il existe un compte 58x on le retourne sinon on cree le compte 581 et on le retourne */
305function association_creer_compte_virement_interne() {
306        /* on recupere tous les comptes de la classe "financier" (classe 5) */
307        $res = association_liste_plan_comptable($GLOBALS['association_metas']['classe_banques']);
308        /* existe-t-il le compte 58x */
309        foreach($res as $code => $libelle) {
310                if (substr($code,0,2)=='58') {
311                        /* j'ai trouve un code qui commence par 58 */
312                        $trouve = TRUE;
313                }
314        }
315        /* j'ai rien trouve, je cree le compte 581 et je retourne */
316        if(!$trouve) {
317                $code = '581';
318                $id_plan = sql_insertq('spip_asso_plan', array(
319                        'code' => $code,
320                        'intitule' => _T('asso:virement_interne'),
321                        'classe' => '5',
322                        'type_op' => 'multi',
323                        'solde_anterieur' => '0',
324                        'date_anterieure' => date('Y-m-d'),
325                        'commentaire' => _T('asso:compte_cree_automatiquement'),
326                        'active' => '1',
327                        'maj' => date('Y-m-d')
328                ));
329        }
330
331        return $code;
332}
333
334?>
Note: See TracBrowser for help on using the repository browser.