<?php
/**
 * DBFORM - 'document_numerise' - Surcharge gen.
 *
 * @package openads
 * @version SVN : $Id: document_numerise.class.php 6565 2017-04-21 16:14:15Z softime $
 */

//
require_once "../gen/obj/document_numerise.class.php";

/**
 *
 */
class document_numerise extends document_numerise_gen {

    /**
     *
     */
    var $activate_class_action = true;

    /**
     * Définition des actions disponibles sur la classe.
     *
     * @return void
     */
    function init_class_actions() {

        // On récupère les actions génériques définies dans la méthode 
        // d'initialisation de la classe parente
        parent::init_class_actions();

        // ACTION - 000 - ajouter
        // 
        $this->class_actions[0]["condition"] = array("is_ajoutable", "can_user_access_dossier_contexte_ajout");
        
        // ACTION - 001 - modifier
        // 
        $this->class_actions[1]["condition"] = array("is_modifiable", "can_user_access_dossier_contexte_modification");
        
        // ACTION - 002 - supprimer
        //
        $this->class_actions[2]["condition"] = array("is_supprimable", "can_user_access_dossier_contexte_modification");

        // ACTION - 004 - view_tab
        // Interface spécifique du tableau des pièces
        $this->class_actions[4] = array(
            "identifier" => "view_tab",
            "view" => "view_tab",
            "permission_suffix" => "tab",
        );

        // ACTION - 100 - Télécharger toutes les pièces numérisées
        $this->class_actions[100] = array(
            "identifier" => "archive_doc",
            "view" => "generate_archive_doc",
             "permission_suffix" => "tab",
        );

        // ACTION - 300 - view_dossier_final
        // Interface spécifique de constitution du dossier final
        $this->class_actions[300] = array(
            "identifier" => "view_dossier_final",
            "view" => "view_dossier_final",
            "permission_suffix" => "dossier_final",
        );

        // ACTION - 301 - Constituer le dossier final
        $this->class_actions[301] = array(
            "identifier" => "constituer_dossier_final",
            "view" => "constituer_dossier_final",
            "permission_suffix" => "dossier_final",
        );

        // ACTION - 302 - Télécharger le dossier final
        $this->class_actions[302] = array(
            "identifier" => "archive_dossier_final",
            "view" => "generate_archive_dossier_final",
            "permission_suffix" => "dossier_final",
        );
    }

    /**
     *
     */
    //Métadonnées spécifiques
    var $metadata = array(
        "uid" => array(
            "dossier" => "getDossier",
            "dossier_version" => "getDossierVersion",
            "numDemandeAutor" => "getNumDemandeAutor",
            "anneemoisDemandeAutor" => "getAnneemoisDemandeAutor",
            "typeInstruction" => "getTypeInstruction",
            "statutAutorisation" => "getStatutAutorisation",
            "typeAutorisation" => "getTypeAutorisation",
            "dateEvenementDocument" => "getDateEvenementDocument",
            "filename" => "getFilename",
            "groupeInstruction" => 'getGroupeInstruction',
            "title" => 'getTitle',
            'consultationPublique' => 'getConsultationPublique',
            'consultationTiers' => 'getConsultationTiers',
            'concerneERP' => 'get_concerne_erp',
        ),
    );

    var $metadonneesArrete = array();
    
    var $abstract_type = array(
        "uid" => "file",
    );

    /**
     * Instance de dossier_message
     *
     * @var null
     */
    var $inst_dossier_message = null;

    /**
     * Instance de document_numerise_type
     *
     * @var null
     */
    var $inst_document_numerise_type = null;

    /**
     * Identifiant du message de notification à l'ajout d'une pièce numérisée.
     *
     * @var null
     */
    var $dossier_message_id = null;

    /**
     * Affiche le bouton toggl permet de changer la vue pour les pièces déposées
     * et toutes les pièces constituant le dossier
     *
     * @return void
     */
    function display_toggl_button($obj, $retourformulaire, $idxformulaire, $class_switch_toggl) {
        //
        $template = '<div id="switch-toutes_les_pieces-pieces_deposees"><div class="switcher__label"><a class="om-prev-icon om-icon-16 consult-16 right" %s>%s</a></div><div class="switcher__label"><a class="om-prev-icon om-icon-16 toutes-les-pieces-16 right" %s>%s</a></div><div class="%s"></div></div>';
        $template_onclick = 'onclick="ajaxIt(\'%1$s\',\'%2$s&obj=%1$s&action=%3$s&objsf=document_numerise&retourformulaire=%4$s&idxformulaire=%5$s\');" href="#"';
        //
        printf(
            $template,
            sprintf($template_onclick, $obj, OM_ROUTE_SOUSFORM, '4', $retourformulaire, $idxformulaire),
            __("Pièces déposées"),
            sprintf($template_onclick, $obj, OM_ROUTE_SOUSFORM, '300', $retourformulaire, $idxformulaire),
            __("Toutes les pièces"),
            $class_switch_toggl
        );
    }

    function display_zip_archive_button() {

    }

