Merge branch 'dev', remote-tracking branch 'origin' into masse_salariale_jp
[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
98d6eb6c
JPC
6
7from django.db.models import Q
8
9from datamaster_modeles import models as ref
98d6eb6c
JPC
10import rh.models as rh
11
12
13KEY_DATE_DEBUT = "debut"
14KEY_DATE_FIN = "fin"
4d17560e
JPC
15
16TYPE_REMUN_BSTG = (3,)
17TYPE_REMUN_MAD = (2,)
18TYPE_REMUN_BASE = (1,)
95ad7aab 19TYPE_REMUN_FONC_RESP = (7, 8)
4d17560e
JPC
20TYPE_REMUN_EXPAT = (4,)
21TYPE_REMUN_LOGEMENT = (6,)
22TYPE_REMUN_TRANSP = (9,)
23TYPE_REMUN_13E = (18,)
95ad7aab 24TYPE_REMUN_AUTRE_RECURR_NOT = (1, 2, 3, 4, 6, 7, 8, 9, 18, 13, 14, 15, 19)
4d17560e 25TYPE_PAIEMENT_PONCTUEL = u"Ponctuel"
95ad7aab
JPC
26TYPE_PRIME_INTERIM = (19,)
27TYPE_PRIME_INSTALLATION = (13,)
28TYPE_PRIME_DEMENAG = (15,)
29TYPE_PRIME_AVION = (14,)
899aea3b
JPC
30TYPE_NATURE_PAIEMENT = u"Accessoire"
31TYPE_NATURE_CHARGES = u"Charges"
32
9163be6f 33
98d6eb6c
JPC
34class 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
40 """
41 date_debut = datetime.date(
42 *time.strptime(date_debut, "%d-%m-%Y")[0:3]
43 )
44 date_fin = datetime.date(*time.strptime(date_fin, "%d-%m-%Y")[0:3])
9163be6f 45 rapport_date_delta = date_fin - date_debut
98d6eb6c
JPC
46
47 self.annee = date_fin.year
48
49 self.devise_base = rh.Devise.objects.filter(code='EUR')[0]
50 self.taux_change = {}
51
52 q_range = self.build_qs("date_", date_debut, date_fin)
53 q_range_d = self.build_qs("dossier__date_", date_debut, date_fin)
54 remunerations = rh.Remuneration.objects.filter(q_range) \
55 .filter(q_range_d) \
023bdc65
JPC
56
57 if custom_filter:
58 remunerations = remunerations.filter(**custom_filter)
59
60 remunerations = remunerations.exclude(supprime=True) \
899aea3b
JPC
61 .select_related(
62 "dossier", "dossier_employe", "dossier_poste", "type"
63 )
98d6eb6c
JPC
64
65 employes = {}
66 for r in remunerations:
67 if r.dossier.employe_id not in employes:
9163be6f
JPC
68 employes[r.dossier.employe_id] = {
69 'dossiers': set(),
70 'remunerations': []
71 }
98d6eb6c
JPC
72 employes[r.dossier.employe_id]['remunerations'].append(r)
73 employes[r.dossier.employe_id]['dossiers'].add(r.dossier)
74
75 self.employes = employes
9163be6f 76
98d6eb6c
JPC
77 self.rapport = []
78
79 pays_list = ref.Pays.objects.all()
80 valeurs_point_par_imp = \
81 dict(
9163be6f
JPC
82 (v.implantation.id, v) for v in \
83 rh.ValeurPoint.objects.filter(annee=self.annee).all()
98d6eb6c
JPC
84 )
85 for item in self.employes.values():
86 dossiers = item['dossiers']
87 remuns = item['remunerations']
88 #TODO, choisir le dossier primaire
89 if len(dossiers) > 1:
90 #TODO
91 pass
92 dossier = list(dossiers)[0]
95ad7aab 93 regime = float(dossier.poste.regime_travail) / 100
9163be6f 94
98d6eb6c
JPC
95 if dossier.poste.expatrie:
96 statut = "E"
97 else:
98 statut = "L"
99
9163be6f
JPC
100 #on détermine la date du début et fin du dossier si année en cours
101 try:
102 d_date_fin = dossier.date_fin \
103 if dossier.date_fin.year == date_fin.year else None
104 except AttributeError:
105 d_date_fin = None
106 try:
107 d_date_debut = dossier.date_debut \
108 if dossier.date_debut.year == date_fin.year else None
109 except AttributeError:
110 d_date_debut = None
98d6eb6c
JPC
111
112 pays = \
113 pays_list[dossier.poste.implantation.adresse_physique_pays.id]
114
115 #on détermine si les rémunérations sont tous dans la même devise
116 devise = remuns[0].devise
117 meme_devise = True
118 for r in remuns[1:]:
119 if devise != r.devise:
120 meme_devise = False
121
122 if not meme_devise:
123 for r in remuns:
124 self.convertir(r)
125
126 bstg_dossier = None
127 for d in dossiers:
128 if d.organisme_bstg:
129 bstg_dossier = d
130
9163be6f 131 bstg_remun = None
98d6eb6c 132 if bstg_dossier:
9163be6f 133 for r in bstg_dossier.rh_remunerations.all():
958e67e8 134 if r.type.id in TYPE_REMUN_BSTG:
9163be6f 135 bstg_remun = r
98d6eb6c 136
958e67e8
JPC
137 if bstg_remun:
138 bstg_remun_euro = bstg_remun
139 self.convertir(bstg_remun_euro)
140 print bstg_remun.devise, bstg_remun_euro.devise
141
4d17560e
JPC
142 salaire_complement = 0.0
143 salaire_base = 0.0
144 indemnites = {
145 'fonc_resp': 0.0,
146 'expat': 0.0,
147 'logement': 0.0,
148 'transp': 0.0,
149 '13e': 0.0,
150 'autre_recurr': 0.0,
151 }
95ad7aab
JPC
152
153 primes = {
154 'interim': 0.0,
155 'installation': 0.0,
156 'demenagement': 0.0,
157 'avion': 0.0,
158 'autre': 0.0,
159 }
899aea3b 160 charges = 0.0
4d17560e
JPC
161 for r in remuns:
162 montant = float(r.montant)
95ad7aab
JPC
163
164 if r.type_id in TYPE_REMUN_MAD:
4d17560e
JPC
165 salaire_complement += montant
166
95ad7aab 167 if r.type_id in TYPE_REMUN_BASE:
4d17560e
JPC
168 salaire_base += montant
169
95ad7aab 170 if r.type_id in TYPE_REMUN_FONC_RESP:
4d17560e
JPC
171 indemnites['fonc_resp'] += montant
172
95ad7aab 173 if r.type_id in TYPE_REMUN_EXPAT:
4d17560e
JPC
174 indemnites['expat'] += montant
175
95ad7aab 176 if r.type_id in TYPE_REMUN_LOGEMENT:
4d17560e
JPC
177 indemnites['logement'] += montant
178
95ad7aab 179 if r.type_id in TYPE_REMUN_TRANSP:
4d17560e
JPC
180 indemnites['transp'] += montant
181
95ad7aab 182 if r.type_id in TYPE_REMUN_13E:
4d17560e
JPC
183 indemnites['13e'] += montant
184
95ad7aab 185 if r.type_id not in TYPE_REMUN_AUTRE_RECURR_NOT \
4d17560e
JPC
186 and r.type.type_paiement != TYPE_PAIEMENT_PONCTUEL:
187 indemnites['autre_recurr'] += montant
188
95ad7aab
JPC
189 if r.type_id in TYPE_PRIME_INTERIM:
190 primes['interim'] += montant
191
192 if r.type_id in TYPE_PRIME_INSTALLATION:
193 primes['installation'] += montant
194
195 if r.type_id in TYPE_PRIME_DEMENAG:
196 primes['demenagement'] += montant
197
198 if r.type_id in TYPE_PRIME_AVION:
199 primes['avion'] += montant
200
201 if r.type_id not in TYPE_REMUN_AUTRE_RECURR_NOT and \
202 r.type.nature_remuneration == TYPE_NATURE_PAIEMENT:
203 primes['autre'] += montant
204
899aea3b
JPC
205 if r.type.nature_remuneration == TYPE_NATURE_CHARGES:
206 charges += montant
207
4d17560e
JPC
208 total_indemnites = sum(indemnites.values())
209
9163be6f 210 #Calcul du nombre de jours pour ce dossier.
4d17560e
JPC
211 if dossier.date_debut and dossier.date_debut > date_debut and \
212 not dossier.date_fin:
213 date_delta = date_fin - dossier.date_fin
214 elif dossier.date_fin and dossier.date_fin < date_fin and \
215 not dossier.date_debut:
216 date_delta = dossier.date_fin - date_debut
217 elif dossier.date_fin and dossier.date_debut:
218 date_delta = dossier.date_fin - date_debut
219 else:
9163be6f 220 date_delta = rapport_date_delta
98d6eb6c 221
899aea3b
JPC
222 masse_salariale = (salaire_base + total_indemnites + \
223 sum(primes.values()) + charges)
023bdc65
JPC
224 masse_salariale_euro = rh.Remuneration(montant=masse_salariale,
225 devise=remuns[0].devise)
226 self.convertir(masse_salariale_euro)
227
228 item_rapport = (
229 ('bureau', dossier.poste.implantation.region.code),
230 ('pays', unicode(pays)),
231 ('implantation', dossier.poste.implantation.nom_court),
232 ('type_implantation', dossier.poste.implantation.type),
233 #'imputation', None),
234 ('valeur_point',
9163be6f 235 #todo valeur du point si pas présent
98d6eb6c
JPC
236 valeurs_point_par_imp.get(
237 dossier.poste.implantation_id
023bdc65
JPC
238 ) or ""),
239 ('numero_employe', dossier.employe_id),
240 ('nom', dossier.employe.nom.upper()),
241 ('prenom', dossier.employe.prenom),
242 ('type_de_poste', dossier.poste.type_poste.nom),
243 ('intitule_de_poste', dossier.poste.nom),
244 ('niveau', unicode(dossier.classement)),
245 ('point', "%s" %
98d6eb6c 246 dossier.classement.coefficient \
9163be6f
JPC
247 if dossier.classement and
248 dossier.classement.coefficient
023bdc65
JPC
249 else ""),
250 ('regime_de_travail', "%s %%" % int(regime * 100)),
251 ('local_expatrie', statut),
252 ('statut', dossier.statut.code),
253 ('date_fin_contrat', dossier.date_fin or ""),
254 ('date_debut', d_date_debut or ""),
255 ('date_fin', d_date_fin or ""),
256 ('nb_jours', date_delta.days),
257 ('devise', remuns[0].devise),
258 ('salaire_bstg_annuel', bstg_remun.montant \
259 if bstg_remun else ""),
958e67e8 260 ('salaire_bstg_total', bstg_remun_euro.montant \
023bdc65
JPC
261 if bstg_remun else ""),
262 ('organisme_bstg', dossier.organisme_bstg or ""),
263 ('salaire_base_brut', \
95ad7aab
JPC
264 salaire_base * regime * (
265 date_delta.days / rapport_date_delta.days
023bdc65
JPC
266 )),
267 ('salaire_complementaire', \
95ad7aab
JPC
268 salaire_complement * regime * (
269 date_delta.days / rapport_date_delta.days
023bdc65
JPC
270 )),
271 #'salaire_total', None
272 ('indemnite_fonctions', indemnites['fonc_resp'] * \
273 regime * \
274 (date_delta.days / rapport_date_delta.days)),
275 ('indemnite_expat', indemnites['expat'] * regime * \
276 (date_delta.days / rapport_date_delta.days)),
277 ('indemnite_logement', indemnites['logement'] * \
278 regime * \
279 (date_delta.days / rapport_date_delta.days)),
280 ('indemnites_transp', indemnites['transp'] * regime * \
281 (date_delta.days / rapport_date_delta.days)),
282 ('indemnites_13e', indemnites['13e'] * regime * \
283 (date_delta.days / rapport_date_delta.days)),
284 ('indemnites_autre', indemnites['autre_recurr'] * \
285 regime * \
286 (date_delta.days / rapport_date_delta.days)),
287 ('indemnites_total', total_indemnites * regime * \
288 (date_delta.days / rapport_date_delta.days)),
289 ('total_brut', (
95ad7aab
JPC
290 total_indemnites + salaire_base +
291 salaire_complement
292 ) * regime * (
293 date_delta.days / rapport_date_delta.days
023bdc65
JPC
294 )),
295 ('prime_interim', primes['interim'] * regime * \
296 (date_delta.days / rapport_date_delta.days)),
297 ('prime_installation', primes['installation'] * regime * \
298 (date_delta.days / rapport_date_delta.days)),
299 ('prime_demenagement', primes['demenagement'] * regime * \
300 (date_delta.days / rapport_date_delta.days)),
301 ('prime_avion', primes['avion'] * regime * \
302 (date_delta.days / rapport_date_delta.days)),
303 ('prime_autre', primes['autre'] * regime * \
304 (date_delta.days / rapport_date_delta.days)),
305 ('prime_total', sum(primes.values()) * regime * \
306 (date_delta.days / rapport_date_delta.days)),
307 ('charges_patronales', charges),
308 ('charges_patronales_%s' % self.annee, charges * regime * \
309 (date_delta.days / rapport_date_delta.days)),
310 ('masse_salariale', masse_salariale),
311 ('masse_salariale_%s' % self.annee, masse_salariale * \
899aea3b
JPC
312 regime * (
313 date_delta.days / rapport_date_delta.days
023bdc65
JPC
314 )),
315 ('masse_salariale__euro_%s' % self.annee, \
316 masse_salariale_euro.montant * regime * (
317 date_delta.days / rapport_date_delta.days
318 )),
319 )
98d6eb6c
JPC
320
321 self.rapport.append(item_rapport)
322
98d6eb6c
JPC
323 def build_qs(self, prefix, date_debut, date_fin):
324 date_debut_null = \
325 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True})
326 date_fin_null = \
327 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True})
328 date_debut_superieure_ou_egale_a_borne_gauche = \
329 Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut})
330 date_debut_inferieure_ou_egale_a_borne_gauche = \
331 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut})
332 date_fin_superieure_ou_egale_a_borne_gauche = \
333 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut})
334 date_fin_inferieure_ou_egale_a_borne_droite = \
335 Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin})
336 date_debut_inferieure_ou_egale_a_borne_droite = \
337 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin})
338 date_fin_superieure_ou_egale_a_borne_droite = \
339 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin})
340
341 q_range = \
342 (
343 date_debut_null & date_fin_null
344 ) | (
345 date_debut_inferieure_ou_egale_a_borne_gauche &
346 date_fin_superieure_ou_egale_a_borne_gauche &
347 date_fin_inferieure_ou_egale_a_borne_droite
348 ) | (
349 date_debut_superieure_ou_egale_a_borne_gauche &
350 date_debut_inferieure_ou_egale_a_borne_droite &
351 date_fin_superieure_ou_egale_a_borne_droite
352 ) | (
353 date_debut_inferieure_ou_egale_a_borne_gauche &
354 date_fin_superieure_ou_egale_a_borne_droite
355 ) | (
356 date_debut_null &
357 date_fin_superieure_ou_egale_a_borne_droite
358 ) | (
359 date_debut_inferieure_ou_egale_a_borne_gauche &
360 date_fin_null
361 )
362
363 return q_range
364
365 def convertir(self, remuneration):
9163be6f
JPC
366 if remuneration.devise != self.devise_base:
367 remuneration.montant = float(remuneration.montant) * \
368 self.trouver_taux(remuneration.devise).taux
369 remuneration.devise = self.devise_base
98d6eb6c
JPC
370
371 def trouver_taux(self, devise):
372 if devise.code not in self.taux_change:
373 t = rh.TauxChange.objects.filter(
374 devise=devise, annee=self.annee
375 )[0]
376 self.taux_change[devise.code] = t
377 return self.taux_change[devise.code]
899aea3b
JPC
378
379 def csv(self):
380 self.csv_handle = StringIO.StringIO()
023bdc65
JPC
381 csv_writer = csv.writer(self.csv_handle, delimiter=",",
382 doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL,
383 )
384 header = [v[0] for v in self.rapport[0]]
385 csv_writer.writerow(header)
386 for row in self.rapport:
387 values = [v[1] for v in row]
388 csv_writer.writerow(
389 [unicode(r).encode('utf-8') for r in values]
390 )