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