    /**
     * VIEW - view_tab
     * 
     * Cette vue permet d'afficher l'interface spécifique du tableau
     * des pièces (liste et bouton d'ajout).
     *
     * @return void
     */
    function view_tab() {

        // Vérification de l'accessibilité sur l'élément
        $this->checkAccessibility();

        /**
         *
         */
        echo "\n\n";
        echo "\n<!-- ########## START VIEW DOCUMENT_NUMERISE ########## -->\n";
        echo "\n\n";

        //
        ($this->f->get_submitted_get_value('idxformulaire') !== null ? $idxformulaire = $this->f->get_submitted_get_value('idxformulaire') : $idxformulaire = "");
        ($this->f->get_submitted_get_value('retourformulaire') !== null ? $retourformulaire = $this->f->get_submitted_get_value('retourformulaire') : $retourformulaire = "");
        ($this->f->get_submitted_get_value('obj') !== null ? $obj = $this->f->get_submitted_get_value('obj') : $obj = "");

        /**
         * Récupération de l'identifiant du dossier
         *
         * En fonction du contexte dans lequel on se trouve, on récupère 
         * l'identifiant du dossier selon une méthode différente : 
         * - dans le contexte du DI, on récupère directement depuis les 
         *   paramètres GET passsés à la vue (idxformulaire) l'id du DI
         * - dans le contexte du DA, on récupère directement depuis les 
         *   paramètres GET passsés à la vue (idxformulaire) l'id du DA
         * - dans le contexte d'une consultation pour un service consulté
         *   (demande_avis), on récupère depuis les paramètres GET 
         *   passsés à la vue (idxformulaire) l'id de la consultation puis
         *   on fait une requête pour récupérer l'id du DI
         */

        //
        $contexte = "";
        if ($retourformulaire == "dossier_autorisation") {
            // Si on se trouve dans le contexte d'un dossier d'autorisation
            $contexte = "dossier_autorisation";
            $dossier_autorisation = $idxformulaire;
        } elseif ($retourformulaire == 'dossier'
            || $retourformulaire == 'dossier_instruction'
            || $retourformulaire == 'dossier_instruction_mes_encours'
            || $retourformulaire == 'dossier_instruction_tous_encours'
            || $retourformulaire == 'dossier_instruction_mes_clotures'
            || $retourformulaire == 'dossier_instruction_tous_clotures'
            || $retourformulaire == 'dossier_contentieux_mes_recours'
            || $retourformulaire == 'dossier_contentieux_tous_recours'
            || $retourformulaire == 'dossier_contentieux_mes_infractions'
            || $retourformulaire == 'dossier_contentieux_toutes_infractions') {
            // Si on se trouve dans le contexte d'un dossier d'instruction
            $contexte = "dossier_instruction";
            $dossier_instruction = $idxformulaire;
            // Action de bascule vers la vue de constitution du dossier final
            // seulement si l'utilisateur connecté a la permission
            if ($this->is_action_available(300) === true) {
                $this->display_toggl_button($obj, $retourformulaire, $idxformulaire, 'switcher__toggle');
            }
        } elseif ($retourformulaire == "demande_avis"
            || $retourformulaire == "demande_avis_encours"
            || $retourformulaire == "demande_avis_passee") {
            // Si on se trouve dans le contexte d'une demande d'avis
            $contexte = "demande_avis";
            $demande_avis = $idxformulaire;
            // Récupération du dossier en fonction du numéro de consultation
            $sql = "
            SELECT 
                dossier 
            FROM 
                ".DB_PREFIXE."consultation 
            WHERE 
                consultation=".$demande_avis;
            $dossier_instruction = $this->f->db->getone($sql);
            $this->f->addToLog(__METHOD__."() : db->getone(\"".$sql."\");", VERBOSE_MODE);
            $this->f->isDatabaseError($dossier_instruction);
        }

        /**
         * Gestion des templates html
         */
        //
        $template_view = '
<div class="formEntete ui-corner-all">
<!-- Action ajouter -->
%s
%s
<!-- Liste des pièces -->
%s
</div>
';
        // ACTION AJOUTER
        $template_link_add = '
<p>
    <a id="action-soustab-blocnote-message-ajouter" onclick="ajaxIt(\'' . $obj . '\', \''.OM_ROUTE_SOUSFORM.'&obj=' . $obj .'&action=0&tri=&objsf=document_numerise&premiersf=0&retourformulaire='.$retourformulaire.'&idxformulaire='.$idxformulaire.'&trisf=&retour=tab\');"
       href="#">
        <span class="om-icon om-icon-16 om-icon-fix add-16" title="Ajouter">Ajouter</span>
        '._("Ajouter une pièce").'
    </a>
</p>
';
        // ACTION TÉLÉCHARGER TOUTES LES PIÈCES
        $template_link_download_zip = "
<p>
    <a id='zip_download_link' onclick='zip_doc_numerise(%s, \"%s\", \"%s\");' href='#'>
        <span class='om-icon om-icon-16 om-icon-fix archive-16'
        title='"._("Télécharger toutes les pièces déposées")."'>"._("Télécharger toutes les pièces déposées")."</span>
        "._("Télécharger toutes les pièces déposées")."
    </a>
</p>
";

        // TABLE - HEAD
        // En-tête de tableau pour afficher la date et la catégorie des documents
        $template_header  = '
    <thead>
        <tr class="ui-tabs-nav ui-accordion ui-state-default tab-title">
            <th class="title col-0 firstcol %s" colspan="%s">
                <span class="name">
                    %s
                </span>
            </th>
        </tr>
    </thead>
';
        // TABLE - CELL content - NOM DU FICHIER
        // Template de visualisation du nom du fichier avec accès au 
        // téléchargement de la pièce
        $template_filename_download = '
<a class="lienTable lienDocumentNumerise"
   href="../app/index.php?module=form&snippet=file&obj=document_numerise&champ=uid&id=%s" 
   target="_blank"
   id="document_numerise_%s">
    <span class="om-prev-icon reqmo-16" title="'._("Télécharger").'">
        %s
    </span>
</a>
';
        // Template de visualisation du nom du fichier en lecture seule 
        // (Pas d'accès au téléchargement de la pièce)
        $template_filename_readonly = '
<p class="lienDocumentNumerise" id="document_numerise_%2$s">%3$s';
        // TABLE - CELL content - ICON
        // Template de visualisation de l'icône de l'action Consulter 
        $template_icon_view_link = '
<a onclick="ajaxIt(\'' . $obj . '\',\''.OM_ROUTE_SOUSFORM.'&obj=' . $obj .'&action=3&idx=%s&tri=&premier=0&objsf=document_numerise&premiersf=0&retourformulaire='.$retourformulaire.'&idxformulaire='.$idxformulaire.'&trisf=&retour=tab\');"
   href="#">
    <span class="om-icon om-icon-16 om-icon-fix consult-16" title="Consulter">
        Consulter
    </span>
</a>
';
        // TABLE - CELL content - DOSSIER ou TYPE DE DOCUMENT
        // 
        $template_info_view_link = '
<a class="lienTable"
   onclick="ajaxIt(\'' . $obj . '\',\''.OM_ROUTE_SOUSFORM.'&obj=' . $obj .'&action=3&idx=%s&tri=&premier=0&objsf=document_numerise&premiersf=0&retourformulaire='.$retourformulaire.'&idxformulaire='.$idxformulaire.'&trisf=&retour=tab\');"
   href="#">
    %s
</a>
';
        // TABLE - BODY - TR TD - STRUCTURE 3 colonnes
        $template_line_3col = '
<tr class="tab-data %s">
    <td class="icons">
        %s
    </td>
    <td class="col-0 firstcol">
        %s
    </td>
    <td class="col-1">
        %s
    </td>
</tr>
';
        // TABLE - BODY - TR TD - STRUCTURE 4 colonnes
        $template_line_4col = '
<tr class="tab-data %s">
    <td class="icons">
        %s
    </td>
    <td class="col-0 firstcol">
        %s
    </td>
    <td class="col-1">
        %s
    </td>
    <td class="col-2">
        %s
    </td>
</tr>
';

        /**
         * Récupération de la liste des pièces (document_numerise)
         * 
         * En fonction du contexte dans lequel on se trouve la requête est 
         * différente.
         */
        //
        $sql = "
        SELECT  
            document_numerise.document_numerise as document_numerise,
            document_numerise.date_creation as date_creation,
            document_numerise_type_categorie.libelle as categorie,
            document_numerise.nom_fichier as nom_fichier,
            document_numerise_type.libelle as type_document,
            document_numerise.uid as uid, 
            dossier.dossier as dossier
        FROM 
            ".DB_PREFIXE."document_numerise 
            LEFT JOIN ".DB_PREFIXE."document_numerise_type
                ON document_numerise.document_numerise_type = document_numerise_type.document_numerise_type
            LEFT JOIN ".DB_PREFIXE."document_numerise_type_categorie
                ON document_numerise_type.document_numerise_type_categorie = document_numerise_type_categorie.document_numerise_type_categorie 
            LEFT JOIN ".DB_PREFIXE."dossier 
                ON document_numerise.dossier = dossier.dossier 
            LEFT JOIN ".DB_PREFIXE."dossier_autorisation
                ON dossier.dossier_autorisation = dossier_autorisation.dossier_autorisation
        WHERE
        ";
        // Filtre sur le DI ou le DA en fonction du contexte
        if ($contexte == "dossier_instruction"
            || $contexte == "demande_avis") {
            $sql .= "
            document_numerise.dossier = '".$dossier_instruction."'
            ";
        } elseif ($contexte == "dossier_autorisation") {
            $sql .= "
            dossier_autorisation.dossier_autorisation = '".$dossier_autorisation."' 
            ";
        }
        // Filtre sur les types de documents lorsqu'on se trouve dans le 
        // contexte du dossier d'autorisation
        if ($contexte === 'dossier_autorisation') {
            // Instance de la classe document_numerise_type
            $inst_dnt = $this->get_inst_document_numerise_type();
            // Récupère la liste des codes dont le champ 'aff_da' est à 'true'
            $da_listing_pieces_filtre = $inst_dnt->get_code_by_filtre('aff_da');
            //
            $filtre = "";
            //
            if ($da_listing_pieces_filtre !== false) {
                // Compose la condition de la requête
                foreach ($da_listing_pieces_filtre as $filtre_code) {
                    $filtre .= " document_numerise_type.code = '".$this->f->db->escapesimple(trim($filtre_code))."' OR ";
                }
                $filtre = substr($filtre, 0, count($filtre) - 4);
            }
            //
            if ($filtre === "" || $filtre === false) {
                //
                $filtre = "document_numerise_type.code = ''";
            }
            //
            $sql .= sprintf(" AND (%s) ", $filtre);
        }

        // Filtre sur les types de documents lorsqu'on se trouve dans le 
        // contexte de la demande d'avis
        if ($contexte === 'demande_avis') {
            // Instance de la classe document_numerise_type
            $inst_dnt = $this->get_inst_document_numerise_type();
            // Récupère la liste des codes dont le champ 'aff_service_consulte' est à 'true'
            $sc_listing_pieces_filtre = $inst_dnt->get_code_by_filtre('aff_service_consulte');
            //
            $filtre = "";
            //
            if ($sc_listing_pieces_filtre !== false) {
                // Compose la condition de la requête
                foreach ($sc_listing_pieces_filtre as $filtre_code) {
                    $filtre .= " document_numerise_type.code = '".$this->f->db->escapesimple(trim($filtre_code))."' OR ";
                }
                $filtre = substr($filtre, 0, count($filtre) - 4);
            }
            //
            if ($filtre === "" || $filtre === false) {
                //
                $filtre = "document_numerise_type.code = ''";
            }
            //
            $sql .= sprintf(" AND (%s) ", $filtre);
        }
        // Le tri sur la requête
        $sql .= " 
        ORDER BY 
            document_numerise.date_creation, 
            document_numerise.nom_fichier
        ";
        // Exécution de la requête
        $res = $this->f->db->query($sql);
        $this->f->addToLog(__METHOD__."(): db->query(\"".$sql."\");", VERBOSE_MODE);
        $this->f->isDatabaseError($res);

        /**
         * Gestion du lien vers l'ajout d'une nouvelle pièce
         *
         * Le lien d'ajout d'une nouvelle pièce est disponible uniquement dans
         * le contexte du dossier d'instruction.
         */
        //
        $ct_link_add = "";
        // 
        if ($contexte == "dossier_instruction" 
            && $this->is_action_available(0)) {
            // Affiche bouton ajouter
            $ct_link_add = $template_link_add;
        }

        /**
         * Gestion du lien vers le téléchargement de toutes les pièces dans une archive.
         *
         * Le lien est disponible dans l'onglet pièce du DA, du DI, des demandes d'avis
         * en cours et passées.
         */
        //
        $ct_link_download_zip = "";
        if (($contexte == "dossier_instruction"
            OR $contexte == "dossier_autorisation" 
            OR $contexte == "demande_avis")
            AND ($this->f->isAccredited("document_numerise_tab")
                OR $this->f->isAccredited("document_numerise"))) {
            // Identifiant du DA ou DI à passer dans le lien de l'archive zip
            if ($contexte == "dossier_autorisation") {
                $dossier = $dossier_autorisation;
            } else {
                $dossier = $dossier_instruction;
            }
            // Affichage du bouton "Télécharger toutes les pièces" et passage des messages
            // d'erreur à la fonction Javascript qui va afficher la fenêtre modale qui 
            // permet de télécharger l'archive zip.
            if($res->numRows() > 0) {
                $zip_messages = array(
                    "title" => _("Téléchargement de l'archive"),
                    "confirm_message" => _("Êtes vous sûr de vouloir télécharger l'intégralité des pièces déposées du dossier ?"),
                    "confirm_button_ok" => _("Oui"),
                    "confirm_button_ko" => _("Non"),
                    "waiting_message" => _("Votre archive est en cours de préparation. Veuillez patienter."),
                    "download_message" => _("Votre archive est prête,"),
                    "download_link_message" => _("Cliquez ici pour la télécharger"),
                    "error_message" => _("L'archive n'a pas pu être créée. Veuillez contacter votre administrateur."),
                );
                $zip_messages_json = json_encode($zip_messages, JSON_HEX_APOS);
                // Remplacement des messages en JSON dans le template
                $ct_link_download_zip = sprintf(
                    $template_link_download_zip,
                    $zip_messages_json,
                    $dossier,
                    $obj
                );
            }
        }

        /**
         * Gestion du lien vers la fiche de visualisation de la pièce
         * 
         * Le lien vers la fiche de visualisation d'une pièce est disponible 
         * uniquement dans le contexte du dossier d'instruction.
         */
        //
        if ($contexte == "dossier_instruction" 
            && ($this->f->isAccredited("document_numerise_consulter")
                || $this->f->isAccredited("document_numerise"))
            ) {
            //
            $template_info_view = $template_info_view_link;
            $template_icon_view = $template_icon_view_link;
        } else {
            //
            $template_info_view = "";
            $template_icon_view = "";
        }

        /**
         * Gestion du lien de téléchargement de la pièce
         */
        //
        if ($this->f->isAccredited(array("document_numerise", "document_numerise_uid_telecharger"), "OR")) {
            //
            $template_filename = $template_filename_download;
        } else {
            //
            $template_filename = $template_filename_readonly;
        }

        /**
         * Gestion de l'affichage
         */
        // Si on se trouve dans le contexte du dossier d'autorisation alors le 
        // tableau affiche une colonne supplémentaire pour afficher le numéro
        // du dossier
        if ($contexte == "dossier_autorisation") {
            $nb_col = 4;
        } else {
            $nb_col = 3;
        }
        //
        $ct_list_dn = "";
        //
        $i = 1;

        //Résultat à $i - 1 pour tester la date et catégorie des documents
        $lastRes = array();
        $lastRes['date_creation'][0] = "";
        $lastRes['categorie'][0] = "";

        //Tant qu'il y a des résultats
        while( $row = &$res->fetchRow(DB_FETCHMODE_ASSOC) ) {

            $lastRes['date_creation'][$i] = $row['date_creation'];
            $lastRes['categorie'][$i] = $row['categorie'];

            //Si la date de création est différente de celle du résultat juste avant
            if ($row['date_creation'] != $lastRes['date_creation'][$i-1]) {
                //Si ce n'est pas le premier résultat on ferme la table
                if($i != 1) {
                    $ct_list_dn .= "</table>";
                } 
                //Affiche la table 
                $ct_list_dn .= "<table class='tab-tab document_numerise'>";
                //Affiche le header de la date
                $ct_list_dn .= sprintf(
                    $template_header, 
                    'headerDate',
                    $nb_col,
                    $this->f->formatDate($row['date_creation'])
                );
                //Affiche le header de la catégorie
                $ct_list_dn .= sprintf(
                    $template_header,
                    'headerCat', 
                    $nb_col,
                    $row['categorie']
                );
                //Style des lignes
                $style = 'odd';
            }
            
            //Si la date de création est identique à celle du résultat juste avant
            //et la catégorie est différente de celle du résultat juste avant
            if ($row['date_creation'] == $lastRes['date_creation'][$i-1] && $row['categorie'] != $lastRes['categorie'][$i-1]) {
                //Affiche le header de la catégorie
                $ct_list_dn .= sprintf(
                    $template_header,
                    'headerCat',
                    $nb_col,
                    $row['categorie']
                );
                //Style des lignes
                $style = 'odd';
            }

            //Si toujours dans la catégorie on change le style de la ligne
            if ($row['categorie'] == $lastRes['categorie'][$i-1] && $row['date_creation'] == $lastRes['date_creation'][$i-1]) {
                $style = ($style=='even')?'odd':'even';
            }

            //
            $style .= " col".$nb_col;

            // Si on est dans la visualisation du DA, on affiche le numéro du dossier 
            // d'instruction auquel est rataché la pièce et le nom du fichier
            if ($contexte === 'dossier_autorisation') {
                //
                $ct_list_dn .= sprintf(
                    $template_line_4col,
                    $style,
                    "",
                    $row['dossier'],
                    sprintf(
                        $template_filename,
                        $row['document_numerise'],
                        $row['document_numerise'],
                        $row['nom_fichier']
                    ),
                    $row['type_document']
                );
            } elseif ($contexte === "demande_avis") {
                //
                $ct_list_dn .= sprintf(
                    $template_line_3col,
                    $style,
                    "",
                    sprintf(
                        $template_filename,
                        $row['document_numerise'],
                        $row['document_numerise'],
                        $row['nom_fichier']
                    ),
                    $row['type_document']
                );
            } elseif ($contexte === 'dossier_instruction') {
                //
                $ct_list_dn .= sprintf(
                    $template_line_3col,
                    $style,
                    sprintf(
                        $template_icon_view, 
                        $row['document_numerise']
                    ),
                    sprintf(
                        $template_filename, 
                        $row['document_numerise'],
                        $row['document_numerise'],
                        $row['nom_fichier']
                    ),
                    sprintf(
                        $template_info_view, 
                        $row['document_numerise'],
                        $row['type_document']
                    )
                );
            }

            //
            $i++;

        }

        //On ferme la table
        $ct_list_dn .= "</table>";

        //S'il n'y a pas de résultat on affiche "Aucun enregistrement"
        if ($res->numrows() == 0) {
            //
            $ct_list_dn = "<p class='noData'>"._("Aucun enregistrement")."</p>";
        }

        /**
         *
         */
        printf(
            $template_view,
            $ct_link_add,
            $ct_link_download_zip,
            $ct_list_dn
        );

        /**
         *
         */
        echo "\n\n";
        echo "\n<!-- ########## END VIEW DOCUMENT_NUMERISE ########## -->\n";
        echo "\n\n";
    }

