68ad7d1c13a44cd68d818f0df966ff69bdf3dba2
[auf_rh_dae.git] / project / rh / masse_salariale.py
1 # -*- encoding: utf-8 -*-
2 import time
3 import datetime
4 import csv
5 import StringIO
6
7 from django.db.models import Q
8
9 from datamaster_modeles import models as ref
10 import rh.models as rh
11
12
13 KEY_DATE_DEBUT = "debut"
14 KEY_DATE_FIN = "fin"
15
16 TYPE_REMUN_BSTG = (3,)
17 TYPE_REMUN_MAD = (2,)
18 TYPE_REMUN_BASE = (1,)
19 TYPE_REMUN_FONC_RESP = (7, 8)
20 TYPE_REMUN_EXPAT = (4,)
21 TYPE_REMUN_LOGEMENT = (6,)
22 TYPE_REMUN_TRANSP = (9,)
23 TYPE_REMUN_13E = (18,)
24 TYPE_REMUN_AUTRE_RECURR_NOT = (1, 2, 3, 4, 6, 7, 8, 9, 18, 13, 14, 15, 19)
25 TYPE_PAIEMENT_PONCTUEL = u"Ponctuel"
26 TYPE_PRIME_INTERIM = (19,)
27 TYPE_PRIME_INSTALLATION = (13,)
28 TYPE_PRIME_DEMENAG = (15,)
29 TYPE_PRIME_AVION = (14,)
30 TYPE_NATURE_PAIEMENT = u"Accessoire"
31 TYPE_NATURE_CHARGES = u"Charges"
32
33
34 class MasseSalariale():
35 """ Rapport de la masse salariale. """
36
37 def __init__(self, date_debut, date_fin, custom_filter=None):
38 """ date_debut: date de début pour les données temporelles
39 date_fin: idem
40 custom_filter: dictionnaire des paramètres à passer au queryset.
41 """
42 if not date_debut and not date_fin:
43 return
44
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])
49 rapport_date_delta = date_fin - date_debut
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) \
60
61 if custom_filter:
62 remunerations = remunerations.filter(**custom_filter)
63
64 remunerations = remunerations.exclude(supprime=True) \
65 .select_related(
66 "dossier", "dossier_employe", "dossier_poste", "type"
67 )
68
69 employes = {}
70 for r in remunerations:
71 if r.dossier.employe_id not in employes:
72 employes[r.dossier.employe_id] = {
73 'dossiers': set(),
74 'remunerations': []
75 }
76 employes[r.dossier.employe_id]['remunerations'].append(r)
77 employes[r.dossier.employe_id]['dossiers'].add(r.dossier)
78
79 self.employes = employes
80
81 self.rapport = []
82
83 pays_list = ref.Pays.objects.all()
84 valeurs_point_par_imp = \
85 dict(
86 (v.implantation.id, v) for v in \
87 rh.ValeurPoint.objects.filter(annee=self.annee).all()
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]
97 regime = float(dossier.poste.regime_travail) / 100
98
99 if dossier.poste.expatrie:
100 statut = "E"
101 else:
102 statut = "L"
103
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
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
135 bstg_remun = None
136 if bstg_dossier:
137 for r in bstg_dossier.rh_remunerations.all():
138 if r.type.id in TYPE_REMUN_BSTG:
139 bstg_remun = r
140
141 if bstg_remun:
142 bstg_remun_euro = rh.Remuneration(
143 montant=bstg_remun.montant, devise=bstg_remun.devise
144 )
145 self.convertir(bstg_remun_euro)
146
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 }
157
158 primes = {
159 'interim': 0.0,
160 'installation': 0.0,
161 'demenagement': 0.0,
162 'avion': 0.0,
163 'autre': 0.0,
164 }
165 charges = 0.0
166 for r in remuns:
167 montant = float(r.montant)
168
169 if r.type_id in TYPE_REMUN_MAD:
170 salaire_complement += montant
171
172 if r.type_id in TYPE_REMUN_BASE:
173 salaire_base += montant
174
175 if r.type_id in TYPE_REMUN_FONC_RESP:
176 indemnites['fonc_resp'] += montant
177
178 if r.type_id in TYPE_REMUN_EXPAT:
179 indemnites['expat'] += montant
180
181 if r.type_id in TYPE_REMUN_LOGEMENT:
182 indemnites['logement'] += montant
183
184 if r.type_id in TYPE_REMUN_TRANSP:
185 indemnites['transp'] += montant
186
187 if r.type_id in TYPE_REMUN_13E:
188 indemnites['13e'] += montant
189
190 if r.type_id not in TYPE_REMUN_AUTRE_RECURR_NOT \
191 and r.type.type_paiement != TYPE_PAIEMENT_PONCTUEL:
192 indemnites['autre_recurr'] += montant
193
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
210 if r.type.nature_remuneration == TYPE_NATURE_CHARGES:
211 charges += montant
212
213 total_indemnites = sum(indemnites.values())
214
215 #Calcul du nombre de jours pour ce dossier.
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:
225 date_delta = rapport_date_delta
226
227 masse_salariale = (salaire_base + total_indemnites + \
228 sum(primes.values()) + charges)
229 masse_salariale_euro = rh.Remuneration(montant=masse_salariale,
230 devise=remuns[0].devise)
231 self.convertir(masse_salariale_euro)
232
233 item_rapport = (
234 ('bureau', dossier.poste.implantation.region.code),
235 ('pays', unicode(pays)),
236 ('implantation', dossier.poste.implantation.nom_court),
237 ('type_implantation', dossier.poste.implantation.type),
238 #'imputation', None),
239 ('valeur_point',
240 #todo valeur du point si pas présent
241 valeurs_point_par_imp.get(
242 dossier.poste.implantation_id
243 ) or ""),
244 ('numero_employe', dossier.employe_id),
245 ('nom', dossier.employe.nom.upper()),
246 ('prenom', dossier.employe.prenom),
247 ('type_de_poste', dossier.poste.type_poste.nom),
248 ('intitule_de_poste', dossier.poste.nom),
249 ('niveau', unicode(dossier.classement)),
250 ('point', "%s" %
251 dossier.classement.coefficient \
252 if dossier.classement and
253 dossier.classement.coefficient
254 else ""),
255 ('regime_de_travail', "%s %%" % int(regime * 100)),
256 ('local_expatrie', statut),
257 ('statut', dossier.statut.code),
258 ('date_fin_contrat', dossier.date_fin or ""),
259 ('date_debut', d_date_debut or ""),
260 ('date_fin', d_date_fin or ""),
261 ('nb_jours', date_delta.days),
262 ('devise', remuns[0].devise),
263 ('salaire_bstg_annuel', bstg_remun.montant \
264 if bstg_remun else ""),
265 ('salaire_bstg_total', bstg_remun_euro.montant \
266 if bstg_remun else ""),
267 ('organisme_bstg', dossier.organisme_bstg or ""),
268 ('salaire_base_brut', \
269 salaire_base * regime * (
270 date_delta.days / rapport_date_delta.days
271 )),
272 ('salaire_complementaire', \
273 salaire_complement * regime * (
274 date_delta.days / rapport_date_delta.days
275 )),
276 #'salaire_total', None
277 ('indemnite_fonctions', indemnites['fonc_resp'] * \
278 regime * \
279 (date_delta.days / rapport_date_delta.days)),
280 ('indemnite_expat', indemnites['expat'] * regime * \
281 (date_delta.days / rapport_date_delta.days)),
282 ('indemnite_logement', indemnites['logement'] * \
283 regime * \
284 (date_delta.days / rapport_date_delta.days)),
285 ('indemnites_transp', indemnites['transp'] * regime * \
286 (date_delta.days / rapport_date_delta.days)),
287 ('indemnites_13e', indemnites['13e'] * regime * \
288 (date_delta.days / rapport_date_delta.days)),
289 ('indemnites_autre', indemnites['autre_recurr'] * \
290 regime * \
291 (date_delta.days / rapport_date_delta.days)),
292 ('indemnites_total', total_indemnites * regime * \
293 (date_delta.days / rapport_date_delta.days)),
294 ('total_brut', (
295 total_indemnites + salaire_base +
296 salaire_complement
297 ) * regime * (
298 date_delta.days / rapport_date_delta.days
299 )),
300 ('prime_interim', primes['interim'] * regime * \
301 (date_delta.days / rapport_date_delta.days)),
302 ('prime_installation', primes['installation'] * regime * \
303 (date_delta.days / rapport_date_delta.days)),
304 ('prime_demenagement', primes['demenagement'] * regime * \
305 (date_delta.days / rapport_date_delta.days)),
306 ('prime_avion', primes['avion'] * regime * \
307 (date_delta.days / rapport_date_delta.days)),
308 ('prime_autre', primes['autre'] * regime * \
309 (date_delta.days / rapport_date_delta.days)),
310 ('prime_total', sum(primes.values()) * regime * \
311 (date_delta.days / rapport_date_delta.days)),
312 ('charges_patronales', charges),
313 ('charges_patronales_%s' % self.annee, charges * regime * \
314 (date_delta.days / rapport_date_delta.days)),
315 ('masse_salariale', masse_salariale),
316 ('masse_salariale_%s' % self.annee, masse_salariale * \
317 regime * (
318 date_delta.days / rapport_date_delta.days
319 )),
320 ('masse_salariale__euro_%s' % self.annee, \
321 masse_salariale_euro.montant * regime * (
322 date_delta.days / rapport_date_delta.days
323 )),
324 )
325
326 self.rapport.append(item_rapport)
327
328 def build_qs(self, prefix, date_debut, date_fin):
329 date_debut_null = \
330 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True})
331 date_fin_null = \
332 Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True})
333 date_debut_superieure_ou_egale_a_borne_gauche = \
334 Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut})
335 date_debut_inferieure_ou_egale_a_borne_gauche = \
336 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut})
337 date_fin_superieure_ou_egale_a_borne_gauche = \
338 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut})
339 date_fin_inferieure_ou_egale_a_borne_droite = \
340 Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin})
341 date_debut_inferieure_ou_egale_a_borne_droite = \
342 Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin})
343 date_fin_superieure_ou_egale_a_borne_droite = \
344 Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin})
345
346 q_range = \
347 (
348 date_debut_null & date_fin_null
349 ) | (
350 date_debut_inferieure_ou_egale_a_borne_gauche &
351 date_fin_superieure_ou_egale_a_borne_gauche &
352 date_fin_inferieure_ou_egale_a_borne_droite
353 ) | (
354 date_debut_superieure_ou_egale_a_borne_gauche &
355 date_debut_inferieure_ou_egale_a_borne_droite &
356 date_fin_superieure_ou_egale_a_borne_droite
357 ) | (
358 date_debut_inferieure_ou_egale_a_borne_gauche &
359 date_fin_superieure_ou_egale_a_borne_droite
360 ) | (
361 date_debut_null &
362 date_fin_superieure_ou_egale_a_borne_droite
363 ) | (
364 date_debut_inferieure_ou_egale_a_borne_gauche &
365 date_fin_null
366 )
367
368 return q_range
369
370 def convertir(self, remuneration):
371 if remuneration.devise != self.devise_base:
372 remuneration.montant = float(remuneration.montant) * \
373 self.trouver_taux(remuneration.devise).taux
374 remuneration.devise = self.devise_base
375
376 def trouver_taux(self, devise):
377 if devise.code not in self.taux_change:
378 t = rh.TauxChange.objects.filter(
379 devise=devise, annee=self.annee
380 )[0]
381 self.taux_change[devise.code] = t
382 return self.taux_change[devise.code]
383
384 def csv(self):
385 self.csv_handle = StringIO.StringIO()
386 csv_writer = csv.writer(self.csv_handle, delimiter=",",
387 doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL,
388 )
389 header = [v[0] for v in self.rapport[0]]
390 csv_writer.writerow(header)
391 for row in self.rapport:
392 values = [v[1] for v in row]
393 csv_writer.writerow(
394 [unicode(r).encode('utf-8') for r in values]
395 )