22b1c638056b60365ecb20306dd6b3b3640b726f
[auf_rh_dae.git] / project / rh / masse_salariale.py
1 # -*- encoding: utf-8 -*-
2 import time
3 import datetime
4 import csv
5 import StringIO
6 import itertools
7
8 from django.db.models import Q
9 from django.db.models import Count
10
11 from datamaster_modeles import models as ref
12 import rh.ods as ods
13 import rh.models as rh
14
15
16 KEY_DATE_DEBUT = "debut"
17 KEY_DATE_FIN = "fin"
18
19 TYPE_REMUN_BSTG = (3,)
20 TYPE_REMUN_MAD = (2,)
21 TYPE_REMUN_BASE = (1,)
22 TYPE_REMUN_FONC_RESP = (7, 8)
23 TYPE_REMUN_EXPAT = (4,)
24 TYPE_REMUN_LOGEMENT = (6,)
25 TYPE_REMUN_SCOLARITE = (5,)
26 TYPE_REMUN_TRANSP = (9,)
27 TYPE_REMUN_13E = (18,)
28 TYPE_PRIME_INTERIM = (19,)
29 TYPE_REMUN_ALL_INDEMNITES = list(itertools.chain(*(
30 TYPE_REMUN_BSTG, TYPE_REMUN_BASE, TYPE_REMUN_FONC_RESP,
31 TYPE_REMUN_EXPAT, TYPE_REMUN_LOGEMENT, TYPE_REMUN_TRANSP,
32 TYPE_REMUN_13E, TYPE_PRIME_INTERIM, TYPE_REMUN_SCOLARITE)))
33 TYPE_PRIME_INSTALLATION = (13,)
34 TYPE_PRIME_DEMENAG = (15,)
35 TYPE_PRIME_AVION = (14,)
36 TYPE_PRIME_ALL = list(itertools.chain(
37 *(TYPE_PRIME_INSTALLATION, TYPE_PRIME_DEMENAG, TYPE_PRIME_AVION)
38 ))
39 TYPE_CHARGE_PATRONALE = (17,)
40 TYPE_CHARGE_ALL = list(itertools.chain(*(TYPE_CHARGE_PATRONALE,)))
41 TYPE_NATURE_INDEMN = u"Indemnité"
42 TYPE_NATURE_PAIEMENT = u"Accessoire"
43 TYPE_NATURE_CHARGES = u"Charges"
44 TYPE_NATURE_TRAITEMENT = u"Traitement"
45 HEADER_SEPARATOR = ('sep', ods.Separator(), {'columnwidth': '0.4cm'})
46
47
48 class MasseSalariale():
49 """ Rapport de la masse salariale. """
50
51 def __init__(self, date_debut, date_fin, custom_filter=None,
52 ne_pas_grouper=False):
53 """ date_debut: date de début pour les données temporelles
54 date_fin: idem
55 custom_filter: dictionnaire des paramètres à passer au queryset.
56 """
57 if not date_debut and not date_fin:
58 return
59
60 date_debut = datetime.date(
61 *time.strptime(date_debut, "%d-%m-%Y")[0:3]
62 )
63 date_fin = datetime.date(*time.strptime(date_fin, "%d-%m-%Y")[0:3])
64
65 rapport_date_delta = date_fin - date_debut
66 rapport_date_delta += datetime.timedelta(days=1)
67
68 self.annee = date_fin.year
69
70 self.devise_base = rh.Devise.objects.filter(code='EUR')[0]
71 self.taux_change = {}
72
73 q_range = self.build_qs("date_", date_debut, date_fin)
74 q_range_d = self.build_qs("dossier__date_", date_debut, date_fin)
75 remunerations = rh.Remuneration.objects.filter(q_range) \
76 .filter(q_range_d) \
77
78 if custom_filter:
79 remunerations = remunerations.filter(**custom_filter)
80 self.custom_filter = custom_filter
81
82 self.region = None
83 self.implantation = None
84 if 'dossier__poste__implantation__region' in custom_filter:
85 self.region = ref.Region.objects.get(
86 id=custom_filter['dossier__poste__implantation__region']
87 )
88 if 'dossier__poste__implantation' in custom_filter:
89 self.implantation = ref.Implantation.objects.get(
90 id=custom_filter['dossier__poste__implantation']
91 )
92
93 remunerations = remunerations.exclude(supprime=True) \
94 .select_related(
95 "dossier", "dossier_employe", "dossier_poste", "type"
96 )
97
98 custom_filter = {}
99 for k, v in self.custom_filter.items():
100 custom_filter[k.replace('dossier__', '')] = v
101 count_dossiers_by_employe = dict((d['id'], d['count']) for d in
102 rh.Dossier.objects.filter(q_range).values('id') \
103 .filter(**custom_filter) \
104 .annotate(count=Count('employe')))
105
106 contenu = {}
107
108 lineariser_dossiers = not ne_pas_grouper
109
110 for r in remunerations:
111 if lineariser_dossiers:
112 key = r.dossier.employe_id
113 else:
114 key = r.dossier_id
115
116 if key not in contenu:
117 contenu[key] = {
118 'dossiers': set(),
119 'remunerations': []
120 }
121 if lineariser_dossiers:
122 contenu[key]['remunerations'].append(r)
123 else:
124 if r.dossier_id == key:
125 contenu[key]['remunerations'].append(r)
126 contenu[key]['dossiers'].add(r.dossier)
127
128 self.rapport = []
129
130 pays_list = {}
131 for pays in ref.Pays.objects.all():
132 pays_list[pays.id] = pays
133
134 valeurs_point_par_imp = \
135 dict(
136 (v.implantation.id, v) for v in \
137 rh.ValeurPoint.objects.filter(annee=self.annee).all()
138 )
139
140 self.headers = (
141 ('bureau', u"Bureau", {'columnwidth': '2cm'}),
142 ('pays', u"Pays", {'columnwidth': '3.5cm'}),
143 ('implantation', u"Implantation", {'columnwidth': '3cm'}),
144 ('valeur_point', u"Valeur du point",
145 {'columnwidth': '2.3cm'}),
146 ('numero_employe', u"Numéro d'employé",
147 {'columnwidth': '2.4cm'}),
148 ('nom', u"Nom", {'columnwidth': '5.4cm'}),
149 ('prenom', u"Prénom", {'columnwidth': '4.8cm'}),
150 ('type_de_poste', u"Type de poste", {'columnwidth': '2.7cm'}),
151 ('intitule_de_poste', u"Intitulé du poste",
152 {'columnwidth': '7.25cm'}),
153 ('niveau', u"Niveau actel", {'columnwidth': '1.75cm'}),
154 ('point', u"Point", {'columnwidth': '1.75cm'}),
155 ('regime_de_travail', u"Régime de travail annuel",
156 {'columnwidth': '2cm'}),
157 ('local_expatrie', u"Local / Expatrié",
158 {'columnwidth': '2.25cm'}),
159 ('statut', u"Statut", {'columnwidth': '1.25cm'}),
160 ('date_fin_contrat', u"Date de fin de contrat",
161 {'columnwidth': '2cm'}),
162 HEADER_SEPARATOR,
163 ('date_debut', u"Date de début", {'columnwidth': '1.92cm'}),
164 ('date_fin', u"Date de fin", {'columnwidth': '1.92cm'}),
165 ('nb_jours', u"Nombre de jours", {'columnwidth': '2.82cm'}),
166 HEADER_SEPARATOR,
167 ('devise', u"Devise", {'columnwidth': '1.46cm'}),
168 ('salaire_bstg_annuel', u"Salaire BSTG ANNUEL",
169 {'columnwidth': '2.5cm'}),
170 ('salaire_bstg_euro', u"Salaire BSTG EUR",
171 {'columnwidth': '2.5cm'}),
172 ('organisme_bstg', u"Organisme BSTG",
173 {'columnwidth': '2.9cm'}),
174 HEADER_SEPARATOR,
175 ('salaire_theorique', u"Salaire théorique ANNUEL",
176 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
177 ('salaire_base_brut', u"Salaire de base brut",
178 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
179 ('salaire_complementaire', u"Salaire complémentaire",
180 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
181 HEADER_SEPARATOR,
182 ('indemnite_fonctions', u"Indemnités de fonctions",
183 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
184 ('indemnite_expat', u"Indemnités d'expatriation",
185 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
186 ('indemnite_scolarite', u"Indemnités de frais de scolarité",
187 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
188 ('indemnite_logement', u"Indemnités de logement",
189 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
190 ('indemnite_transp', u"Indemnités de transport",
191 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
192 ('indemnite_13e', u"Indemnités 13e mois",
193 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
194 ('prime_interim', u"Prime d'intérim",
195 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
196 ('indemnite_autre', u"Autre indemnités",
197 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
198 ('indemnite_sous_total', u"Sous-total d'indemnités",
199 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
200 HEADER_SEPARATOR,
201 ('prime_installation', u"Prime d'installation",
202 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
203 ('prime_demenagement', u"Prime de déménagement",
204 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
205 ('prime_avion', u"Prime d'avion",
206 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
207 ('prime_autre', u"Autre prime",
208 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
209 ('prime_sous_total', u"Total des primes",
210 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
211 HEADER_SEPARATOR,
212 ('charges_patronales', u"Charges patronales",
213 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
214 ('charges_autre', u"Autres charges patronales",
215 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
216 ('charges_sous_total', u"Sous-total des charges patronales",
217 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
218 HEADER_SEPARATOR,
219 ('sous_total_traitement_annee', u"Total traitements",
220 {'background-color': '#ecab44'}),
221 ('sous_total_indemnite_annee', u"Total indemnités",
222 {'background-color': '#fff840'}),
223 ('sous_total_accessoire_annee', u"Total accessoires",
224 {'background-color': '#d7fb0f'}),
225 ('sous_total_charges_annee', u"Total charges",
226 {'background-color': '#fb680f'}),
227 HEADER_SEPARATOR,
228 ('masse_salariale', u"Masse salariale ANNUELLE",
229 {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
230 ('masse_salariale_annee', u"Masse salariale",
231 {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
232 ('masse_salariale_annee_euro', u"Masse salariale %s EUR" % \
233 self.annee, {
234 'columnwidth': '2.5cm',
235 'background-color': '#e6c6ed'
236 }
237 ),
238 )
239
240 grand_total = 0.0
241 grand_total_euro = 0.0
242
243 if not lineariser_dossiers:
244 for dossier_id, count in count_dossiers_by_employe.items():
245 if dossier_id not in contenu or \
246 len(contenu[dossier_id]['dossiers']) != count:
247 not_in = []
248 if dossier_id in contenu:
249 for d in contenu[dossier_id]['dossiers']:
250 not_in.append(d.id)
251 custom_filter = {}
252 for k, v in self.custom_filter.items():
253 custom_filter[k.replace('dossier__', '')] = v
254
255 employe_id = rh.Dossier.objects.values('employe').filter(
256 id=dossier_id).all()[0]['employe']
257 dossiers = rh.Dossier.objects.filter(q_range) \
258 .filter(employe=employe_id) \
259 .filter(**custom_filter) \
260 .all()
261 for d in dossiers:
262 if d.id not in contenu:
263 contenu[d.id] = {
264 'dossiers': set((d,)),
265 'remunerations': []
266 }
267 else:
268 contenu[d.id]['dossiers'].add(d)
269
270 postes = rh.Poste.objects
271
272 custom_filter = {}
273 for k, v in self.custom_filter.items():
274 custom_filter[k.replace('dossier__poste__', '')] = v
275
276 if custom_filter:
277 postes = postes.filter(**custom_filter)
278
279 postes_vacants = [p for p in postes.filter(q_range).all()
280 if p.is_vacant()]
281 remuneration_base = rh.TypeRemuneration.objects.get(
282 id=TYPE_REMUN_BASE[0])
283 remuneration_indem = rh.TypeRemuneration(
284 nature_remuneration=TYPE_NATURE_INDEMN)
285 remuneration_charge = rh.TypeRemuneration(
286 nature_remuneration=TYPE_NATURE_CHARGES)
287 for p in postes_vacants:
288 d = rh.Dossier()
289 d.employe = rh.Employe()
290 d.statut = rh.Statut()
291 d.poste = p
292 d.classement = p.classement_max
293 d.point = p.valeur_point_max
294 contenu['p_%s' % p.id] = {
295 'dossiers': set([d]),
296 'remunerations': [
297 rh.Remuneration(montant=p.salaire_max,
298 devise=p.devise_max, type=remuneration_base),
299 rh.Remuneration(montant=p.indemn_max,
300 devise=p.devise_max, type=remuneration_indem),
301 rh.Remuneration(montant=p.autre_max,
302 devise=p.devise_max, type=remuneration_charge),
303 ]
304 }
305
306 for item in contenu.values():
307 dossiers = item['dossiers']
308 remuns = item['remunerations']
309
310 if not dossiers:
311 continue
312 dossier = list(dossiers)[0]
313 for d in dossiers:
314 if d.principal:
315 dossier = d
316
317 regime = (float(dossier.regime_travail) / 100)
318
319 if dossier.statut_residence == "expat":
320 statut = "E"
321 else:
322 statut = "L"
323
324 #on détermine la date du début et fin du dossier si année en cours
325 try:
326 d_date_fin = dossier.date_fin \
327 if dossier.date_fin.year == date_fin.year else None
328 except AttributeError:
329 d_date_fin = None
330 try:
331 d_date_debut = dossier.date_debut \
332 if dossier.date_debut.year == date_fin.year else None
333 except AttributeError:
334 d_date_debut = None
335
336 pays = \
337 pays_list[dossier.poste.implantation.adresse_physique_pays.id]
338
339 #on détermine si les rémunérations sont tous dans la même devise
340 try:
341 devise = remuns[0].devise
342 except IndexError:
343 devise = self.devise_base
344 meme_devise = True
345 for r in remuns[1:]:
346 if devise != r.devise:
347 meme_devise = False
348
349 if not meme_devise:
350 for r in remuns:
351 self.convertir(r)
352 devise = remuns[0].devise
353
354 bstg_dossier = None
355 for d in dossiers:
356 if d.organisme_bstg:
357 bstg_dossier = d
358
359 bstg_remun = None
360 if bstg_dossier:
361 for r in bstg_dossier.rh_remunerations.all():
362 if r.type.id in TYPE_REMUN_MAD:
363 bstg_remun = rh.Remuneration(
364 montant=float(r.montant),
365 devise=r.devise
366 )
367
368 if bstg_remun:
369 bstg_remun_euro = rh.Remuneration(
370 montant=float(bstg_remun.montant),
371 devise=bstg_remun.devise
372 )
373 self.convertir(bstg_remun_euro)
374
375 salaire_complement = 0.0
376 salaire_base = 0.0
377 indemnites = {
378 'fonc_resp': 0.0,
379 'expat': 0.0,
380 'scolarite': 0.0,
381 'logement': 0.0,
382 'transp': 0.0,
383 '13e': 0.0,
384 'autre_recurr': 0.0,
385 'interim': 0.0,
386 }
387
388 primes = {
389 'installation': 0.0,
390 'demenagement': 0.0,
391 'avion': 0.0,
392 'autre': 0.0,
393 }
394 charges = {
395 'patronale': 0.0,
396 'autre': 0.0,
397 }
398
399 total_remun_annee = {
400 'traitement': 0.0,
401 'indemnite': 0.0,
402 'accessoire': 0.0,
403 'charges': 0.0,
404 }
405
406 #Calcul du nombre de jours pour ce dossier.
407 dossier_date_delta = self.calculer_nombre_jours(
408 dossier.date_debut, dossier.date_fin,
409 date_debut, date_fin)
410
411 masse_salariale = 0.0
412 masse_salariale_annee = 0.0
413 for r in remuns:
414 montant = float(r.montant)
415 if r.date_fin is None and dossier.date_fin is not None:
416 r.date_fin = min(date_fin, dossier.date_fin)
417 facteur = self.calculer_nombre_jours(
418 r.date_debut, r.date_fin,
419 date_debut, date_fin).days \
420 / float(rapport_date_delta.days)
421
422 if r.type_id in TYPE_REMUN_BSTG:
423 salaire_complement += montant * facteur
424
425 if r.type_id not in TYPE_REMUN_MAD:
426 masse_salariale += montant
427 masse_salariale_annee += montant * regime
428
429 if r.type_id in TYPE_REMUN_BASE:
430 salaire_base += montant * facteur
431
432 if r.type_id in TYPE_REMUN_FONC_RESP:
433 indemnites['fonc_resp'] += montant * facteur
434
435 if r.type_id in TYPE_REMUN_EXPAT:
436 indemnites['expat'] += montant * facteur
437
438 if r.type_id in TYPE_REMUN_SCOLARITE:
439 indemnites['scolarite'] += montant * facteur
440
441 if r.type_id in TYPE_REMUN_LOGEMENT:
442 indemnites['logement'] += montant * facteur
443
444 if r.type_id in TYPE_REMUN_TRANSP:
445 indemnites['transp'] += montant * facteur
446
447 if r.type_id in TYPE_REMUN_13E:
448 indemnites['13e'] += montant * facteur
449
450 if r.type_id in TYPE_PRIME_INTERIM:
451 indemnites['interim'] += montant * facteur
452
453 if r.type_id not in TYPE_REMUN_ALL_INDEMNITES \
454 and r.type.nature_remuneration == TYPE_NATURE_INDEMN \
455 and r.type_id != TYPE_REMUN_MAD:
456 indemnites['autre_recurr'] += montant * facteur
457
458 if r.type_id in TYPE_PRIME_INSTALLATION:
459 primes['installation'] += montant * facteur
460
461 if r.type_id in TYPE_PRIME_DEMENAG:
462 primes['demenagement'] += montant * facteur
463
464 if r.type_id in TYPE_PRIME_AVION:
465 primes['avion'] += montant * facteur
466
467 if r.type_id not in TYPE_PRIME_ALL and \
468 r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
469 primes['autre'] += montant * facteur
470
471 if r.type_id in TYPE_CHARGE_PATRONALE:
472 charges['patronale'] += montant * facteur
473
474 if r.type_id not in TYPE_CHARGE_ALL and \
475 r.type.nature_remuneration == TYPE_NATURE_CHARGES:
476 charges['autre'] += montant * facteur
477
478 if r.type.nature_remuneration == TYPE_NATURE_INDEMN or \
479 r.type.id in (7,):
480 total_remun_annee['indemnite'] += montant * facteur
481
482 if r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
483 total_remun_annee['accessoire'] += montant * facteur
484
485 if r.type.nature_remuneration == TYPE_NATURE_CHARGES:
486 total_remun_annee['charges'] += montant * facteur
487
488 if (r.type.nature_remuneration == TYPE_NATURE_TRAITEMENT and
489 r.type.id not in (TYPE_REMUN_MAD, 7)
490 ) or r.type_id == TYPE_REMUN_BSTG:
491 total_remun_annee['traitement'] += montant * facteur
492
493 total_indemnites = sum(indemnites.values())
494
495 masse_salariale_euro = rh.Remuneration(
496 montant=masse_salariale_annee, devise=devise)
497 self.convertir(masse_salariale_euro)
498
499 if dossier.classement and dossier.classement.coefficient:
500 coefficient = dossier.classement.coefficient
501 else:
502 coefficient = ""
503
504 #todo valeur du point si pas présent
505 valeur_point = valeurs_point_par_imp.get(
506 dossier.poste.implantation_id
507 )
508 if valeur_point:
509 valeur_point_label = "%s %s" % (valeur_point.valeur,
510 valeur_point.devise.code)
511 else:
512 valeur_point_label = ""
513
514 salaire_theorique = (
515 round(valeur_point.valeur * int(coefficient) * regime, 2) \
516 if valeur_point and coefficient and regime else None)
517
518 item_rapport = {
519 'bureau': dossier.poste.implantation.region.code,
520 'pays': unicode(pays),
521 'implantation': dossier.poste.implantation.nom_court,
522 'type_implantation': dossier.poste.implantation.type,
523 #'imputation': None,
524 'valeur_point': valeur_point_label,
525 'numero_employe': dossier.employe_id,
526 'nom': dossier.employe.nom.upper(),
527 'prenom': dossier.employe.prenom,
528 'type_de_poste': dossier.poste.type_poste.nom,
529 'intitule_de_poste': dossier.poste.nom_feminin
530 if dossier.employe.genre == "F" else
531 dossier.poste.nom,
532 'niveau': dossier.classement,
533 'point': coefficient,
534 'regime_de_travail': "%s %%" % int(regime * 100),
535 'local_expatrie': statut,
536 'statut': dossier.statut.code,
537 'date_fin_contrat': dossier.date_fin or "",
538 'date_debut': d_date_debut or "",
539 'date_fin': d_date_fin or "",
540 'nb_jours': dossier_date_delta.days,
541 'devise': devise.code,
542 'salaire_bstg_annuel': bstg_remun.montant \
543 if bstg_remun else "",
544 'salaire_bstg_euro': bstg_remun_euro.montant \
545 if bstg_remun else "",
546 'organisme_bstg': dossier.organisme_bstg or "",
547 'salaire_theorique': salaire_theorique,
548 'salaire_base_brut': \
549 salaire_base * regime,
550 'salaire_complementaire': \
551 salaire_complement * regime,
552 #'salaire_total': None
553 'indemnite_fonctions': indemnites['fonc_resp'] * \
554 regime,
555 'indemnite_expat': indemnites['expat'] * regime,
556 'indemnite_scolarite': indemnites['scolarite'] * \
557 regime,
558 'indemnite_logement': indemnites['logement'] * \
559 regime,
560 'indemnite_transp': indemnites['transp'] * regime,
561 'indemnite_13e': indemnites['13e'] * regime,
562 'prime_interim': indemnites['interim'] * regime,
563 'indemnite_autre': indemnites['autre_recurr'] * \
564 regime,
565 'indemnite_sous_total': total_indemnites * regime,
566 'total_brut': (
567 total_indemnites + salaire_base +
568 salaire_complement
569 ) * regime,
570 'prime_installation': primes['installation'] * regime,
571 'prime_demenagement': primes['demenagement'] * regime,
572 'prime_avion': primes['avion'] * regime,
573 'prime_autre': primes['autre'] * regime,
574 'prime_sous_total': sum(primes.values()) * regime,
575 'charges_patronales': charges['patronale'] * regime,
576 'charges_autre': charges['autre'] * regime,
577 'charges_sous_total': sum(charges.values()) * regime,
578 'sous_total_traitement_annee': \
579 total_remun_annee['traitement'] * regime,
580 'sous_total_indemnite_annee': \
581 total_remun_annee['indemnite'] * regime,
582 'sous_total_accessoire_annee': \
583 total_remun_annee['accessoire'] * regime,
584 'sous_total_charges_annee': \
585 total_remun_annee['charges'] * regime,
586 'masse_salariale': masse_salariale * regime,
587 'masse_salariale_annee': masse_salariale_annee * regime,
588 'masse_salariale_annee_euro': \
589 masse_salariale_euro.montant * regime,
590 'sep': ods.Separator(),
591 }
592
593 grand_total_euro += round(masse_salariale_euro.montant * regime
594 * (
595 dossier_date_delta.days / rapport_date_delta.days
596 ), 2)
597
598 self.rapport.append(item_rapport)
599
600 self.rapport = sorted(self.rapport, key=lambda r: r['nom'])
601
602 self.grand_totaux = (grand_total, grand_total_euro)
603
604 def calculer_nombre_jours(self, debut, fin, debut_limite, fin_limite):
605 """Calcul le nombre de jours entre fin et debut, sans dépasser
606 les limites. Si debut ou fin set null, on prend debut_limite/fin_limi
607 """
608
609 if not debut:
610 debut = debut_limite
611 if not fin:
612 fin = fin_limite
613
614 if debut < debut_limite:
615 debut = debut_limite
616 if fin > fin_limite:
617 fin = fin_limite
618
619 fin += datetime.timedelta(days=1)
620 return fin - debut
621
622 def build_qs(self, prefix, date_debut, date_fin):
623 date_debut_null = \
624 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True})
625 date_fin_null = \
626 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True})
627 date_debut_superieure_ou_egale_a_borne_gauche = \
628 Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut})
629 date_debut_inferieure_ou_egale_a_borne_gauche = \
630 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut})
631 date_fin_superieure_ou_egale_a_borne_gauche = \
632 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut})
633 date_fin_inferieure_ou_egale_a_borne_droite = \
634 Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin})
635 date_debut_inferieure_ou_egale_a_borne_droite = \
636 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin})
637 date_fin_superieure_ou_egale_a_borne_droite = \
638 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin})
639
640 q_range = \
641 (
642 date_debut_null & date_fin_null
643 ) | (
644 date_fin_superieure_ou_egale_a_borne_gauche &
645 date_fin_inferieure_ou_egale_a_borne_droite &
646 (
647 date_debut_inferieure_ou_egale_a_borne_gauche |
648 date_debut_null
649 )
650 ) | (
651 date_debut_superieure_ou_egale_a_borne_gauche &
652 date_debut_inferieure_ou_egale_a_borne_droite &
653 (
654 date_fin_superieure_ou_egale_a_borne_droite |
655 date_fin_null
656 )
657 ) | (
658 date_debut_inferieure_ou_egale_a_borne_gauche &
659 date_fin_superieure_ou_egale_a_borne_droite
660 ) | (
661 date_debut_null &
662 date_fin_superieure_ou_egale_a_borne_droite
663 ) | (
664 date_debut_inferieure_ou_egale_a_borne_gauche &
665 date_fin_null
666 )
667 return q_range
668
669 def convertir(self, remuneration):
670 if remuneration.devise != self.devise_base:
671 try:
672 remuneration.montant = float(remuneration.montant) * \
673 self.trouver_taux(remuneration.devise).taux
674 remuneration.devise = self.devise_base
675 except AttributeError:
676 pass
677
678 def trouver_taux(self, devise):
679 if devise.code not in self.taux_change:
680 try:
681 t = rh.TauxChange.objects.filter(
682 devise=devise, annee=self.annee
683 )[0]
684 except IndexError:
685 return None
686 self.taux_change[devise.code] = t
687 return self.taux_change[devise.code]
688
689 def csv(self):
690 self.csv_handle = StringIO.StringIO()
691 csv_writer = csv.writer(self.csv_handle, delimiter=",",
692 doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL,
693 )
694 header = [v[0] for v in self.rapport[0]]
695 csv_writer.writerow(header)
696 for row in self.rapport:
697 values = [v[1] for v in row]
698 csv_writer.writerow(
699 [unicode(r).encode('utf-8') for r in values]
700 )
701
702 def ods(self):
703 self.doc = ods.OpenDocumentSpreadsheet()
704
705 nom = u"Masse salariale %s" % self.annee
706 if self.region:
707 nom += u" %s" % self.region
708 elif self.implantation:
709 nom += u" %s" % self.implantation
710
711 table = self.doc.add_table(name=nom)
712
713 for h in self.headers:
714 if len(h) > 2:
715 table.add_column(**h[2])
716
717 table.add_row([h[1] for h in self.headers], rowheight='2cm')
718
719 for r in self.rapport:
720 table.add_row([r[h[0]] for h in self.headers])
721
722 #a.doc.write('hello_world.ods')