    /**
     * VIEW - view_dossier_final
     *
     * Vue permettant de constituer le dossier final.
     *
     * @return void
     */
    function view_dossier_final() {
        // Vérification de l'accessibilité sur l'élément
        $this->checkAccessibility();

        // Récupèration des variables nécessaires
        $idxformulaire = $this->getParameter('idxformulaire');
        $retourformulaire = $this->getParameter('retourformulaire');
        $obj = get_class($this);

        // La vue n'est pas affichée si le contexte n'est un dossier d'instruction
        if (in_array($retourformulaire, $this->foreign_keys_extended["dossier"]) !== true) {
            return;
        }

        /**
         *
         */
        echo "\n\n";
        echo "\n<!-- ########## START VIEW DOSSIER FINAL ########## -->\n";
        echo "\n\n";

        // ACTION BASCULER VERS DOSSIER FINAL
        $this->display_toggl_button($obj, $retourformulaire, $idxformulaire, 'switcher__toggle toutes_les_pieces');

        // Message affiché à l'utilisateur
        printf('<div id="form-message-dossier-final"></div>');

        //Requête de récupération des dates les plus récente pour chaque type de document
        //dont la recommandation doit se baser dessus.
        $sql_last_date_instruction = "
        SELECT 
            max(date_evenement) as last_date,
            'instruction' as type_document
        FROM 
            ".DB_PREFIXE."instruction
        WHERE
            instruction.dossier = '".$idxformulaire."'
        AND om_fichier_instruction is not null
        ";
        $sql_last_date_document_numerise = "
        SELECT
            max(document_numerise.date_creation) as last_date,
            document_numerise_type.libelle as type_document
        FROM 
            ".DB_PREFIXE."document_numerise 
            LEFT JOIN ".DB_PREFIXE."document_numerise_type
                ON document_numerise.document_numerise_type = document_numerise_type.document_numerise_type
            LEFT JOIN ".DB_PREFIXE."document_numerise_type_categorie
                ON document_numerise_type.document_numerise_type_categorie = document_numerise_type_categorie.document_numerise_type_categorie 
            LEFT JOIN ".DB_PREFIXE."dossier 
                ON document_numerise.dossier = dossier.dossier 
            LEFT JOIN ".DB_PREFIXE."dossier_autorisation
                ON dossier.dossier_autorisation = dossier_autorisation.dossier_autorisation
        WHERE
            document_numerise.dossier = '".$idxformulaire."'
        GROUP by type_document 
        ";
        $last_date_query =sprintf("
        (%s)
        UNION
        (%s)
        ",
        $sql_last_date_document_numerise,
        $sql_last_date_instruction);
        //
        $res_last_date = $this->f->db->query($last_date_query);
        $this->f->addToLog(__METHOD__."(): db->query(\"".$last_date_query."\");", VERBOSE_MODE);
        $this->f->isDatabaseError($res_last_date);
        //Tableau contenant les dates indexées par le type de document
        $last_date = array(); 
        while($row = $res_last_date->fetchRow(DB_FETCHMODE_ASSOC)) {
            $last_date[$row["type_document"]] = $row["last_date"];
        }
        /*
        *Requêtes de récupération des fichiers 
        */
        $sql_document_numerise="
        SELECT  
            document_numerise.document_numerise as id,
            document_numerise.date_creation as date_depot,
            document_numerise_type_categorie.libelle as categorie,
            document_numerise.nom_fichier as nom_fichier,
            document_numerise_type.libelle as type_document,
            document_numerise.uid as uid,
            'document_numerise' as classe,
            uid_dossier_final as dossier_final
        FROM 
            ".DB_PREFIXE."document_numerise 
            LEFT JOIN ".DB_PREFIXE."document_numerise_type
                ON document_numerise.document_numerise_type = document_numerise_type.document_numerise_type
            LEFT JOIN ".DB_PREFIXE."document_numerise_type_categorie
                ON document_numerise_type.document_numerise_type_categorie = document_numerise_type_categorie.document_numerise_type_categorie 
            LEFT JOIN ".DB_PREFIXE."dossier 
                ON document_numerise.dossier = dossier.dossier 
            LEFT JOIN ".DB_PREFIXE."dossier_autorisation
                ON dossier.dossier_autorisation = dossier_autorisation.dossier_autorisation
        WHERE
            document_numerise.dossier = '".$idxformulaire."'
        ";

        $sql_document_instruction = "
        SELECT  
            instruction.instruction as id,
            instruction.date_evenement as date_depot,
            '".__("document généré")."' as categorie,
            CONCAT('instruction_',instruction.instruction) as nom_fichier,
             'instruction' as type_document,
            instruction.om_fichier_instruction as uid,
            'instruction' as classe,
            om_fichier_instruction_dossier_final as dossier_final
        FROM 
            ".DB_PREFIXE."instruction 
        WHERE
            instruction.dossier = '".$idxformulaire."'
        AND instruction.om_fichier_instruction is not null
        ";

        $sql_document_consultation = "
        SELECT
            consultation.consultation as id,
            CASE WHEN consultation.date_retour IS NOT NULL 
                    THEN consultation.date_retour
                    ELSE consultation.date_envoi 
                END as date_depot,
            CASE WHEN consultation.fichier IS NOT NULL 
                    THEN '%s'
                    ELSE '%s'
                END as categorie,
            CASE WHEN consultation.fichier IS NOT NULL 
                    THEN CONCAT('consultation_avis_',consultation.consultation)
                    ELSE CONCAT('consultation_',consultation.consultation)
                END as nom_fichier,
            CASE WHEN consultation.fichier IS NOT NULL 
                    THEN CONCAT('consultation_avis_',service.type_consultation)
                    ELSE %s
                END as type_document,
            CASE WHEN consultation.fichier IS NOT NULL 
                    THEN fichier
                    ELSE om_fichier_consultation
                END as uid,
            'consultation' as classe,
            CASE WHEN consultation.fichier IS NOT NULL 
                    THEN consultation.fichier_dossier_final
                    ELSE consultation.om_fichier_consultation_dossier_final
                END as dossier_final
        FROM
            %sconsultation
        JOIN %sservice 
            ON consultation.service = service.service
        WHERE
            consultation.dossier = '%s'
        AND (consultation.fichier IS NOT NULL
            OR consultation.om_fichier_consultation IS NOT NULL)
        ";
        //Variation du type du document en cas d'avis tacite défini
        $id_tacite = $this->f->getParameter('id_avis_consultation_tacite');
        $consultation_else_type_document = "CONCAT('consultation_', service.type_consultation)";
        if ($id_tacite !== null && trim($id_tacite) !== '') {
            $consultation_else_type_document = sprintf("CASE WHEN consultation.avis_consultation IS NOT NULL
            THEN CASE WHEN consultation.avis_consultation = %s
                    THEN CONCAT('consultation_', service.type_consultation, '_tacite')
                    ELSE CONCAT('consultation_', service.type_consultation)
                END 
            ELSE CONCAT('consultation_',service.type_consultation)
            END ",
            $id_tacite
            );
        }
        $sql_document_consultation = sprintf($sql_document_consultation, $this->db->escapeSimple(__("retour d'avis")), __("document généré"), $consultation_else_type_document, DB_PREFIXE, DB_PREFIXE, $idxformulaire);

        $union_query = sprintf("
            (%s)
            UNION
            (%s)
            UNION
            (%s)",
            $sql_document_numerise,
            $sql_document_instruction,
            $sql_document_consultation
        );

        // Exécution de la requête de récupération des fichiers
        $res = $this->f->db->query($union_query);
        $this->f->addToLog(__METHOD__."(): db->query(\"".$union_query."\");", VERBOSE_MODE);
        $this->f->isDatabaseError($res);

        //Affichage du formulaire de constitution du dossier final
        $dossier_final_archive = array();
        $champs_tableau = array();
        $champs_tableau["date_none"] = array();
        $champs_tableau["date_exists"] = array();
        while($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
            // id, date_depot,categorie,nom_fichier,type_document,uid,class,dossier_final_piece_recommandee
            if ($row['dossier_final'] === 't' || $row['dossier_final'] === true ) {
                $dossier_final = 'true';
                $dossier_final_archive[] = $row["uid"];
            } else {
                $dossier_final = 'false';
            }
            $dossier_final_piece_recommandee = 'false';
            //Le fichier généré d'une consultation n'est pas recommandé en général
            //Le fichier joint à un avis à une consultation est recommandé en général
            if ($row["categorie"] === __("document généré")){
                $dossier_final_piece_recommandee = 'false';
            } else if ($row["categorie"] === __("retour d'avis")) {
                $dossier_final_piece_recommandee = 'true';
            }
            //Le fichier généré d'un avis tacite est recommandé
            if (substr($row["type_document"], -6) === 'tacite'){
                $dossier_final_piece_recommandee = 'true';
            }
            //Les fichiers sans date de dépot associée vont dans un tableau à part
            if ($row['date_depot'] === null || trim($row['date_depot']) === "") {
                $key_date = "date_none";
                $dossier_final_piece_recommandee = 'true';
            } else {
                $key_date = "date_exists";
                if ($row["type_document"] === "consultation_pour_information"
                    || $row["type_document"] === "consultation_avis_pour_information"
                    || $row["type_document"] === "consultation_pour_information_tacite") {
                    //
                    $dossier_final_piece_recommandee = 'false';
                } else if (isset($last_date[$row["type_document"]]) === true && $last_date[$row["type_document"]]!== null) {
                    $dossier_final_piece_recommandee = ($row['date_depot'] === $last_date[$row["type_document"]]) ? 'true':'false';
                }
            }
            $champs_tableau[$key_date][] = array(
                "nom_fichier" => $row['nom_fichier'],
                "uid" => $row['uid'],
                "type_document" => $row['type_document'],
                "id" => $row['id'],
                "categorie" => $row['categorie'],
                "classe" => $row['classe'],
                "dossier_final" => $dossier_final,
                "dossier_final_piece_recommandee" => $dossier_final_piece_recommandee,
                "date_document" => $row['date_depot']
            );
        }

        /*
        * Traitement des fichiers sans date ( càd dont la base ne comporte pas de champ de date) - DEBUT
        *
        */
        $sql_rapport_instruction = "
        SELECT  
            rapport_instruction.rapport_instruction as id,
            '".__("document généré")."' as categorie,
            '".$this->db->escapeSimple(__("rapport d'instruction"))."' as nom_fichier,
            'rapport_instruction' as type_document,
           rapport_instruction.om_fichier_rapport_instruction as uid,
            'rapport_instruction' as classe,
            om_fichier_rapport_instruction_dossier_final as dossier_final
        FROM 
            ".DB_PREFIXE."rapport_instruction 
        WHERE
            rapport_instruction.dossier_instruction = '".$idxformulaire."'
        AND om_final_rapport_instruction is true
          ";
        $res_date_none = $this->f->db->query($sql_rapport_instruction);
        $this->f->addToLog(__METHOD__."(): db->query(\"".$sql_rapport_instruction."\");", VERBOSE_MODE);
        $this->f->isDatabaseError($res_date_none);
        while($row = $res_date_none->fetchRow(DB_FETCHMODE_ASSOC)) {
            $dossier_final = 'false';
            if ($row['dossier_final'] === 't' || $row['dossier_final'] === true ){
                $dossier_final = 'true';
                $dossier_final_archive[] = $row["uid"];
            }
            $champs_tableau["date_none"][] = array(
                "nom_fichier" => $row['nom_fichier'],
                "uid" => $row['uid'],
                "type_document" => $row['type_document'],
                "id" => $row['id'],
                "categorie" => $row['categorie'],
                "classe" => $row['classe'],
                "dossier_final" => $dossier_final,
                "dossier_final_piece_recommandee" => 'true',
                "date_document" => ''
            );
        }
        /*
        * Entrée: tableau $champs_tableau[date_none ou date_exists][arrays des fichiers non triés]
        * Tri des colonnes du tableau 
        */
        foreach ($champs_tableau as &$champ_tableau) {
            // Tri alphabétique par nom de fichier 
            usort($champ_tableau, function($element1, $element2)  {
                return strnatcmp($element1['nom_fichier'], $element2['nom_fichier']);
            });
            // Tri alphabétique par catégorie
            usort($champ_tableau, function($element1, $element2)  {
                return strnatcmp($element1['categorie'], $element2['categorie']);
            });
            // Tri par date_document décroissante
            usort($champ_tableau, function($element1, $element2)  {
                return (strtotime($element2['date_document']) - strtotime($element1['date_document']));
            });
        }
        /* Sortie: 
        * tableau $champs_tableau[date_none ou date_exists][arrays des fichiers triés 
        * par date_document/catégorie/nom_fichier]
        */

        // Template du lien pour la visualisation du document
        $template_link_file = '<a class="lienTable" href="../app/index.php?module=form&snippet=file&obj=%s&champ=%s&id=%s" target="_blank"><span class="om-prev-icon reqmo-16" title="%s">%s</span></a>';
        // Template d'une checkbow
        $template_checkbox = '<div><input type="checkbox" name="%1$s" id="%2$s" %3$s="%4$s" class="%5$s" %6$s /> <label for="%2$s">%7$s</label></div>';
        // Template pour l'affichage d'une ligne du tableau
        $template_row = '<tr class="tab-data %s">%s</tr>';
        // Template pour l'affichage d'une cellule
        $template_cell = '<td class="col-%s %s">%s</td>';

        $form = $this->f->get_inst__om_formulaire();

        /*
        * Affichage du formulaire
        */
        $this->f->layout->display__form_controls_container__begin(array(
            "controls" => "top",
        ));

        printf($template_checkbox, 'checkbox_select_all_none', 'checkbox_select_all_none', 'onclick', 'dossier_final_checkbox_select_all_none(this);', 'checkbox_select_all_none', '', __('Tout sélectionner / désélectionner'));
        $this->f->layout->display__form_input_submit(array(
            "value" => _("Sélectionner les pièces recommandées"),
            "onclick" => "dossier_final_select_recommandees();",
            "class" => 'dossier_final_select_recommandees',
        ));

        /*
        * Construction du lien de téléchargement du dossier final
        */
        $link_telecharger_dossier_final = "";
        if($dossier_final_archive !== array()){
            $zip_messages = array(
                    "title" => _("Téléchargement du dossier final"),
                    "confirm_message" => _("Êtes vous sûr(e) de vouloir télécharger l'ensemble des pièces du dossier final ?"),
                    "confirm_button_ok" => _("Oui"),
                    "confirm_button_ko" => _("Non"),
                    "waiting_message" => _("Votre archive est en cours de préparation. Veuillez patienter."),
                    "download_message" => _("Votre archive est prête,"),
                    "download_link_message" => _("Cliquez ici pour la télécharger"),
                    "error_message" => _("L'archive n'a pas pu être créée. Veuillez contacter votre administrateur."),
                );
            $zip_messages_json = json_encode($zip_messages, JSON_HEX_APOS);
            $dossier_final_archive_json = json_encode($dossier_final_archive, JSON_HEX_APOS);
            $link_telecharger_dossier_final = sprintf("
                <a id='telecharger_dossier_final' onclick='generate_archive_dossier_final(%s,%s,\"%s\", \"%s\");' href='#'>
                    <span class='om-icon om-icon-16 om-icon-fix archive-16'
                    title='"._("Télécharger le dossier final")."'>"._("Télécharger le dossier final")."</span>
                    "._("Télécharger le dossier final")."
                </a>
                ",
                $zip_messages_json,
                $dossier_final_archive_json,
                $idxformulaire,
                $obj
            );
        }
        printf("
            <div id='telecharger-dossier-final'>%s</div>",
            $link_telecharger_dossier_final
        );

        $this->f->layout->display__form_controls_container__end();

        // Début du formulaire
        $form->entete();

        // Ouverture de la balise table
        // - Affichage des entêtes de colonne
        $param = array(
            'idcolumntoggle' => "dossier_final"
        );
        $this->f->layout->display_table_start_class_default($param);
        $array_dossier_final = array("selection", "Date depot", "type", "nom", "catégorie");
        echo "<thead>\n";
        echo "<tr class=\"ui-tabs-nav ui-accordion ui-state-default tab-title\">\n";
        $param = array(
                    "key" => 0,
                    "info" =>  $array_dossier_final
             );
        $this->f->layout->display_table_cellule_entete_colonnes($param);
        echo "&nbsp;&nbsp;";
        echo "</th>";
        $param = array(
                    "key" => 1,
                    "info" => $array_dossier_final
             );
        $this->f->layout->display_table_cellule_entete_colonnes($param);
        echo __("date de depot");
        echo "</th>";
        $param = array(
                    "key" => 2,
                    "info" => $array_dossier_final
             );
        $this->f->layout->display_table_cellule_entete_colonnes($param);
        echo __("type");
        $param = array(
                    "key" => 3,
                    "info" => $array_dossier_final
             );
        $this->f->layout->display_table_cellule_entete_colonnes($param);
        echo __("nom du fichier");
        echo "</th>";
        $param = array(
                    "key" => 5,
                    "info" => $array_dossier_final
             );
        $this->f->layout->display_table_cellule_entete_colonnes($param);
        echo __("categorie");
        echo "</th>\n";
        echo "</tr>\n";
        echo "</thead>\n";

        // Affichage des documents non daté, en tête de tableau
        $i = 0;
        foreach($champs_tableau["date_none"] as $value){
            //
            switch($value["classe"]) {
                case "rapport_instruction" : 
                    $champ_uid = "om_fichier_rapport_instruction"; 
                    break;
            }
            $nom_fichier = sprintf($template_link_file, $value["classe"], $champ_uid, $value["id"], __('Ouvrir le fichier'), $value["nom_fichier"]);
            // On construit la case à cocher
            $checked = '';
            if ($value["dossier_final"] === 'true') {
                $checked = 'checked="checked"';
            }
            $box = sprintf($template_checkbox, $value["classe"], $value["uid"], 'champ_uid', $champ_uid, 'checkbox-dossier_final', $checked, '');
            //Détermination des classes de la balise <tr>
            $tr_class = " odd ";
            if ($i % 2 === 1) {
                $tr_class = " even ";
            }
            if ($value["dossier_final_piece_recommandee"] === 'true') {
                $tr_class .= " dossier_final_piece_recommandee";
            }
            $date = __("Non applicable");
            // Composition des cellules
            $colls = sprintf($template_cell, 0, "", $box);
            $colls .= sprintf($template_cell, 1, "", $date);
            $colls .= sprintf($template_cell, 2, "", $value["type_document"]);
            $colls .= sprintf($template_cell, 3, "", $nom_fichier);
            $colls .= sprintf($template_cell, 4, "", $value["categorie"]);
            // Affichage de la ligne du tableau
            printf($template_row, $tr_class, $colls);
            $i++;
        }
        // Affichage des documents ayant une date
        foreach ($champs_tableau["date_exists"] as $value) {
            //
            switch($value["classe"]) {
                case "consultation" :
                    if ($value["categorie"] === __("retour d'avis")) {
                        $champ_uid = "fichier";
                    } else {
                        $champ_uid = "om_fichier_consultation";
                    }
                    break;
                case "instruction" : 
                    $champ_uid = "om_fichier_instruction";
                    break;
                case "document_numerise" : 
                    $champ_uid = "uid";
                    break;
            }
            $nom_fichier = sprintf($template_link_file, $value["classe"], $champ_uid, $value["id"], __('Ouvrir le fichier'), $value["nom_fichier"]);
            // On construit la case à cocher
            $checked = '';
            if ($value["dossier_final"] === 'true') {
                $checked = 'checked="checked"';
            }
            $box = sprintf($template_checkbox, $value["classe"], $value["uid"], 'champ_uid', $champ_uid, 'checkbox-dossier_final', $checked, '');
            //Détermination des classes de la balise <tr>
            $tr_class = " odd ";
            if ($i % 2 === 1) {
                $tr_class = " even ";
            }
            if ($value["dossier_final_piece_recommandee"] === 'true'){
                $tr_class .= " dossier_final_piece_recommandee";
            }
            $timestamp = strtotime($value["date_document"]);
            $date_affichee = date("d/m/Y", $timestamp);
            // Composition des cellules
            $colls = sprintf($template_cell, 0, "", $box);
            $colls .= sprintf($template_cell, 1, "", $date_affichee);
            $colls .= sprintf($template_cell, 2, "", $value["type_document"]);
            $colls .= sprintf($template_cell, 3, "", $nom_fichier);
            $colls .= sprintf($template_cell, 4, "", $value["categorie"]);
            // Affichage de la ligne du tableau
            printf($template_row, $tr_class, $colls);
            $i++;
        }
        printf('</table>');
        // Ferme le formulaire
        $form->enpied();

        //Fin de l'affichage du formulaire de constitution du dossier final 
        $this->f->layout->display__form_controls_container__begin(array(
            "controls" => "bottom",
        ));
        $this->f->layout->display_form_button(array(
            "name" => "constituer_dossier_final",
            "value" => __("Constituer le dossier final"),
            "onclick" => sprintf("constituer_dossier_final('%s','%s');", $idxformulaire, $obj)
        ));

        // Fermeture du conteneur des actions de controles du formulaire
        $this->f->layout->display__form_controls_container__end();
    }
    /**
     * VIEW - constituer_dossier_final.
     *
     * Permet de constituer le dossier final et de (re)-créer le bouton de
     * téléchargement de l'archive du dossier final
     *
     * @return void
     */
    function constituer_dossier_final(){
        $response = array();
        $response["msg_error"] = "";
        $dossier_final_archive = array();
        $obj = get_class($this);
        $dossier_instruction = $this->f->get_submitted_get_value("dossier");
        //Préparation du bouton (argument var_text dans le onclick)
        $zip_messages = array(
                    "title" => _("Téléchargement du dossier final"),
                    "confirm_message" => _("Êtes vous sûr(e) de vouloir télécharger l'ensemble des pièces du dossier final ?"),
                    "confirm_button_ok" => _("Oui"),
                    "confirm_button_ko" => _("Non"),
                    "waiting_message" => _("Votre archive est en cours de préparation. Veuillez patienter."),
                    "download_message" => _("Votre archive est prête,"),
                    "download_link_message" => _("Cliquez ici pour la télécharger"),
                    "error_message" => _("L'archive n'a pas pu être créée. Veuillez contacter votre administrateur."),
                );
        $zip_messages_json = json_encode($zip_messages, JSON_HEX_APOS);
        //
        $dossier_final = "";
        // Récupération des références cadastrales passées en paramètre
        if ($this->f->get_submitted_post_value("dossier_final") != null) {
            $dossier_final = $this->f->get_submitted_post_value("dossier_final");
        }
        // Si ce n'est pas un tableau de références
        if (is_array($dossier_final) === false || $dossier_final === array()) {
            $msg_error = __("Aucun fichier trouvé pour le dossier final.");
            $this->f->addToLog(__METHOD__."(): ".$msg_error, VERBOSE_MODE);
            printf(json_encode(["msg_error" => $msg_error]));
            return;
        }
        //
        foreach ($dossier_final as $key => $fichier) {

            // Met à jour le TODO
            $res = $this->f->db->autoExecute(
                DB_PREFIXE.$fichier["table"],
                [$fichier["champ_uid"]."_dossier_final" => $fichier["val"]],
                DB_AUTOQUERY_UPDATE,
                $fichier["champ_uid"]."='".$fichier["uid"]."'");
            //
            if ($this->f->isDatabaseError($res, true) === true) {
                $msg_error = sprintf(__("Erreur lors de l'ajout d'un fichier au dossier final (uid: %s)"), $fichier["uid"]);
                $this->f->addToLog(__METHOD__."(): ".$msg_error, DEBUG_MODE);
                printf(json_encode(["msg_error" => $msg_error]));
                return;
            }
            if ($fichier["val"] === "true" || $fichier["val"] === true) {
                $dossier_final_archive[] = $fichier["uid"];
            }
        }

        // Si aucun fichier n'est sélectionné, le bouton permettant de
        // télécharger l'intégralité des documents dans une archive, est caché
        $link_telecharger_dossier_final = "";
        if (count($dossier_final_archive) !== 0) {
            $dossier_final_archive_json = json_encode($dossier_final_archive, JSON_HEX_APOS);
            $link_telecharger_dossier_final = sprintf("
                <a id='telecharger_dossier_final' onclick='generate_archive_dossier_final(%s,%s,\"%s\", \"%s\");' href='#'>
                    <span class='om-icon om-icon-16 om-icon-fix archive-16'
                    title='"._("Télécharger le dossier final")."'>"._("Télécharger le dossier final")."</span>
                    "._("Télécharger le dossier final")."
                </a>
                ",
                $zip_messages_json,
                $dossier_final_archive_json,
                $dossier_instruction,
                $obj
            );
        }

        $response["button_content"] = $link_telecharger_dossier_final;
        printf(json_encode($response), JSON_HEX_APOS);
    }

