Commit | Line | Data |
---|---|---|
98d6eb6c JPC |
1 | # -*- encoding: utf-8 -*- |
2 | import time | |
3 | import datetime | |
899aea3b JPC |
4 | import csv |
5 | import StringIO | |
98d6eb6c JPC |
6 | |
7 | from django.db.models import Q | |
8 | ||
9 | from datamaster_modeles import models as ref | |
98d6eb6c JPC |
10 | import rh.models as rh |
11 | ||
12 | ||
13 | KEY_DATE_DEBUT = "debut" | |
14 | KEY_DATE_FIN = "fin" | |
4d17560e JPC |
15 | |
16 | TYPE_REMUN_BSTG = (3,) | |
17 | TYPE_REMUN_MAD = (2,) | |
18 | TYPE_REMUN_BASE = (1,) | |
95ad7aab | 19 | TYPE_REMUN_FONC_RESP = (7, 8) |
4d17560e JPC |
20 | TYPE_REMUN_EXPAT = (4,) |
21 | TYPE_REMUN_LOGEMENT = (6,) | |
22 | TYPE_REMUN_TRANSP = (9,) | |
23 | TYPE_REMUN_13E = (18,) | |
95ad7aab | 24 | TYPE_REMUN_AUTRE_RECURR_NOT = (1, 2, 3, 4, 6, 7, 8, 9, 18, 13, 14, 15, 19) |
4d17560e | 25 | TYPE_PAIEMENT_PONCTUEL = u"Ponctuel" |
95ad7aab JPC |
26 | TYPE_PRIME_INTERIM = (19,) |
27 | TYPE_PRIME_INSTALLATION = (13,) | |
28 | TYPE_PRIME_DEMENAG = (15,) | |
29 | TYPE_PRIME_AVION = (14,) | |
899aea3b JPC |
30 | TYPE_NATURE_PAIEMENT = u"Accessoire" |
31 | TYPE_NATURE_CHARGES = u"Charges" | |
32 | ||
9163be6f | 33 | |
98d6eb6c JPC |
34 | class MasseSalariale(): |
35 | """ Rapport de la masse salariale. """ | |
36 | ||
023bdc65 | 37 | def __init__(self, date_debut, date_fin, custom_filter=None): |
98d6eb6c JPC |
38 | """ date_debut: date de début pour les données temporelles |
39 | date_fin: idem | |
df37184c | 40 | custom_filter: dictionnaire des paramètres à passer au queryset. |
98d6eb6c | 41 | """ |
df37184c JPC |
42 | if not date_debut and not date_fin: |
43 | return | |
44 | ||
98d6eb6c JPC |
45 | date_debut = datetime.date( |
46 | *time.strptime(date_debut, "%d-%m-%Y")[0:3] | |
47 | ) | |
48 | date_fin = datetime.date(*time.strptime(date_fin, "%d-%m-%Y")[0:3]) | |
9163be6f | 49 | rapport_date_delta = date_fin - date_debut |
98d6eb6c JPC |
50 | |
51 | self.annee = date_fin.year | |
52 | ||
53 | self.devise_base = rh.Devise.objects.filter(code='EUR')[0] | |
54 | self.taux_change = {} | |
55 | ||
56 | q_range = self.build_qs("date_", date_debut, date_fin) | |
57 | q_range_d = self.build_qs("dossier__date_", date_debut, date_fin) | |
58 | remunerations = rh.Remuneration.objects.filter(q_range) \ | |
59 | .filter(q_range_d) \ | |
023bdc65 JPC |
60 | |
61 | if custom_filter: | |
62 | remunerations = remunerations.filter(**custom_filter) | |
63 | ||
64 | remunerations = remunerations.exclude(supprime=True) \ | |
899aea3b JPC |
65 | .select_related( |
66 | "dossier", "dossier_employe", "dossier_poste", "type" | |
67 | ) | |
98d6eb6c JPC |
68 | |
69 | employes = {} | |
70 | for r in remunerations: | |
71 | if r.dossier.employe_id not in employes: | |
9163be6f JPC |
72 | employes[r.dossier.employe_id] = { |
73 | 'dossiers': set(), | |
74 | 'remunerations': [] | |
75 | } | |
98d6eb6c JPC |
76 | employes[r.dossier.employe_id]['remunerations'].append(r) |
77 | employes[r.dossier.employe_id]['dossiers'].add(r.dossier) | |
78 | ||
79 | self.employes = employes | |
9163be6f | 80 | |
98d6eb6c JPC |
81 | self.rapport = [] |
82 | ||
57e2b793 JPC |
83 | pays_list = {} |
84 | for pays in ref.Pays.objects.all(): | |
85 | pays_list[pays.id] = pays | |
86 | ||
98d6eb6c JPC |
87 | valeurs_point_par_imp = \ |
88 | dict( | |
9163be6f JPC |
89 | (v.implantation.id, v) for v in \ |
90 | rh.ValeurPoint.objects.filter(annee=self.annee).all() | |
98d6eb6c | 91 | ) |
57e2b793 JPC |
92 | |
93 | self.headers = ( | |
94 | ('bureau', u"Bureau"), | |
95 | ('pays', u"Pays"), | |
96 | ('implantation', u"Implantation"), | |
97 | ('valeur_point', u"Valeur du point"), | |
98 | ('numero_employe', u"Numéro d'employé"), | |
99 | ('nom', u"Nom"), | |
100 | ('prenom', u"Prénom"), | |
101 | ('type_de_poste', u"Type de poste"), | |
102 | ('intitule_de_poste', u"Intitulé du poste"), | |
103 | ('niveau', u"Niveau"), | |
104 | ('point', u"Point"), | |
105 | ('regime_de_travail', u"Régime de travail"), | |
106 | ('local_expatrie', u"Local / Expatrié"), | |
107 | ('statut', u"Statut"), | |
108 | ('date_fin_contrat', u"Date de fin de contrat"), | |
109 | ('date_debut', u"Date de début"), | |
110 | ('date_fin', u"Date de fin"), | |
111 | ('nb_jours', u"Nombre de jours"), | |
112 | ('devise', u"Devise"), | |
113 | ('salaire_bstg_annuel', u"Salaire annuel BSTG"), | |
114 | ('salaire_bstg_total', u"Salaire total BSTG"), | |
115 | ('organisme_bstg', u"Organisme BSTG"), | |
116 | ('salaire_theorique', u"Salaire théorique"), | |
117 | ('salaire_base_brut', u"Salaire de base brut"), | |
118 | ('salaire_complementaire', u"Salaire complémentaire"), | |
119 | ('indemnite_fonctions', u"Indemnités de fonctions"), | |
120 | ('indemnite_expat', u"Indemnités d'expatriation"), | |
121 | ('indemnite_logement', u"Indemnités de logement"), | |
122 | ('indemnite_transp', u"Indemnités de transport"), | |
123 | ('indemnite_13e', u"Indemnités 13e mois"), | |
124 | ('indemnite_autre', u"Autre indemnités"), | |
125 | ('total_brut', u"Total brut"), | |
126 | ('prime_interim', u"Prime d'intérim"), | |
127 | ('prime_installation', u"Prime d'installation"), | |
128 | ('prime_demenagement', u"Prime de déménagement"), | |
129 | ('prime_avion', u"Prime d'avion"), | |
130 | ('prime_autre', u"Autre prime"), | |
131 | ('prime_total', u"Total des primes"), | |
132 | ('charges_patronales', u"Charges patronales"), | |
133 | ('charges_patronales_annee', u"Charge patronale %s" % \ | |
134 | self.annee), | |
135 | ('masse_salariale', u"Masse salariale"), | |
136 | ('masse_salariale_annee', u"Masse salariale %s" % self.annee), | |
137 | ('masse_salariale_annee_euro', u"Masse salariale euro %s" % \ | |
138 | self.annee), | |
139 | ) | |
140 | ||
98d6eb6c JPC |
141 | for item in self.employes.values(): |
142 | dossiers = item['dossiers'] | |
143 | remuns = item['remunerations'] | |
144 | #TODO, choisir le dossier primaire | |
145 | if len(dossiers) > 1: | |
146 | #TODO | |
147 | pass | |
148 | dossier = list(dossiers)[0] | |
95ad7aab | 149 | regime = float(dossier.poste.regime_travail) / 100 |
9163be6f | 150 | |
98d6eb6c JPC |
151 | if dossier.poste.expatrie: |
152 | statut = "E" | |
153 | else: | |
154 | statut = "L" | |
155 | ||
9163be6f JPC |
156 | #on détermine la date du début et fin du dossier si année en cours |
157 | try: | |
158 | d_date_fin = dossier.date_fin \ | |
159 | if dossier.date_fin.year == date_fin.year else None | |
160 | except AttributeError: | |
161 | d_date_fin = None | |
162 | try: | |
163 | d_date_debut = dossier.date_debut \ | |
164 | if dossier.date_debut.year == date_fin.year else None | |
165 | except AttributeError: | |
166 | d_date_debut = None | |
98d6eb6c JPC |
167 | |
168 | pays = \ | |
169 | pays_list[dossier.poste.implantation.adresse_physique_pays.id] | |
170 | ||
171 | #on détermine si les rémunérations sont tous dans la même devise | |
172 | devise = remuns[0].devise | |
173 | meme_devise = True | |
174 | for r in remuns[1:]: | |
175 | if devise != r.devise: | |
176 | meme_devise = False | |
177 | ||
178 | if not meme_devise: | |
179 | for r in remuns: | |
180 | self.convertir(r) | |
181 | ||
182 | bstg_dossier = None | |
183 | for d in dossiers: | |
184 | if d.organisme_bstg: | |
185 | bstg_dossier = d | |
186 | ||
9163be6f | 187 | bstg_remun = None |
98d6eb6c | 188 | if bstg_dossier: |
9163be6f | 189 | for r in bstg_dossier.rh_remunerations.all(): |
958e67e8 | 190 | if r.type.id in TYPE_REMUN_BSTG: |
9163be6f | 191 | bstg_remun = r |
98d6eb6c | 192 | |
958e67e8 | 193 | if bstg_remun: |
df37184c JPC |
194 | bstg_remun_euro = rh.Remuneration( |
195 | montant=bstg_remun.montant, devise=bstg_remun.devise | |
196 | ) | |
958e67e8 | 197 | self.convertir(bstg_remun_euro) |
958e67e8 | 198 | |
4d17560e JPC |
199 | salaire_complement = 0.0 |
200 | salaire_base = 0.0 | |
201 | indemnites = { | |
202 | 'fonc_resp': 0.0, | |
203 | 'expat': 0.0, | |
204 | 'logement': 0.0, | |
205 | 'transp': 0.0, | |
206 | '13e': 0.0, | |
207 | 'autre_recurr': 0.0, | |
208 | } | |
95ad7aab JPC |
209 | |
210 | primes = { | |
211 | 'interim': 0.0, | |
212 | 'installation': 0.0, | |
213 | 'demenagement': 0.0, | |
214 | 'avion': 0.0, | |
215 | 'autre': 0.0, | |
216 | } | |
899aea3b | 217 | charges = 0.0 |
4d17560e JPC |
218 | for r in remuns: |
219 | montant = float(r.montant) | |
95ad7aab JPC |
220 | |
221 | if r.type_id in TYPE_REMUN_MAD: | |
4d17560e JPC |
222 | salaire_complement += montant |
223 | ||
95ad7aab | 224 | if r.type_id in TYPE_REMUN_BASE: |
4d17560e JPC |
225 | salaire_base += montant |
226 | ||
95ad7aab | 227 | if r.type_id in TYPE_REMUN_FONC_RESP: |
4d17560e JPC |
228 | indemnites['fonc_resp'] += montant |
229 | ||
95ad7aab | 230 | if r.type_id in TYPE_REMUN_EXPAT: |
4d17560e JPC |
231 | indemnites['expat'] += montant |
232 | ||
95ad7aab | 233 | if r.type_id in TYPE_REMUN_LOGEMENT: |
4d17560e JPC |
234 | indemnites['logement'] += montant |
235 | ||
95ad7aab | 236 | if r.type_id in TYPE_REMUN_TRANSP: |
4d17560e JPC |
237 | indemnites['transp'] += montant |
238 | ||
95ad7aab | 239 | if r.type_id in TYPE_REMUN_13E: |
4d17560e JPC |
240 | indemnites['13e'] += montant |
241 | ||
95ad7aab | 242 | if r.type_id not in TYPE_REMUN_AUTRE_RECURR_NOT \ |
4d17560e JPC |
243 | and r.type.type_paiement != TYPE_PAIEMENT_PONCTUEL: |
244 | indemnites['autre_recurr'] += montant | |
245 | ||
95ad7aab JPC |
246 | if r.type_id in TYPE_PRIME_INTERIM: |
247 | primes['interim'] += montant | |
248 | ||
249 | if r.type_id in TYPE_PRIME_INSTALLATION: | |
250 | primes['installation'] += montant | |
251 | ||
252 | if r.type_id in TYPE_PRIME_DEMENAG: | |
253 | primes['demenagement'] += montant | |
254 | ||
255 | if r.type_id in TYPE_PRIME_AVION: | |
256 | primes['avion'] += montant | |
257 | ||
258 | if r.type_id not in TYPE_REMUN_AUTRE_RECURR_NOT and \ | |
259 | r.type.nature_remuneration == TYPE_NATURE_PAIEMENT: | |
260 | primes['autre'] += montant | |
261 | ||
899aea3b JPC |
262 | if r.type.nature_remuneration == TYPE_NATURE_CHARGES: |
263 | charges += montant | |
264 | ||
4d17560e JPC |
265 | total_indemnites = sum(indemnites.values()) |
266 | ||
9163be6f | 267 | #Calcul du nombre de jours pour ce dossier. |
4d17560e JPC |
268 | if dossier.date_debut and dossier.date_debut > date_debut and \ |
269 | not dossier.date_fin: | |
270 | date_delta = date_fin - dossier.date_fin | |
271 | elif dossier.date_fin and dossier.date_fin < date_fin and \ | |
272 | not dossier.date_debut: | |
273 | date_delta = dossier.date_fin - date_debut | |
274 | elif dossier.date_fin and dossier.date_debut: | |
275 | date_delta = dossier.date_fin - date_debut | |
276 | else: | |
9163be6f | 277 | date_delta = rapport_date_delta |
98d6eb6c | 278 | |
899aea3b JPC |
279 | masse_salariale = (salaire_base + total_indemnites + \ |
280 | sum(primes.values()) + charges) | |
df37184c | 281 | masse_salariale_euro = rh.Remuneration(montant=masse_salariale, |
023bdc65 JPC |
282 | devise=remuns[0].devise) |
283 | self.convertir(masse_salariale_euro) | |
284 | ||
22b53270 JPC |
285 | if dossier.classement and dossier.classement.coefficient: |
286 | coefficient = dossier.classement.coefficient | |
287 | else: | |
288 | coefficient = "" | |
289 | ||
290 | #todo valeur du point si pas présent | |
291 | valeur_point = valeurs_point_par_imp.get( | |
292 | dossier.poste.implantation_id | |
293 | ) or "" | |
294 | ||
295 | salaire_theorique = "%s" % ( | |
296 | round(valeur_point.valeur * int(coefficient) * regime, 2) \ | |
297 | if valeur_point and coefficient and regime else "") | |
298 | ||
57e2b793 JPC |
299 | item_rapport = { |
300 | 'bureau': dossier.poste.implantation.region.code, | |
301 | 'pays': unicode(pays), | |
302 | 'implantation': dossier.poste.implantation.nom_court, | |
303 | 'type_implantation': dossier.poste.implantation.type, | |
304 | #'imputation': None, | |
305 | 'valeur_point': valeur_point, | |
306 | 'numero_employe': dossier.employe_id, | |
307 | 'nom': dossier.employe.nom.upper(), | |
308 | 'prenom': dossier.employe.prenom, | |
309 | 'type_de_poste': dossier.poste.type_poste.nom, | |
310 | 'intitule_de_poste': dossier.poste.nom, | |
311 | 'niveau': unicode(dossier.classement), | |
312 | 'point': coefficient, | |
313 | 'regime_de_travail': "%s %%" % int(regime * 100), | |
314 | 'local_expatrie': statut, | |
315 | 'statut': dossier.statut.code, | |
316 | 'date_fin_contrat': dossier.date_fin or "", | |
317 | 'date_debut': d_date_debut or "", | |
318 | 'date_fin': d_date_fin or "", | |
319 | 'nb_jours': date_delta.days, | |
320 | 'devise': remuns[0].devise, | |
321 | 'salaire_bstg_annuel': bstg_remun.montant \ | |
322 | if bstg_remun else "", | |
323 | 'salaire_bstg_total': bstg_remun_euro.montant \ | |
324 | if bstg_remun else "", | |
325 | 'organisme_bstg': dossier.organisme_bstg or "", | |
326 | 'salaire_theorique': salaire_theorique, | |
327 | 'salaire_base_brut': \ | |
95ad7aab JPC |
328 | salaire_base * regime * ( |
329 | date_delta.days / rapport_date_delta.days | |
57e2b793 JPC |
330 | ), |
331 | 'salaire_complementaire': \ | |
95ad7aab JPC |
332 | salaire_complement * regime * ( |
333 | date_delta.days / rapport_date_delta.days | |
57e2b793 JPC |
334 | ), |
335 | #'salaire_total': None | |
336 | 'indemnite_fonctions': indemnites['fonc_resp'] * \ | |
023bdc65 | 337 | regime * \ |
57e2b793 JPC |
338 | (date_delta.days / rapport_date_delta.days), |
339 | 'indemnite_expat': indemnites['expat'] * regime * \ | |
340 | (date_delta.days / rapport_date_delta.days), | |
341 | 'indemnite_logement': indemnites['logement'] * \ | |
023bdc65 | 342 | regime * \ |
57e2b793 JPC |
343 | (date_delta.days / rapport_date_delta.days), |
344 | 'indemnite_transp': indemnites['transp'] * regime * \ | |
345 | (date_delta.days / rapport_date_delta.days), | |
346 | 'indemnite_13e': indemnites['13e'] * regime * \ | |
347 | (date_delta.days / rapport_date_delta.days), | |
348 | 'indemnite_autre': indemnites['autre_recurr'] * \ | |
023bdc65 | 349 | regime * \ |
57e2b793 JPC |
350 | (date_delta.days / rapport_date_delta.days), |
351 | 'indemnite_total': total_indemnites * regime * \ | |
352 | (date_delta.days / rapport_date_delta.days), | |
353 | 'total_brut': ( | |
95ad7aab JPC |
354 | total_indemnites + salaire_base + |
355 | salaire_complement | |
356 | ) * regime * ( | |
357 | date_delta.days / rapport_date_delta.days | |
57e2b793 JPC |
358 | ), |
359 | 'prime_interim': primes['interim'] * regime * \ | |
360 | (date_delta.days / rapport_date_delta.days), | |
361 | 'prime_installation': primes['installation'] * regime * \ | |
362 | (date_delta.days / rapport_date_delta.days), | |
363 | 'prime_demenagement': primes['demenagement'] * regime * \ | |
364 | (date_delta.days / rapport_date_delta.days), | |
365 | 'prime_avion': primes['avion'] * regime * \ | |
366 | (date_delta.days / rapport_date_delta.days), | |
367 | 'prime_autre': primes['autre'] * regime * \ | |
368 | (date_delta.days / rapport_date_delta.days), | |
369 | 'prime_total': sum(primes.values()) * regime * \ | |
370 | (date_delta.days / rapport_date_delta.days), | |
371 | 'charges_patronales': charges, | |
372 | 'charges_patronales_annee': charges * regime * \ | |
373 | (date_delta.days / rapport_date_delta.days), | |
374 | 'masse_salariale': masse_salariale, | |
375 | 'masse_salariale_annee': masse_salariale * \ | |
899aea3b JPC |
376 | regime * ( |
377 | date_delta.days / rapport_date_delta.days | |
57e2b793 JPC |
378 | ), |
379 | 'masse_salariale_annee_euro': \ | |
023bdc65 JPC |
380 | masse_salariale_euro.montant * regime * ( |
381 | date_delta.days / rapport_date_delta.days | |
57e2b793 JPC |
382 | ), |
383 | } | |
98d6eb6c JPC |
384 | |
385 | self.rapport.append(item_rapport) | |
386 | ||
98d6eb6c JPC |
387 | def build_qs(self, prefix, date_debut, date_fin): |
388 | date_debut_null = \ | |
389 | Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True}) | |
390 | date_fin_null = \ | |
391 | Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True}) | |
392 | date_debut_superieure_ou_egale_a_borne_gauche = \ | |
393 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut}) | |
394 | date_debut_inferieure_ou_egale_a_borne_gauche = \ | |
395 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut}) | |
396 | date_fin_superieure_ou_egale_a_borne_gauche = \ | |
397 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut}) | |
398 | date_fin_inferieure_ou_egale_a_borne_droite = \ | |
399 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin}) | |
400 | date_debut_inferieure_ou_egale_a_borne_droite = \ | |
401 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin}) | |
402 | date_fin_superieure_ou_egale_a_borne_droite = \ | |
403 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin}) | |
404 | ||
405 | q_range = \ | |
406 | ( | |
407 | date_debut_null & date_fin_null | |
408 | ) | ( | |
409 | date_debut_inferieure_ou_egale_a_borne_gauche & | |
410 | date_fin_superieure_ou_egale_a_borne_gauche & | |
411 | date_fin_inferieure_ou_egale_a_borne_droite | |
412 | ) | ( | |
413 | date_debut_superieure_ou_egale_a_borne_gauche & | |
414 | date_debut_inferieure_ou_egale_a_borne_droite & | |
415 | date_fin_superieure_ou_egale_a_borne_droite | |
416 | ) | ( | |
417 | date_debut_inferieure_ou_egale_a_borne_gauche & | |
418 | date_fin_superieure_ou_egale_a_borne_droite | |
419 | ) | ( | |
420 | date_debut_null & | |
421 | date_fin_superieure_ou_egale_a_borne_droite | |
422 | ) | ( | |
423 | date_debut_inferieure_ou_egale_a_borne_gauche & | |
424 | date_fin_null | |
425 | ) | |
426 | ||
427 | return q_range | |
428 | ||
429 | def convertir(self, remuneration): | |
9163be6f JPC |
430 | if remuneration.devise != self.devise_base: |
431 | remuneration.montant = float(remuneration.montant) * \ | |
432 | self.trouver_taux(remuneration.devise).taux | |
433 | remuneration.devise = self.devise_base | |
98d6eb6c JPC |
434 | |
435 | def trouver_taux(self, devise): | |
436 | if devise.code not in self.taux_change: | |
437 | t = rh.TauxChange.objects.filter( | |
438 | devise=devise, annee=self.annee | |
439 | )[0] | |
440 | self.taux_change[devise.code] = t | |
441 | return self.taux_change[devise.code] | |
899aea3b JPC |
442 | |
443 | def csv(self): | |
444 | self.csv_handle = StringIO.StringIO() | |
023bdc65 JPC |
445 | csv_writer = csv.writer(self.csv_handle, delimiter=",", |
446 | doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL, | |
447 | ) | |
448 | header = [v[0] for v in self.rapport[0]] | |
449 | csv_writer.writerow(header) | |
450 | for row in self.rapport: | |
451 | values = [v[1] for v in row] | |
452 | csv_writer.writerow( | |
453 | [unicode(r).encode('utf-8') for r in values] | |
454 | ) |