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