    /**
     * VIEW - generate_archive_dossier_final
     *
     * Permet de générer une archive zip contenant les documents constitutifs du
     * dossier final
     *
     * @return void
     */
    function generate_archive_dossier_final() {
        $this->f->disableLog();

        $return = array();

        // Liste des documents à télécharger séparés par une virgule ","
        if ($this->f->get_submitted_get_value('ids') === null) {
            printf(json_encode(_("Aucun document fourni")));
            return;
        }
        $uids = $this->f->get_submitted_get_value('ids');
        $uids = explode(",", $uids);

        if ($this->f->get_submitted_get_value('dossier') === null) {
            printf(json_encode(_("Aucun dossier fourni")));
            return;
        }
        $dossier = $this->f->get_submitted_get_value('dossier');

        // Création du storage temporaire
        $temp = "0";
        $metadata = array(
            "filename" => time().".zip",
            "size" => 1,
            "mimetype" => "application/zip",
        );
        // Création du fichier zip en filestorage temporary
        if ($this->f->storage === null) {
            printf(json_encode(_("Erreur lors de la création de l'archive")));
            return;
        }
        $temp_uid = $this->f->storage->create_temporary($temp, $metadata);
        if ($temp_uid === OP_FAILURE) {
            printf(json_encode(_("Erreur lors de la création de l'archive")));
            return;
        }
        // Récupération de son path pour ziparchive
        $temp_path = $this->f->storage->getPath_temporary($temp_uid);
        // Instanciation de l'archive
        $zip = new ZipArchive;
        $zip->open($temp_path, ZipArchive::OVERWRITE);
        // On rempli l'archive avec les documents récupérés sur le storage
        foreach ($uids as $uid) {
            $file = $this->f->storage->get($uid);
            if ($file === OP_FAILURE) {
                $return['status'] = false;
            } else {
               $zip->addFromString($file['metadata']['filename'], $file['file_content']); 
            }
        }
        $zip->close();

        // Création d'un second temporary pour mettre à jour les métadonnées
        $size = filesize($temp_path);
        $file_name = $dossier.'_dossier_final_'.date("Ymd");
        $metadata = array(
            "filename" => $file_name.".zip",
            "size" => $size,
            "mimetype" => "application/zip",
        );
        $uid_dossier_final = $this->f->storage->create_temporary($temp_path, $metadata, "from_path");
        $return['status'] = true;

        if ($uid_dossier_final === OP_FAILURE) {
            $return['status'] = false;
        }
        $return['file'] = $uid_dossier_final;
        printf(json_encode($return));
    }

