[#2658] Intégration de reversion à l'app rh
[auf_rh_dae.git] / project / rh / masse_salariale.py
CommitLineData
98d6eb6c 1# -*- encoding: utf-8 -*-
899aea3b 2import csv
4ba84959 3import datetime
07f120f3 4import itertools
4ba84959
EMS
5import StringIO
6import time
98d6eb6c 7
4c17e518 8from auf.django.references import models as ref
d104b0ae 9from django.db.models import Q, Count
75f0e87b 10
4ba84959
EMS
11from project.rh import ods
12from project.rh import models as rh
98d6eb6c
JPC
13
14
15KEY_DATE_DEBUT = "debut"
16KEY_DATE_FIN = "fin"
4d17560e
JPC
17
18TYPE_REMUN_BSTG = (3,)
19TYPE_REMUN_MAD = (2,)
20TYPE_REMUN_BASE = (1,)
95ad7aab 21TYPE_REMUN_FONC_RESP = (7, 8)
4d17560e
JPC
22TYPE_REMUN_EXPAT = (4,)
23TYPE_REMUN_LOGEMENT = (6,)
9fd09bdc 24TYPE_REMUN_SCOLARITE = (5,)
4d17560e
JPC
25TYPE_REMUN_TRANSP = (9,)
26TYPE_REMUN_13E = (18,)
95ad7aab 27TYPE_PRIME_INTERIM = (19,)
a6927189
JPC
28TYPE_REMUN_ALL_INDEMNITES = list(itertools.chain(*(
29 TYPE_REMUN_BSTG, TYPE_REMUN_BASE, TYPE_REMUN_FONC_RESP,
07f120f3 30 TYPE_REMUN_EXPAT, TYPE_REMUN_LOGEMENT, TYPE_REMUN_TRANSP,
9fd09bdc 31 TYPE_REMUN_13E, TYPE_PRIME_INTERIM, TYPE_REMUN_SCOLARITE)))
95ad7aab
JPC
32TYPE_PRIME_INSTALLATION = (13,)
33TYPE_PRIME_DEMENAG = (15,)
34TYPE_PRIME_AVION = (14,)
07f120f3
JPC
35TYPE_PRIME_ALL = list(itertools.chain(
36 *(TYPE_PRIME_INSTALLATION, TYPE_PRIME_DEMENAG, TYPE_PRIME_AVION)
37 ))
38TYPE_CHARGE_PATRONALE = (17,)
39TYPE_CHARGE_ALL = list(itertools.chain(*(TYPE_CHARGE_PATRONALE,)))
40TYPE_NATURE_INDEMN = u"Indemnité"
899aea3b
JPC
41TYPE_NATURE_PAIEMENT = u"Accessoire"
42TYPE_NATURE_CHARGES = u"Charges"
5c5de149 43TYPE_NATURE_TRAITEMENT = u"Traitement"
eabb27fd 44HEADER_SEPARATOR = ('sep', ods.Separator(), {'columnwidth': '0.4cm'})
899aea3b 45
9163be6f 46
98d6eb6c
JPC
47class MasseSalariale():
48 """ Rapport de la masse salariale. """
49
c99116c3
JPC
50 def __init__(self, date_debut, date_fin, custom_filter=None,
51 ne_pas_grouper=False):
98d6eb6c
JPC
52 """ date_debut: date de début pour les données temporelles
53 date_fin: idem
df37184c 54 custom_filter: dictionnaire des paramètres à passer au queryset.
98d6eb6c 55 """
df37184c
JPC
56 if not date_debut and not date_fin:
57 return
58
98d6eb6c
JPC
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])
5c5de149 63
9163be6f 64 rapport_date_delta = date_fin - date_debut
e5a3a08e 65 rapport_date_delta += datetime.timedelta(days=1)
98d6eb6c
JPC
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) \
023bdc65
JPC
76
77 if custom_filter:
78 remunerations = remunerations.filter(**custom_filter)
d9de50fa 79 self.custom_filter = custom_filter
023bdc65 80
e5d10ada
JPC
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
45066657
EMS
92 remunerations = remunerations.select_related(
93 "dossier", "dossier_employe", "dossier_poste", "type"
94 )
98d6eb6c 95
d9de50fa
JPC
96 custom_filter = {}
97 for k, v in self.custom_filter.items():
98 custom_filter[k.replace('dossier__', '')] = v
a6927189 99 count_dossiers_by_employe = dict((d['id'], d['count']) for d in
d9de50fa
JPC
100 rh.Dossier.objects.filter(q_range).values('id') \
101 .filter(**custom_filter) \
102 .annotate(count=Count('employe')))
103
c99116c3
JPC
104 contenu = {}
105
106 lineariser_dossiers = not ne_pas_grouper
107
98d6eb6c 108 for r in remunerations:
c99116c3
JPC
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] = {
9163be6f
JPC
116 'dossiers': set(),
117 'remunerations': []
118 }
c99116c3
JPC
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)
9163be6f 125
98d6eb6c
JPC
126 self.rapport = []
127
57e2b793
JPC
128 pays_list = {}
129 for pays in ref.Pays.objects.all():
130 pays_list[pays.id] = pays
131
98d6eb6c
JPC
132 valeurs_point_par_imp = \
133 dict(
9163be6f
JPC
134 (v.implantation.id, v) for v in \
135 rh.ValeurPoint.objects.filter(annee=self.annee).all()
98d6eb6c 136 )
57e2b793
JPC
137
138 self.headers = (
3c8ffdfb
JPC
139 ('bureau', u"Bureau", {'columnwidth': '2cm'}),
140 ('pays', u"Pays", {'columnwidth': '3.5cm'}),
141 ('implantation', u"Implantation", {'columnwidth': '3cm'}),
5c5de149 142 ('valeur_point', u"Valeur du point",
3c8ffdfb
JPC
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'}),
fa4ae139 151 ('niveau', u"Niveau actel", {'columnwidth': '1.75cm'}),
3c8ffdfb 152 ('point', u"Point", {'columnwidth': '1.75cm'}),
a6927189 153 ('regime_de_travail', u"Régime de travail annuel",
3c8ffdfb
JPC
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'}),
e232bfe8 160 HEADER_SEPARATOR,
3c8ffdfb
JPC
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'}),
e232bfe8 164 HEADER_SEPARATOR,
3c8ffdfb 165 ('devise', u"Devise", {'columnwidth': '1.46cm'}),
bab8ce55 166 ('salaire_bstg_annuel', u"Salaire BSTG ANNUEL",
3c8ffdfb 167 {'columnwidth': '2.5cm'}),
a6927189 168 ('salaire_bstg_euro', u"Salaire BSTG EUR",
3c8ffdfb
JPC
169 {'columnwidth': '2.5cm'}),
170 ('organisme_bstg', u"Organisme BSTG",
171 {'columnwidth': '2.9cm'}),
e232bfe8 172 HEADER_SEPARATOR,
bab8ce55 173 ('salaire_theorique', u"Salaire théorique ANNUEL",
9fd09bdc 174 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
3c8ffdfb 175 ('salaire_base_brut', u"Salaire de base brut",
9fd09bdc 176 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
3c8ffdfb 177 ('salaire_complementaire', u"Salaire complémentaire",
9fd09bdc 178 {'columnwidth': '2.5cm', 'background-color': '#ecab44'}),
e232bfe8 179 HEADER_SEPARATOR,
3c8ffdfb 180 ('indemnite_fonctions', u"Indemnités de fonctions",
9fd09bdc 181 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 182 ('indemnite_expat', u"Indemnités d'expatriation",
9fd09bdc
JPC
183 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
184 ('indemnite_scolarite', u"Indemnités de frais de scolarité",
185 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 186 ('indemnite_logement', u"Indemnités de logement",
9fd09bdc 187 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 188 ('indemnite_transp', u"Indemnités de transport",
9fd09bdc 189 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 190 ('indemnite_13e', u"Indemnités 13e mois",
9fd09bdc 191 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 192 ('prime_interim', u"Prime d'intérim",
9fd09bdc 193 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 194 ('indemnite_autre', u"Autre indemnités",
9fd09bdc 195 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
3c8ffdfb 196 ('indemnite_sous_total', u"Sous-total d'indemnités",
9fd09bdc 197 {'columnwidth': '2.5cm', 'background-color': '#fff840'}),
e232bfe8 198 HEADER_SEPARATOR,
3c8ffdfb 199 ('prime_installation', u"Prime d'installation",
9fd09bdc 200 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
3c8ffdfb 201 ('prime_demenagement', u"Prime de déménagement",
9fd09bdc 202 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
3c8ffdfb 203 ('prime_avion', u"Prime d'avion",
9fd09bdc 204 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
3c8ffdfb 205 ('prime_autre', u"Autre prime",
9fd09bdc 206 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
3c8ffdfb 207 ('prime_sous_total', u"Total des primes",
9fd09bdc 208 {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}),
e232bfe8 209 HEADER_SEPARATOR,
3c8ffdfb 210 ('charges_patronales', u"Charges patronales",
9fd09bdc 211 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
3c8ffdfb 212 ('charges_autre', u"Autres charges patronales",
9fd09bdc 213 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
3c8ffdfb 214 ('charges_sous_total', u"Sous-total des charges patronales",
9fd09bdc 215 {'columnwidth': '2.5cm', 'background-color': '#fb680f'}),
e232bfe8 216 HEADER_SEPARATOR,
bab8ce55 217 ('sous_total_traitement_annee', u"Total traitements",
7ab6c3c6 218 {'background-color': '#ecab44'}),
bab8ce55 219 ('sous_total_indemnite_annee', u"Total indemnités",
7ab6c3c6 220 {'background-color': '#fff840'}),
bab8ce55 221 ('sous_total_accessoire_annee', u"Total accessoires",
7ab6c3c6 222 {'background-color': '#d7fb0f'}),
bab8ce55 223 ('sous_total_charges_annee', u"Total charges",
7ab6c3c6 224 {'background-color': '#fb680f'}),
e232bfe8 225 HEADER_SEPARATOR,
bab8ce55 226 ('masse_salariale', u"Masse salariale ANNUELLE",
9fd09bdc 227 {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
bab8ce55 228 ('masse_salariale_annee', u"Masse salariale",
9fd09bdc 229 {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}),
cb9cce2b 230 ('masse_salariale_annee_euro', u"Masse salariale %s EUR" % \
9fd09bdc
JPC
231 self.annee, {
232 'columnwidth': '2.5cm',
233 'background-color': '#e6c6ed'
234 }
235 ),
57e2b793
JPC
236 )
237
778fb9d6
JPC
238 grand_total = 0.0
239 grand_total_euro = 0.0
240
d9de50fa
JPC
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
bab8ce55
JPC
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
9ff35df5
EMS
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 ]
bab8ce55 317 contenu['p_%s' % p.id] = {
9ff35df5
EMS
318 'dossiers': set([d]),
319 'remunerations': remunerations
320 }
bab8ce55 321
c99116c3 322 for item in contenu.values():
98d6eb6c
JPC
323 dossiers = item['dossiers']
324 remuns = item['remunerations']
07f120f3 325
86bea0ed
EMS
326 if not dossiers:
327 continue
328 dossier = list(dossiers)[0]
07f120f3
JPC
329 for d in dossiers:
330 if d.principal:
86bea0ed 331 dossier = d
07f120f3 332
d3e403b2 333 regime = (float(dossier.regime_travail) / 100)
9163be6f 334
f7fc1166 335 if dossier.statut_residence == "expat":
98d6eb6c
JPC
336 statut = "E"
337 else:
338 statut = "L"
339
9163be6f
JPC
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
98d6eb6c
JPC
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
d9de50fa
JPC
356 try:
357 devise = remuns[0].devise
358 except IndexError:
359 devise = self.devise_base
98d6eb6c
JPC
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)
a6927189 368 devise = remuns[0].devise
98d6eb6c
JPC
369
370 bstg_dossier = None
371 for d in dossiers:
372 if d.organisme_bstg:
373 bstg_dossier = d
374
9163be6f 375 bstg_remun = None
98d6eb6c 376 if bstg_dossier:
9163be6f 377 for r in bstg_dossier.rh_remunerations.all():
a6927189
JPC
378 if r.type.id in TYPE_REMUN_MAD:
379 bstg_remun = rh.Remuneration(
380 montant=float(r.montant),
381 devise=r.devise
382 )
98d6eb6c 383
958e67e8 384 if bstg_remun:
df37184c 385 bstg_remun_euro = rh.Remuneration(
a6927189
JPC
386 montant=float(bstg_remun.montant),
387 devise=bstg_remun.devise
df37184c 388 )
958e67e8 389 self.convertir(bstg_remun_euro)
958e67e8 390
4d17560e
JPC
391 salaire_complement = 0.0
392 salaire_base = 0.0
393 indemnites = {
394 'fonc_resp': 0.0,
395 'expat': 0.0,
9fd09bdc 396 'scolarite': 0.0,
4d17560e
JPC
397 'logement': 0.0,
398 'transp': 0.0,
399 '13e': 0.0,
400 'autre_recurr': 0.0,
07f120f3 401 'interim': 0.0,
4d17560e 402 }
95ad7aab
JPC
403
404 primes = {
95ad7aab
JPC
405 'installation': 0.0,
406 'demenagement': 0.0,
407 'avion': 0.0,
408 'autre': 0.0,
409 }
07f120f3
JPC
410 charges = {
411 'patronale': 0.0,
412 'autre': 0.0,
413 }
5c5de149
JPC
414
415 total_remun_annee = {
416 'traitement': 0.0,
417 'indemnite': 0.0,
418 'accessoire': 0.0,
419 'charges': 0.0,
420 }
421
b4869de0 422 #Calcul du nombre de jours pour ce dossier.
34b3b5c6
JPC
423 dossier_date_delta = self.calculer_nombre_jours(
424 dossier.date_debut, dossier.date_fin,
425 date_debut, date_fin)
b4869de0 426
2139e9a7
JPC
427 masse_salariale = 0.0
428 masse_salariale_annee = 0.0
4d17560e 429 for r in remuns:
2139e9a7 430 montant = float(r.montant)
fa4ae139
JPC
431 if r.date_fin is None and dossier.date_fin is not None:
432 r.date_fin = min(date_fin, dossier.date_fin)
2139e9a7 433 facteur = self.calculer_nombre_jours(
fa4ae139
JPC
434 r.date_debut, r.date_fin,
435 date_debut, date_fin).days \
436 / float(rapport_date_delta.days)
95ad7aab 437
a6927189 438 if r.type_id in TYPE_REMUN_BSTG:
2139e9a7 439 salaire_complement += montant * facteur
a6927189
JPC
440
441 if r.type_id not in TYPE_REMUN_MAD:
2139e9a7 442 masse_salariale += montant
44083888 443 masse_salariale_annee += montant * regime
4d17560e 444
95ad7aab 445 if r.type_id in TYPE_REMUN_BASE:
2139e9a7 446 salaire_base += montant * facteur
4d17560e 447
95ad7aab 448 if r.type_id in TYPE_REMUN_FONC_RESP:
2139e9a7 449 indemnites['fonc_resp'] += montant * facteur
4d17560e 450
95ad7aab 451 if r.type_id in TYPE_REMUN_EXPAT:
2139e9a7 452 indemnites['expat'] += montant * facteur
4d17560e 453
9fd09bdc 454 if r.type_id in TYPE_REMUN_SCOLARITE:
2139e9a7 455 indemnites['scolarite'] += montant * facteur
9fd09bdc 456
95ad7aab 457 if r.type_id in TYPE_REMUN_LOGEMENT:
2139e9a7 458 indemnites['logement'] += montant * facteur
4d17560e 459
95ad7aab 460 if r.type_id in TYPE_REMUN_TRANSP:
2139e9a7 461 indemnites['transp'] += montant * facteur
4d17560e 462
95ad7aab 463 if r.type_id in TYPE_REMUN_13E:
2139e9a7 464 indemnites['13e'] += montant * facteur
4d17560e 465
95ad7aab 466 if r.type_id in TYPE_PRIME_INTERIM:
2139e9a7 467 indemnites['interim'] += montant * facteur
07f120f3
JPC
468
469 if r.type_id not in TYPE_REMUN_ALL_INDEMNITES \
a6927189
JPC
470 and r.type.nature_remuneration == TYPE_NATURE_INDEMN \
471 and r.type_id != TYPE_REMUN_MAD:
2139e9a7 472 indemnites['autre_recurr'] += montant * facteur
95ad7aab
JPC
473
474 if r.type_id in TYPE_PRIME_INSTALLATION:
2139e9a7 475 primes['installation'] += montant * facteur
95ad7aab
JPC
476
477 if r.type_id in TYPE_PRIME_DEMENAG:
2139e9a7 478 primes['demenagement'] += montant * facteur
95ad7aab
JPC
479
480 if r.type_id in TYPE_PRIME_AVION:
2139e9a7 481 primes['avion'] += montant * facteur
95ad7aab 482
07f120f3 483 if r.type_id not in TYPE_PRIME_ALL and \
95ad7aab 484 r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
2139e9a7 485 primes['autre'] += montant * facteur
95ad7aab 486
07f120f3 487 if r.type_id in TYPE_CHARGE_PATRONALE:
2139e9a7 488 charges['patronale'] += montant * facteur
07f120f3
JPC
489
490 if r.type_id not in TYPE_CHARGE_ALL and \
491 r.type.nature_remuneration == TYPE_NATURE_CHARGES:
2139e9a7 492 charges['autre'] += montant * facteur
899aea3b 493
494eba48
JPC
494 if r.type.nature_remuneration == TYPE_NATURE_INDEMN or \
495 r.type.id in (7,):
2139e9a7 496 total_remun_annee['indemnite'] += montant * facteur
5c5de149
JPC
497
498 if r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
2139e9a7 499 total_remun_annee['accessoire'] += montant * facteur
5c5de149
JPC
500
501 if r.type.nature_remuneration == TYPE_NATURE_CHARGES:
2139e9a7 502 total_remun_annee['charges'] += montant * facteur
5c5de149 503
a6927189 504 if (r.type.nature_remuneration == TYPE_NATURE_TRAITEMENT and
494eba48 505 r.type.id not in (TYPE_REMUN_MAD, 7)
a6927189 506 ) or r.type_id == TYPE_REMUN_BSTG:
2139e9a7 507 total_remun_annee['traitement'] += montant * facteur
5c5de149 508
4d17560e
JPC
509 total_indemnites = sum(indemnites.values())
510
31566c3d
JPC
511 masse_salariale_euro = rh.Remuneration(
512 montant=masse_salariale_annee, devise=devise)
023bdc65
JPC
513 self.convertir(masse_salariale_euro)
514
22b53270
JPC
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
c48caab9
JPC
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 = ""
22b53270 529
3244a3c2 530 salaire_theorique = (
22b53270 531 round(valeur_point.valeur * int(coefficient) * regime, 2) \
3244a3c2 532 if valeur_point and coefficient and regime else None)
22b53270 533
57e2b793
JPC
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,
c48caab9 540 'valeur_point': valeur_point_label,
57e2b793
JPC
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,
f7fc1166
JPC
545 'intitule_de_poste': dossier.poste.nom_feminin
546 if dossier.employe.genre == "F" else
547 dossier.poste.nom,
bab8ce55 548 'niveau': dossier.classement,
57e2b793
JPC
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 "",
b4869de0 556 'nb_jours': dossier_date_delta.days,
d9de50fa 557 'devise': devise.code,
57e2b793
JPC
558 'salaire_bstg_annuel': bstg_remun.montant \
559 if bstg_remun else "",
a6927189 560 'salaire_bstg_euro': bstg_remun_euro.montant \
57e2b793
JPC
561 if bstg_remun else "",
562 'organisme_bstg': dossier.organisme_bstg or "",
563 'salaire_theorique': salaire_theorique,
564 'salaire_base_brut': \
0c5e0d8e 565 salaire_base * regime,
57e2b793 566 'salaire_complementaire': \
0c5e0d8e 567 salaire_complement * regime,
57e2b793
JPC
568 #'salaire_total': None
569 'indemnite_fonctions': indemnites['fonc_resp'] * \
0c5e0d8e
JPC
570 regime,
571 'indemnite_expat': indemnites['expat'] * regime,
9fd09bdc 572 'indemnite_scolarite': indemnites['scolarite'] * \
0c5e0d8e 573 regime,
57e2b793 574 'indemnite_logement': indemnites['logement'] * \
0c5e0d8e
JPC
575 regime,
576 'indemnite_transp': indemnites['transp'] * regime,
577 'indemnite_13e': indemnites['13e'] * regime,
578 'prime_interim': indemnites['interim'] * regime,
57e2b793 579 'indemnite_autre': indemnites['autre_recurr'] * \
0c5e0d8e
JPC
580 regime,
581 'indemnite_sous_total': total_indemnites * regime,
57e2b793 582 'total_brut': (
95ad7aab
JPC
583 total_indemnites + salaire_base +
584 salaire_complement
0c5e0d8e
JPC
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,
2139e9a7
JPC
591 'charges_patronales': charges['patronale'] * regime,
592 'charges_autre': charges['autre'] * regime,
593 'charges_sous_total': sum(charges.values()) * regime,
5c5de149 594 'sous_total_traitement_annee': \
2139e9a7 595 total_remun_annee['traitement'] * regime,
5c5de149 596 'sous_total_indemnite_annee': \
2139e9a7 597 total_remun_annee['indemnite'] * regime,
5c5de149 598 'sous_total_accessoire_annee': \
2139e9a7 599 total_remun_annee['accessoire'] * regime,
5c5de149 600 'sous_total_charges_annee': \
2139e9a7
JPC
601 total_remun_annee['charges'] * regime,
602 'masse_salariale': masse_salariale * regime,
603 'masse_salariale_annee': masse_salariale_annee * regime,
5c5de149 604 'masse_salariale_annee_euro': \
0c5e0d8e 605 masse_salariale_euro.montant * regime,
43b30700 606 'sep': ods.Separator(),
57e2b793 607 }
98d6eb6c 608
c99116c3 609 grand_total_euro += round(masse_salariale_euro.montant * regime
b4869de0
JPC
610 * (
611 dossier_date_delta.days / rapport_date_delta.days
612 ), 2)
778fb9d6 613
98d6eb6c
JPC
614 self.rapport.append(item_rapport)
615
3b1a2937
JPC
616 self.rapport = sorted(self.rapport, key=lambda r: r['nom'])
617
778fb9d6
JPC
618 self.grand_totaux = (grand_total, grand_total_euro)
619
2139e9a7
JPC
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
34b3b5c6
JPC
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
98d6eb6c
JPC
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 (
0c5e0d8e 658 date_debut_null & date_fin_null
98d6eb6c 659 ) | (
0c5e0d8e
JPC
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 )
98d6eb6c 666 ) | (
0c5e0d8e
JPC
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 )
98d6eb6c 673 ) | (
0c5e0d8e
JPC
674 date_debut_inferieure_ou_egale_a_borne_gauche &
675 date_fin_superieure_ou_egale_a_borne_droite
98d6eb6c 676 ) | (
0c5e0d8e
JPC
677 date_debut_null &
678 date_fin_superieure_ou_egale_a_borne_droite
98d6eb6c 679 ) | (
0c5e0d8e
JPC
680 date_debut_inferieure_ou_egale_a_borne_gauche &
681 date_fin_null
98d6eb6c 682 )
98d6eb6c
JPC
683 return q_range
684
685 def convertir(self, remuneration):
9163be6f 686 if remuneration.devise != self.devise_base:
8b6e7b9a
JPC
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
98d6eb6c
JPC
693
694 def trouver_taux(self, devise):
695 if devise.code not in self.taux_change:
8b6e7b9a
JPC
696 try:
697 t = rh.TauxChange.objects.filter(
698 devise=devise, annee=self.annee
699 )[0]
700 except IndexError:
701 return None
98d6eb6c
JPC
702 self.taux_change[devise.code] = t
703 return self.taux_change[devise.code]
899aea3b
JPC
704
705 def csv(self):
706 self.csv_handle = StringIO.StringIO()
023bdc65
JPC
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 )
c99116c3
JPC
717
718 def ods(self):
3c8ffdfb 719 self.doc = ods.OpenDocumentSpreadsheet()
e5d10ada
JPC
720
721 nom = u"Masse salariale %s" % self.annee
722 if self.region:
fba0dde4 723 nom += u" %s" % self.region
e5d10ada 724 elif self.implantation:
fba0dde4 725 nom += u" %s" % self.implantation
e5d10ada
JPC
726
727 table = self.doc.add_table(name=nom)
3c8ffdfb
JPC
728
729 for h in self.headers:
730 if len(h) > 2:
731 table.add_column(**h[2])
732
6d7419c4
JPC
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])
3c8ffdfb 737
028b8438 738 #a.doc.write('hello_world.ods')