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