    function setType(&$form,$maj) {
        parent::setType($form,$maj);

        //type
        $form->setType('document_numerise','hidden');
        $form->setType('dossier','hidden');
        $form->setType('nom_fichier','hidden');
        $form->setType('uid_dossier_final','hidden');

        if ($maj==0){ //ajout
            $form->setType('nom_fichier','hidden');
            if($this->retourformulaire == "") {
                $form->setType('uid','upload');
            } else {
                $form->setType('uid','upload2');
            }
        }// fin ajout

        if ($maj==1){ //modifier
            $form->setType('nom_fichier','hiddenstatic');
            if($this->retourformulaire == "") {
                $form->setType('uid','upload');
            } else {
                $form->setType('uid','upload2');
            }
        }// fin modifier

        if ($maj==2){ //supprimer
            $form->setType('uid','filestatic');
            $form->setType('date_creation','datestatic');
        }// fin supprimer

        if ($maj==3){ //consulter
            $form->setType('uid','file');
        }// fin consulter
    }

    function setValsousformulaire(&$form, $maj, $validation, $idxformulaire, $retourformulaire, $typeformulaire, &$dnu1 = null, $dnu2 = null) {
        //
        parent::setValsousformulaire($form, $maj, $validation, $idxformulaire, $retourformulaire, $typeformulaire);
        
        $this->retourformulaire = $retourformulaire;

        if($maj == 0 && 
            ($retourformulaire =='dossier' 
              || $retourformulaire =='dossier_instruction'
              || $retourformulaire=='dossier_instruction_tous_clotures'
              || $retourformulaire=='dossier_instruction_mes_clotures'
              || $retourformulaire=='dossier_instruction_tous_encours'
              || $retourformulaire=='dossier_instruction_mes_encours'
              || $retourformulaire=='dossier_contentieux_mes_infractions'
              || $retourformulaire=='dossier_contentieux_toutes_infractions'
              || $retourformulaire=='dossier_contentieux_mes_recours'
              || $retourformulaire=='dossier_contentieux_tous_recours')) {
            $form->setVal('dossier', $idxformulaire);
            $form->setVal('date_creation', date("d/m/Y"));
        }

    }// fin setValsousformulaire

    /**
     * [setLib description]
     * @param [type] $form [description]
     * @param [type] $maj  [description]
     */
    function setLib(&$form, $maj) {
        parent::setLib($form, $maj);

        //
        $form->setLib("uid", _("fichier"));
    }


    /**
     * Méthode de traitement des données retournées par le formulaire
     */
    function setvalF($val = array()) {
        parent::setvalF($val);

        //Si le type est renseigné
        if ($val['document_numerise_type'] != "") {
          //Recupère le code du type du document
          $document_numerise_type = $this->get_document_numerise_type_code_by_id($val["document_numerise_type"]);

        } else {
          $document_numerise_type = "";
        }

        if ($val["date_creation"] == "") {
            $this->valF["date_creation"] = "";
        }

        //Génération automatique nom du fichier
        if ($val["nom_fichier"] == "" || $this->getParameter("maj") != 0) {
            $this->valF['nom_fichier'] = $this->generateFilename($this->valF["date_creation"], $document_numerise_type);
        }
    }

    /**
     * Permet de mettre à jour un champs dans la table instruction sans passer par ses triggers
     * @param   string $document_numerise Identifiant du fichier
     * @param   integer $instruction L'identifiant de l'instruction à mettre à jour
     */
    private function updateInstructionAutoExecute($document_numerise, $instruction) {

      // valeurs à mettre à jour
      $val = array("document_numerise"=>$document_numerise);
      // met à jour la table instruction sans passer par ses triggers
      $res = $this->db->autoExecute(DB_PREFIXE."instruction", $val, DB_AUTOQUERY_UPDATE,"instruction=".$instruction);
      // Exécution du traitement
      $this->f->addToLog("updateInstructionDocumentArrete() : db->autoExecute(".$res.")", VERBOSE_MODE);
      if (database::isError($res)) {
          die();
      }
    }

    /**
     * TRIGGER - triggerajouterapres.
     *
     * - Interface avec le référentiel ERP [113]
     * - Notification de l'instructeur par message
     *
     * @return boolean
     */
    function triggerajouterapres($id, &$db = null, $val = array(), $DEBUG = null) {

        // On a besoin de l'instance du dossier lié au document numérisé
        $inst_di = $this->get_inst_dossier($this->valF['dossier']);

        /**
         * Interface avec le référentiel ERP.
         *
         * (WS->ERP)[113] Ajout d'une nouvelle pièce
         * Déclencheur :
         *  - L'option ERP est activée
         *  - Le dossier est marqué comme "connecté au référentiel ERP"
         *  - Une nouvelle pièce est ajoutée au dossier
         */
        //
        if ($this->f->is_option_referentiel_erp_enabled($inst_di->getVal('om_collectivite')) === true
            && $inst_di->is_connected_to_referentiel_erp() === true) {
            //
            $inst_document_numerise_type = $this->get_inst_document_numerise_type($this->valF['document_numerise_type']);

            // Vérifie que le type du document peut être partagé avec des
            // services tiers
            if ($inst_document_numerise_type->getVal('aff_service_consulte') === 't') {
                //
                $infos = array(
                    "dossier_instruction" => $inst_di->getVal($inst_di->clePrimaire),
                    "date_creation" => $this->valF["date_creation"],
                    "nom_fichier" => $this->valF["nom_fichier"],
                    "type" => $inst_document_numerise_type->getVal('libelle'),
                    "categorie" => $this->get_document_numerise_type_categorie_libelle($this->valF['document_numerise_type']),
                );
                //
                $ret = $this->f->send_message_to_referentiel_erp(113, $infos);
                if ($ret !== true) {
                    $this->cleanMessage();
                    $this->addToMessage(_("Une erreur s'est produite lors de la notification (113) du référentiel ERP. Contactez votre administrateur."));
                    return false;
                }
                $this->addToMessage(_("Notification (113) du référentiel ERP OK."));
            }
        }

        /**
         * Notification de l'instructeur par message.
         */
        // Si l'option de notification par message est activée
        if ($this->f->getParameter('option_notification_piece_numerisee') === 'true') {
            // Instancie la classe dossier_message
            $dossier_message = $this->get_inst_dossier_message(0);
            // Ajoute le message de notification
            $dossier_message_val = array();
            $dossier_message_val['dossier'] = $val['dossier'];
            $dossier_message_val['type'] = _('Ajout de pièce(s)');
            $dossier_message_val['emetteur'] = $this->f->get_connected_user_login_name();
            $dossier_message_val['login'] = $_SESSION['login'];
            $dossier_message_val['date_emission'] = date('Y-m-d H:i:s');
            $dossier_message_val['contenu'] = _('Une ou plusieurs pièces ont été ajoutées sur le dossier.');
            $add = $dossier_message->add_notification_message($dossier_message_val);
            // Si une erreur se produit pendant l'ajout
            if ($add !== true) {
                // Message d'erreur affiché à l'utilisateur
                $this->addToMessage(_("Le message de notification n'a pas pu être ajouté."));
                $this->correct = false;
                return false;
            }

            // Récupère l'identifiant du message
            if (isset($dossier_message->valF[$dossier_message->clePrimaire]) === true) {
                $this->set_dossier_message_id($dossier_message->valF[$dossier_message->clePrimaire]);
            }
        }

        //
        return true;
    }

    /**
     * Affecte une valeur à l'attribut de l'identifiant du message.
     *
     * @param integer $value Valeur à stocker dans l'attribut.
     *
     * @return void
     */
    private function set_dossier_message_id($value) {
        //
        $this->dossier_message_id = $value;
    }


