You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

619 lines
19 KiB

<?php
class ControleExpertManager {
//********************************************************************************************
//
// VARIABLES
//
//********************************************************************************************/
private $etat_cible = array(
0 => 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;
}
}
?>