rapports configurables (closes #257021)

authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
changeset770f22a7a535
branchdefault
phasedraft
hiddenno
parent revision#a6dca0423d32 supprime état de facturation (closes #261949)
child revision#dcd2c800fa19 [comptas] permet plusieurs sous-comptas, #21f227c3477f [render] pycompta-render to html, json or csv (closes #268913)
files modified by this revision
lib/comptas.py
lib/config.py
lib/definitions.py
lib/entities.py
lib/render.py
lib/visitors.py
main.py
test/smoketest.py
test/test_lib.py
# HG changeset patch
# User Nicolas Chauvat <nicolas.chauvat@logilab.fr>
# Date 1348769066 -7200
# Thu Sep 27 20:04:26 2012 +0200
# Node ID 770f22a7a535d109a07465e6f7994336a682168e
# Parent a6dca0423d32add077391a87a264e6e540cb822b
rapports configurables (closes #257021)

diff --git a/lib/comptas.py b/lib/comptas.py
@@ -76,19 +76,20 @@
1  class Comptabilite(AbstractCompta) :
2      """
3      Regroupe les différents livres
4      """
5 
6 -    def __init__(self, debut, fin, ecritures, immobilisations, sous_compta=None) :
7 +    def __init__(self, debut, fin, ecritures, immobilisations, rapports, sous_compta=None) :
8          """
9          --pre:
10          type(debut) is DateTimeType
11          type(fin) is DateTimeType
12          """
13          self.debut = debut
14          self.fin = fin
15          self.ecritures = ecritures
16 +        self.rapports = rapports
17 
18          self.paye = sous_compta
19          if self.paye :
20              report_paye = self.paye.get_reports()
21          else:
@@ -97,12 +98,12 @@
22          self.livrimmo = LivreImmobilisations(immobilisations)
23          amort = self.livrimmo.get_amortissements(debut, fin)
24          self.journal = Journal(ecritures+amort+report_paye)
25          self.glivre = GrandLivre(self.journal)
26          self.balance = Balance(self.glivre)
27 -        self.resultat = CompteResultat(self.glivre)
28 -        self.bilan = Bilan(self.resultat)
29 +        self.resultat = CompteResultat(self.glivre, rapports)
30 +        self.bilan = Bilan(self.resultat, rapports)
31 
32          if self.paye :
33              toutes_ecritures = ecritures + self.paye.journal.ecritures
34          else :
35              toutes_ecritures = ecritures
diff --git a/lib/config.py b/lib/config.py
@@ -21,19 +21,21 @@
36                       'repertoire_ecritures_paye_prev':'./paye/ecritures_prev',
37                       'immobilisations':'livre-immo.xml',
38                       'immobilisations_prev':'livre-immo.prev.xml',
39                       'comptes.png':'comptes.png',
40                       'tresorerie.png':'tresorerie.png',
41 +                     'rapports': 'rapports.py',
42                       }
43 
44      def normalize_paths(self) :
45          """normalise tous les chemins supposés relatifs à répertoire
46          du fichier de config
47          """
48          source = os.path.dirname(self.config_path)
49          self.data['exercice'] = source
50 -        for key in ['societe', 'immobilisations', 'immobilisations_prev'] :
51 +        for key in ['societe', 'immobilisations', 'immobilisations_prev',
52 +                    'rapports'] :
53              self.data[key] = absjoin(source, self.data[key])
54          for key in ['repertoire_ecritures', 'repertoire_ecritures_prev',
55                      'repertoire_ecritures_paye', 'repertoire_ecritures_paye_prev'] :
56              self.data[key] = absjoin(source, self.data[key])
57          dest = self.data['repertoire_cible']
diff --git a/lib/definitions.py b/lib/definitions.py
@@ -318,11 +318,14 @@
58            (u'416', None),
59            (u'418', None)],
60           [(u'491', None)],
61           []),
62          (u'3.2.3.2', u'Autres',
63 -         [(u'4096', None),
64 +         [(u'4093', None),
65 +          (u'4094', None),
66 +          (u'4095', None),
67 +          (u'4096', None),
68            (u'4097', None),
69            (u'4098', None),
70            (u'425', None),
71            (u'428', 'D'),
72            (u'438', 'D')],
@@ -638,6 +641,11 @@
73         []),
74        ]),
75      ]
76 
77 
78 -
79 +RAPPORTS = {
80 +    'CHARGES': CHARGES,
81 +    'PRODUITS': PRODUITS,
82 +    'ACTIF': ACTIF,
83 +    'PASSIF': PASSIF,
84 +    }
diff --git a/lib/entities.py b/lib/entities.py
@@ -13,11 +13,10 @@
85  import types
86  import logging
87 
88  from pycompta import L1, DEBUT #, FIN
89  from pycompta import RelativeDateTime, DateTimeType
90 -from pycompta.lib import definitions
91 
92  # ECRITURES ####################################################################
93 
94  class ExceptionEcriture(Exception):
95      """Ecriture a un probleme: est pas equilibree"""
@@ -505,12 +504,13 @@
96  class CompteResultat(object):
97      """
98      Compte de résultat qui regroupe par postes les charges et les produits
99      """
100 
101 -    def __init__(self, glivre) :
102 +    def __init__(self, glivre, rapports) :
103          self.glivre = glivre
104 +        self.rapports = rapports
105 
106      def get_total(self, debut, fin, poste) :
107          """
108          renvoie le total d'un poste pour la période
109          """
@@ -531,19 +531,19 @@
110 
111      def get_resultat(self, debut, fin) :
112          """
113          renvoie le couple (total chargs, total produits)
114          """
115 -        charges = self.get_total(debut, fin, ('','',[],definitions.CHARGES))
116 -        produits = self.get_total(debut, fin, ('','',[],definitions.PRODUITS))
117 +        charges = self.get_total(debut, fin, ('','',[], self.rapports['CHARGES']))
118 +        produits = self.get_total(debut, fin, ('','',[],self.rapports['PRODUITS']))
119          # assert charges <= 0, "Charges %d, Produits %d" % (charges,produits)
120          return -charges, produits
121 
122      def check(self): # XXX FIXME
123          errors = []
124          comptes = set()
125 -        for poste in definitions.CHARGES + definitions.PRODUITS:
126 +        for poste in self.rapports['CHARGES'] + self.rapports['PRODUITS']:
127              for c_num, c in flatten_desc(poste):
128                  comptes.add(c_num)
129          for c_num in comptes:
130              for num, c in self.glivre.get_comptes(c_num):
131                  c.tag_resultat = True
@@ -558,12 +558,13 @@
132  class Bilan(object):
133      """
134      Bilan comptable qui regroupe par postes actif et passif
135      """
136 
137 -    def __init__(self, resultat) :
138 +    def __init__(self, resultat, rapports) :
139          self.resultat = resultat
140 +        self.rapports = rapports
141 
142      def _get_solde_compte(self, debut, fin, cnum, condition) :
143          """
144          renvoie le solde d'un compte si condition est satisfaite
145          """
@@ -617,12 +618,12 @@
146 
147      def get_bilan(self, debut, fin) :
148          """
149          renvoie couple des montants (actif, passif)
150          """
151 -        p_actif = ('', '', [], [], definitions.ACTIF)
152 -        p_passif = ('', '', [], definitions.PASSIF)
153 +        p_actif = ('', '', [], [], self.rapports['ACTIF'])
154 +        p_passif = ('', '', [], self.rapports['PASSIF'])
155 
156          brut, amort = self.get_solde_compte_diff(debut, fin, p_actif)
157          actif = brut + amort
158          passif = self.get_solde_poste(debut, fin, p_passif)
159 
@@ -638,14 +639,14 @@
160          return actif == passif
161 
162      def check(self):
163          errors = []
164          comptes = set()
165 -        for poste in definitions.ACTIF:
166 +        for poste in self.rapports['ACTIF']:
167              for c_num, c in flatten_desc(poste, True):
168                  comptes.add(c_num)
169 -        for poste in definitions.PASSIF:
170 +        for poste in self.rapports['PASSIF']:
171              for c_num, c in flatten_desc(poste):
172                  comptes.add(c_num)
173          for c_num in comptes:
174              for num, c in self.resultat.glivre.get_comptes(c_num):
175                  c.tag_bilan = True
diff --git a/lib/render.py b/lib/render.py
@@ -56,14 +56,14 @@
176      visitors.write_journal(file(JO+'xml','w'), compta.journal, debut, fin)
177      visitors.write_grand_livre(file(GL+'xml','w'), compta.glivre, debut, fin)
178      visitors.write_balance(file(BA+'xml','w'), compta.balance, debut, fin)
179      if not isinstance(compta, Comptabilite):
180          return
181 -    visitors.write_compte_resultat(file(CR+'xml','w'), compta.resultat, compta.debut, fin)
182 -    visitors.write_bilan(file(BI+'xml','w'), compta.bilan, compta.debut, fin)
183 +    visitors.write_compte_resultat(file(CR+'xml','w'), compta.resultat, compta.debut, fin, compta.rapports)
184 +    visitors.write_bilan(file(BI+'xml','w'), compta.bilan, compta.debut, fin, compta.rapports)
185      visitors.write_livre_immo(file(IM+'xml','w'), compta.livrimmo, debut, fin)
186 -    visitors.write_bilan_immo(file(IB+'xml','w'), compta.resultat, debut, fin)
187 +    visitors.write_bilan_immo(file(IB+'xml','w'), compta.resultat, debut, fin, compta.rapports)
188      if compta.paye:
189          visitors.write_journal(file(JP+'xml','w'), compta.paye.journal, debut, fin)
190          visitors.write_grand_livre(file(GP+'xml','w'), compta.paye.glivre, debut, fin)
191          visitors.write_balance(file(BP+'xml','w'), compta.paye.balance, debut, fin)
192      visitors.write_journal(file(BJ+'xml','w'), compta.banque_journal, debut, fin)
diff --git a/lib/visitors.py b/lib/visitors.py
@@ -8,11 +8,11 @@
193  """
194 
195  __revision__ = "$Id: visitors.py,v 1.34 2005-10-31 18:10:57 nico Exp $"
196 
197  from pycompta import L1, version, DEBUT
198 -from pycompta.lib import entities, definitions
199 +from pycompta.lib import entities
200  from pycompta import DateTimeDelta, DateTimeType
201 
202  def toxml(s) :
203      """
204      Transforme objet en chaîne prête à être écrite dans un fichier XML.
@@ -100,24 +100,24 @@
205              _w_i(out, glivre, n, debut, fin, mul)
206      else:
207          write_vue_comptes(out, glivre, vc)
208      out.write('</poste>\n')
209 
210 -def write_bilan_immo(out, bimmo, debut, fin) :
211 +def write_bilan_immo(out, bimmo, debut, fin, rapports) :
212      """
213      Ecrit le bilan des immobilisations en XML.
214      """
215      out.write(ENTETE)
216      out.write('<bilan-immo debut="%s" fin="%s" ' % (debut.date, fin.date))
217      comptes = []
218 -    for poste in definitions.IMMO_AMORT:
219 +    for poste in rapports['IMMO_AMORT']:
220          comptes += list(all_comptes(poste))
221      vc = bimmo.glivre.get_vue_comptes(debut, fin, comptes)
222      out.write(' report-solde="%i" solde="%i"' % (-1*vc.total_debut, -1*vc.total_fin))
223      out.write(' var-credit="%i" var-debit="%i"' % (vc.variations))
224      out.write('>\n')
225 -    for p in definitions.IMMO_AMORT :
226 +    for p in rapports['IMMO_AMORT']:
227          _w_i(out, bimmo.glivre, p, debut, fin, 1)
228      out.write('</bilan-immo>\n')
229 
230  # JOURNAL ######################################################################
231 
@@ -243,23 +243,23 @@
232  	for cnum, cond in liste_comptes :
233  	    out.write('<compte num="%s" credit="%s" debit="%s" />\n' \
234  		      % ((cnum,) + resultat.glivre.get_solde_comptes(debut, fin, cnum)))
235      out.write('</poste>\n')
236 
237 -def write_compte_resultat(out, resultat, debut, fin) :
238 +def write_compte_resultat(out, resultat, debut, fin, rapports) :
239      """
240      Ecrit le compte de résultat en XML.
241      """
242      out.write(ENTETE)
243      out.write('<compte-resultat debut="%s" fin="%s">\n' % (debut.date, fin.date))
244      charges, produits = resultat.get_resultat(debut, fin)
245      out.write('  <charges id="charges" montant="%s">\n' % charges)
246 -    for p in definitions.CHARGES :
247 +    for p in rapports['CHARGES']:
248          _w_c_r(out, resultat, p, debut, fin, -1)
249      out.write('  </charges>\n')
250      out.write('  <produits id="produits" montant="%s">\n' % produits)
251 -    for p in definitions.PRODUITS :
252 +    for p in rapports['PRODUITS']:
253          _w_c_r(out, resultat, p, debut, fin, 1)
254      out.write('  </produits>\n')
255      out.write('</compte-resultat>\n')
256 
257  # BILAN ########################################################################
@@ -301,23 +301,23 @@
258  		      % ((cnum,) + bilan.resultat.glivre.get_solde_comptes(debut, fin, cnum) +
259                           (cond or '',)))
260      out.write('</poste>\n')
261 
262 
263 -def write_bilan(out, bilan, debut, fin) :
264 +def write_bilan(out, bilan, debut, fin, rapports) :
265      """
266      Ecrit le bilan en XML.
267      """
268      out.write(ENTETE)
269      out.write('<bilan debut="%s" fin="%s">\n' % (debut.date, fin.date))
270      actif, passif = bilan.get_bilan(DEBUT, fin) # XXX was debut
271      out.write('  <actif montant="%s">\n' % actif)
272 -    for n in definitions.ACTIF :
273 +    for n in rapports['ACTIF'] :
274          _w_b_actif(out, bilan, n, DEBUT, fin, -1) # XXX
275      out.write('  </actif>\n')
276      out.write('  <passif montant="%s">\n' % passif)
277 -    for n in definitions.PASSIF :
278 +    for n in rapports['PASSIF'] :
279          _w_b_passif(out, bilan, n, DEBUT, fin, 1)
280      out.write('  </passif>\n')
281      out.write('</bilan>\n')
282 
283  # PILOTE #######################################################################
diff --git a/main.py b/main.py
@@ -75,15 +75,17 @@
284      else:
285          ecritures_paye = None
286      immo = xmlreader.get_immobilisations(file(config['immobilisations']))
287      log(" OK (%s ecritures lues)\n" % (len(ecritures)+len(immo)))
288      log("   calcul...")
289 +    rapports = dict()
290 +    execfile(config.data['rapports'], rapports)
291      if ecritures_paye:
292          compta_paye = SousComptabilite(debut, fin, ecritures_paye, 'Paye')
293 -        compta = Comptabilite(debut, fin, ecritures, immo, compta_paye)
294 +        compta = Comptabilite(debut, fin, ecritures, immo, rapports, compta_paye)
295      else:
296 -        compta = Comptabilite(debut, fin, ecritures, immo)
297 +        compta = Comptabilite(debut, fin, ecritures, immo, rapports)
298      log(" OK\n")
299 
300      # vérifie cohérence
301      errors = compta.check()
302      if errors:
@@ -116,15 +118,17 @@
303              compta_paye_prev = SousComptabilite(debut, prev,
304                                                  ecritures_paye+ecritures_paye_prev)
305              compta_prev = Comptabilite(debut, prev,
306                                         ecritures+ecritures_prev,
307                                         immo+immo_prev,
308 +                                       rapports,
309                                         compta_paye_prev)
310          else:
311              compta_prev = Comptabilite(debut, prev,
312                                         ecritures+ecritures_prev,
313 -                                       immo+immo_prev)
314 +                                       immo+immo_prev,
315 +                                       rapports)
316          log(" OK\n")
317          errors = compta_prev.check()
318          if errors:
319              logging.error('\n'.join(errors))
320      else :
diff --git a/test/smoketest.py b/test/smoketest.py
@@ -12,10 +12,11 @@
321  from logilab.common import testlib
322 
323  from pycompta import main, Date
324  from pycompta.lib import entities, xmlreader
325  from pycompta.lib.comptas import Comptabilite
326 +from pycompta.lib.definitions import RAPPORTS
327 
328  import xml.etree.ElementTree as ET
329 
330  class CasBrico(testlib.TestCase) :
331      """
@@ -139,11 +140,11 @@
332          e.add_credit(u'530',60000)
333          self.ecritures.append(e)
334 
335          for e in self.ecritures:
336              e.groupe = 'aaa'
337 -        self.compta = Comptabilite(self.debut, self.fin, self.ecritures, [])
338 +        self.compta = Comptabilite(self.debut, self.fin, self.ecritures, [], RAPPORTS)
339 
340      def test_balance(self) :
341          """v�rifie balance � la fin de l'ann�e"""
342          BALANCE = {u'101': (     0, 195000,      0, 195000),
343                     u'164': (  8400,  42000,      0,  33600),
diff --git a/test/test_lib.py b/test/test_lib.py
@@ -12,12 +12,13 @@
344  from cStringIO import StringIO
345  from logilab.common import testlib
346 
347  from pycompta import DEBUT, FIN, Date
348  from pycompta import version as VERSION
349 -from pycompta.lib import entities, visitors, xmlreader, definitions, diagrams
350 +from pycompta.lib import entities, visitors, xmlreader, diagrams
351  from pycompta.lib.comptas import Comptabilite
352 +from pycompta.lib.definitions import RAPPORTS
353 
354  #from aspects.weaver import weaver
355  #from aspects.lib.contracts import ContractAspect
356  #weaver.weave_module(entities,ContractAspect)
357 
@@ -458,11 +459,11 @@
358          self.e2 = _mk_e2()
359          self.e3 = _mk_e3()
360          self.e4 = _mk_e4()
361          self.journal = entities.Journal([self.e1, self.e2, self.e3])
362          self.glivre = entities.GrandLivre(self.journal)
363 -        self.resultat = entities.CompteResultat(self.glivre)
364 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
365 
366      def test_get_total(self) :
367          """calcul des totaux des postes"""
368          r = self.resultat
369          node = (u'1', u'Poste1', [(u'101', None)], [])
@@ -480,11 +481,11 @@
370      def test_get_resultat(self) :
371          """calcul du résultat"""
372          self.e4 = _mk_e4()
373          self.journal = entities.Journal([self.e4])
374          self.glivre = entities.GrandLivre(self.journal)
375 -        self.resultat = entities.CompteResultat(self.glivre)
376 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
377          self.assertEqual(self.resultat.get_resultat(DEBUT,FIN), (20000,30000))
378 
379  class VisitorsResultat(testlib.TestCase) :
380      """Tests pour affichage du compte de résultat"""
381 
@@ -494,14 +495,14 @@
382 
383      def test_write_1(self):
384          """écriture compte résultat en XML"""
385          self.journal = entities.Journal([self.e4])
386          self.glivre = entities.GrandLivre(self.journal)
387 -        self.resultat = entities.CompteResultat(self.glivre)
388 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
389          out = StringIO()
390          visitors.write_compte_resultat(out, self.resultat,
391 -                                       Date(2002,1,1), Date(2002,1,31))
392 +                                       Date(2002,1,1), Date(2002,1,31), RAPPORTS)
393          with file(self.datapath('compte-resultat.xml')) as stream:
394              data = stream.read().replace('x.y.z', VERSION)
395              expected = '\n'.join([line.strip() for line in data.splitlines()])
396          result = '\n'.join([line.strip() for line in out.getvalue().splitlines()])
397          self.assertMultiLineEqual(expected, result)
@@ -518,12 +519,12 @@
398          self.e1 = _mk_e1()
399          self.e2 = _mk_e2()
400          self.e3 = _mk_e3()
401          self.journal = entities.Journal([self.e1, self.e2, self.e3])
402          self.glivre = entities.GrandLivre(self.journal)
403 -        self.resultat = entities.CompteResultat(self.glivre)
404 -        self.bilan = entities.Bilan(self.resultat)
405 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
406 +        self.bilan = entities.Bilan(self.resultat, RAPPORTS)
407 
408      def test_get_soldes(self) :
409          """calcul des soldes des postes"""
410          b = self.bilan
411 
@@ -558,17 +559,17 @@
412          self.e1 = _mk_e1()
413          self.e2 = _mk_e2()
414          self.e3 = _mk_e3()
415          self.journal = entities.Journal([self.e1, self.e2, self.e3])
416          self.glivre = entities.GrandLivre(self.journal)
417 -        self.resultat = entities.CompteResultat(self.glivre)
418 -        self.bilan = entities.Bilan(self.resultat)
419 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
420 +        self.bilan = entities.Bilan(self.resultat, RAPPORTS)
421 
422      def test_write_1(self):
423          """écriture d'un bilan simple en XML"""
424          out = StringIO()
425 -        visitors.write_bilan(out, self.bilan, Date(2002,1,1), Date(2002,2,1))
426 +        visitors.write_bilan(out, self.bilan, Date(2002,1,1), Date(2002,2,1), RAPPORTS)
427          lines = out.getvalue().splitlines()
428          #self.assertEqual( out.getvalue(), '')
429          actif_found = 0
430          passif_found = 0
431          poste_found = 0
@@ -595,11 +596,11 @@
432  class FlattenTC(testlib.TestCase) :
433      """Tests pour lecture montants"""
434 
435      def test(self) :
436          """tout"""
437 -        comptes = list(entities.flatten_desc(definitions.ACTIF[0], True))
438 +        comptes = list(entities.flatten_desc(RAPPORTS['ACTIF'][0], True))
439          self.assertEqual(len(comptes), 48)
440 
441 
442  # IMMOBILISATION ###############################################################
443 
@@ -692,11 +693,12 @@
444          self.e1 = _mk_e1()
445          self.e2 = _mk_e2()
446          self.e3 = _mk_e3()
447          self.i = _mk_i()
448          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
449 -                                   [self.e1, self.e2, self.e3], [self.i])
450 +                                   [self.e1, self.e2, self.e3], [self.i],
451 +                                   RAPPORTS)
452 
453      def test_get_etat(self) :
454          """calcul de l'état au début deuxième mois"""
455          self.assertEqual( self.pilote.get_etat( Date(2002,2,-1) ),
456                            {'annee':2002, 'mois':2,
@@ -723,11 +725,12 @@
457          self.e1 = _mk_e1()
458          self.e2 = _mk_e2()
459          self.e3 = _mk_e3()
460          self.i = _mk_i()
461          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
462 -                                   [self.e1, self.e2, self.e3], [self.i])
463 +                                   [self.e1, self.e2, self.e3], [self.i],
464 +                                   RAPPORTS)
465 
466      def test_ecriture_xml(self) :
467          """écriture du pilote en XML"""
468          buf = StringIO()
469          dates = [Date(2002,1,1)]
@@ -740,11 +743,12 @@
470          self.e1 = _mk_e1()
471          self.e2 = _mk_e2()
472          self.e3 = _mk_e3()
473          self.i = _mk_i()
474          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
475 -                                   [self.e1, self.e2, self.e3], [self.i])
476 +                                   [self.e1, self.e2, self.e3], [self.i],
477 +                                   RAPPORTS)
478 
479      def test_diag_matplotlib(self) :
480          """écriture du diagramme"""
481          dates = [Date(2002,1,1), Date(2002,2,-1)]
482          diagrams.diagram('/tmp/diag.png', self.pilote, dates)