    /**
     * Retourne l'identifiant du message stocké dans l'attribut.
     *
     * @return integer
     */
    private function get_dossier_message_id() {
        //
        return $this->dossier_message_id;
    }


    /**
     * Permet d’effectuer des actions avant la modification des données dans la base
     */
    function triggermodifier($id, &$db = null, $val = array(), $DEBUG = null) {

      // si le fichier n'a pas été déjà modifié
      if (stripos($val['uid'], 'tmp') === false) {
        // récupération du fichier et de ses métadonnées
        $file = $this->f->storage->get($val['uid']);
        // créé un fichier temporaire
        $tmp_file = $this->f->storage->create_temporary($file['file_content'], $file['metadata'], "from_content");
        // remplace le fichier par le temporaire pour obliger la modification du fichier
        $this->valF['uid'] = 'tmp|'.$tmp_file;
      }
    }

    /**
     * Surcharge du bouton retour des sous-formulaire
     */
    function retoursousformulaire($idxformulaire = NULL, $retourformulaire = NULL, $val = NULL,
                                  $objsf = NULL, $premiersf = NULL, $tricolsf = NULL, $validation = NULL,
                                  $idx = NULL, $maj = NULL, $retour = NULL) {

        if(($maj == 0 || $maj == 3 || $maj == 2) && ($retourformulaire === "dossier_instruction"
          || $retourformulaire==='dossier_instruction_tous_clotures'
          || $retourformulaire==='dossier_instruction_mes_clotures'
          || $retourformulaire==='dossier_instruction_tous_encours'
          || $retourformulaire==='dossier_instruction_mes_encours'
          || $retourformulaire==='dossier_contentieux_mes_infractions'
          || $retourformulaire==='dossier_contentieux_toutes_infractions'
          || $retourformulaire==='dossier_contentieux_mes_recours'
          || $retourformulaire==='dossier_contentieux_tous_recours')) {
            
            echo "\n<a class=\"retour\" ";
            echo "href=\"#\" ";
            
            echo "onclick=\"ajaxIt('".$objsf."', '"; 
            echo OM_ROUTE_SOUSFORM."&obj=" . $objsf
                ."&idx=$idxformulaire"
                ."&action=4"
                ."&retourformulaire=$retourformulaire"
                ."&idxformulaire=$idxformulaire"
                ."&retour=form');\"";
            echo  "\" ";
            echo ">";
            //
            echo _("Retour");
            //
            echo "</a>\n";
            
        } else {
            parent::retoursousformulaire($idxformulaire, $retourformulaire, $val,
                                  $objsf, $premiersf, $tricolsf, $validation,
                                  $idx, $maj, $retour);
        }
    }

    /**
     * Ajout des contraintes spécifiques pour l'ajout d'un fichier en retour de 
     * consultation
     */
    function setSelect(&$form, $maj, &$dnu1 = null, $dnu2 = null) {

        // On appelle la methode de la classe parent
        // parent::setSelect($form, $maj);

        // Inclusion du fichier de requêtes
        if (file_exists("../sql/".OM_DB_PHPTYPE."/".$this->table.".form.inc.php")) {
            include "../sql/".OM_DB_PHPTYPE."/".$this->table.".form.inc.php";
        } elseif (file_exists("../sql/".OM_DB_PHPTYPE."/".$this->table.".form.inc")) {
            include "../sql/".OM_DB_PHPTYPE."/".$this->table.".form.inc";
        }
        // Si l'utilisateur a une entrée dans la table instructeur, on affiche les types
        // de pièces ayant la valeur ajout_instructeur valant true
        if ($this->f->isUserInstructeur() !== null AND $this->f->isUserInstructeur() !== false){
            $sql_document_numerise_type = str_replace('<om_utilisateur_login>', $this->f->om_utilisateur['login'], $sql_document_numerise_type_for_user);
        }
        $this->init_select($form, $this->f->db, $maj, null, "document_numerise_type", $sql_document_numerise_type, $sql_document_numerise_type_by_id, false);
        
        //Seulement dans le cas d'un dossier d'instruction
        if($this->retourformulaire =='dossier_instruction'
              || $this->retourformulaire=='dossier_instruction_tous_clotures'
              || $this->retourformulaire=='dossier_instruction_mes_clotures'
              || $this->retourformulaire=='dossier_instruction_tous_encours'
              || $this->retourformulaire=='dossier_instruction_mes_encours'
              || $this->retourformulaire=='dossier_contentieux_mes_infractions'
              || $this->retourformulaire=='dossier_contentieux_toutes_infractions'
              || $this->retourformulaire=='dossier_contentieux_mes_recours'
              || $this->retourformulaire=='dossier_contentieux_tous_recours') {
            
            //Tableau des contraintes
            $params = array(
                "constraint" => array(
                    "extension" => ".pdf"
                ),
            );
            
            $form->setSelect("uid", $params);
        }
    }

