rapports configurables (closes #257021)

authorNicolas Chauvat <nicolas.chauvat@logilab.fr>
changeset1f04560fc4c9
branchdefault
phasedraft
hiddenyes
parent revision#43eda9a925cf Added tag pycompta-version-0.9.0, pycompta-debian-version-0.9.0-1 for changeset 8089820b8b17
child revision#bba1d3f3afd5 pycompta-render to html, json or csv
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/data/compte-resultat.xml
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 1f04560fc4c93d19a56cfd69602f4a2f1a41950b
# Parent 43eda9a925cff998f20576852686614425eeb5eb
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"""
@@ -497,12 +496,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          """
@@ -523,19 +523,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
@@ -550,12 +550,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          """
@@ -609,12 +610,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 
@@ -630,14 +631,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
@@ -72,15 +72,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:
@@ -113,15 +115,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/data/compte-resultat.xml b/test/data/compte-resultat.xml
@@ -1,7 +1,7 @@
321  <?xml version="1.0" encoding="ISO-8859-1"?>
322 -<!-- pycompta version 0.8.3 -->
323 +<!-- pycompta version 0.8.4 -->
324  <compte-resultat debut="2002-01-01" fin="2002-01-31">
325    <charges id="charges" montant="20000">
326      <poste id="1.1" nom="Charges d'exploitation" montant="20000">
327        <poste id="1.1.1" nom="Achats de marchandises" montant="20000">
328  	<compte num="607" credit="0" debit="20000" />
diff --git a/test/smoketest.py b/test/smoketest.py
@@ -12,10 +12,11 @@
329  from logilab.common import testlib
330 
331  from pycompta import main, Date
332  from pycompta.lib import entities, xmlreader
333  from pycompta.lib.comptas import Comptabilite
334 +from pycompta.lib.definitions import RAPPORTS
335 
336  import xml.etree.ElementTree as ET
337 
338  class CasBrico(testlib.TestCase) :
339      """
@@ -139,11 +140,11 @@
340          e.add_credit(u'530',60000)
341          self.ecritures.append(e)
342 
343          for e in self.ecritures:
344              e.groupe = 'aaa'
345 -        self.compta = Comptabilite(self.debut, self.fin, self.ecritures, [])
346 +        self.compta = Comptabilite(self.debut, self.fin, self.ecritures, [], RAPPORTS)
347 
348      def test_balance(self) :
349          """v�rifie balance � la fin de l'ann�e"""
350          BALANCE = {u'101': (     0, 195000,      0, 195000),
351                     u'164': (  8400,  42000,      0,  33600),
diff --git a/test/test_lib.py b/test/test_lib.py
@@ -12,12 +12,13 @@
352  from cStringIO import StringIO
353  from logilab.common import testlib
354 
355  from pycompta import DEBUT, FIN, Date
356  from pycompta import version as VERSION
357 -from pycompta.lib import entities, visitors, xmlreader, definitions, diagrams
358 +from pycompta.lib import entities, visitors, xmlreader, diagrams
359  from pycompta.lib.comptas import Comptabilite
360 +from pycompta.lib.definitions import RAPPORTS
361 
362  #from aspects.weaver import weaver
363  #from aspects.lib.contracts import ContractAspect
364  #weaver.weave_module(entities,ContractAspect)
365 
@@ -458,11 +459,11 @@
366          self.e2 = _mk_e2()
367          self.e3 = _mk_e3()
368          self.e4 = _mk_e4()
369          self.journal = entities.Journal([self.e1, self.e2, self.e3])
370          self.glivre = entities.GrandLivre(self.journal)
371 -        self.resultat = entities.CompteResultat(self.glivre)
372 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
373 
374      def test_get_total(self) :
375          """calcul des totaux des postes"""
376          r = self.resultat
377          node = (u'1', u'Poste1', [(u'101', None)], [])
@@ -480,11 +481,11 @@
378      def test_get_resultat(self) :
379          """calcul du résultat"""
380          self.e4 = _mk_e4()
381          self.journal = entities.Journal([self.e4])
382          self.glivre = entities.GrandLivre(self.journal)
383 -        self.resultat = entities.CompteResultat(self.glivre)
384 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
385          self.assertEqual(self.resultat.get_resultat(DEBUT,FIN), (20000,30000))
386 
387  class VisitorsResultat(testlib.TestCase) :
388      """Tests pour affichage du compte de résultat"""
389 
@@ -494,14 +495,14 @@
390 
391      def test_write_1(self):
392          """écriture compte résultat en XML"""
393          self.journal = entities.Journal([self.e4])
394          self.glivre = entities.GrandLivre(self.journal)
395 -        self.resultat = entities.CompteResultat(self.glivre)
396 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
397          out = StringIO()
398          visitors.write_compte_resultat(out, self.resultat,
399 -                                       Date(2002,1,1), Date(2002,1,31))
400 +                                       Date(2002,1,1), Date(2002,1,31), RAPPORTS)
401          expected = '\n'.join([line.strip() for line in file(self.datapath('compte-resultat.xml'))])
402          result = '\n'.join([line.strip() for line in out.getvalue().splitlines()])
403          self.assertMultiLineEqual(expected, result)
404 
405 
@@ -516,12 +517,12 @@
406          self.e1 = _mk_e1()
407          self.e2 = _mk_e2()
408          self.e3 = _mk_e3()
409          self.journal = entities.Journal([self.e1, self.e2, self.e3])
410          self.glivre = entities.GrandLivre(self.journal)
411 -        self.resultat = entities.CompteResultat(self.glivre)
412 -        self.bilan = entities.Bilan(self.resultat)
413 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
414 +        self.bilan = entities.Bilan(self.resultat, RAPPORTS)
415 
416      def test_get_soldes(self) :
417          """calcul des soldes des postes"""
418          b = self.bilan
419 
@@ -556,17 +557,17 @@
420          self.e1 = _mk_e1()
421          self.e2 = _mk_e2()
422          self.e3 = _mk_e3()
423          self.journal = entities.Journal([self.e1, self.e2, self.e3])
424          self.glivre = entities.GrandLivre(self.journal)
425 -        self.resultat = entities.CompteResultat(self.glivre)
426 -        self.bilan = entities.Bilan(self.resultat)
427 +        self.resultat = entities.CompteResultat(self.glivre, RAPPORTS)
428 +        self.bilan = entities.Bilan(self.resultat, RAPPORTS)
429 
430      def test_write_1(self):
431          """écriture d'un bilan simple en XML"""
432          out = StringIO()
433 -        visitors.write_bilan(out, self.bilan, Date(2002,1,1), Date(2002,2,1))
434 +        visitors.write_bilan(out, self.bilan, Date(2002,1,1), Date(2002,2,1), RAPPORTS)
435          lines = out.getvalue().splitlines()
436          #self.assertEqual( out.getvalue(), '')
437          actif_found = 0
438          passif_found = 0
439          poste_found = 0
@@ -593,11 +594,11 @@
440  class FlattenTC(testlib.TestCase) :
441      """Tests pour lecture montants"""
442 
443      def test(self) :
444          """tout"""
445 -        comptes = list(entities.flatten_desc(definitions.ACTIF[0], True))
446 +        comptes = list(entities.flatten_desc(RAPPORTS['ACTIF'][0], True))
447          self.assertEqual(len(comptes), 48)
448 
449 
450  # IMMOBILISATION ###############################################################
451 
@@ -690,11 +691,12 @@
452          self.e1 = _mk_e1()
453          self.e2 = _mk_e2()
454          self.e3 = _mk_e3()
455          self.i = _mk_i()
456          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
457 -                                   [self.e1, self.e2, self.e3], [self.i])
458 +                                   [self.e1, self.e2, self.e3], [self.i],
459 +                                   RAPPORTS)
460 
461      def test_get_etat(self) :
462          """calcul de l'état au début deuxième mois"""
463          self.assertEqual( self.pilote.get_etat( Date(2002,2,-1) ),
464                            {'annee':2002, 'mois':2,
@@ -721,11 +723,12 @@
465          self.e1 = _mk_e1()
466          self.e2 = _mk_e2()
467          self.e3 = _mk_e3()
468          self.i = _mk_i()
469          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
470 -                                   [self.e1, self.e2, self.e3], [self.i])
471 +                                   [self.e1, self.e2, self.e3], [self.i],
472 +                                   RAPPORTS)
473 
474      def test_ecriture_xml(self) :
475          """écriture du pilote en XML"""
476          buf = StringIO()
477          dates = [Date(2002,1,1)]
@@ -738,11 +741,12 @@
478          self.e1 = _mk_e1()
479          self.e2 = _mk_e2()
480          self.e3 = _mk_e3()
481          self.i = _mk_i()
482          self.pilote = Comptabilite(Date(2002,1,1), Date(2002,2,-1),
483 -                                   [self.e1, self.e2, self.e3], [self.i])
484 +                                   [self.e1, self.e2, self.e3], [self.i],
485 +                                   RAPPORTS)
486 
487      def test_diag_matplotlib(self) :
488          """écriture du diagramme"""
489          dates = [Date(2002,1,1), Date(2002,2,-1)]
490          diagrams.diagram('/tmp/diag.png', self.pilote, dates)