array( "name" => 'Tous', "where" => ''), 1 => array( "name" => 'Présents', "where" => 'AND ((code_sorti IS DISTINCT FROM 1) OR (date_sortie >= date(now())))'), 2 => array( "name" => 'Non facturés', "where" => "AND date_facture = '2099-12-31'::date") ); const JUSTIF_SEPARATOR = ":"; // Nom de la base de données iCTI const DATABASE_NAME = 'iCTI'; // Classe de la connexion à la base iCTI const DATABASE_CLASS = 'Database'; // Tables sur lequelles on peut faire tourner des règles private $tables = array( // séjours 0 => array( "name" => 'v_sejours_1', "fictive" => false, "from" => 'activite.v_sejours_1', "fields" => array(), "defaults" => array('v_sejours_1.sejour_id', 'v_sejours_1.no_sejour', 'v_sejours_1.date_sortie')), // mouvements 1 => array( "name" => 'v_mouvements_sejour_r_1', "fictive" => false, "from" => 'activite.v_mouvements_sejour_r_1', "fields" => array(), "defaults" => array('v_mouvements_sejour_r_1.sejour_id', 'v_mouvements_sejour_r_1.no_sejour', 'v_mouvements_sejour_r_1.date_sortie')), // factures 2 => array( "name" => 'v_factures_reference_r_2', "fictive" => false, "from" => 'activite.v_factures_reference_r_2', "fields" => array(), "defaults" => array('v_factures_reference_r_2.sejour_id', 'v_factures_reference_r_2.no_sejour', 'v_factures_reference_r_2.date_sortie')), // lignes factures honoraires 3 => array( "name" => 'v_factures_lignes_h_r_1', "fictive" => false, "from" => 'activite.v_factures_lignes_h_r_1', "fields" => array(), "defaults" => array('v_factures_lignes_h_r_1.sejour_id', 'v_factures_lignes_h_r_1.no_sejour', 'v_factures_lignes_h_r_1.date_sortie')), // sql brut 99 => array( "name" => '', "fictive" => true, "from" => '', "fields" => array(), "defaults" => array('v_sejours_1.sejour_id', 'v_sejours_1.no_sejour', 'v_sejours_1.date_sortie')) ); // Tableau des contrôles private $controls; // Connexion à la base de données private $database; // Indique le que le manager de controle expert est prêt à fonctionner (Connction DB OK et // initialisations réalisées private $ready; // Message d'erreur en cas d'erreur justement private $error_msg; // Indique si le module expert est activé private $expert_active; // Date à partir de laquelle les séjours sont contrôlables private $expert_date_debut; // Nombre de résultats positifs aux contrôles expert private $nb_results; // Message de retour private $msg; // Nombre de contrôles chargés private $nb_controls; // Emplacement absolu du fichier de traduction des champs des justificatifs private $dictionary; // Tableau des valeurs du dictionnaire de traduction private $dict_array; // Module qui exécute le contrôle expert (activite, pmsi...) private $module; // Nombre de controles activés private $nb_realisables; // Prestataire private $prestataire; //******************************************************************************************** // // PUBLIC FUNCTIONS // //********************************************************************************************/ /** * Constructeur * */ function __construct($schema) { $this->ready = false; $this->error_msg = ''; $this->msg = ''; $this->database = null; $this->expert_active = false; $this->expert_date_debut = '2013-01-01'; $this->nb_controls = 0; $this->nb_results = 0; $this->dictionary = ''; $this->module = $schema; $this->init(); } public function __set($property, $value) { if (property_exists($this, $property)) { $this->$property = $value; } return $this; } public function __get($property) { if (property_exists($this, $property)) { return $this->$property; } } /** * Execute les controles dont la liste est passée en paramètre. * Si aucun paramètre n'est passé, tous les contrôles sont exécutés * * @param $oids : tableau des oid des controles à exécuter */ public function run_controls($oids=null) { // SI le module expert n'est pas activé, on sort if (!$this->expert_active) { $this->error_msg = "Le module expert n'est pas activé"; return false; } // Récupère la liste des contrôles si ça n'a pas déjà été fait if (count($this->controls) == 0) { if (!$this->get_controls($oids)) { return false; }; } // EXECUTION DS CONTROLES ---------------------------------------------------------- // Nombre de contrôles réalisés avec succès (avec ou sans résultats) $nb_succes = 0; // Un contrôle est réalisé s'il est actif et si le prestataire pour lequel il doit s'exécuter est celui configuré dans l'environnement $controles_realises = array(); // Détermine si on exécute des contrôles précis via une liste d'oids ou si on les exécute tous $specific = is_array($oids); foreach($this->controls as $key => $control) { // Vérifie si le controle est bien dans la liste des controles à exécuter if (!$specific || in_array($control->oid, $oids)) { // Vérifie que le contrôle est réalisable (activé et bon prestataire) if ($control->realisable) { if($control->run()) { $nb_succes++; } else { // En cas d'erreur, on récupère le message d'erreur du controle $this->error_msg .= $control->error_msg; } $controles_realises[] = $control->oid; } } } // ECRITURE DES RESULTATS ------------------------------------------------------------ // Désactive les indexes de la table de stockage des résultats $i = 0; while(++$i < 7) { $result = $this->database->exec("SELECT base.cti_disable_index('activite', 'i_expert_sejour_controle_$i')"); } // Suppression des résultats précédents pour les contrôles exécutés if (count($controles_realises) > 0) { $request = "DELETE FROM activite.p_expert_sejour_controle WHERE controle_id IN (" . implode(',', $controles_realises) . ")"; $result = $this->database->exec($request); } // Préparation de la requête de stockage des résultats $request = "INSERT INTO activite.p_expert_sejour_controle (sejour_id, no_sejour, date_sortie, controle_id, date_signalement, code_justificatif) VALUES "; // Nombre de séjours positifs aux controles experts $nb_results = 0; // Tableau de mise en forme de chaque résultat $values = array(); foreach($this->controls as $control_id => $control) { // Mise à jour des infos du controle if ($control->last_execution_timestamp != '' && $control->last_execution_ok != '') { $update_request = " UPDATE activite.t_expert_controle SET last_execution_timestamp = '" . $control->last_execution_timestamp . "'::timestamp, last_execution_ok = '" . $control->last_execution_ok . "' WHERE oid = " . $control_id . "::bigint;"; $result = $this->database->exec($update_request); if ($result === false) { $this->error_msg .= "Impossible de mettre à jour les informations du contrôle " . $control->code . PHP_EOL; } } // Lecture des résultats de chaque contrôle foreach($control->results as $sejour_id => $result) { $nb_results ++; $date_sortie = $result['infos']['date_sortie']; $no_sejour = $result['infos']['no_sejour']; $justifs = array(); foreach($result['justificatifs'] as $name => $justif) { $justifs[] = $this->decode_key($name) . self::JUSTIF_SEPARATOR . $justif; } // S'il y a plusieurs justificatifs, ils seront séparés par une barre verticale $code_justificatif = implode(' | ', $justifs); $values[] = "(" . $sejour_id . "::bigint, '" . $no_sejour . "'::text, '" . $date_sortie . "'::date, " . $control_id . "::bigint, CURRENT_DATE, '" . $code_justificatif . "'::text)"; } } if ($nb_results > 0) { // la commande implode génère une erreur de dépassement de taille mémoire si trop de résultats sont retournés, // elle a été remplacée par une boucle sur les résultats $request .= implode(', ', $values); /*foreach($values as $value) { $request .= $value . ', '; } if (substr($request, -2) == ', ') { $request = substr($request, 0, -2); } */ $result = $this->database->exec($request); if ($result === false) { $this->error_msg = "Impossible de peupler la table des résultats des contrôles"; } } // Ré-active les indexes de la table de stockage des résultats $i = 0; while(++$i < 7) { $result = $this->database->exec("SELECT base.cti_enable_index('activite', 'i_expert_sejour_controle_$i')"); } // Nettoyage et rangement de la table des contrôles experts $result = $this->database->exec("VACUUM ANALYSE activite.p_expert_sejour_controle;"); $pluriel_lances = $this->nb_controls > 1 ? " contrôles lancés, " : " contrôle lancé, "; $pluriel_realises = $this->nb_realisables > 1 ? " contrôles réalisés, " : " contrôle réalisé, "; $pluriel_resultats = $nb_results > 1 ? " résultats positifs. " : " résultat positif. "; $this->msg = PHP_EOL . $this->nb_controls . $pluriel_lances . PHP_EOL . $this->nb_realisables . $pluriel_realises . PHP_EOL . $nb_results . $pluriel_resultats; $this->database->close(); if (strlen($this->error_msg) > 0) { return false; } else { return true; } } /** * Récupère la liste des contrôles expert */ public function get_controls($oids=null) { $success = true; if (!$this->init()) { if($this->error_msg === ''){ $this->error_msg = 'Initialisation des paramètres des contrôles expert en erreur'; } return false; } $this->nb_controls = 0; $this->nb_realisables = 0; // Si aucune liste d'oids n'est passsée en paramètre, on récupère tous les contrôles $nb_oids = count($oids); if ($nb_oids == 1) { $where = " AND t_expert_controle.oid =" . $oids[0] . " "; } else if ($nb_oids > 1) { $where = " AND t_expert_controle.oid IN (" . implode(',', $oids) . ") "; } else { $where = ""; } $request = " SELECT t_expert_controle.oid as control_id, t_expert_controle.code, t_expert_controle.texte, t_expert_controle.date_validite_debut, t_expert_controle.date_validite_fin, t_expert_controle.last_execution_timestamp, t_expert_controle.last_execution_ok, t_expert_controle.gravite_id as gravite, COALESCE(t_expert_controle.etat_cible, 0) as etat_cible, t_expert_controle.is_active, COALESCE(t_prestataires.alias, 'tous') as prestataire FROM activite.t_expert_controle LEFT JOIN base.t_prestataires ON t_prestataires.oid = t_expert_controle.prestataire_id WHERE 1=1 " . $where; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Erreur pendant la récupération des contrôles. Requête erronée'; $success = false; } else { while ($row = pg_fetch_array($result)) { $control = new ControleExpert($this->database); $control->oid = $row['control_id']; $control->code = $row['code']; $control->texte = $row['texte']; $control->date_validite_debut = $row['date_validite_debut']; $control->date_validite_fin = $row['date_validite_fin']; $control->last_execution_timestamp = $row['last_execution_timestamp']; $control->last_execution_ok = $row['last_execution_ok']; $control->gravite = $row['gravite']; $control->actif = $row['is_active'] == "1" ? true : false; $control->expert_date_debut = $this->expert_date_debut; $control->etat_cible = $this->etat_cible[$row['etat_cible']]; $control->tables = $this->tables; $control->prestataire = $row['prestataire']; if(!$control->get_rules()) { $this->error_msg = 'Impossible de récupérer la liste des règles du contrôle ' . $control->code; $success = false; break; } $this->controls[$row['control_id']] = $control; $this->nb_controls++; // Vérifie que le contrôle est actif et qu'il s'exécute sur le prestataire de l'environnement qui exécute les contrôles if ($control->actif && ($control->prestataire == 'tous' || $control->prestataire == $this->prestataire)) { $control->realisable = true; $this->nb_realisables++; } else { $control->realisable = false; } } } return $success; } //******************************************************************************************** // // PRIVATE FUNCTIONS // //********************************************************************************************/ private function connect_db() { if (get_class($this->database) != self::DATABASE_CLASS) { $this->database = new Database(self::DATABASE_NAME); if (get_class($this->database) == self::DATABASE_CLASS) { return true; } else { return false; } } else { return true; } } /** * Remplace le code justificatif par un code à 3 ou 4 lettres plus court. * Le dictionnaire de traduction (format JSON) peut/doit être complété * modules/base/php/expert/dictionary.json * * @param $key code à traduire */ private function decode_key($key) { // Chargement du dictionnaire de traduction des codes des justificatifs si jamais chargé auparavant if (!is_array($this->dict_array)) { if (file_exists($this->dictionary)) { // Parsage du JSON pour ne récupérer que la section du module qui va bien // http://stackoverflow.com/questions/4343596/parsing-json-file-with-php?answertab=votes#tab-top $string = file_get_contents($this->dictionary); $dict = json_decode($string, true); $jsonIterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($dict), RecursiveIteratorIterator::SELF_FIRST); foreach ($jsonIterator as $mod => $entries) { if ($mod == $this->module) { $this->dict_array = $entries; break; } } } } $s = strtolower($key); // Parcours du dictionnaire pour remplacer le justificatif if (is_array($this->dict_array)) { foreach ($this->dict_array as $old => $new) { $s = str_replace($old, $new, $s); } } return $s; } private function init() { if ($this->ready) { return true; } else { if (!$this->connect_db()) { $this->ready = false; $this->error_msg = 'Connexion impossible à la base CTI'; return false; } } // Initialisation des variables $this->controls = array(); $this->ready = true; // Récupération des champs pour les justificatifs. // Pour chaque table, on récupère et on stocke le nom de chaque colonne // La table fictive 'SQL brut' est ignorée par cette boucle foreach($this->tables as $key => $table) { if (strlen($table['from']) > 0) { $fields = array(); $request = "SELECT array_to_string(base.cti_array_accum(column_name),'|') AS fields FROM ( SELECT column_name::text FROM information_schema.columns WHERE (table_schema || '.' || table_name) = '" . $table['from'] . "' ORDER BY ordinal_position ) subview"; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Récupération des tables _ requête erronée'; $this->ready = false; return false; } $record = $this->database->nextRecordAssoc(); $fields = explode("|",trim($record["fields"])); $this->tables[$key]['fields'] = $fields; } } // Initialisation des paramètres Expert $request = " INSERT INTO activite.t_divers (code, texte, valeur, description) SELECT 'EXPERT_ACTIVE', 'Module EXPERT activé', '0', '1=Activé' WHERE 'EXPERT_ACTIVE' NOT IN (SELECT code FROM activite.t_divers); "; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Initilisation des paramètres : Erreur d\'insertion dans la table activite.t_divers'; } $request = " INSERT INTO activite.t_divers (code, texte, valeur, description, valeur_date) SELECT 'EXPERT_DATE_DEBUT', 'Date séjours à contrôler', '20130101', 'Date de début des séjours à contrôler', '20130101' WHERE 'EXPERT_DATE_DEBUT' NOT IN (SELECT code FROM activite.t_divers); "; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Initilisation des paramètres : Erreur d\'insertion de la date de début des séjours à contrôler'; } // Désactivation controles inutiles $request = " UPDATE activite.t_expert_controle SET is_active = subview.is_active FROM ( SELECT t_expert_controle.oid, CASE WHEN MAX(to_id) > 0 THEN '1' ELSE '0' END AS is_active FROM activite.t_expert_controle JOIN ( SELECT 'CTI_SEJ_AMB_03'::text AS controle_code, 'CTI_UF_AMBU'::text AS liste_code UNION SELECT 'CTI_MVT_SER_KO', 'CTI_SER_KO' UNION SELECT 'CTI_MVT_ETA_KO', 'CTI_ETA_KO' UNION SELECT 'CTI_SEJ_MED_KO', 'CTI_MED_KO' ) subview ON t_expert_controle.code = controle_code LEFT JOIN activite.t_listes ON t_listes.code = liste_code LEFT JOIN activite.t_listes_contenu ON liste_id = t_listes.oid GROUP BY 1 ) subview WHERE t_expert_controle.oid = subview.oid AND t_expert_controle.is_active <> subview.is_active ; UPDATE activite.t_expert_controle SET is_active = '0' WHERE t_expert_controle.code = 'CTI_SEJ_SER_FINESS' AND is_active = '1' AND (SELECT MAX(finess_id) FROM activite.t_services_facturation ) = 0 ; "; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Initilisation des paramètres : La désactivation des controles inutiles a échoué'; } // Ménage / désactivés $request = " DELETE FROM activite.p_expert_sejour_controle WHERE controle_id IN (SELECT oid FROM activite.t_expert_controle WHERE is_active <> '1') "; $result = $this->database->exec($request); if ($result === false) { $this->error_msg = 'Initilisation des paramètres : La suppression des contrôles désactivés a échoué'; } // Vérification de l'activation du module Expert $request = " SELECT * FROM activite.t_divers WHERE code = 'EXPERT_ACTIVE' AND valeur = '1'; "; $result = $this->database->exec($request); if ($result !== false) { if (pg_num_rows($result) == 0) { $this->error_msg = 'Module Expert inactif'; $this->expert_active = false; } else { $this->expert_active = true; } } // Récupération de la date de départ des controles expert $request = " SELECT valeur_date FROM activite.t_divers WHERE code = 'EXPERT_DATE_DEBUT'; "; $result = $this->database->exec($request); if ($result !== false) { while ($row = pg_fetch_array($result)) { $this->expert_date_debut = $row['valeur_date']; } } // Vérification de l'existance de règles $request = " SELECT * FROM pmsi.t_expert_controle_rule LIMIT 1; "; $result = $this->database->exec($request); if ($result !== false && pg_num_rows($result) == 0) { $this->error_msg = 'Pas de règles'; } if (strlen($this->error_msg) > 0) { $this->ready = false; } return $this->ready; } } ?>