Commit | Line | Data |
---|---|---|
98d6eb6c | 1 | # -*- encoding: utf-8 -*- |
899aea3b | 2 | import csv |
4ba84959 | 3 | import datetime |
07f120f3 | 4 | import itertools |
4ba84959 EMS |
5 | import StringIO |
6 | import time | |
98d6eb6c | 7 | |
4c17e518 | 8 | from auf.django.references import models as ref |
d104b0ae | 9 | from django.db.models import Q, Count |
75f0e87b | 10 | |
4ba84959 EMS |
11 | from project.rh import ods |
12 | from project.rh import models as rh | |
98d6eb6c JPC |
13 | |
14 | ||
15 | KEY_DATE_DEBUT = "debut" | |
16 | KEY_DATE_FIN = "fin" | |
4d17560e JPC |
17 | |
18 | TYPE_REMUN_BSTG = (3,) | |
19 | TYPE_REMUN_MAD = (2,) | |
20 | TYPE_REMUN_BASE = (1,) | |
95ad7aab | 21 | TYPE_REMUN_FONC_RESP = (7, 8) |
4d17560e JPC |
22 | TYPE_REMUN_EXPAT = (4,) |
23 | TYPE_REMUN_LOGEMENT = (6,) | |
9fd09bdc | 24 | TYPE_REMUN_SCOLARITE = (5,) |
4d17560e JPC |
25 | TYPE_REMUN_TRANSP = (9,) |
26 | TYPE_REMUN_13E = (18,) | |
95ad7aab | 27 | TYPE_PRIME_INTERIM = (19,) |
a6927189 JPC |
28 | TYPE_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 |
32 | TYPE_PRIME_INSTALLATION = (13,) |
33 | TYPE_PRIME_DEMENAG = (15,) | |
34 | TYPE_PRIME_AVION = (14,) | |
07f120f3 JPC |
35 | TYPE_PRIME_ALL = list(itertools.chain( |
36 | *(TYPE_PRIME_INSTALLATION, TYPE_PRIME_DEMENAG, TYPE_PRIME_AVION) | |
37 | )) | |
38 | TYPE_CHARGE_PATRONALE = (17,) | |
39 | TYPE_CHARGE_ALL = list(itertools.chain(*(TYPE_CHARGE_PATRONALE,))) | |
40 | TYPE_NATURE_INDEMN = u"Indemnité" | |
899aea3b JPC |
41 | TYPE_NATURE_PAIEMENT = u"Accessoire" |
42 | TYPE_NATURE_CHARGES = u"Charges" | |
5c5de149 | 43 | TYPE_NATURE_TRAITEMENT = u"Traitement" |
eabb27fd | 44 | HEADER_SEPARATOR = ('sep', ods.Separator(), {'columnwidth': '0.4cm'}) |
899aea3b | 45 | |
9163be6f | 46 | |
98d6eb6c JPC |
47 | class 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 | ||
023bdc65 | 92 | remunerations = remunerations.exclude(supprime=True) \ |
899aea3b JPC |
93 | .select_related( |
94 | "dossier", "dossier_employe", "dossier_poste", "type" | |
95 | ) | |
98d6eb6c | 96 | |
d9de50fa JPC |
97 | custom_filter = {} |
98 | for k, v in self.custom_filter.items(): | |
99 | custom_filter[k.replace('dossier__', '')] = v | |
a6927189 | 100 | count_dossiers_by_employe = dict((d['id'], d['count']) for d in |
d9de50fa JPC |
101 | rh.Dossier.objects.filter(q_range).values('id') \ |
102 | .filter(**custom_filter) \ | |
103 | .annotate(count=Count('employe'))) | |
104 | ||
c99116c3 JPC |
105 | contenu = {} |
106 | ||
107 | lineariser_dossiers = not ne_pas_grouper | |
108 | ||
98d6eb6c | 109 | for r in remunerations: |
c99116c3 JPC |
110 | if lineariser_dossiers: |
111 | key = r.dossier.employe_id | |
112 | else: | |
113 | key = r.dossier_id | |
114 | ||
115 | if key not in contenu: | |
116 | contenu[key] = { | |
9163be6f JPC |
117 | 'dossiers': set(), |
118 | 'remunerations': [] | |
119 | } | |
c99116c3 JPC |
120 | if lineariser_dossiers: |
121 | contenu[key]['remunerations'].append(r) | |
122 | else: | |
123 | if r.dossier_id == key: | |
124 | contenu[key]['remunerations'].append(r) | |
125 | contenu[key]['dossiers'].add(r.dossier) | |
9163be6f | 126 | |
98d6eb6c JPC |
127 | self.rapport = [] |
128 | ||
57e2b793 JPC |
129 | pays_list = {} |
130 | for pays in ref.Pays.objects.all(): | |
131 | pays_list[pays.id] = pays | |
132 | ||
98d6eb6c JPC |
133 | valeurs_point_par_imp = \ |
134 | dict( | |
9163be6f JPC |
135 | (v.implantation.id, v) for v in \ |
136 | rh.ValeurPoint.objects.filter(annee=self.annee).all() | |
98d6eb6c | 137 | ) |
57e2b793 JPC |
138 | |
139 | self.headers = ( | |
3c8ffdfb JPC |
140 | ('bureau', u"Bureau", {'columnwidth': '2cm'}), |
141 | ('pays', u"Pays", {'columnwidth': '3.5cm'}), | |
142 | ('implantation', u"Implantation", {'columnwidth': '3cm'}), | |
5c5de149 | 143 | ('valeur_point', u"Valeur du point", |
3c8ffdfb JPC |
144 | {'columnwidth': '2.3cm'}), |
145 | ('numero_employe', u"Numéro d'employé", | |
146 | {'columnwidth': '2.4cm'}), | |
147 | ('nom', u"Nom", {'columnwidth': '5.4cm'}), | |
148 | ('prenom', u"Prénom", {'columnwidth': '4.8cm'}), | |
149 | ('type_de_poste', u"Type de poste", {'columnwidth': '2.7cm'}), | |
150 | ('intitule_de_poste', u"Intitulé du poste", | |
151 | {'columnwidth': '7.25cm'}), | |
fa4ae139 | 152 | ('niveau', u"Niveau actel", {'columnwidth': '1.75cm'}), |
3c8ffdfb | 153 | ('point', u"Point", {'columnwidth': '1.75cm'}), |
a6927189 | 154 | ('regime_de_travail', u"Régime de travail annuel", |
3c8ffdfb JPC |
155 | {'columnwidth': '2cm'}), |
156 | ('local_expatrie', u"Local / Expatrié", | |
157 | {'columnwidth': '2.25cm'}), | |
158 | ('statut', u"Statut", {'columnwidth': '1.25cm'}), | |
159 | ('date_fin_contrat', u"Date de fin de contrat", | |
160 | {'columnwidth': '2cm'}), | |
e232bfe8 | 161 | HEADER_SEPARATOR, |
3c8ffdfb JPC |
162 | ('date_debut', u"Date de début", {'columnwidth': '1.92cm'}), |
163 | ('date_fin', u"Date de fin", {'columnwidth': '1.92cm'}), | |
164 | ('nb_jours', u"Nombre de jours", {'columnwidth': '2.82cm'}), | |
e232bfe8 | 165 | HEADER_SEPARATOR, |
3c8ffdfb | 166 | ('devise', u"Devise", {'columnwidth': '1.46cm'}), |
bab8ce55 | 167 | ('salaire_bstg_annuel', u"Salaire BSTG ANNUEL", |
3c8ffdfb | 168 | {'columnwidth': '2.5cm'}), |
a6927189 | 169 | ('salaire_bstg_euro', u"Salaire BSTG EUR", |
3c8ffdfb JPC |
170 | {'columnwidth': '2.5cm'}), |
171 | ('organisme_bstg', u"Organisme BSTG", | |
172 | {'columnwidth': '2.9cm'}), | |
e232bfe8 | 173 | HEADER_SEPARATOR, |
bab8ce55 | 174 | ('salaire_theorique', u"Salaire théorique ANNUEL", |
9fd09bdc | 175 | {'columnwidth': '2.5cm', 'background-color': '#ecab44'}), |
3c8ffdfb | 176 | ('salaire_base_brut', u"Salaire de base brut", |
9fd09bdc | 177 | {'columnwidth': '2.5cm', 'background-color': '#ecab44'}), |
3c8ffdfb | 178 | ('salaire_complementaire', u"Salaire complémentaire", |
9fd09bdc | 179 | {'columnwidth': '2.5cm', 'background-color': '#ecab44'}), |
e232bfe8 | 180 | HEADER_SEPARATOR, |
3c8ffdfb | 181 | ('indemnite_fonctions', u"Indemnités de fonctions", |
9fd09bdc | 182 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 183 | ('indemnite_expat', u"Indemnités d'expatriation", |
9fd09bdc JPC |
184 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
185 | ('indemnite_scolarite', u"Indemnités de frais de scolarité", | |
186 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), | |
3c8ffdfb | 187 | ('indemnite_logement', u"Indemnités de logement", |
9fd09bdc | 188 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 189 | ('indemnite_transp', u"Indemnités de transport", |
9fd09bdc | 190 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 191 | ('indemnite_13e', u"Indemnités 13e mois", |
9fd09bdc | 192 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 193 | ('prime_interim', u"Prime d'intérim", |
9fd09bdc | 194 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 195 | ('indemnite_autre', u"Autre indemnités", |
9fd09bdc | 196 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
3c8ffdfb | 197 | ('indemnite_sous_total', u"Sous-total d'indemnités", |
9fd09bdc | 198 | {'columnwidth': '2.5cm', 'background-color': '#fff840'}), |
e232bfe8 | 199 | HEADER_SEPARATOR, |
3c8ffdfb | 200 | ('prime_installation', u"Prime d'installation", |
9fd09bdc | 201 | {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}), |
3c8ffdfb | 202 | ('prime_demenagement', u"Prime de déménagement", |
9fd09bdc | 203 | {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}), |
3c8ffdfb | 204 | ('prime_avion', u"Prime d'avion", |
9fd09bdc | 205 | {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}), |
3c8ffdfb | 206 | ('prime_autre', u"Autre prime", |
9fd09bdc | 207 | {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}), |
3c8ffdfb | 208 | ('prime_sous_total', u"Total des primes", |
9fd09bdc | 209 | {'columnwidth': '2.5cm', 'background-color': '#d7fb0f'}), |
e232bfe8 | 210 | HEADER_SEPARATOR, |
3c8ffdfb | 211 | ('charges_patronales', u"Charges patronales", |
9fd09bdc | 212 | {'columnwidth': '2.5cm', 'background-color': '#fb680f'}), |
3c8ffdfb | 213 | ('charges_autre', u"Autres charges patronales", |
9fd09bdc | 214 | {'columnwidth': '2.5cm', 'background-color': '#fb680f'}), |
3c8ffdfb | 215 | ('charges_sous_total', u"Sous-total des charges patronales", |
9fd09bdc | 216 | {'columnwidth': '2.5cm', 'background-color': '#fb680f'}), |
e232bfe8 | 217 | HEADER_SEPARATOR, |
bab8ce55 | 218 | ('sous_total_traitement_annee', u"Total traitements", |
7ab6c3c6 | 219 | {'background-color': '#ecab44'}), |
bab8ce55 | 220 | ('sous_total_indemnite_annee', u"Total indemnités", |
7ab6c3c6 | 221 | {'background-color': '#fff840'}), |
bab8ce55 | 222 | ('sous_total_accessoire_annee', u"Total accessoires", |
7ab6c3c6 | 223 | {'background-color': '#d7fb0f'}), |
bab8ce55 | 224 | ('sous_total_charges_annee', u"Total charges", |
7ab6c3c6 | 225 | {'background-color': '#fb680f'}), |
e232bfe8 | 226 | HEADER_SEPARATOR, |
bab8ce55 | 227 | ('masse_salariale', u"Masse salariale ANNUELLE", |
9fd09bdc | 228 | {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}), |
bab8ce55 | 229 | ('masse_salariale_annee', u"Masse salariale", |
9fd09bdc | 230 | {'columnwidth': '2.5cm', 'background-color': '#e6c6ed'}), |
cb9cce2b | 231 | ('masse_salariale_annee_euro', u"Masse salariale %s EUR" % \ |
9fd09bdc JPC |
232 | self.annee, { |
233 | 'columnwidth': '2.5cm', | |
234 | 'background-color': '#e6c6ed' | |
235 | } | |
236 | ), | |
57e2b793 JPC |
237 | ) |
238 | ||
778fb9d6 JPC |
239 | grand_total = 0.0 |
240 | grand_total_euro = 0.0 | |
241 | ||
d9de50fa JPC |
242 | if not lineariser_dossiers: |
243 | for dossier_id, count in count_dossiers_by_employe.items(): | |
244 | if dossier_id not in contenu or \ | |
245 | len(contenu[dossier_id]['dossiers']) != count: | |
246 | not_in = [] | |
247 | if dossier_id in contenu: | |
248 | for d in contenu[dossier_id]['dossiers']: | |
249 | not_in.append(d.id) | |
250 | custom_filter = {} | |
251 | for k, v in self.custom_filter.items(): | |
252 | custom_filter[k.replace('dossier__', '')] = v | |
253 | ||
254 | employe_id = rh.Dossier.objects.values('employe').filter( | |
255 | id=dossier_id).all()[0]['employe'] | |
256 | dossiers = rh.Dossier.objects.filter(q_range) \ | |
257 | .filter(employe=employe_id) \ | |
258 | .filter(**custom_filter) \ | |
259 | .all() | |
260 | for d in dossiers: | |
261 | if d.id not in contenu: | |
262 | contenu[d.id] = { | |
263 | 'dossiers': set((d,)), | |
264 | 'remunerations': [] | |
265 | } | |
266 | else: | |
267 | contenu[d.id]['dossiers'].add(d) | |
268 | ||
bab8ce55 JPC |
269 | postes = rh.Poste.objects |
270 | ||
271 | custom_filter = {} | |
272 | for k, v in self.custom_filter.items(): | |
273 | custom_filter[k.replace('dossier__poste__', '')] = v | |
274 | ||
275 | if custom_filter: | |
276 | postes = postes.filter(**custom_filter) | |
277 | ||
278 | postes_vacants = [p for p in postes.filter(q_range).all() | |
279 | if p.is_vacant()] | |
280 | remuneration_base = rh.TypeRemuneration.objects.get( | |
281 | id=TYPE_REMUN_BASE[0]) | |
282 | remuneration_indem = rh.TypeRemuneration( | |
283 | nature_remuneration=TYPE_NATURE_INDEMN) | |
284 | remuneration_charge = rh.TypeRemuneration( | |
285 | nature_remuneration=TYPE_NATURE_CHARGES) | |
286 | for p in postes_vacants: | |
287 | d = rh.Dossier() | |
288 | d.employe = rh.Employe() | |
289 | d.statut = rh.Statut() | |
290 | d.poste = p | |
291 | d.classement = p.classement_max | |
292 | d.point = p.valeur_point_max | |
9ff35df5 EMS |
293 | if p.devise_max: |
294 | remunerations = [ | |
295 | rh.Remuneration( | |
296 | montant=p.salaire_max, devise=p.devise_max, | |
297 | type=remuneration_base | |
298 | ), | |
299 | rh.Remuneration( | |
300 | montant=p.indemn_max, devise=p.devise_max, | |
301 | type=remuneration_indem | |
302 | ), | |
303 | rh.Remuneration( | |
304 | montant=p.autre_max, devise=p.devise_max, | |
305 | type=remuneration_charge | |
306 | ) | |
307 | ] | |
308 | else: | |
309 | remunerations = [ | |
310 | rh.Remuneration( | |
311 | montant=0, devise=self.devise_base, type=type | |
312 | ) | |
313 | for type in ( | |
314 | remuneration_base, remuneration_indem, | |
315 | remuneration_charge | |
316 | ) | |
317 | ] | |
bab8ce55 | 318 | contenu['p_%s' % p.id] = { |
9ff35df5 EMS |
319 | 'dossiers': set([d]), |
320 | 'remunerations': remunerations | |
321 | } | |
bab8ce55 | 322 | |
c99116c3 | 323 | for item in contenu.values(): |
98d6eb6c JPC |
324 | dossiers = item['dossiers'] |
325 | remuns = item['remunerations'] | |
07f120f3 | 326 | |
86bea0ed EMS |
327 | if not dossiers: |
328 | continue | |
329 | dossier = list(dossiers)[0] | |
07f120f3 JPC |
330 | for d in dossiers: |
331 | if d.principal: | |
86bea0ed | 332 | dossier = d |
07f120f3 | 333 | |
d3e403b2 | 334 | regime = (float(dossier.regime_travail) / 100) |
9163be6f | 335 | |
f7fc1166 | 336 | if dossier.statut_residence == "expat": |
98d6eb6c JPC |
337 | statut = "E" |
338 | else: | |
339 | statut = "L" | |
340 | ||
9163be6f JPC |
341 | #on détermine la date du début et fin du dossier si année en cours |
342 | try: | |
343 | d_date_fin = dossier.date_fin \ | |
344 | if dossier.date_fin.year == date_fin.year else None | |
345 | except AttributeError: | |
346 | d_date_fin = None | |
347 | try: | |
348 | d_date_debut = dossier.date_debut \ | |
349 | if dossier.date_debut.year == date_fin.year else None | |
350 | except AttributeError: | |
351 | d_date_debut = None | |
98d6eb6c JPC |
352 | |
353 | pays = \ | |
354 | pays_list[dossier.poste.implantation.adresse_physique_pays.id] | |
355 | ||
356 | #on détermine si les rémunérations sont tous dans la même devise | |
d9de50fa JPC |
357 | try: |
358 | devise = remuns[0].devise | |
359 | except IndexError: | |
360 | devise = self.devise_base | |
98d6eb6c JPC |
361 | meme_devise = True |
362 | for r in remuns[1:]: | |
363 | if devise != r.devise: | |
364 | meme_devise = False | |
365 | ||
366 | if not meme_devise: | |
367 | for r in remuns: | |
368 | self.convertir(r) | |
a6927189 | 369 | devise = remuns[0].devise |
98d6eb6c JPC |
370 | |
371 | bstg_dossier = None | |
372 | for d in dossiers: | |
373 | if d.organisme_bstg: | |
374 | bstg_dossier = d | |
375 | ||
9163be6f | 376 | bstg_remun = None |
98d6eb6c | 377 | if bstg_dossier: |
9163be6f | 378 | for r in bstg_dossier.rh_remunerations.all(): |
a6927189 JPC |
379 | if r.type.id in TYPE_REMUN_MAD: |
380 | bstg_remun = rh.Remuneration( | |
381 | montant=float(r.montant), | |
382 | devise=r.devise | |
383 | ) | |
98d6eb6c | 384 | |
958e67e8 | 385 | if bstg_remun: |
df37184c | 386 | bstg_remun_euro = rh.Remuneration( |
a6927189 JPC |
387 | montant=float(bstg_remun.montant), |
388 | devise=bstg_remun.devise | |
df37184c | 389 | ) |
958e67e8 | 390 | self.convertir(bstg_remun_euro) |
958e67e8 | 391 | |
4d17560e JPC |
392 | salaire_complement = 0.0 |
393 | salaire_base = 0.0 | |
394 | indemnites = { | |
395 | 'fonc_resp': 0.0, | |
396 | 'expat': 0.0, | |
9fd09bdc | 397 | 'scolarite': 0.0, |
4d17560e JPC |
398 | 'logement': 0.0, |
399 | 'transp': 0.0, | |
400 | '13e': 0.0, | |
401 | 'autre_recurr': 0.0, | |
07f120f3 | 402 | 'interim': 0.0, |
4d17560e | 403 | } |
95ad7aab JPC |
404 | |
405 | primes = { | |
95ad7aab JPC |
406 | 'installation': 0.0, |
407 | 'demenagement': 0.0, | |
408 | 'avion': 0.0, | |
409 | 'autre': 0.0, | |
410 | } | |
07f120f3 JPC |
411 | charges = { |
412 | 'patronale': 0.0, | |
413 | 'autre': 0.0, | |
414 | } | |
5c5de149 JPC |
415 | |
416 | total_remun_annee = { | |
417 | 'traitement': 0.0, | |
418 | 'indemnite': 0.0, | |
419 | 'accessoire': 0.0, | |
420 | 'charges': 0.0, | |
421 | } | |
422 | ||
b4869de0 | 423 | #Calcul du nombre de jours pour ce dossier. |
34b3b5c6 JPC |
424 | dossier_date_delta = self.calculer_nombre_jours( |
425 | dossier.date_debut, dossier.date_fin, | |
426 | date_debut, date_fin) | |
b4869de0 | 427 | |
2139e9a7 JPC |
428 | masse_salariale = 0.0 |
429 | masse_salariale_annee = 0.0 | |
4d17560e | 430 | for r in remuns: |
2139e9a7 | 431 | montant = float(r.montant) |
fa4ae139 JPC |
432 | if r.date_fin is None and dossier.date_fin is not None: |
433 | r.date_fin = min(date_fin, dossier.date_fin) | |
2139e9a7 | 434 | facteur = self.calculer_nombre_jours( |
fa4ae139 JPC |
435 | r.date_debut, r.date_fin, |
436 | date_debut, date_fin).days \ | |
437 | / float(rapport_date_delta.days) | |
95ad7aab | 438 | |
a6927189 | 439 | if r.type_id in TYPE_REMUN_BSTG: |
2139e9a7 | 440 | salaire_complement += montant * facteur |
a6927189 JPC |
441 | |
442 | if r.type_id not in TYPE_REMUN_MAD: | |
2139e9a7 | 443 | masse_salariale += montant |
44083888 | 444 | masse_salariale_annee += montant * regime |
4d17560e | 445 | |
95ad7aab | 446 | if r.type_id in TYPE_REMUN_BASE: |
2139e9a7 | 447 | salaire_base += montant * facteur |
4d17560e | 448 | |
95ad7aab | 449 | if r.type_id in TYPE_REMUN_FONC_RESP: |
2139e9a7 | 450 | indemnites['fonc_resp'] += montant * facteur |
4d17560e | 451 | |
95ad7aab | 452 | if r.type_id in TYPE_REMUN_EXPAT: |
2139e9a7 | 453 | indemnites['expat'] += montant * facteur |
4d17560e | 454 | |
9fd09bdc | 455 | if r.type_id in TYPE_REMUN_SCOLARITE: |
2139e9a7 | 456 | indemnites['scolarite'] += montant * facteur |
9fd09bdc | 457 | |
95ad7aab | 458 | if r.type_id in TYPE_REMUN_LOGEMENT: |
2139e9a7 | 459 | indemnites['logement'] += montant * facteur |
4d17560e | 460 | |
95ad7aab | 461 | if r.type_id in TYPE_REMUN_TRANSP: |
2139e9a7 | 462 | indemnites['transp'] += montant * facteur |
4d17560e | 463 | |
95ad7aab | 464 | if r.type_id in TYPE_REMUN_13E: |
2139e9a7 | 465 | indemnites['13e'] += montant * facteur |
4d17560e | 466 | |
95ad7aab | 467 | if r.type_id in TYPE_PRIME_INTERIM: |
2139e9a7 | 468 | indemnites['interim'] += montant * facteur |
07f120f3 JPC |
469 | |
470 | if r.type_id not in TYPE_REMUN_ALL_INDEMNITES \ | |
a6927189 JPC |
471 | and r.type.nature_remuneration == TYPE_NATURE_INDEMN \ |
472 | and r.type_id != TYPE_REMUN_MAD: | |
2139e9a7 | 473 | indemnites['autre_recurr'] += montant * facteur |
95ad7aab JPC |
474 | |
475 | if r.type_id in TYPE_PRIME_INSTALLATION: | |
2139e9a7 | 476 | primes['installation'] += montant * facteur |
95ad7aab JPC |
477 | |
478 | if r.type_id in TYPE_PRIME_DEMENAG: | |
2139e9a7 | 479 | primes['demenagement'] += montant * facteur |
95ad7aab JPC |
480 | |
481 | if r.type_id in TYPE_PRIME_AVION: | |
2139e9a7 | 482 | primes['avion'] += montant * facteur |
95ad7aab | 483 | |
07f120f3 | 484 | if r.type_id not in TYPE_PRIME_ALL and \ |
95ad7aab | 485 | r.type.nature_remuneration == TYPE_NATURE_PAIEMENT: |
2139e9a7 | 486 | primes['autre'] += montant * facteur |
95ad7aab | 487 | |
07f120f3 | 488 | if r.type_id in TYPE_CHARGE_PATRONALE: |
2139e9a7 | 489 | charges['patronale'] += montant * facteur |
07f120f3 JPC |
490 | |
491 | if r.type_id not in TYPE_CHARGE_ALL and \ | |
492 | r.type.nature_remuneration == TYPE_NATURE_CHARGES: | |
2139e9a7 | 493 | charges['autre'] += montant * facteur |
899aea3b | 494 | |
494eba48 JPC |
495 | if r.type.nature_remuneration == TYPE_NATURE_INDEMN or \ |
496 | r.type.id in (7,): | |
2139e9a7 | 497 | total_remun_annee['indemnite'] += montant * facteur |
5c5de149 JPC |
498 | |
499 | if r.type.nature_remuneration == TYPE_NATURE_PAIEMENT: | |
2139e9a7 | 500 | total_remun_annee['accessoire'] += montant * facteur |
5c5de149 JPC |
501 | |
502 | if r.type.nature_remuneration == TYPE_NATURE_CHARGES: | |
2139e9a7 | 503 | total_remun_annee['charges'] += montant * facteur |
5c5de149 | 504 | |
a6927189 | 505 | if (r.type.nature_remuneration == TYPE_NATURE_TRAITEMENT and |
494eba48 | 506 | r.type.id not in (TYPE_REMUN_MAD, 7) |
a6927189 | 507 | ) or r.type_id == TYPE_REMUN_BSTG: |
2139e9a7 | 508 | total_remun_annee['traitement'] += montant * facteur |
5c5de149 | 509 | |
4d17560e JPC |
510 | total_indemnites = sum(indemnites.values()) |
511 | ||
31566c3d JPC |
512 | masse_salariale_euro = rh.Remuneration( |
513 | montant=masse_salariale_annee, devise=devise) | |
023bdc65 JPC |
514 | self.convertir(masse_salariale_euro) |
515 | ||
22b53270 JPC |
516 | if dossier.classement and dossier.classement.coefficient: |
517 | coefficient = dossier.classement.coefficient | |
518 | else: | |
519 | coefficient = "" | |
520 | ||
521 | #todo valeur du point si pas présent | |
522 | valeur_point = valeurs_point_par_imp.get( | |
523 | dossier.poste.implantation_id | |
c48caab9 JPC |
524 | ) |
525 | if valeur_point: | |
526 | valeur_point_label = "%s %s" % (valeur_point.valeur, | |
527 | valeur_point.devise.code) | |
528 | else: | |
529 | valeur_point_label = "" | |
22b53270 | 530 | |
3244a3c2 | 531 | salaire_theorique = ( |
22b53270 | 532 | round(valeur_point.valeur * int(coefficient) * regime, 2) \ |
3244a3c2 | 533 | if valeur_point and coefficient and regime else None) |
22b53270 | 534 | |
57e2b793 JPC |
535 | item_rapport = { |
536 | 'bureau': dossier.poste.implantation.region.code, | |
537 | 'pays': unicode(pays), | |
538 | 'implantation': dossier.poste.implantation.nom_court, | |
539 | 'type_implantation': dossier.poste.implantation.type, | |
540 | #'imputation': None, | |
c48caab9 | 541 | 'valeur_point': valeur_point_label, |
57e2b793 JPC |
542 | 'numero_employe': dossier.employe_id, |
543 | 'nom': dossier.employe.nom.upper(), | |
544 | 'prenom': dossier.employe.prenom, | |
545 | 'type_de_poste': dossier.poste.type_poste.nom, | |
f7fc1166 JPC |
546 | 'intitule_de_poste': dossier.poste.nom_feminin |
547 | if dossier.employe.genre == "F" else | |
548 | dossier.poste.nom, | |
bab8ce55 | 549 | 'niveau': dossier.classement, |
57e2b793 JPC |
550 | 'point': coefficient, |
551 | 'regime_de_travail': "%s %%" % int(regime * 100), | |
552 | 'local_expatrie': statut, | |
553 | 'statut': dossier.statut.code, | |
554 | 'date_fin_contrat': dossier.date_fin or "", | |
555 | 'date_debut': d_date_debut or "", | |
556 | 'date_fin': d_date_fin or "", | |
b4869de0 | 557 | 'nb_jours': dossier_date_delta.days, |
d9de50fa | 558 | 'devise': devise.code, |
57e2b793 JPC |
559 | 'salaire_bstg_annuel': bstg_remun.montant \ |
560 | if bstg_remun else "", | |
a6927189 | 561 | 'salaire_bstg_euro': bstg_remun_euro.montant \ |
57e2b793 JPC |
562 | if bstg_remun else "", |
563 | 'organisme_bstg': dossier.organisme_bstg or "", | |
564 | 'salaire_theorique': salaire_theorique, | |
565 | 'salaire_base_brut': \ | |
0c5e0d8e | 566 | salaire_base * regime, |
57e2b793 | 567 | 'salaire_complementaire': \ |
0c5e0d8e | 568 | salaire_complement * regime, |
57e2b793 JPC |
569 | #'salaire_total': None |
570 | 'indemnite_fonctions': indemnites['fonc_resp'] * \ | |
0c5e0d8e JPC |
571 | regime, |
572 | 'indemnite_expat': indemnites['expat'] * regime, | |
9fd09bdc | 573 | 'indemnite_scolarite': indemnites['scolarite'] * \ |
0c5e0d8e | 574 | regime, |
57e2b793 | 575 | 'indemnite_logement': indemnites['logement'] * \ |
0c5e0d8e JPC |
576 | regime, |
577 | 'indemnite_transp': indemnites['transp'] * regime, | |
578 | 'indemnite_13e': indemnites['13e'] * regime, | |
579 | 'prime_interim': indemnites['interim'] * regime, | |
57e2b793 | 580 | 'indemnite_autre': indemnites['autre_recurr'] * \ |
0c5e0d8e JPC |
581 | regime, |
582 | 'indemnite_sous_total': total_indemnites * regime, | |
57e2b793 | 583 | 'total_brut': ( |
95ad7aab JPC |
584 | total_indemnites + salaire_base + |
585 | salaire_complement | |
0c5e0d8e JPC |
586 | ) * regime, |
587 | 'prime_installation': primes['installation'] * regime, | |
588 | 'prime_demenagement': primes['demenagement'] * regime, | |
589 | 'prime_avion': primes['avion'] * regime, | |
590 | 'prime_autre': primes['autre'] * regime, | |
591 | 'prime_sous_total': sum(primes.values()) * regime, | |
2139e9a7 JPC |
592 | 'charges_patronales': charges['patronale'] * regime, |
593 | 'charges_autre': charges['autre'] * regime, | |
594 | 'charges_sous_total': sum(charges.values()) * regime, | |
5c5de149 | 595 | 'sous_total_traitement_annee': \ |
2139e9a7 | 596 | total_remun_annee['traitement'] * regime, |
5c5de149 | 597 | 'sous_total_indemnite_annee': \ |
2139e9a7 | 598 | total_remun_annee['indemnite'] * regime, |
5c5de149 | 599 | 'sous_total_accessoire_annee': \ |
2139e9a7 | 600 | total_remun_annee['accessoire'] * regime, |
5c5de149 | 601 | 'sous_total_charges_annee': \ |
2139e9a7 JPC |
602 | total_remun_annee['charges'] * regime, |
603 | 'masse_salariale': masse_salariale * regime, | |
604 | 'masse_salariale_annee': masse_salariale_annee * regime, | |
5c5de149 | 605 | 'masse_salariale_annee_euro': \ |
0c5e0d8e | 606 | masse_salariale_euro.montant * regime, |
43b30700 | 607 | 'sep': ods.Separator(), |
57e2b793 | 608 | } |
98d6eb6c | 609 | |
c99116c3 | 610 | grand_total_euro += round(masse_salariale_euro.montant * regime |
b4869de0 JPC |
611 | * ( |
612 | dossier_date_delta.days / rapport_date_delta.days | |
613 | ), 2) | |
778fb9d6 | 614 | |
98d6eb6c JPC |
615 | self.rapport.append(item_rapport) |
616 | ||
3b1a2937 JPC |
617 | self.rapport = sorted(self.rapport, key=lambda r: r['nom']) |
618 | ||
778fb9d6 JPC |
619 | self.grand_totaux = (grand_total, grand_total_euro) |
620 | ||
2139e9a7 JPC |
621 | def calculer_nombre_jours(self, debut, fin, debut_limite, fin_limite): |
622 | """Calcul le nombre de jours entre fin et debut, sans dépasser | |
34b3b5c6 JPC |
623 | les limites. Si debut ou fin set null, on prend debut_limite/fin_limi |
624 | """ | |
625 | ||
626 | if not debut: | |
627 | debut = debut_limite | |
628 | if not fin: | |
629 | fin = fin_limite | |
630 | ||
631 | if debut < debut_limite: | |
632 | debut = debut_limite | |
633 | if fin > fin_limite: | |
634 | fin = fin_limite | |
635 | ||
636 | fin += datetime.timedelta(days=1) | |
637 | return fin - debut | |
638 | ||
98d6eb6c JPC |
639 | def build_qs(self, prefix, date_debut, date_fin): |
640 | date_debut_null = \ | |
641 | Q(**{"%s%s__isnull" % (prefix, KEY_DATE_DEBUT): True}) | |
642 | date_fin_null = \ | |
643 | Q(**{"%s%s__isnull" % (prefix, KEY_DATE_FIN): True}) | |
644 | date_debut_superieure_ou_egale_a_borne_gauche = \ | |
645 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_DEBUT): date_debut}) | |
646 | date_debut_inferieure_ou_egale_a_borne_gauche = \ | |
647 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_debut}) | |
648 | date_fin_superieure_ou_egale_a_borne_gauche = \ | |
649 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_debut}) | |
650 | date_fin_inferieure_ou_egale_a_borne_droite = \ | |
651 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_FIN): date_fin}) | |
652 | date_debut_inferieure_ou_egale_a_borne_droite = \ | |
653 | Q(**{"%s%s__lte" % (prefix, KEY_DATE_DEBUT): date_fin}) | |
654 | date_fin_superieure_ou_egale_a_borne_droite = \ | |
655 | Q(**{"%s%s__gte" % (prefix, KEY_DATE_FIN): date_fin}) | |
656 | ||
657 | q_range = \ | |
658 | ( | |
0c5e0d8e | 659 | date_debut_null & date_fin_null |
98d6eb6c | 660 | ) | ( |
0c5e0d8e JPC |
661 | date_fin_superieure_ou_egale_a_borne_gauche & |
662 | date_fin_inferieure_ou_egale_a_borne_droite & | |
663 | ( | |
664 | date_debut_inferieure_ou_egale_a_borne_gauche | | |
665 | date_debut_null | |
666 | ) | |
98d6eb6c | 667 | ) | ( |
0c5e0d8e JPC |
668 | date_debut_superieure_ou_egale_a_borne_gauche & |
669 | date_debut_inferieure_ou_egale_a_borne_droite & | |
670 | ( | |
671 | date_fin_superieure_ou_egale_a_borne_droite | | |
672 | date_fin_null | |
673 | ) | |
98d6eb6c | 674 | ) | ( |
0c5e0d8e JPC |
675 | date_debut_inferieure_ou_egale_a_borne_gauche & |
676 | date_fin_superieure_ou_egale_a_borne_droite | |
98d6eb6c | 677 | ) | ( |
0c5e0d8e JPC |
678 | date_debut_null & |
679 | date_fin_superieure_ou_egale_a_borne_droite | |
98d6eb6c | 680 | ) | ( |
0c5e0d8e JPC |
681 | date_debut_inferieure_ou_egale_a_borne_gauche & |
682 | date_fin_null | |
98d6eb6c | 683 | ) |
98d6eb6c JPC |
684 | return q_range |
685 | ||
686 | def convertir(self, remuneration): | |
9163be6f | 687 | if remuneration.devise != self.devise_base: |
8b6e7b9a JPC |
688 | try: |
689 | remuneration.montant = float(remuneration.montant) * \ | |
690 | self.trouver_taux(remuneration.devise).taux | |
691 | remuneration.devise = self.devise_base | |
692 | except AttributeError: | |
693 | pass | |
98d6eb6c JPC |
694 | |
695 | def trouver_taux(self, devise): | |
696 | if devise.code not in self.taux_change: | |
8b6e7b9a JPC |
697 | try: |
698 | t = rh.TauxChange.objects.filter( | |
699 | devise=devise, annee=self.annee | |
700 | )[0] | |
701 | except IndexError: | |
702 | return None | |
98d6eb6c JPC |
703 | self.taux_change[devise.code] = t |
704 | return self.taux_change[devise.code] | |
899aea3b JPC |
705 | |
706 | def csv(self): | |
707 | self.csv_handle = StringIO.StringIO() | |
023bdc65 JPC |
708 | csv_writer = csv.writer(self.csv_handle, delimiter=",", |
709 | doublequote=False, escapechar="\\", quoting=csv.QUOTE_ALL, | |
710 | ) | |
711 | header = [v[0] for v in self.rapport[0]] | |
712 | csv_writer.writerow(header) | |
713 | for row in self.rapport: | |
714 | values = [v[1] for v in row] | |
715 | csv_writer.writerow( | |
716 | [unicode(r).encode('utf-8') for r in values] | |
717 | ) | |
c99116c3 JPC |
718 | |
719 | def ods(self): | |
3c8ffdfb | 720 | self.doc = ods.OpenDocumentSpreadsheet() |
e5d10ada JPC |
721 | |
722 | nom = u"Masse salariale %s" % self.annee | |
723 | if self.region: | |
fba0dde4 | 724 | nom += u" %s" % self.region |
e5d10ada | 725 | elif self.implantation: |
fba0dde4 | 726 | nom += u" %s" % self.implantation |
e5d10ada JPC |
727 | |
728 | table = self.doc.add_table(name=nom) | |
3c8ffdfb JPC |
729 | |
730 | for h in self.headers: | |
731 | if len(h) > 2: | |
732 | table.add_column(**h[2]) | |
733 | ||
6d7419c4 JPC |
734 | table.add_row([h[1] for h in self.headers], rowheight='2cm') |
735 | ||
736 | for r in self.rapport: | |
737 | table.add_row([r[h[0]] for h in self.headers]) | |
3c8ffdfb | 738 | |
028b8438 | 739 | #a.doc.write('hello_world.ods') |