agrhum_traitement.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. """
  2. Traite les données importées dans PDA pour peupler les tables de la base AGRHum
  3. usage: agrhum_traitement [-c <codeagent>] [-m <mois>] [-a <annee>] [--auto]
  4. Options:
  5. -c <codeagent> Code de l'agent à traiter
  6. -m <mois> Mois
  7. -a <annee> Annee
  8. --auto Pas d'interaction utilisateur
  9. -h, --help Affiche l'aide
  10. @author: emmanuel.pheulpin et olivier.massot, juill 2018
  11. """
  12. from datetime import datetime
  13. import logging
  14. from docopt import docopt
  15. from path import Path # @UnusedImport
  16. from core import logconf
  17. from core.model import Sql
  18. from core.pde import AgrhumDb , FraisDeplacement, HeureSupp
  19. logger = logging.getLogger("ctrl2analytique")
  20. logconf.start("ctrl2analytique", logging.DEBUG)
  21. # # POUR TESTER, décommenter les lignes suivantes
  22. ##-----------------------------------------------
  23. # AgrhumDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\BDD_ParcRH.mdb")
  24. # logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)]
  25. # logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>")
  26. ##-----------------------------------------------
  27. agrhum_db = AgrhumDb(autocommit=False)
  28. # Vérification dans la table tbl_suiviRH si la ligne agent mois annnée existe
  29. # Vérification si état != de Importé ou si valide = True : demande confirmation pour retraitement
  30. # Si retraitement on supprime des tables cibles tbl_formHS et tbl_formDep
  31. # Parcours de tbl_importRH transfo donnée et écriture dans tbl_formdep
  32. # Parcours de tbl_importRH transfo donnée et écriture dans tbl_formHS
  33. def main(CodeAgent, MoisRH, AnneeRH, auto=False):
  34. logger.error("> Traitement des données de l'agent %s pour le mois %s/%s", CodeAgent, MoisRH, AnneeRH)
  35. suivi = agrhum_db.first(Sql.format("SELECT * FROM tbl_SuiviRH WHERE CodeAgent ={:text} AND MoisRH = {} AND AnneeRH = {}",
  36. CodeAgent, MoisRH, AnneeRH))
  37. if not suivi:
  38. logger.error("Les données de l'agent %s pour le mois %s/%s n'ont pas été importées dans la base PDA. Opération annulée.", CodeAgent, MoisRH, AnneeRH)
  39. return
  40. if suivi.Etat == "Validé":
  41. logger.error("Impossible de traiter des données qui ont déjà été validées. Opération annulée.")
  42. return
  43. if agrhum_db.exists(Sql.format("SELECT * FROM tbl_FormDep WHERE CodeAgent ={:text} AND MoisRH = {} AND AnneeRH = {}", CodeAgent, MoisRH, AnneeRH)):
  44. logger.warning("Les données de l'agent %s pour le mois %s/%s ont déjà été traitées.", CodeAgent, MoisRH, AnneeRH)
  45. if not auto and input("Voulez vous retraiter ces données? Toute modification sur les données existantes seront perdues. (o/n)") == "o" :
  46. logger.info(">> Effacement des anciennes données")
  47. agrhum_db.execute(Sql.format("DELETE * FROM tbl_FormDep WHERE CodeAgent ={:text} AND MoisRH = {} AND AnneeRH = {}",
  48. CodeAgent, MoisRH, AnneeRH))
  49. agrhum_db.execute(Sql.format("DELETE * FROM tbl_FormHS WHERE CodeAgent ={:text} AND MoisRH = {} AND AnneeRH = {}",
  50. CodeAgent, MoisRH, AnneeRH))
  51. else:
  52. logger.info("Opération annulée")
  53. return
  54. # Chargement des baremes en memoire
  55. sql = Sql.format("""SELECT tbl_baremes.NomBareme, tbl_baremes.BorneInf, tbl_baremes.BorneSup, tbl_baremes.Valeur,
  56. tbl_PeriodeBareme.DateInf, tbl_PeriodeBareme.DateSup
  57. FROM tbl_baremes
  58. INNER JOIN tbl_PeriodeBareme ON (tbl_baremes.PeriodeValidite = tbl_PeriodeBareme.CodePeriode) AND (tbl_baremes.NomBareme = tbl_PeriodeBareme.NomBareme)
  59. WHERE tbl_baremes.NomBareme = 'Heures de route' or tbl_baremes.NomBareme = 'Heures de route (nuit)'
  60. AND tbl_PeriodeBareme.DateInf <= {:date}
  61. AND (tbl_PeriodeBareme.DateSup is null or tbl_PeriodeBareme.DateSup > {:date}) """,
  62. datetime(AnneeRH, MoisRH, 1), datetime(AnneeRH, MoisRH, 1))
  63. baremes = agrhum_db.read_all(sql)
  64. logger.info("Parcours des données")
  65. data = agrhum_db.read_all(Sql.format("""SELECT * FROM tbl_ImportRh
  66. WHERE codeagent ={:text} AND Month([daterh]) = {} AND Year([daterh]) = {}
  67. ORDER BY DateRH""", CodeAgent, MoisRH, AnneeRH))
  68. logger.info("Mise à jour de frais de déplacement")
  69. # Parcours des données de la requête
  70. index_dep = {}
  71. for el in data :
  72. # Génération des objets FraisDeplacement
  73. if not el.DateRH.day in index_dep :
  74. fraisdep = FraisDeplacement()
  75. fraisdep.IDSuivi = suivi.IDSuivi
  76. fraisdep.AnneeRH = AnneeRH
  77. fraisdep.CodeAgent = CodeAgent
  78. fraisdep.MoisRH = MoisRH
  79. fraisdep.JourRH = el.DateRH.day
  80. fraisdep.Depart = el.Depart
  81. # mettre a jour le codedepart
  82. fraisdep.Itineraire = " - ".join([loc for loc in (fraisdep.Depart, el.Localisation) if loc])
  83. fraisdep.Distance1_perso = int(el.DistanceTranche1) if el.VehiculePersoTranche1 == "True" else 0
  84. fraisdep.Distance2_perso = int(el.DistanceTranche2) if el.VehiculePersoTranche2 == "True" else 0
  85. fraisdep.Distance2_service = int(el.DistanceTranche2) if not el.VehiculePersoTranche2 == "True" else 0
  86. fraisdep.Repas = int(el.Repas)
  87. # Indexation des objets par jour
  88. index_dep[el.DateRH.day] = fraisdep
  89. else :
  90. # Mise à jour d'un objet existant
  91. index_dep[el.DateRH.day].Itineraire += " - {}".format(el.Localisation)
  92. index_dep[el.DateRH.day].Distance1_perso += int(el.DistanceTranche1) if el.VehiculePersoTranche1 == "True" else 0
  93. index_dep[el.DateRH.day].Distance2_perso += int(el.DistanceTranche2) if el.VehiculePersoTranche2 == "True" else 0
  94. index_dep[el.DateRH.day].Distance2_service += int(el.DistanceTranche2) if not el.VehiculePersoTranche2 == "True" else 0
  95. index_dep[el.DateRH.day].Repas += int(el.Repas)
  96. # Insertion des données en base
  97. for fraisdep in index_dep.values() :
  98. distance2 = (fraisdep.Distance2_perso + fraisdep.Distance2_service)
  99. fraisdep.HeuresDep = next((bareme.Valeur for bareme in baremes if bareme.NomBareme == 'Heures de route' and bareme.BorneInf <= distance2 and bareme.BorneSup > distance2))
  100. fraisdep.HeuresDepNuit = next((bareme.Valeur for bareme in baremes if bareme.NomBareme == 'Heures de route (nuit)' and bareme.BorneInf <= distance2 and bareme.BorneSup > distance2))
  101. sql = Sql.format("""INSERT INTO tbl_FormDep
  102. ( IDSuivi, CodeAgent, JourRH, MoisRH,
  103. AnneeRH, Depart, Itineraire,
  104. Distance2_perso, Distance2_service, Distance1_perso,
  105. HeuresDep, HeuresDepNuit, Repas, Remarque,
  106. Valide, CreePar, CreeLe )
  107. VALUES
  108. ({fraisdep.IDSuivi}, {fraisdep.CodeAgent:text}, {fraisdep.JourRH}, {fraisdep.MoisRH},
  109. {fraisdep.AnneeRH}, {fraisdep.Depart:text}, {fraisdep.Itineraire:text},
  110. {fraisdep.Distance2_perso}, {fraisdep.Distance2_service}, {fraisdep.Distance1_perso},
  111. {fraisdep.HeuresDep}, {fraisdep.HeuresDepNuit}, {fraisdep.Repas}, {fraisdep.Remarque:text},
  112. {fraisdep.Valide}, {fraisdep.CreePar:text}, {fraisdep.CreeLe:date})""", fraisdep=fraisdep)
  113. agrhum_db.execute(sql)
  114. # on re-parcourt des données de la requête
  115. logger.info("Mise à jour des heures supplémentaires")
  116. index_hs = {}
  117. for el in data :
  118. if not el.DateRH.day in index_hs :
  119. hs = HeureSupp()
  120. hs.IDSuivi = suivi.IDSuivi
  121. hs.AnneeRH = AnneeRH
  122. hs.CodeAgent = CodeAgent
  123. hs.MoisRH = MoisRH
  124. hs.JourRH = el.DateRH.day
  125. hs.HeureSup1 = el.HeureSup1
  126. hs.HeuresDep = index_dep[el.DateRH.day].HeuresDep
  127. hs.HeuresDepNuit = index_dep[el.DateRH.day].HeuresDepNuit
  128. hs.HeureSupNuit = float(el.HeureSup2) + hs.HeuresDepNuit
  129. hs.HeureSupDim = el.HeureSupDimanche
  130. hs.HS_VHCanal = float(el.HeureSup1) + float(el.HeureSup2) + float(el.HeureSupDimanche) if el.strCategorieInterventionId == "07" else 0.0
  131. hs.HS_Chantier = float(el.HeureSup1) + float(el.HeureSup2) + float(el.HeureSupDimanche) if el.strCategorieInterventionId != "07" else 0.0
  132. index_hs[el.DateRH.day] = hs
  133. else :
  134. index_hs[el.DateRH.day].HeureSup1 += float(el.HeureSup1)
  135. index_hs[el.DateRH.day].HeureSupNuit += float(el.HeureSup2)
  136. index_hs[el.DateRH.day].HeureSupDim += float(el.HeureSupDimanche)
  137. index_hs[el.DateRH.day].HS_VHCanal += float(el.HeureSup1) + float(el.HeureSup2) + float(el.HeureSupDimanche) if el.strCategorieInterventionId == "07" else 0.0
  138. index_hs[el.DateRH.day].HS_Chantier += float(el.HeureSup1) + float(el.HeureSup2) + float(el.HeureSupDimanche) if el.strCategorieInterventionId != "07" else 0.0
  139. # Calcul des dépassements du seuil des 14h
  140. # NB: On mesure le depassement uniquement pour les heures de jour,
  141. # mais on tient compte des autres heures pour le cumul
  142. cumulmois = 0.0
  143. for hs in sorted(index_hs.values(), key=lambda x: x.JourRH) :
  144. hsjour = hs.HeureSup1 + hs.HeuresDep
  145. if cumulmois > 14:
  146. hs.HeureSup1_inf_14 = 0.0
  147. hs.HeureSup1_sup_14 = hsjour
  148. elif cumulmois + hsjour > 14:
  149. hs.HeureSup1_inf_14 = 14.0 - cumulmois
  150. hs.HeureSup1_sup_14 = (cumulmois + hsjour) - 14.0
  151. else:
  152. hs.HeureSup1_inf_14 = hsjour
  153. hs.HeureSup1_sup_14 = 0.0
  154. cumulmois += (hsjour + hs.HeureSupNuit + hs.HeureSupDim)
  155. # Insertion en base
  156. for hs in index_hs.values() :
  157. sql = Sql.format("""INSERT INTO tbl_FormHS
  158. ( IDSuivi, CodeAgent, JourRH, MoisRH, AnneeRH,
  159. HeureSup1, HeuresDep, HeuresDepNuit, [HeureSup1<=14],
  160. [HeureSup1>14], HeureSupNuit, HeureSupDim,
  161. HS_VHCanal, HS_Chantier, Valide, CreePar, CreeLe )
  162. VALUES
  163. ({hs.IDSuivi}, {hs.CodeAgent:text}, {hs.JourRH}, {hs.MoisRH}, {hs.AnneeRH},
  164. {hs.HeureSup1}, {hs.HeuresDep}, {hs.HeuresDepNuit}, {hs.HeureSup1_inf_14},
  165. {hs.HeureSup1_sup_14}, {hs.HeureSupNuit}, {hs.HeureSupDim},
  166. {hs.HS_VHCanal}, {hs.HS_Chantier}, {hs.Valide}, {hs.CreePar:text}, {hs.CreeLe:date})
  167. """, hs=hs)
  168. agrhum_db.execute(sql)
  169. # Commit des données
  170. logger.info("Commit des modifications")
  171. agrhum_db.commit()
  172. if __name__ == "__main__":
  173. # Parse les arguments
  174. args = docopt(__doc__, help=False)
  175. CodeAgent = args["-c"] if args["-c"] else None
  176. MoisRH = args["-m"] if args["-m"] else None
  177. AnneeRH = args["-a"] if args["-a"] else None
  178. if not CodeAgent:
  179. CodeAgent = input("Veuillez saisir le code de l'agent à traiter (ex: T9): ")
  180. if not MoisRH:
  181. MoisRH = input("Veuillez saisir le mois (ex: 3): ")
  182. if not AnneeRH:
  183. AnneeRH = input("Veuillez saisir l'année (ex: 2018): ")
  184. main(CodeAgent, int(MoisRH), int(AnneeRH), args["--auto"])
  185. logger.info("-- Fin --")