    // {{{ 
    // Méthodes de récupération des métadonnées document
    /**
     * Récupération du numéro de dossier d'instruction à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getDossier() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->dossier;
    }
    /**
     * Récupération la version du dossier d'instruction à ajouter aux métadonnées
     * @return int Version
     */
    protected function getDossierVersion() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->version;
    }
    /**
     * Récupération du numéro de dossier d'autorisation à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getNumDemandeAutor() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->dossier_autorisation;
    }
    /**
     * Récupération de la date de demande initiale du dossier à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getAnneemoisDemandeAutor() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->date_demande_initiale;
    }
    /**
     * Récupération du type de dossier d'instruction à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getTypeInstruction() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->dossier_instruction_type;
    }
    /**
     * Récupération du statut du dossier d'autorisation à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getStatutAutorisation() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->statut;
    }
    /**
     * Récupération du type de dossier d'autorisation à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getTypeAutorisation() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->dossier_autorisation_type;
    }
    /**
     * Récupération nom du fichier à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getFilename() {
        return $this->valF["nom_fichier"];
    }
    /**
     * Récupération de la date d'ajout de document à ajouter aux métadonnées
     * @return [type] [description]
     */
    protected function getDateEvenementDocument() {
        return date("Y-m-d", strtotime($this->valF["date_creation"]));
    }
    /**
     * Récupération du groupe d'instruction à ajouter aux métadonnées
     * @return string Groupe d'instruction
     */
    protected function getGroupeInstruction() {
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        return $this->specificMetadata->groupe_instruction;
    }
    /**
     * Récupération du libellé du type du document à ajouter aux métadonnées
     * @return string Groupe d'instruction
     */
    protected function getTitle() {
        //Requête sql
        $sql = "SELECT libelle
                FROM ".DB_PREFIXE."document_numerise_type
                WHERE document_numerise_type = ".$this->valF["document_numerise_type"];
        $document_numerise_type_libelle = $this->db->getOne($sql);
        $this->addToLog("db->getone(\"".$sql."\");", VERBOSE_MODE);
        $this->f->addToLog("getTitle() : db->getOne(".$sql.")", VERBOSE_MODE);
        if (database::isError($document_numerise_type_libelle)) {
            die();
        }

        //Retourne le code du type de document
        return $document_numerise_type_libelle;
    }


    /**
     * Récupération du paramètre d'affichage publique du document.
     *
     * @return boolean
     */
    public function getConsultationPublique() {

        // Identifiant du type de pièce
        $dnt_id = null;
        if ($this->getParameter('maj') == '0') {
            $dnt_id = $this->valF['document_numerise_type'];
        }

        // Instance du type de la pièce
        $inst_dnt = $this->get_inst_document_numerise_type($dnt_id);

        //
        $value = $this->get_boolean_from_pgsql_value($inst_dnt->getVal('aff_da'));
        //
        if ($value === true) {
            return 'true';
        }
        //
        if ($value === false) {
            return 'false';
        }
        //
        return null;
    }


    /**
     * Récupération du paramètre d'affichage aux tiers du document.
     *
     * @return boolean
     */
    public function getConsultationTiers() {

        //  Identifiant du type de pièce
        $dnt_id = null;
        if ($this->getParameter('maj') == '0') {
            $dnt_id = $this->valF['document_numerise_type'];
        }

        // Instance du type de la pièce
        $inst_dnt = $this->get_inst_document_numerise_type($dnt_id);

        //
        $value = $this->get_boolean_from_pgsql_value($inst_dnt->getVal('aff_service_consulte'));
        //
        if ($value === true) {
            return 'true';
        }
        //
        if ($value === false) {
            return 'false';
        }
        //
        return null;
    }


    /**
     * Récupération du champ ERP du dossier d'instruction.
     *
     * @return boolean
     */
    public function get_concerne_erp() {
        //
        if(empty($this->specificMetadata)) {
            $this->getSpecificMetadata();
        }
        //
        return $this->specificMetadata->erp;
    }


    // Fin des méthodes de récupération des métadonnées
    // }}}

    /**
     * Génère le nom du fichier avec les information du formulaire
     * @param  string $date    Date de création du document
     * @param  string $codeDoc Code du type de document
     * @return string          Nom du fichier
     */
    private function generateFilename($date, $codeDoc) {

        //Change le format de la date
        $date = date("Ymd", strtotime($date));

        //Compose le nom du fichier date + code document + extension
        $filename = $date.$codeDoc.'.pdf';
        $counter = 1;
        while ($this->filename_exists_for_dossier_instruction($filename)) {
            $filename = $date.$codeDoc.'-'.$counter.'.pdf';
            $counter++;
        }
        //Retourne le nom du fichier
        return $filename;
    }

    /**
     * Permet de vérifier si le du document numérisé est déjà utilisé dans la BDD pour le
     * dossier d'instruction courant.
     * 
     * @param  string $filename Le nom du fichier dont on veut vérifier l'existence.
     * @return bool             true si le fichier existe, sinon false.
     */
    private function filename_exists_for_dossier_instruction($filename) {

        $sql = "SELECT count(document_numerise)
                FROM ".DB_PREFIXE."document_numerise
                WHERE dossier ='".$this->valF['dossier']."'
                AND nom_fichier ='".$filename."'";
        // Exécution de la requête
        $nb_lignes = $this->f->db->getOne($sql);
        $this->addToLog(__METHOD__."() db->query(\"".$sql."\");", VERBOSE_MODE);
        $this->f->isDatabaseError($nb_lignes);
        // Si le nom de fichier existe une ou plusieurs fois
        if ($nb_lignes >= 1) {
            return true;
        }
        //
        return false;
    }

    /**
     * VIEW - generate_archive_doc
     * Permet de générer une archive zip contenant les documents passés en paramètre
     * 
     * @param string $ids Identifiant des documents numérisés séparés par une virgule.
     *
     * @return uid du fichier zip ou false si erreur.
     */
    function generate_archive_doc() {
        $this->f->disableLog();

        $return = array();

        if($this->f->get_submitted_get_value('ids') === null
            || $this->f->get_submitted_get_value('dossier') === null) {
            $return['status'] = false;
        }
        $ids = $this->f->get_submitted_get_value('ids');
        // Identifiant du DI ou DA (selon contexte des pièces)
        $dossier = $this->f->get_submitted_get_value('dossier');

        // Création du storage temporaire
        $temp = "0";
        $metadata = array(
            "filename" => time().".zip",
            "size" => 1,
            "mimetype" => "application/zip",
        );

        // Création du fichier zip en filestorage temporary
        if($this->f->storage == null) {
            $return['status'] = false;
        }
        $temp_uid = $this->f->storage->create_temporary($temp, $metadata);
        if($temp_uid == OP_FAILURE) {
            $return['status'] = false;
        }
        // Récupération de son path pour ziparchive
        $temp_path = $this->f->storage->getPath_temporary($temp_uid);
        // Récupération des uid de documents
        $sql_uid = "SELECT uid FROM ".DB_PREFIXE."document_numerise WHERE document_numerise IN (".$ids.")";
        $res_uid = $this->f->db->query($sql_uid);
        if($this->f->isDatabaseError($res_uid, true) === true) {
            $return['status'] = false;
        }
        // Instanciation de l'archive
        $zip = new ZipArchive;
        $zip->open($temp_path, ZipArchive::OVERWRITE);
        // On rempli l'archive avec les documents récupérés sur le storage
        while($row = $res_uid->fetchRow(DB_FETCHMODE_ASSOC)) {
            $file = $this->f->storage->get($row['uid']);
            if($file == OP_FAILURE) {
            $return['status'] = false;
            }
            $zip->addFromString($file['metadata']['filename'], $file['file_content']);
        }
        $zip->close();

        // Création d'un second temporary pour mettre à jour les métadonnées
        $size = filesize($temp_path);
        $id_doc = explode(',', $ids);
        $file_name = $dossier.'_'.date("Ymd");
        $metadata = array(
            "filename" => $file_name.".zip",
            "size" => $size,
            "mimetype" => "application/zip",
        );
        $uid = $this->f->storage->create_temporary($temp_path, $metadata, "from_path");
        // Suppression du temporaire
        $this->f->storage->delete_temporary($temp_uid);
        $return['status'] = true;

        if($uid == OP_FAILURE) {
            $return['status'] = false;
        }
        $return['file'] = $uid;
        echo json_encode($return);
    }


    /**
     * Méthode de traitement de fichier : trouillotage du fichier temporaire
     *
     * @param string $uid    uid du fichier à trouilloter
     * @param string $stamp    tampon pour le trouillotage du fichier
     * @return string/boolean retourne uid du fichier trouilloté ou false
     */
    function traitementFichierTrouillotage($uid, $stamp = "") {

        //
        $fichier_temporaire = $this->f->storage->storage->temporary_storage->get($uid);

        /*
         * DEBUT - Trouillotage du fichier
         */
        $msg_trouillotage = __("Erreur lors du trouillotage du fichier."); 

        //Récupération du contenu du fichier temporaire
        if ($fichier_temporaire === null || $fichier_temporaire === OP_FAILURE) {
            $this->addToMessage($msg_trouillotage." ".__("Le fichier est introuvable."));
            return false;
        }
        $fichier_content = base64_encode($fichier_temporaire["file_content"]);
        //Si on a pu récupérer le contenu, on le trouillote
        if ($fichier_content === false){
            $this->addToMessage($msg_trouillotage." ".__("Le contenu du fichier n'a pas pu etre recupere."));
            return false;
        }

        //Debut - STAMP
        $data = array(
            "base64" => $fichier_content,
            "stamp_value" => $stamp
        );
        if (file_exists("../dyn/services.inc.php")) {
            require "../dyn/services.inc.php";
        }
        // Vérification de la configuration du service de trouillotage
        if (isset($STAMP_WS_URL_) === false) {
            $this->addToMessage($msg_trouillotage." ".__("Le service de trouillotage numérique n'est pas configuré."));
            return false;
        }
        require_once PATH_OPENMAIRIE."om_rest_client.class.php";
        $inst_om_rest_client = new om_rest_client(
            $STAMP_WS_URL_
        );
        $response = $inst_om_rest_client->execute(
            "POST",
            "application/json",
            json_encode($data)
        );
        $fichier_trouillote = false;
        if ($inst_om_rest_client->getResponseCode() === 200) {
            $fichier_trouillote = base64_decode($response["base64"]);
        }
        if ($fichier_trouillote === false) {
            $this->addToMessage($msg_trouillotage." ".__("Le contenu trouillote du fichier n'a pas pu etre recupere."));
            return false;
        }
        //Fin - STAMP

        //Constitution des metadata du fichier temporaire trouilloté
        $metadata = $fichier_temporaire['metadata'];
        $metadata["size"] = strlen($fichier_trouillote);
        //Creation d'un fichier temporaire trouilloté à partir du contenu
        $tmp_fichier_trouillote = $this->f->storage->create_temporary($fichier_trouillote, $metadata, "from_content");
        if ($tmp_fichier_trouillote === OP_FAILURE) {
            $this->addToMessage($msg_trouillotage." ".__("Erreur lors de la creation du fichier trouillote temporaire."));
            return false;
        }
        return $tmp_fichier_trouillote;
    }


    /**
     * Méthode de traitement de fichier uploadé : récupération du fichier
     * temporaire, pour l'ajout avec trouillotage si l'option est activée. 
     *
     * @return string/boolean retourne true ou un message d'erreur
     */
    function traitementFichierUploadAjoutModification() {
        if ($this->f->is_option_trouillotage_numerique_enabled() !== true){
            return parent::traitementFichierUploadAjoutModification();
        }
         // Récupération du mode de l'action
        $crud = $this->get_action_crud();

        $type_list = array();
        // Récupération du tableau abstract_type si il existe sinon on utilise
        // les type de champs définis dans le formulaire
        if (isset($this->abstract_type)) {
            $type_list = $this->abstract_type;
        } elseif (isset($this->form->type)) {
            $type_list = $this->form->type;
        }
        
        // Pour chaque champs configurés avec les widgets upload, upload2 ou filestatic
        // ou chaque champs de type abstrait file défini dans le tableau abstract_type
        foreach ($type_list as $champ => $type) {
            //
            if ($type == "upload" OR $type == "upload2" OR $type == "filestatic"
                OR (isset($this->abstract_type) AND $type == "file")) {

                // Message d'erreur
                $msg = "";

                // Cas d'un ajout de fichier
                // Condition : si la valeur existante en base est vide ou que
                // nous sommes en mode 'AJOUT' ET qu'une valeur est postée pour
                // le champ fichier
                if (($this->getVal($champ) == ""
                        OR ($crud === 'create'
                            OR ($crud === null AND $this->getParameter('maj') == 0)))
                    AND isset($this->valF[$champ])
                    AND $this->valF[$champ] != "") {

                    // Si la valeur du champ contient le marqueur 'temporary'
                    $temporary_test = explode("|", $this->valF[$champ]);
                    //
                    if (isset($temporary_test[0]) && $temporary_test[0] == "tmp") {
                        //
                        if (!isset($temporary_test[1])) {
                            //
                            $msg = __("Erreur lors de la creation du fichier sur le champ").
                            " \"".$this->table.".".$champ."\". ";
                            $this->addToLog(__METHOD__."(): ".$msg, DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez contacter votre administrateur."));
                            return $msg.__("Veuillez contacter votre administrateur.");
                        }

                        //Constitution du tampon 
                        $date_depot = $this->getDateEvenementDocument()!==null ? $this->getDateEvenementDocument():date(("Y-m-d H:i:s"));
                        $stamp = sprintf("%s %s",
                            $this->getDossier(),
                            $date_depot);
                        //Trouillotage
                        $fichier_trouillote = $this->traitementFichierTrouillotage($temporary_test[1],$stamp);
                        if(isset($fichier_trouillote) !== true
                            || $fichier_trouillote === false){
                            //
                            return $msg.__("Le contenu trouillote du fichier n'a pas pu etre recupere.");
                        }

                        // Récupération des métadonnées calculées après validation
                        $metadata = $this->getMetadata($champ); 
                        //Création du fichier définitif à partir du fichier temporaire trouilloté
                        $this->valF[$champ] = $this->f->storage->create($fichier_trouillote, $metadata, "from_temporary");
                        // Si le fichier est vérouillé
                        if ($this->valF[$champ] === false) {
                            //
                            $msg =  __("Le fichier sur le champ")." ".$this->table.".".$champ." ".
                            __("est verouille. ");
                            $this->addToLog(__METHOD__."(): ".$msg, DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez revalider le formulaire."));
                            return $msg.__("Veuillez revalider le formulaire.");
                        }
                        // Gestion du retour d'erreur
                        if ($this->valF[$champ] == OP_FAILURE) {
                            //
                            $msg = __("Erreur lors de la creation du fichier sur le champ").
                            " \"".$this->table.".".$champ."\". ";
                            $this->addToLog(__METHOD__."(): ".$msg, DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez contacter votre administrateur."));
                            return  $msg.__("Veuillez contacter votre administrateur.");
                        }
                    }
                }

                // Cas d'une modification de fichier
                // Condition : si nous ne sommes pas en mode 'AJOUT' ET si la
                // valeur existante en base n'est pas vide ET qu'une valeur est
                // postée pour le champ fichier ET que la valeur postée est
                // différente de la valeur présente en base
                if ((($crud !== null AND $crud !== 'create')
                      OR ($crud === null AND $this->getParameter('maj') != 0))
                    AND $this->getVal($champ) != ""
                    AND isset($this->valF[$champ])
                    AND $this->valF[$champ] != ""
                    AND $this->getVal($champ) != $this->valF[$champ]) {

                    // Si la valeur du champ contient le marqueur 'temporary'
                    $temporary_test = explode("|", $this->valF[$champ]);
                    //
                    if (isset($temporary_test[0]) && $temporary_test[0] == "tmp") {
                        //
                        if (!isset($temporary_test[1])) {
                            //
                            $msg = __("Erreur lors de la mise a jour du fichier sur le champ").
                            " \"".$this->table.".".$champ."\". ";
                            $this->addToLog(__METHOD__."(): ".$msg.__("id")." = ".$this->valF[$this->clePrimaire]." - ".__("uid fichier")." = ".$this->getVal($champ), DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez contacter votre administrateur."));
                            return $msg.__("Veuillez contacter votre administrateur.");
                        }

                        //Constitution du tampon 
                        $date_depot = $this->getDateEvenementDocument()!==null ? $this->getDateEvenementDocument():date(("Y-m-d H:i:s"));
                        $stamp = sprintf("%s %s",
                            $this->getDossier(),
                            $date_depot);
                        //Trouillotage
                        $fichier_trouillote = $this->traitementFichierTrouillotage($temporary_test[1],$stamp);
                        if(isset($fichier_trouillote) !== true
                            || $fichier_trouillote === false){
                            //
                            return $msg.__("Le contenu trouillote du fichier n'a pas pu etre recupere.");
                        }

                        // Sauvegarde de l'ancien fichier
                        $this->tmpFile[$champ] = $this->f->storage->get($this->getVal($champ));
                        // Récupération des métadonnées calculées après validation
                        $metadata = $this->getMetadata($champ);
                        //
                        $this->valF[$champ] = $this->f->storage->update($this->getVal($champ),$fichier_trouillote, $metadata, "from_temporary");
                        // Si le fichier est vérouillé
                        if ($this->valF[$champ] === false) {
                            //
                            $msg = __("Le fichier sur le champ")." ".$this->table.".".$champ." ".
                            __("est verouille. ");
                            $this->addToLog(__METHOD__."(): ".$msg.__("id")." = ".$this->valF[$this->clePrimaire]." - ".__("uid fichier")." = ".$this->getVal($champ), DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez revalider le formulaire."));
                            return $msg.__("Veuillez revalider le formulaire");
                        }
                        // Gestion du retour d'erreur
                        if ($this->valF[$champ] == OP_FAILURE) {
                            //
                            $msg = __("Erreur lors de la mise a jour du fichier sur le champ").
                            " \"".$this->table.".".$champ."\". ";
                            $this->addToLog(__METHOD__."(): ".$msg.__("id")." = ".$this->valF[$this->clePrimaire]." - ".__("uid fichier")." = ".$this->getVal($champ), DEBUG_MODE);
                            $this->addToMessage($msg.__("Veuillez contacter votre administrateur."));
                            return $msg.__("Veuillez contacter votre administrateur.");
                        }
                    }
                }
            }
        }
        return true;
    }


    /**
     * Permet de recupérer le code du type de document par la clé primaire
     * @param  int $document_numerise_type Clé primaire d'un donnée de document_numerise_type
     * @return string                      Code du type de document 
     */
    private function get_document_numerise_type_code_by_id($document_numerise_type) {

        //Requête sql
        $sql = "SELECT code
                FROM ".DB_PREFIXE."document_numerise_type
                WHERE document_numerise_type = ".$document_numerise_type;
        $document_numerise_type_code = $this->db->getOne($sql);
        $this->addToLog("db->getone(\"".$sql."\");", VERBOSE_MODE);
        $this->f->addToLog("obj/document_numerise.class.php : db->getOne(".$sql.")", VERBOSE_MODE);
        if (database::isError($document_numerise_type_code)) {
            die();
        }

        //Retourne le code du type de document
        return $document_numerise_type_code;
    }

    /**
     * Permet de récupérer le libellé de la catégorie du type de document
     * @param  int $document_numerise_type    Clé primaire d'un donnée de document_numerise_type
     * @return string                         Libellé de la catégorie du type de document
     */
    private function get_document_numerise_type_categorie_libelle($document_numerise_type) {

      // Requête sql
      $sql = "SELECT document_numerise_type_categorie.libelle 
              FROM ".DB_PREFIXE."document_numerise_type
                LEFT JOIN ".DB_PREFIXE."document_numerise_type_categorie 
                  ON document_numerise_type.document_numerise_type_categorie = document_numerise_type_categorie.document_numerise_type_categorie
              WHERE document_numerise_type.document_numerise_type = ".$document_numerise_type;
      $document_numerise_type_categorie_libelle = $this->db->getOne($sql);
      $this->addToLog("db->getone(\"".$sql."\");", VERBOSE_MODE);
      $this->f->addToLog("obj/document_numerise.class.php : db->getOne(".$sql.")", VERBOSE_MODE);
      if (database::isError($document_numerise_type_categorie_libelle)) {
          die();
      }

      //Retourne le code du type de document
      return $document_numerise_type_categorie_libelle;
    }


    /**
     * Cette méthode permet de stocker en attribut toutes les métadonnées
     * nécessaire à l'ajout d'un document.
     */
    public function getSpecificMetadata() {

        //Requête pour récupérer les informations essentiels sur le dossier d'instruction
        $sql = "SELECT dossier.dossier as dossier,
                        dossier_autorisation.dossier_autorisation as dossier_autorisation, 
                        to_char(dossier.date_demande, 'YYYY/MM') as date_demande_initiale,
                        dossier_instruction_type.code as dossier_instruction_type, 
                        etat_dossier_autorisation.libelle as statut,
                        dossier_autorisation_type.code as dossier_autorisation_type,
                        groupe.code as groupe_instruction,
                        CASE WHEN dossier.erp IS TRUE
                            THEN 'true'
                            ELSE 'false'
                        END as erp
                FROM ".DB_PREFIXE."dossier 
                    LEFT JOIN ".DB_PREFIXE."dossier_instruction_type  
                        ON dossier.dossier_instruction_type = dossier_instruction_type.dossier_instruction_type
                    LEFT JOIN ".DB_PREFIXE."dossier_autorisation 
                        ON dossier.dossier_autorisation = dossier_autorisation.dossier_autorisation 
                    LEFT JOIN ".DB_PREFIXE."etat_dossier_autorisation
                        ON  dossier_autorisation.etat_dossier_autorisation = etat_dossier_autorisation.etat_dossier_autorisation
                    LEFT JOIN ".DB_PREFIXE."dossier_autorisation_type_detaille
                        ON dossier_autorisation.dossier_autorisation_type_detaille = dossier_autorisation_type_detaille.dossier_autorisation_type_detaille
                    LEFT JOIN ".DB_PREFIXE."dossier_autorisation_type
                        ON dossier_autorisation_type_detaille.dossier_autorisation_type = dossier_autorisation_type.dossier_autorisation_type
                    LEFT JOIN ".DB_PREFIXE."groupe
                        ON dossier_autorisation_type.groupe = groupe.groupe
                WHERE dossier.dossier = '".$this->valF["dossier"]."'";
        $res = $this->db->query($sql);
        $this->f->addToLog("getSpecificMetadata : db->query(".$sql.")", VERBOSE_MODE);
        if ( database::isError($res)){
            die();
        }
        
        //Le résultat est récupéré dans un objet
        $row =& $res->fetchRow(DB_FETCHMODE_OBJECT);

        //Si il y a un résultat
        if ($row !== null) {

            // Instrance de la classe dossier
            $inst_dossier = $this->get_inst_dossier($this->valF["dossier"]);

            // Insère l'attribut version à l'objet
            $row->version = $inst_dossier->get_dossier_instruction_version();

            //Alors on créé l'objet dossier_instruction
            $this->specificMetadata = $row;

        }
    }



    /**
     * CONDITION - is_ajoutable.
     *
     * Condition pour pouvoir ajouter
     *
     * @return boolean
     */
    function is_ajoutable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_ajouter_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable($this->getParameter("idxformulaire"));
    }

    /**
     * CONDITION - is_modifiable.
     *
     * Condition pour afficher le bouton modifier
     *
     * @return boolean
     */
    function is_modifiable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_modifier_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable();
    }

    /**
     * CONDITION - is_supprimable.
     *
     * Condition pour afficher le bouton supprimer
     * @return boolean
     */
    function is_supprimable() {
        // Test du bypass
        if ($this->f->isAccredited($this->get_absolute_class_name()."_supprimer_bypass")) {
            return true;
        }
        // Test des autres conditions
        return $this->is_ajoutable_or_modifiable_or_supprimable();
    }


    /**
     * Conditions pour afficher les boutons modifier et supprimer
     *
     * @return boolean
     */
    function is_ajoutable_or_modifiable_or_supprimable() {
        // Tester si le dossier est cloturé ,
        // et si l'instructeur est de la même division
        if ($this->is_instructeur_from_division_dossier() === true and
            $this->is_dossier_instruction_not_closed() === true){
            return true;
        }

        return false;
    }


    /**
     * Retourne le statut du dossier d'instruction
     * @param string $idx Identifiant du dossier d'instruction
     * @return string Le statut du dossier d'instruction
     */
    function getStatutAutorisationDossier($idx){
        
        $statut = '';
        
        //Si l'identifiant du dossier d'instruction fourni est correct
        if ( $idx != '' ){
            
            //On récupère le statut de l'état du dossier d'instruction à partir de 
            //l'identifiant du dossier d'instruction
            $sql = "SELECT etat.statut
                FROM ".DB_PREFIXE."dossier
                LEFT JOIN
                    ".DB_PREFIXE."etat
                    ON
                        dossier.etat = etat.etat
                WHERE dossier ='".$idx."'";
            $statut = $this->db->getOne($sql);
            $this->f->addToLog("getStatutAutorisationDossier() : db->getOne(\"".$sql."\")", VERBOSE_MODE);
            if ( database::isError($statut)){
                die();
            }
        }
        return $statut;
    }


    /**
     * Récupère l'état d'un dossier d'instruction
     * @param $idxDossier L'identifiant du dossier d'instruction
     * @return L'état du dossier d'instruction 
     */
    function getEtatDossier($idxDossier){
            
        $etat = "";
        
        $sql = "SELECT etat.etat 
            FROM ".DB_PREFIXE."etat
            LEFT JOIN
                ".DB_PREFIXE."dossier
                ON
                dossier.etat = etat.etat
            WHERE dossier.dossier = '".$idxDossier."'";
        $etat = $this->db->getOne($sql);
        $this->addToLog("getEtatDossier(): db->getOne(\"".$sql."\");", VERBOSE_MODE);
        // Si une erreur survient on die
        if (database::isError($etat, true)) {
            // Appel de la methode de recuperation des erreurs
            $this->erreur_db($etat->getDebugInfo(), $etat->getMessage(), 'document_numerise');
        }
        
        return $etat;
    }


    /**
     * Instance de la demande d'avis
     *
     * @var null
     */
    var $inst_demande_avis = null;

    /**
     * Récupère l'instance de la demande d'avis
     *
     * @param integer $demande_avis Identifiant de la demande d'avis
     *
     * @return object
     */
    function get_inst_demande_avis($demande_avis = null) {
        //
        if (is_null($this->inst_demande_avis)) {
            //
            if (is_null($demande_avis)) {
                // Récupère l'identifiant du formulaire parent
                $demande_avis = $this->getParameter("idxformulaire");
            }
            // Instancie la demande d'avis
            $this->inst_demande_avis = $this->f->get_inst__om_dbform(array(
                "obj" => "demande_avis",
                "idx" => $demande_avis,
            ));
        }
        //
        return $this->inst_demande_avis;
    }


    /**
    * Permet de recupérer l'identifiant du dossier d'instruction.
    *
    * @param integer $document_numerise Clé primaire de document_numerise.
    *
    * @return string dossier
    */
    private function get_libelle_dossier($document_numerise) {
    
        //Requête sql
        $sql = "SELECT dossier
            FROM ".DB_PREFIXE."document_numerise
            WHERE document_numerise = ".$document_numerise;
        $dossier = $this->db->getOne($sql);
        $this->addToLog("db->getone(\"".$sql."\");", VERBOSE_MODE);
        $this->f->addToLog("obj/document_numerise.class.php : db->getOne(".$sql.")", VERBOSE_MODE);
        if($this->f->isDatabaseError($dossier, true) === true) {
            return false;
        }
        
        //Retourne le code du dossier
        return $dossier;
    }


    /**
     * Récupère l'instance de dossier message.
     *
     * @param string $dossier_message Identifiant du message.
     *
     * @return object
     */
    private function get_inst_dossier_message($dossier_message = null) {
        //
        return $this->get_inst_common("dossier_message", $dossier_message);
    }


    /**
     * Récupère l'instance de document_numerise_type.
     *
     * @param string $document_numerise_type Identifiant du message.
     *
     * @return object
     */
    private function get_inst_document_numerise_type($document_numerise_type = null) {
        //
        return $this->get_inst_common("document_numerise_type", $document_numerise_type);
    }


    /**
     * Ajout d'un contenu spécifique à la fin du sous-formulaire.
     *
     * @param integer $maj État du formulaire.
     *
     * @return void
     */
    public function sousFormSpecificContent($maj) {
        // Si l'option de notification par message de l'ajout d'une pièce
        // numérisée est activée
        if ($this->f->getParameter('option_notification_piece_numerisee') === 'true') {
            //
            echo "<input id=\"dossier_message_id\" name=\"dossier_message_id\" type=\"hidden\" value=\"".$this->get_dossier_message_id()."\" />";
        }
    }

    /*
     * CONDITION - can_user_access_dossier_contexte_ajout
     *
     * Vérifie que l'utilisateur a bien accès au dossier d'instruction passé dans le
     * formulaire d'ajout.
     * Cette méthode vérifie que l'utilisateur est lié au groupe du dossier, et si le
     * dossier est confidentiel qu'il a accès aux confidentiels de ce groupe.
     * 
     */
    function can_user_access_dossier_contexte_ajout() {

        ($this->f->get_submitted_get_value('idxformulaire') !== null ? $id_dossier = 
            $this->f->get_submitted_get_value('idxformulaire') : $id_dossier = "");
        //
        if ($id_dossier !== "") {
            $dossier = $this->f->get_inst__om_dbform(array(
                "obj" => "dossier_instruction",
                "idx" => $id_dossier,
            ));
            //
            return $dossier->can_user_access_dossier();
        }
        return false;
    }

   /*
     * CONDITION - can_user_access_dossier_contexte_modification
     *
     * Vérifie que l'utilisateur a bien accès au dossier lié au document instancié.
     * Cette méthode vérifie que l'utilisateur est lié au groupe du dossier, et si le
     * dossier est confidentiel qu'il a accès aux confidentiels de ce groupe.
     * 
     */
    function can_user_access_dossier_contexte_modification() {

        $id_dossier = $this->getVal('dossier');
        //
        if ($id_dossier !== "" && $id_dossier !== null) {
            $dossier = $this->f->get_inst__om_dbform(array(
                "obj" => "dossier_instruction",
                "idx" => $id_dossier,
            ));
            //
            return $dossier->can_user_access_dossier();
        }
        return false;
    }


    /**
     * Indique si la redirection vers le lien de retour est activée ou non.
     *
     * L'objectif de cette méthode est de permettre d'activer ou de désactiver
     * la redirection dans certains contextes.
     *
     * @return boolean
     */
    function is_back_link_redirect_activated() {
        //
        return false;
    }


}// fin classe

