''' Génère les affaires dans la base Analytique à partir des données de la base Contrôles. **IMPORTANT**: pour lancer le script sans interaction avec l'utilisateur (par ex, dans le cas d'une tâche planifiée), appeller le script avec l'option '--auto'. @author: olivier.massot, févr. 2018 ''' from datetime import datetime, timedelta import logging import sys from path import Path # @UnusedImport from core import logconf from core.pde import ControlesDb, AnalytiqueDb, CommunDb, Affaire, \ Interv, Tarification from core.sqlformatter import SqlFormatter logger = logging.getLogger("ctrl2analytique") logconf.start("ctrl2analytique", logging.DEBUG) # # POUR TESTER, décommenter les lignes suivantes # > Lancer le script /resources/test_ctrl2analytique.py pour reinitialiser les données de la base de test ##----------------------------------------------- ControlesDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\cg67Parc_data.mdb") AnalytiqueDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Db_analytique.mdb") CommunDb._path = Path(r"\\h2o\local\4-transversal\BDD\mdb_test\Commun_Data.mdb") logger.handlers = [h for h in logger.handlers if (type(h) == logging.StreamHandler)] logger.warning("<<<<<<<<<<<<<< Mode TEST >>>>>>>>>>>>>>>>>") ##----------------------------------------------- def main(): # ######### INITIALISATION ########## logger.info("Initialisation...") Sql = SqlFormatter() no_prompt = ("--auto" in sys.argv) if no_prompt: logger.info("> Lancé en mode automatique (sans interruption)") # Connexion à Analytique analytique_db = AnalytiqueDb(autocommit=False) # Connexion à Controles controles_db = ControlesDb(autocommit=False) # Connexion à CommunDb commun_db = CommunDb(autocommit=False) # date zéro pour Access date_zero = datetime(1899, 12, 30, 0, 0, 0) def get_type_id(lngChantierId, bytCommandeId): """ Recupère le type de chantier. 'ZP': Chantier de contrôle d'étanchéité 'ZC': Chantier de contrôle du compactage 'ZI': Chantier d'inspection vidéo 'ZZ': Chantier mixte. '': Inconnu """ sql = """SELECT lngChantierId, 'ZP' as type FROM tblEtancheiteBases WHERE [lngChantierId] = {chantier} AND [bytCommandeId] = {commande} UNION SELECT lngChantierId, 'ZC' as type FROM tblCompactageBases WHERE [lngChantierId] = {chantier} UNION SELECT lngChantierId, 'ZI' as type FROM tblVideoBases WHERE [lngChantierId] = {chantier}; """.format(chantier=lngChantierId, commande=bytCommandeId) res = controles_db.read_all(sql) if len(res) == 0: return "" elif len(res) == 1: return res[0].type else: return "ZZ" def get_coeff_k(lngChantierId): """ Récupère le coefficient de calcul des frais généraux (batiments, frais administratifs...Etc.) """ # On déduit l'année du chantier à partir du code chantier annee = "20" + str(lngChantierId)[:2] if len(str(lngChantierId)) == 6 else "200" + str(lngChantierId)[:1] return analytique_db.first(Sql.format("SELECT [COEFFG] FROM tbl_COEFFG WHERE [ANNEE] = {}", annee)).COEFFG / 100 # ########## IMPORT DES AFFAIRES ########## # Parcourt les chantiers de contrôle pour lesquels aucune affaire n'a été créée sql = """ SELECT tblCommandes.lngChantierId, tblCommandes.bytCommandeId, tblChantiers.strSubdivisionId, tblChantiers.strCollectiviteId as ChantierCollectiviteId, tblChantiers.strLocChantier, tblChantiers.strEntrepriseId, tblCommandes.strCollectiviteId as CommandeCollectiviteId, tblCommandes.dtmCommande, tblCommandes.strRefCommande, tblCommandes.blnMarche, tblCommandes.dblMtMarche, tblCommandes.strdevis FROM tblChantiers INNER JOIN tblCommandes ON tblChantiers.lngChantierId = tblCommandes.lngChantierId WHERE (((tblCommandes.sngAffaireIdMos) Is Null Or (tblCommandes.sngAffaireIdMos)=0)) """ affaires = [] for data in controles_db.read(sql): # Création de l'affaire affaire = Affaire() affaire.strLiaisonControle = "{}/{}".format(data.lngChantierId, data.bytCommandeId) affaire.strMOeId = data.strSubdivisionId affaire.strCommneId = data.ChantierCollectiviteId affaire.strLieux = data.strLocChantier affaire.strEntrepriseId = data.strEntrepriseId affaire.strMOId = data.CommandeCollectiviteId affaire.dtmCommande = data.dtmCommande affaire.Ref = data.strRefCommande affaire.blnMarche = data.blnMarche affaire.dblMarche = data.dblMtMarche affaire.intDevisId = data.strdevis if data.strdevis else 0 affaire.intTypeContrat = 1 affaire.strCT = '1' affaire.strTypeId = get_type_id(data.lngChantierId, data.bytCommandeId) affaire.intCoefFG = get_coeff_k(data.lngChantierId) affaire.strSituation = "En cours" # pour garder le lien avec la donnée d'origine: affaire.lngChantierId = data.lngChantierId affaire.bytCommandeId = data.bytCommandeId affaires.append(affaire) logger.info("> {} affaires".format(len(affaires))) # ########## IMPORT DES INTERVENTIONS DE COMPACTAGE ########## # Importe les interventions de contrôle du compactage def get_periode_validite(date_interv): """ retourne la préiode comptable correspondant à la date de l'intervention """ if not date_interv: return None sql = Sql.format("""SELECT intPeriodeValiditeId FROM tblTarifValidite WHERE [dtmValiditeDebut] <= {date_interv:date} AND [dtmValiditeFin] > {date_interv:date} AND [bytClasseTarifId]=1 """, date_interv=date_interv) periode = commun_db.first(sql) return periode.intPeriodeValiditeId if periode else None def get_type_compactage_interv(observation): """ retourne le sous-type d'intervention à partir du commentaire associé """ if "ASSAINISEMENT" or "ASSAINISEMENT" in observation: return "CC3" elif "CABLE" in observation: return "CC1" elif "A.E.P" in observation: return "CC2" elif "GAZ" in observation: return "CC4" else: return "CC3" interventions_cc = [] sql = """SELECT tblCompactageIntervs.lngChantierId, tblCompactageIntervs.bytCommandeId, tblCompactageIntervs.bytIntervId, tblCompactageIntervs.strEquipeId, tblCompactageEngins.strEnginId, tblCompactageIntervs.lngRapportId, tblCompactageBases.memTravaux, tblCompactageResultats.dtmEssai, tblCompactageResultats.dtmDuree, tblCompactagePartChantiers.strTrcRegard, tblMateriaux.strMatériau AS str_materiau_remblai, tblMateriaux_1.strMatériau AS str_materiau_enrobage, tblMateriaux_2.strMatériau AS str_materiau_lit, tblCompactageResultats.bytPartChantierId, tblCompactageIntervs.sngIntervIdMos FROM ((tblMateriaux RIGHT JOIN ((((tblCompactageIntervs LEFT JOIN tblCompactageEngins ON tblCompactageIntervs.strEquipeId = tblCompactageEngins.strEquipeId) INNER JOIN tblCompactageResultats ON (tblCompactageIntervs.lngChantierId = tblCompactageResultats.lngChantierId) AND (tblCompactageIntervs.bytIntervId = tblCompactageResultats.bytIntervId)) INNER JOIN tblCompactagePartChantiers ON (tblCompactageResultats.lngChantierId = tblCompactagePartChantiers.lngChantierId) AND (tblCompactageResultats.bytPartChantierId = tblCompactagePartChantiers.bytPartChantierId)) INNER JOIN tblCompactageBases ON tblCompactageIntervs.lngChantierId = tblCompactageBases.lngChantierId) ON tblMateriaux.strMateriauId = tblCompactagePartChantiers.strMateriauRemblaiId) LEFT JOIN tblMateriaux AS tblMateriaux_1 ON tblCompactagePartChantiers.strMateriauEnrobageId = tblMateriaux_1.strMateriauId) LEFT JOIN tblMateriaux AS tblMateriaux_2 ON tblCompactagePartChantiers.strMateriauLitId = tblMateriaux_2.strMateriauId WHERE (((tblCompactageIntervs.sngIntervIdMos)=0 Or (tblCompactageIntervs.sngIntervIdMos) Is Null)) """ for data in controles_db.read(sql): interv = Interv() interv.strEquipeId = "C{}".format(data.strEquipeId) interv.strEnginId = data.strEnginId interv.strRapportId = data.lngRapportId interv.strTypeInterventionId = get_type_compactage_interv(data.memTravaux) interv.strCatégorieInterventionId = "CC" interv.dblquantite = 1.0 interv.strunite = "u" interv.dtmIntervention = data.dtmEssai interv.dtmDureeIntervention = data.dtmDuree interv.dtmDureeInstallation = date_zero # Les temps d'installation seront calculés en fin de traitement interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId) interv.strArticleId = data.strEnginId interv.intPeriode = get_periode_validite(data.dtmEssai) interv.remarques = data.strTrcRegard if data.strTrcRegard else "-" interv.strgrandeur1 = data.str_materiau_remblai interv.strgrandeur2 = data.str_materiau_lit interv.strgrandeur3 = data.str_materiau_enrobage interv.strcaracteristique1 = "Matériau remblai" interv.strcaracteristique2 = "Matériau lit de pose" interv.strcaracteristique3 = "Matériau enrobage" interv.strunite1 = "" interv.strunite2 = "" interv.strunite3 = "" interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d")) interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId) interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId) # pour garder le lien avec la donnée d'origine: interv.lngChantierId = data.lngChantierId interv.bytCommandeId = data.bytCommandeId interv.bytIntervId = data.bytIntervId interventions_cc.append(interv) logger.info("> {} interventions Compactage".format(len(interventions_cc))) # ########## IMPORT DES INTERVENTIONS D'ETANCHEITE ########## # Importe les interventions de contrôle d'étanchéité interventions_ce = [] sql = """SELECT tblEtancheiteIntervs.lngChantierId, tblEtancheiteIntervs.bytCommandeId, tblEtancheiteIntervs.bytIntervId, tblEtancheiteIntervs.strEquipeId, tblEtancheiteIntervs.lngRapportId, tblEtancheitePartChantiers.bytTypeEssai, tblMateriaux.strMateriauId, tblMateriaux.strMatériau, tblEtancheitePartChantiers.intDiametre, tblEtancheitePartChantiers.sngLgHt, tblEtancheitePartChantiers.intNbJoint, tblEtancheiteResultats.dtmDuree, tblEtancheiteResultats.dtmEssai, tblEtancheitePartChantiers.strTrcRegard, tblEtancheiteResultats.bytPartChantierId FROM ((tblEtancheiteIntervs INNER JOIN tblEtancheiteResultats ON (tblEtancheiteIntervs.lngChantierId = tblEtancheiteResultats.lngChantierId) AND (tblEtancheiteIntervs.bytIntervId = tblEtancheiteResultats.bytIntervId)) INNER JOIN tblEtancheitePartChantiers ON (tblEtancheiteResultats.lngChantierId = tblEtancheitePartChantiers.lngChantierId) AND (tblEtancheiteResultats.bytPartChantierId = tblEtancheitePartChantiers.bytPartChantierId)) INNER JOIN tblMateriaux ON tblEtancheitePartChantiers.strMateriauId = tblMateriaux.strMateriauId WHERE (((tblEtancheiteIntervs.sngIntervIdMos)=0 Or (tblEtancheiteIntervs.sngIntervIdMos) Is Null)); """ def get_engin_etancheite(equipe, diametre, materiau, type_essai): """ retourne l'engin correspondant à l'essai en fonction eds caractéristiques de l'essai """ sql = """SELECT strEnginId FROM tblEtancheiteEngins WHERE ([strEquipeId] = '{}') AND ([intDiametre] = {}) AND ([strMateriauId] = '{}') AND ([bytTypeEssaiId] ={}) """.format(equipe, diametre, materiau, type_essai) row = controles_db.first(sql) return row.strEnginId if row else "" for data in controles_db.read(sql): interv = Interv() interv.strEquipeId = "C{}".format(data.strEquipeId) interv.strEnginId = get_engin_etancheite(data.strEquipeId, data.intDiametre, data.strMateriauId, data.bytTypeEssai) interv.strRapportId = data.lngRapportId interv.strTypeInterventionId = "CE{}".format(data.bytTypeEssai) interv.strCatégorieInterventionId = "CE" interv.dblquantite = float(data.intNbJoint) interv.strunite = "u" interv.dtmIntervention = data.dtmEssai interv.dtmDureeIntervention = data.dtmDuree interv.dtmDureeInstallation = date_zero # Les temps d'installation seront recalculés en fin de traitement interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId) interv.strArticleId = interv.strEnginId interv.intPeriode = get_periode_validite(data.dtmEssai) interv.remarques = data.strTrcRegard if data.strTrcRegard else "-" interv.strgrandeur1 = data.strMatériau interv.strgrandeur2 = data.intDiametre interv.strgrandeur3 = data.sngLgHt interv.strcaracteristique1 = "Matériau" interv.strcaracteristique2 = "Diamètre" interv.strcaracteristique3 = "Longueur" interv.strunite1 = "" interv.strunite2 = "mm" interv.strunite3 = "m" interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d")) interv.strTest = "{}/{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId, data.bytPartChantierId) interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId) # pour garder le lien avec la donnée d'origine: interv.lngChantierId = data.lngChantierId interv.bytCommandeId = data.bytCommandeId interv.bytIntervId = data.bytIntervId interventions_ce.append(interv) logger.info("> {} interventions Etanchéité".format(len(interventions_ce))) # ########## IMPORT DES INTERVENTIONS D'INSPECTION VIDEO ########## # Importe les interventions d'inspection vidéo interventions_ci = [] sql = """SELECT tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId, tblVideoEngins.strEnginId, tblVideoIntervs.lngRapportId, First(tblso_rate_Analyse.MateriauCourt) AS strmateriau, tblVideoIntervs.lngTroncon, tblVideoIntervs.sngNbJourFact, First(tblso_rate_Analyse.MaxDeDiametre) AS diam, tblVideoIntervs.dtmDuree, tblVideoIntervs.dtmIntervDu, First(tblVideoIntervs.memObservation) AS memObservation, tblChantiers.strEntrepriseId FROM ((tblVideoEngins RIGHT JOIN tblVideoIntervs ON tblVideoEngins.strEquipeId = tblVideoIntervs.strEquipeId) INNER JOIN tblso_rate_Analyse ON (tblVideoIntervs.lngChantierId = tblso_rate_Analyse.lngChantierId) AND (tblVideoIntervs.bytIntervId = tblso_rate_Analyse.bytIntervId)) INNER JOIN tblChantiers ON tblVideoIntervs.lngChantierId = tblChantiers.lngChantierId WHERE (((tblVideoIntervs.sngIntervIdMos) Is Null Or (tblVideoIntervs.sngIntervIdMos)=0)) GROUP BY tblVideoIntervs.lngChantierId, tblVideoIntervs.bytCommandeId, tblVideoIntervs.bytIntervId, tblVideoIntervs.strEquipeId, tblVideoIntervs.lngRapportId, tblVideoIntervs.lngTroncon, tblVideoIntervs.sngNbJourFact, tblVideoIntervs.dtmDuree, tblVideoIntervs.dtmIntervDu, tblVideoEngins.strEnginId, tblChantiers.strEntrepriseId """ for data in controles_db.read(sql): interv = Interv() interv.strEquipeId = "C{}".format(data.strEquipeId) interv.strEnginId = data.strEnginId interv.strRapportId = data.lngRapportId interv.strTypeInterventionId = "CI1" if data.strEntrepriseId != 195 else "CI2" interv.strCatégorieInterventionId = "CI" interv.dblquantite = float(data.sngNbJourFact) interv.strunite = "j" interv.dtmIntervention = data.dtmIntervDu interv.dtmDureeIntervention = data.dtmDuree interv.dtmDureeInstallation = date_zero # Les temps d'installation seront recalculés en fin de traitement interv.strLiaisonControle = "{}/{}/{}".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId) interv.strArticleId = data.strEnginId interv.intPeriode = get_periode_validite(data.dtmIntervDu) interv.remarques = data.memObservation if data.memObservation else "-" interv.strgrandeur1 = data.strmateriau interv.strgrandeur2 = data.diam interv.strgrandeur3 = data.lngTroncon interv.strcaracteristique1 = "Matériau" interv.strcaracteristique2 = "Diamètre" interv.strcaracteristique3 = "Longueur inspectée" interv.strunite1 = "" interv.strunite2 = "mm" interv.strunite3 = "m" interv.dtmImportation = "{}".format(datetime.now().strftime("%Y-%m-%d")) interv.strTest = "{}/{}/{}/1".format(data.lngChantierId, data.bytCommandeId, data.bytIntervId) interv.LienAff = "{}/{}".format(data.lngChantierId, data.bytCommandeId) # pour garder le lien avec la donnée d'origine: interv.lngChantierId = data.lngChantierId interv.bytCommandeId = data.bytCommandeId interv.bytIntervId = data.bytIntervId interventions_ci.append(interv) logger.info("> {} interventions ITV".format(len(interventions_ci))) interventions = interventions_cc + interventions_ce + interventions_ci # ########## CONTROLE ET CORRECTION DES DONNEES ########## # En cas d'erreurs, on liste celles-ci et on annule l'import. errors = [] logger.info("# Contrôle des données...") for affaire in affaires: prefix = "Affaire {}: ".format(affaire.strLiaisonControle) if not affaire.strMOId: errors.append(prefix + "MO manquant") else: if not commun_db.exists(Sql.format("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}", affaire.strMOId)): errors.append(prefix + "Le MO {} n'existe pas dans tblTiers".format(affaire.strMOId)) if not affaire.strMOeId: errors.append(prefix + "MOe manquant") else: if not commun_db.exists(Sql.format("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}", affaire.strMOeId)): errors.append(prefix + "Le MOe {} n'existe pas dans tblTiers".format(affaire.strMOeId)) if not affaire.strEntrepriseId: errors.append(prefix + "Entreprise manquante") else: if not commun_db.exists(Sql.format("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}", affaire.strEntrepriseId)): errors.append(prefix + "L'entreprise {} n'existe pas dans tblTiers".format(affaire.strEntrepriseId)) if not affaire.strCommneId: errors.append(prefix + "Commune manquante") else: if not commun_db.exists(Sql.format("SELECT [lngTiersId] FROM tblTiers WHERE [lngTiersId]={}", affaire.strCommneId)): errors.append(prefix + "La commune {} n'existe pas dans tblTiers".format(affaire.strCommneId)) if not affaire.strTypeId: errors.append(prefix + "Type d'affaire manquant") if not affaire.dtmCommande: errors.append(prefix + "Date de commande manquante") if affaire.blnMarche == True: if not affaire.intDevisId: errors.append(prefix + "Numéro de devis manquant") if analytique_db.exists(Sql.format("SELECT dblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'", affaire.strLiaisonControle)): errors.append(prefix + "Une affaire portant ce code existe déjà: {}".format(affaire.strLiaisonControle)) for interv in interventions: prefix = "Intervention {}: ".format(interv.strTest) if not interv.strEquipeId: errors.append(prefix + "Equipe manquante") else: if not analytique_db.exists(Sql.format("SELECT [strEquipesId] FROM tbl_Equipe WHERE [strEquipesId]={:text}", interv.strEquipeId)): errors.append(prefix + "L'equipe {} n'existe pas dans tbl_Equipe".format(interv.strEquipeId)) if not interv.strEnginId: errors.append(prefix + "Engin manquant") else: if not analytique_db.exists(Sql.format("SELECT [strEnginId] FROM tbl_Engin WHERE [strEnginId]={:text}", interv.strEnginId)): errors.append(prefix + "L'engin {} n'existe pas dans tbl_Engin".format(interv.strEnginId)) if not interv.strRapportId: errors.append(prefix + "Rapport manquant") if not interv.strCatégorieInterventionId: errors.append(prefix + "Catégorie de l'intervention manquante") else: if not analytique_db.exists(Sql.format("SELECT [strCategorieInterventioinId] FROM tbl_CategorieIntervention WHERE [strCategorieInterventioinId]={:text}", interv.strCatégorieInterventionId)): errors.append(prefix + "La catégorie d'intervention {} n'existe pas dans tbl_CategorieIntervention".format(interv.strCatégorieInterventionId)) if not interv.strTypeInterventionId: errors.append(prefix + "Type d'intervention manquant") else: if not analytique_db.exists(Sql.format("SELECT [strTypeInterventionId] FROM tbl_TypeIntervention WHERE [strTypeInterventionId]={:text}", interv.strTypeInterventionId)): errors.append(prefix + "Le type d'intervention {} n'existe pas dans tbl_TypeIntervention".format(interv.strTypeInterventionId)) if not interv.dblquantite: errors.append(prefix + "Quantité nulle") if not interv.strunite: errors.append(prefix + "Unité non renseignée") else: if not commun_db.exists(Sql.format("SELECT [strUniteCourt] FROM tblUnite WHERE [strUniteCourt]={:text}", interv.strunite)): errors.append(prefix + "L'unité {} n'existe pas dans tblUnite".format(interv.strunite)) if not interv.dtmIntervention: errors.append(prefix + "Erreur : date d'intervention") if not interv.dtmDureeIntervention or interv.dtmDureeIntervention == date_zero: errors.append(prefix + "Durée d'intervention nulle") # *** 6- Interruption pour corection manuelle des données (si nécessaire) if errors: logging.error(" Des erreurs ont été détectées dans les données à importer. ") for msg in errors: logging.error(msg) logger.info("# Annulation de l'import") return else: logging.info("Aucune erreur n'a été détectée dans les données.") if not no_prompt: input("Appuyez sur Entée pour continuer...") # ########## MISE A JOUR DE LA BASE DE DONNEES ANALYTIQUE ########## logger.info("# Mise à jour de la base Analytique") logger.info("> NB: Les modifications ne seront appliquées à la base que si toutes les opérations se déroulent normalement.") # On insère les affaires, interventions dans Analytique, et on génère la ou les lignes de tarification associées for affaire in affaires: # insertion dans tbl_Affaires sql = Sql.format(""" INSERT INTO tbl_Affaires ( strMOId, strMOeId, strEntrepriseId, strCommneId, strLieux, strTypeId, dtmCommande, Ref, blnMarche, dblMarche, intTypeContrat, strCT, strLiaisonControle, blnTarification, blnAnalyse, strSituation, intCoefFG ) VALUES ({affaire.strMOId:text}, {affaire.strMOeId:text}, {affaire.strEntrepriseId:text}, {affaire.strCommneId:text}, {affaire.strLieux:text}, {affaire.strTypeId:text}, {affaire.dtmCommande:date}, {affaire.Ref:text}, {affaire.blnMarche}, {affaire.dblMarche}, {affaire.intTypeContrat}, {affaire.strCT:text}, {affaire.strLiaisonControle:text}, True, False, {affaire.strSituation:text}, {affaire.intCoefFG}) """, affaire=affaire) analytique_db.execute(sql) logger.info("> Ajout de l'affaire: {}".format(affaire.strLiaisonControle)) # On insère les interventions dans tbl_Intervention for interv in interventions: affaire = analytique_db.first(Sql.format("SELECT TOP 1 DblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]='{}'", interv.LienAff)) if not affaire: logger.error("Intervention {} : Impossible de trouver l'affaire {}".format(interv.strTest, interv.LienAff)) continue interv.dblAffaireId = affaire.DblAffaireId if not interv.intPeriode: interv.intPeriode = get_periode_validite(data.dtmIntervDu) # Si la date d'interv manquait avant la validation, la periode n'a pa été mise à jour sql = Sql.format("""INSERT INTO tbl_Intervention ( DblAffaireId, strEquipeId, strEnginId, strRapportId, strCatégorieInterventionId, strTypeInterventionId, dblquantite, strunite, dtmIntervention, dtmDureeIntervention, dtmDureeInstallation, strcaracteristique1, strgrandeur1, strunite1, strcaracteristique2, strgrandeur2, strunite2, strcaracteristique3, strgrandeur3, strunite3, strLiaisonControle, strarticleId, intPeriode, blnTarification, blnAnalyse, blnFacturer, remarques, blnPeriode, dtmImportation, strTest ) VALUES ({interv.dblAffaireId}, {interv.strEquipeId:text}, {interv.strEnginId:text}, {interv.strRapportId:text}, {interv.strCatégorieInterventionId:text}, {interv.strTypeInterventionId:text}, {interv.dblquantite}, {interv.strunite:text}, {interv.dtmIntervention:date}, {interv.dtmDureeIntervention:date}, {date_zero:date}, {interv.strcaracteristique1:text}, {interv.strgrandeur1:text}, {interv.strunite1:text}, {interv.strcaracteristique2:text}, {interv.strgrandeur2:text}, {interv.strunite2:text}, {interv.strcaracteristique3:text}, {interv.strgrandeur3:text}, {interv.strunite3:text}, {interv.strLiaisonControle:text}, {interv.strArticleId:text}, {interv.intPeriode}, True, False, False, {interv.remarques:text}, False, {interv.dtmImportation:date}, {interv.strTest:text}) """, interv=interv, date_zero=date_zero) analytique_db.execute(sql) logger.info("> Ajout de l'intervention: {}".format(interv.strTest)) # Calcul de la tarification et ajout à tbl_Tarification # > On va créer une ligne de tarification pour chaque groupe d'interventions # > partageant le même lngRapportid et strArticleId (cad le même engin) for strRapportId, strArticleId in set([(interv.strRapportId, interv.strArticleId) for interv in interventions]): tarif = Tarification() tarif.intervs = [interv for interv in interventions if interv.strRapportId == strRapportId and interv.strArticleId == strArticleId] # recupere le prix unitaire de l'engin tarif_engin = commun_db.first(Sql.format("""SELECT dblPU FROM tblTarif WHERE [strArticleId]={:text} AND [intPeriodeValiditeId]={} """, strArticleId, get_periode_validite(interventions[0].dtmIntervention))) if not tarif_engin: logger.error("Aucun tarif trouvé dans tblTarif pour l'article {}, periode {}".format(strArticleId, tarif.intervs[0].intPeriode)) prix_unitaire = tarif_engin.dblPU # recupere le taux de tva applicable à l'engin taux_tva = commun_db.first(Sql.format("""SELECT tblTVATaux.dblTVATaux FROM tblArticle INNER JOIN tblTVATaux ON tblArticle.bytTVAArticleId = tblTVATaux.bytTVAId WHERE tblArticle.strArticleId={:text};""", strArticleId)).dblTVATaux tarif.DblAffaireId = tarif.intervs[0].dblAffaireId tarif.strRapportId = strRapportId tarif.strArticleId = strArticleId tarif.dblQuantite = sum([float(interv.dblquantite) for interv in tarif.intervs]) tarif.strUnite = tarif.intervs[0].strunite tarif.dtmDebut = min([interv.dtmIntervention for interv in tarif.intervs]) tarif.dtmFin = max([interv.dtmIntervention for interv in tarif.intervs]) tarif.bytPeriode = tarif.intervs[0].intPeriode tarif.dblPrixUnitaire = prix_unitaire tarif.dblPrixTotal = tarif.dblQuantite * tarif.dblPrixUnitaire tarif.dblTauxTVA = taux_tva tarif.dblPrixTVA = tarif.dblPrixTotal * (0.01 * tarif.dblTauxTVA) tarif.strStatut = 'A facturer' sql = Sql.format(""" INSERT INTO tbl_Tarification ( DblAffaireId, strRapportId, strArticleId, dblQuantite, strUnite, dtmDebut, dtmFin, bytPeriode, dblPrixUnitaire, dblPrixTotal, dblTauxTVA, dblPrixTVA, strStatut ) VALUES ({tarif.DblAffaireId}, {tarif.strRapportId:text}, {tarif.strArticleId:text}, {tarif.dblQuantite}, {tarif.strUnite:text}, {tarif.dtmDebut:date}, {tarif.dtmFin:date}, {tarif.bytPeriode}, {tarif.dblPrixUnitaire}, {tarif.dblPrixTotal}, {tarif.dblTauxTVA}, {tarif.dblPrixTVA}, {tarif.strStatut:text}) """, tarif=tarif) analytique_db.execute(sql) logger.info("> Génération d'une ligne de tarification pour l'affaire {} (rapport {}, article: {})".format(tarif.intervs[0].LienAff, strRapportId, strArticleId)) # Maj champs MOS # Ces champs sont utilisés dans les tables Controles pour savoir si une ligne a déjà été importée for affaire in affaires: dblAffaireId = analytique_db.first(Sql.format("SELECT TOP 1 DblAffaireId FROM tbl_Affaires WHERE [strLiaisonControle]={:text}", affaire.strLiaisonControle)).DblAffaireId sql = Sql.format("""UPDATE tblCommandes SET tblCommandes.sngAffaireIdMos = {DblAffaireId} WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId} """, DblAffaireId=dblAffaireId, lngChantierId=affaire.lngChantierId, bytCommandeId=affaire.bytCommandeId) controles_db.execute(sql) for interv in interventions: if interv.strCatégorieInterventionId == "CC": tbl = "tblCompactageIntervs" elif interv.strCatégorieInterventionId == "CE": tbl = "tblEtancheiteIntervs" elif interv.strCatégorieInterventionId == "CI": tbl = "tblVideoIntervs" else: continue sql = Sql.format("""UPDATE {tbl} SET {tbl}.sngIntervIdMos = {DblAffaireId} WHERE [lngChantierId]={lngChantierId} AND [bytCommandeId]={bytCommandeId} AND [bytIntervId]={bytIntervId} """, tbl=tbl, DblAffaireId=interv.dblAffaireId, lngChantierId=interv.lngChantierId, bytCommandeId=interv.bytCommandeId, bytIntervId=interv.bytIntervId) controles_db.execute(sql) logger.info("> Mise à jour des champs MOS") # On commit les modifications logger.info("Commit des modifications...") analytique_db.commit() controles_db.commit() # ########## MISE A JOUR DES TEMPS D'INSTALLATION ########## # > Le temps d'installation est le temps passé par chaque agent en transport, préparation, reporting...etc. # > C'est donc le temps de travail théorique, moins le temps d'intervention. # > pour des raisons de performances, on ne commence le traitement qu'à partir de l'année N-1 logger.info("Mise à jour des temps d'installation...") # On parcourt les interventions. # Lorsque le temps d'intervention total d'une même équipe un même jour est inférieur à 8h, # On affecte la différence de temps à la première intervention en tant que 'temps d'installation' sql = Sql.format("""SELECT First(tbl_Intervention.dblInterventionId) AS dblInterventionId, tbl_Intervention.strEquipeId, tbl_Intervention.dtmIntervention, CDate(Sum(tbl_Intervention.dtmDureeIntervention)) AS SD FROM tbl_Intervention WHERE tbl_Intervention.strLiaisonControle Like '%/%' AND Year([dtmIntervention])>={} AND tbl_Intervention.dtmDureeIntervention > 0 AND tbl_Intervention.strEquipeId Is Not Null GROUP BY tbl_Intervention.strEquipeId, tbl_Intervention.dtmIntervention HAVING (((CDate(Sum(tbl_Intervention.dtmDureeIntervention)))<#1899/12/30 8:0:0#)) """, datetime.now().year - 1) for interv in analytique_db.read_all(sql): tps_install = (date_zero + timedelta(hours=8) - interv.SD) sql = Sql.format("""UPDATE tbl_Intervention SET dtmDureeInstallation = #{}# WHERE dblInterventionId={}""", date_zero + tps_install, interv.dblInterventionId) analytique_db.execute(sql) logger.debug("* Mise à jour du temps d'installation de l'intervention {}".format(interv.dblInterventionId)) logger.info("Commit des modifications...") analytique_db.commit() if __name__ == "__main__": main() logger.info("-- Fin --")