<?php

/**
 * Classe permettant de gérer les BR
 *
 */
class BR
{

    protected $br_entete;

    protected $br_ligne;

    protected $array_br_ligne;

    protected $array_type_inc;

    protected $errmsg;

    protected $statut;
 // O-> Ok, E ->erreur
    protected $listeRepartionBR;
 // Tableau contenant le contenu des infos pour la répartition des lignes de BR -- standard spec 2974
                                 
    // Constructeur
    public function __construct()
    {
        $this->br_entete = new BR_entete();
        $this->br_ligne = new BR_ligne();
    }

    // Méthodes GET
    public function &getArrayBrLigne()
    {
        return $this->array_br_ligne;
    }

    public function &getArrayTypeInc()
    {
        return $this->array_type_inc;
    }

    public function &getBr_entete()
    {
        return $this->br_entete;
    }

    // Méthodes SET
    public function setArrayBrLigne($array_ligne_br)
    {
        $this->array_br_ligne = & $array_ligne_br;
    }

    public function setArrayTypeInc($array_type_inc)
    {
        $this->array_type_inc = & $array_type_inc;
    }

    /**
     * Fonction permettant de supprimer l'entete et les lignes d'un BR en cours de création
     * 
     * @param
     *            string login : login de l'utilisateur auquel appartient le BR en création
     * @return boolean : retourne true si le commit est ok
     */
    public static function resetBRcreation(& $login)
    {
        $pile_rq = new PileSql(DB_OXAPROCDB);
        $pile_rq->AddRequeteSql(SqlBr::rqResetBrEnteteEnCours($login));
        $pile_rq->AddRequeteSql(Sqlbr::deleteCSBr());
        
        $pile_rq->AddRequeteSql(SqlBr::rqResetBrLigneEnCours($login));
        /*** SPEC 4241 Caractéristiques complémentaires : suppression des CC dans CC_LDOC avec DOC_TYPE='BRT' et ID_USER_BASKET=$_SESSION['id_user']  ***/
        $pile_rq->AddRequeteSql(SqlCaracteristiquesCompl::rqSupCCDoc('BRT', null, null, $_SESSION['id_user']));
        return $pile_rq->Commit();
    }

    /**
     * Fonction initialisant entete + lignes pour une création de BR sur une commande donnée
     *
     * @param string $login
     *            : login de l'utilisateur
     * @param int $no_cde
     *            : numéro de la cde
     * @param string $contexte
     *            : contexte de l'initialisation des lignes
     */
    public static function initBR(& $login, $no_cde, $contexte)
    {
        return (BR_entete::initBR($login, $no_cde) && BR_ligne::initBR($login, $no_cde, $contexte));
    }

    public function getBRCreation(& $login, $no_ligne, $inc, $ctrlRal = false)
    {
        $this->br_entete->getBR_entete($login);
        if ($array = SqlBr::getLigneBRforCreation($login, $no_ligne, $inc, false, 0, false, $ctrlRal)->TrouveTous())
            foreach ($array as & $element) {
                
                $ligne = new BR_ligne();
                $ligne->setIs_reception(BoolSql($element['is_reception']));
                $ligne->setNo_ligne_cde($element['no_ligne_cde']);
                $ligne->setNo_ligne_br($element['no_ligne_br']);
                $ligne->setQte_r($element['qte_r']);
                $ligne->setQte_c($element['qte_c']);
                $ligne->setQte_a($element['qte_a']);
                $ligne->setPrixRemise($element['PU_REMISE']);
                
                $ligne->setMontantRec($element['MNT_REC']);
                $ligne->setMontantRet($element['MNT_RET']);
                $ligne->setTypeDeReception($element['TYPE_RECEPT_POSSIBLE']);
                $ligne->setReceptionEnMontant(BoolSql($element['EN_MNT']));
                
                $ligne->setQTE_ANNULE($element['QTE_ANNULE']);
                $ligne->setIsAnnule($element['IS_ANNULE']);
                $ligne->setIs_incident(BoolSql($element['is_incident']));
                $ligne->setCode_inc($element['code_inc']);
                $ligne->setComment_inc(trim($element['comment_inc']));
                $ligne->setIs_ctrl_qualite(BoolSql($element['is_ctrl_qualite']));
                $ligne->setCtrl_qualite_done(BoolSql($element['ctrl_qualite_done']));
                $ligne->setType_ctrl($element['type_ctrl']);
                $ligne->setCOMMENT($element['COMMENT']);
                $ligne->setDteLiv($element['DTE_LIV']);
                
                $ligne->setRal($element['ral']);
                $ligne->setRalMontant($element['ral'] * (1 - $element['PU_REMISE'] / 100));
                
                $this->array_br_ligne[] = $ligne;
            }
    }

    /**
     * Fonction retournant le nombre de ligne annulée sur un bon de retour en cours d'un utilisateur
     *
     * @param string $login
     * @return int
     */
    public static function getNbLigneAnnuleOnBonRetour($login)
    {
        $array = SqlBr::getLigneBRforCreation($login, false, false, false, 0, true, false)->TrouveTous();
        return count($array);
    }

    /**
     * Fonction testant la présence d'incident potentiel
     */
    public static function IsIncident(& $login)
    {
        return SqlBr::rqIsIncident($login)->TrouveTous();
    }

    public static function DiffAccCpt(& $login)
    {
        return SqlBr::rqDiffAccCpt($login)->TrouveTous();
    }

    public static function DiffCptRecu(& $login)
    {
        return SqlBr::rqDiffCptRecu($login)->TrouveTous();
    }

    /**
     * Fonction testant la présence d'incident potentiel
     */
    public function &IsCtrlIncident(& $login)
    {
        return SqlBr::rqIsCtrlIncident($login)->TrouveTous();
    }

    /**
     * Fonction retournant le nombre de ligne sur un BR en creation pour lesquelles le flag is_incident est à vrai
     */
    public function &getNbLigneIsInc(& $login)
    {
        $result = SqlBr::rqGetNbLigneIsInc($login)->Trouve1();
        return $result['NB_INC'];
    }

    /**
     * Fonction initialisant un tableau des types d'incidents possibles.
     */
    public function &buildXMLListIncident()
    {
        // On récupère la liste des incidents HAPLUS
        if ($listeTmp = SqlBr::rqGetListeIncidentLivraison()->TrouveTous())
            // On construit la liste des incidents pour l'affichage dans la XML
            foreach ($listeTmp as & $tmp)
                $this->array_type_inc[] = array(
                    '!code' => & $tmp['COD_INC'],
                    '!libelle' => & $tmp['LIBELLE']
                );
        
        return $this->array_type_inc;
    }

    /**
     * Fonction permettant l'appel du wsdl BR en mode enregistrement sans les incidents
     * 
     * @param string $mode
     *            : mode d'appel du WSDL
     * @param boolean $incident
     *            : doit on prendre en compte les incidents
     *            
     */
    function &getWsdlXmlBrEnreg($mode, $incident)
    {
        $no_bl = $this->br_entete->getNo_bl();
        $date_bl = $this->br_entete->getDate_bl();
        $type_br = $this->br_entete->getTYPE_BR();
        
        // Création de la structure XML qui sera passée en paramètre au wsdl
        $niv_1 = "<Utilisateur>{$this->br_entete->getLogin()}</Utilisateur>"; // Login de l'utilisateur
                                                                              // On définit le type de BR
        $niv_1 .= "<Type>{$type_br}</Type>";
        
        // On définit le mode création : C ou controle T
        $niv_1 .= "<Mode>$mode</Mode>";
        
        // En mode création de BR et de bon de retour
        if ($mode == 'C') {
            $niv_1 .= "<NumBR></NumBR>"; // Vide car on est en mode création
            $niv_1 .= "<NumCde>{$this->br_entete->getNo_cde()}</NumCde>";
        }        // En mode contrôle technique sur BR ou modification de BR ou modification de bon de retour
        elseif ($mode == 'T' || $mode == 'M') 
        {
           /// print_r($_SESSION['Session_Doc_Rattache']); exit; 
           

            $niv_1 .= "<NumBR>{$this->br_entete->getNo_br()}</NumBR>";
            $niv_1 .= "<NumCde>{$this->br_entete->getNo_cde()}</NumCde>";
        }
        
        // S'il s'agit d'un bon de retour
        if ($type_br == 'A') {
            $niv_1 .= "<NumBRAnnule>{$this->br_entete->getNUM_BR_ANNULE()}</NumBRAnnule>";
        }
        
        // On applique la conversion d'encodage au champs texte en saisie libre pour l'utilisateur
        XmlEntities($no_bl);
        $comment = $this->br_entete->getCommentaire();
        XmlEntities($comment);
        
        $blocNotes = $this->br_entete->getBLOC_NOTES();
        XmlEntities($blocNotes);
        
        $niv_1 .= "<RefBL>{$no_bl}</RefBL>";
        $niv_1 .= '<DateBL>' . $date_bl . '</DateBL>';
        
        $date_per = $this->br_entete->getDate_PER();
        $niv_1 .= '<DatePer>' . $date_per . '</DatePer>';
        
        $niv_1 .= '<Comment>' . $comment . '</Comment>';
        $niv_1 .= '<BlocNote>' . $blocNotes . '</BlocNote>';
        
        $listeCS = sqlCS::getCSBR_OXAPROC()->TrouveTous();
        
        $niv_1 .= ' <ListChampsSup>';
            foreach($listeCS as $cs) {
                $niv_1 .= '<ChpSup>
                        <NOCS>'.$cs['NUM_FIX'].'</NOCS>
                        <VALEUR>'.$cs['VALEUR'].'</VALEUR>
                      </ChpSup>';
            }
        $niv_1 .= ' </ListChampsSup>';
        $niv_2 = '';
        
        foreach ($this->array_br_ligne as & $ligne) {
            // Si la ligne est cochée receptionnée ou bien si on est dans le cadre d'un contrôle qualité et que le contrôle a été effectué
            if ($ligne->isReception() || ($mode == 'T' && $ligne->isCtrlQualiteDone()) || ($type_br != 'R' && $ligne->isAnnule())) {
                $comment_inc = $ligne->getComment_inc();
                XmlEntities($comment_inc);
                
                $niv_2 .= '<LigBR>';
                $niv_2 .= "<LigCde>{$ligne->getNo_ligne_cde()}</LigCde>";
                
                $niv_2 .= '<TypeRecepMnt>' . BoolWsdl($ligne->isReceptionEnMontant()) . '</TypeRecepMnt>';
                if ($type_br == 'A') {
                    $niv_2 .= "<NoLigBRAnn>{$ligne->getNo_ligne_br()}</NoLigBRAnn>";
                    if ($ligne->isReceptionEnMontant())
                        $niv_2 .= "<MontantRetour>{$ligne->getMontantRet()}</MontantRetour>";
                    else
                        $niv_2 .= "<QteRetour>{$ligne->getQTE_ANNULE()}</QteRetour>";
                } else if ($ligne->isReceptionEnMontant())
                    $niv_2 .= "<MontantRecep>{$ligne->getMontantRec()}</MontantRecep>";
                else {
                    $niv_2 .= "<QteRecep>{$ligne->getQte_r()}</QteRecep>";
                    $niv_2 .= "<QteCompt>{$ligne->getQte_c()}</QteCompt>";
                    $niv_2 .= "<QteAccept>{$ligne->getQte_a()}</QteAccept>";
                }
                
                $comment = $ligne->getCOMMENT();
                XmlEntities($comment);
                
                $niv_2 .= "<Comment>{$comment}</Comment>";
                
                // Si le mode incident est activé et que la ligne est marquée comme incidentée
                if ($incident && $ligne->getIs_incident() == 1) {
                    $niv_2 .= '<Incident>true</Incident>';
                    $niv_2 .= "<CodeInc>{$ligne->getCode_inc()}</CodeInc>";
                    $niv_2 .= "<ComInc>{$comment_inc}</ComInc>";
                } else {
                    $niv_2 .= '<Incident>false</Incident>';
                    $niv_2 .= '<CodeInc></CodeInc>';
                    $niv_2 .= '<ComInc></ComInc>';
                }
                
                // Si il s'agit du mode controle et si le controle a été effectué
                if ($mode == 'T' && $ligne->isCtrlQualiteDone())
                    $niv_2 .= '<Controle>true</Controle>';
                else
                    $niv_2 .= '<Controle>false</Controle>';


                /*** SPEC 4241 Caractéristiques complémentaires : Intégration des CC de la ligne ***/
                if(($this->br_entete->getNo_br() ?? 0) != 0){
                    $ligneCC = $ligne->getNo_ligne_br();
                }else{
                    $ligneCC = $ligne->getNo_ligne_cde();
                }
                $ListeCCLigne = SqlCaracteristiquesCompl::getCCDoc('BRT', $this->br_entete->getNo_br() ?? 0, $ligneCC, $_SESSION['id_user'])->TrouveTous();
                $listeCarComp = '';
                if (is_array($ListeCCLigne)){
                    foreach ($ListeCCLigne as $ligneCC) {
                        if ($ligneCC['FORMAT'] == 'L'){
                            $ligneCC['VALEUR'] = Wsdl::convertBooleenCheckboxForWsdl($ligneCC['VALEUR']);
                        }

                        $listeCarComp .= 
                        "<CarComp>
                            <CC_ID>".$ligneCC['CC_ID']."</CC_ID>
                            <CC_FREE>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_FREE'])."</CC_FREE>
                            <CC_DISPLAY_NUM>".$ligneCC['CC_DISPLAY_NUM']."</CC_DISPLAY_NUM>
                            <CC_IS_TITLE>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_IS_TITLE'])."</CC_IS_TITLE>
                            <CC_NAME>".htmlspecialchars($ligneCC['NOM'])."</CC_NAME>
                            <CC_TYPE>".$ligneCC['CC_TYPE']."</CC_TYPE>
                            <CC_UPD_ONLY_RECEIPT>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_UPD_ONLY_RECEIPT'])."</CC_UPD_ONLY_RECEIPT>
                            <CC_INVIS_RECEIPT>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_INVIS_RECEIPT'])."</CC_INVIS_RECEIPT>
                            <CC_REQUIRED>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_REQUIRED'])."</CC_REQUIRED>
                            <CC_PRINTED_OF>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_PRINTED_OF'])."</CC_PRINTED_OF>
                            <CC_CALC>".Wsdl::convertBooleenCheckboxForWsdlTrueFalse($ligneCC['CC_CALC'])."</CC_CALC>
                            <CC_CALC_EXP>".htmlspecialchars($ligneCC['CC_CALC_EXP'])."</CC_CALC_EXP>
                            <CC_VALUE>".htmlspecialchars($ligneCC['VALEUR'])."</CC_VALUE>
                        </CarComp>";
                    }
                }
                $niv_2 .= '<ListCarComp>' . $listeCarComp . '</ListCarComp>';     
                
                $niv_2 .= '</LigBR>';
            }
        }
        
        $niv_3 = "<ListLigBR>{$niv_2}</ListLigBR>";
        $envoi = "<BRIn LngUtilisation='{$_SESSION['Session_Langue']}'>" . $niv_1 . $niv_3 . '</BRIn>';
        
        return $envoi;
    }

    function &callWsdlBrEnreg($mode, $incident = false)
    {
        $envoi = $this->getWsdlXmlBrEnreg($mode, $incident);
        $result = Wsdl::wsdlBR('OXAPRC_ENREGBR', $envoi);
          
        $_SESSION['BR_LIVR_EXCEDENT_CONFIRM'] = false;
        
        return ($result);
    }

    /**
     * Fonction appelant le wsdl de validation, dévalidation et suppression
     */
    public function &actionOnBR($mode, & $num_br)
    {
        $content = "<Utilisateur>{$_SESSION['Session_Login']}</Utilisateur>";
        $content .= "<Mode>$mode</Mode>";
        $content .= "<NumBR>$num_br</NumBR>";
        $envoi = "<BRIn LngUtilisation='{$_SESSION['Session_Langue']}'>" . $content . '</BRIn>';
        
        return Wsdl::wsdlBR('OXAPRC_VALDEVALSUPBR', $envoi);
    }

    public function &getErrorMsg()
    {
        return $this->errmsg;
    }

    /**
     * Fonction insérant dans la table oxa_br_ligne l'ensemble des lignes du BR à modifier + toutes les lignes de la CDE qui sont réceptionnables et qui ne sont pas déjà présentes dans le BR
     *
     * @param string $login
     * @param int $no_br
     * @param int $no_cde
     * @return boolean
     */
    public static function setBRRowsForUpdate(& $login, & $no_br, $mode = '')
    {
        // Sélection des lignes de commande à réceptionner et des lignes déjà réceptionnées
        $array_header = SqlBr::rqGetBrHeaderForUpdate($no_br)->Trouve1();
        $array_lines = SqlBr::rqGetBrLinesForUpdate($no_br)->TrouveTous();
       
        if (is_array($array_header) && is_array($array_lines)) {
            // Pour chaque ligne on réalise l'insertion dans la table oxa_br_ligne
            $pile_rq = new PileSql(DB_OXAPROCDB);
            
            // insertion de l'entete
            $pile_rq->AddRequeteSql(SqlBr::rqInsertHeaderBRUpdate($login, $array_header));
            $pile_rq->AddRequeteSql(Sqlbr::initCSBr($no_br));
            
            $i = 0; 
            // insertion des lignes
            foreach ($array_lines as & $ligne)
            {
               
                if($mode == 'M')
                {
                    $ligne['modif'] = 'M'; 
                       //  $ligne['ral'] = ( ($ligne['PU']* (1 - $array['REMISE'] / 100)) * $ligne['QTE_COMM']) - sqlbr::rqDejaLivrerCde($array)->Trouve1()['dejaLivre'];
                    //  $ligne['ral_ori'] = ( ($ligne['PU']* (1 - $array['REMISE'] / 100)) * $ligne['QTE_COMM']) - sqlbr::rqDejaLivrerCde($array)->Trouve1()['dejaLivre'] - $ligne['MNT_REC'];
                }
                

                if($ligne['en_montant']==1)
                {
                    $array=[
                        'PU' => $ligne['PU'],
                        'REMISE' => $ligne['REMISE'],
                        'NO_CDE' => $ligne['NO_CDE'],
                        'NO_PO' => $ligne['no_ligne_cde'],
                    ];
                    
                    $ligne['TYPE_RECEPT_POSSIBLE'] = 'M';
                    $ligne['PU_REMISE'] = ($ligne['PU']* (1 - $array['REMISE'] / 100));
        
                    //  $ligne['ral'] = ( ($ligne['PU']* (1 - $array['REMISE'] / 100)) * $ligne['QTE_COMM']) - sqlbr::rqDejaLivrerCde($array)->Trouve1()['dejaLivre'];
                    //  $ligne['ral_ori'] = ( ($ligne['PU']* (1 - $array['REMISE'] / 100)) * $ligne['QTE_COMM']) - sqlbr::rqDejaLivrerCde($array)->Trouve1()['dejaLivre'] - $ligne['MNT_REC'];
                    
                     $ligne['ral_mnt'] = ( ($ligne['PU']* (1 - $array['REMISE'] / 100)) * $ligne['QTE_COMM']) - sqlbr::rqDejaLivrerCde($array)->Trouve1()['dejaLivre'];
                     
                    //  print_r($ligne['ral_mnt']); exit; 


                }

                $pile_rq->AddRequeteSql(SqlBr::rqInsertLineBRUpdate($login, $ligne));

                /*** SPEC 4241 Caractéristiques complémentaires : duplication des CC de la ligne du BR en BRT  ***/
                $no_line = $ligne['no_ligne_br'];
                $tbl_source = ['DOC_TYPE'=> 'BR', 'DOC_NUM' => $no_br, 'DOC_LINE_NUM' => $no_line, 'ID_USER_BASKET' => 0];
                $pile_rq->AddRequeteSql(SqlCaracteristiquesCompl::rqDuplicateCCLigne($tbl_source, ['DOC_TYPE'=> 'BRT', 'DOC_NUM' => $no_br, 'DOC_LINE_NUM' => $no_line, 'ID_USER_BASKET' => $_SESSION['id_user']]));
                // print_r($array_lines); exit;
                $i++;  
            }

            // On commit la pile de requete insert, retourne true si ok
            return $pile_rq->Commit();
        }
    }

    /**
     * Fonction insérant dans la table oxa_br_ligne l'ensemble des lignes du bon de retour à modifier + toutes les lignes du BR qui sont réceptionnables et qui ne sont pas déjà présentes dans le bon de retour
     *
     * @param string $login
     * @param int $no_br
     * @param int $no_cde
     * @return boolean
     */
    public static function setBonRetourRowsForUpdate(& $login, & $no_br)
    {
        // Sélection des lignes du bon de réception associé au bon de retour
        $array_header = SqlBr::rqGetBrHeaderForUpdate($no_br)->Trouve1();
        $array_lines = SqlBr::rqGetBonRetourLinesForUpdate($no_br)->TrouveTous();
        
        if (is_array($array_header) && is_array($array_lines)) {
            // Pour chaque ligne on réalise l'insertion dans la table oxa_br_ligne
            $pile_rq = new PileSql(DB_OXAPROCDB);
            
            // insertion de l'entete
            $pile_rq->AddRequeteSql(SqlBr::rqInsertHeaderBRUpdate($login, $array_header));
            
            // insertion des lignes
            foreach ($array_lines as & $ligne) {
                if (! is_numeric($ligne['QTE_ANNULE'])) {
                    $ligne['QTE_ANNULE'] = 0;
                    $ligne['IS_ANNULE'] = 0;
                } else
                    $ligne['IS_ANNULE'] = 1;
                
                $pile_rq->AddRequeteSql(SqlBr::rqInsertLineBRUpdate($login, $ligne));
            }
            
            // On commit la pile de requete insert, retourne true si ok
            return $pile_rq->Commit();
        }
    }

    /**
     * Fonction appellant le wsdl permettant de solder physiquement une commande
     * 
     * @param string $login
     *            : login de l'utilisateur soldant la commande
     * @param int $num_cde
     *            : numéro de la commande à solder
     */
    public static function &CallWsdlForSoldeCde(& $login, & $num_cde)
    {
        $envoi = "<CdeIn LngUtilisation='{$_SESSION['Session_Langue']}'>";
        $envoi .= "<Utilisateur>$login</Utilisateur>";
        $envoi .= "<NumCde>$num_cde</NumCde>";
        $envoi .= '</CdeIn>';
        
        return Wsdl::wsdlCallGen('Oxaproc_Commande.wsdl', 'OXAPRC_CDE_SOLDEPHYSIQUE', $envoi);
    }

    /**
     * Fonction appellant le wsdl permettant de solder financierement une commande
     * 
     * @param string $login
     *            : login de l'utilisateur soldant la commande
     * @param int $num_cde
     *            : numéro de la commande à solder
     */
    public static function &CallWsdlForSoldeCdeFinanc(& $login, & $num_cde)
    {
        $envoi = "<CdeIn LngUtilisation='{$_SESSION['Session_Langue']}'>";
        $envoi .= "<Utilisateur>$login</Utilisateur>";
        $envoi .= "<NumCde>$num_cde</NumCde>";
        $envoi .= '</CdeIn>';
        
        return Wsdl::wsdlCallGen('Oxaproc_Commande.wsdl', 'OXAPRC_CDE_SOLDEFINANCIER', $envoi);
    }

       /**
     * Fonction appellant le wsdl permettant de désolder financierement une commande
     * 
     * @param string $login
     *            : login de l'utilisateur soldant la commande
     * @param int $num_cde
     *            : numéro de la commande à solder
     */
    public static function CallWsdlForDesoldeCdeFinanc($login, $num_cde, $operation, $commentaire)
    {
        $envoi = "<SoldeFinCde_In LngUtilisation='{$_SESSION['Session_Langue']}'>";
        $envoi .= "<Utilisateur>$login</Utilisateur>";
        $envoi .= "<Operation>$operation</Operation>";
        $envoi .= "<NumCde>$num_cde</NumCde>";
        $envoi .= "<Commentaire>$commentaire</Commentaire>";
        $envoi .= '</SoldeFinCde_In>';
        
        return Wsdl::wsdlCallGen('Oxaproc_Commande.wsdl', 'OXAPRC_CDE_SOLDEFINANCIER', $envoi);
    }

    /**
     * Fonction permettant de récuperer le numéro d'une commande associé à un BR
     * 
     * @param int $num_br
     * @return string numero de commande
     */
    public static function &getNumCdeFromBr(& $num_br)
    {
        $r = SqlBr::rqGetInfoOnBrEntete($num_br)->Trouve1();
        return $r['NUM_CDE'];
    }

    /**
     * Fonction permettant de controler en fonction du paramétrage HAPLUS la saisie d'une date de livraison et d'un numéro de BL
     *
     * @param string $num_bl
     *            : numéro de BL saisi par l'utilisateur
     * @param string $dte_liv
     *            : date de livraison saisie par l'utilisateur
     * @param string $dte_per
     *            : date de période saisie par l'utilisateur
     * @return boolean true si controle ok sinon false
     */
    public static function &CtrlNumBlAndDteLiv(& $num_bl, $dte_liv, $dte_per, $no_cde)
    {
        $saisi_ok = true; // Flag permettant d'indiquer si le controle des 2 champs est OK ou non
        
        if (Param::IsNumBlOblForBr() && trim($num_bl) == '') {
            Affichage::messageJS(trad('Le numéro de Bon de livraison (N°BL) est obligatoire, veuillez le renseigner.'));
            $saisi_ok = false;
        }
        
        if (Param::IsDteLivOblForBr() && ! ControleSaisie::isDateValide($dte_liv)) {
            Affichage::messageJS(trad('La date de livraison est obligatoire, veuillez la renseigner.'));
            $saisi_ok = false;
        }
        
        /** SPEC 4284 : Contrôle de la date période : en fonction de la date de fin, de la date de clôture prévisionnelle globale ou de la date de clôture prévisionnelle de la société pour la sous période concernée. **/
        $r = SqlParam::rqGetParamParavrac('OXAPROC', 'BR_DATE_PERIODE')->Trouve1();
        $ouvertureSousPeriodeBR = is_array($r) && array_key_exists('LIB01PARV', $r) && $r['LIB01PARV'] == 'O';
        if ($ouvertureSousPeriodeBR) {
            if(ControleSaisie::isDateValide($dte_per)){
                // SPEC 4284 : Contrôle de l'ouverture de la sous-période si paramétrage activé
                $info_entete_commande = SqlCde::getInfoOnEnteteCDE($no_cde)->Trouve1();            
                $r = SqlParam::rqGetParamParavrac('PARAMGEN', 'SPER_AVEC_OUV_FERM')->Trouve1();
                $ouvertureSousPeriode = is_array($r) && array_key_exists('LIB01PARV', $r) && $r['LIB01PARV'] == 'O';
                $r = SqlParam::rqGetParamParavrac('PARAMGEN', 'CTRL_SSPERIODE_BR')->Trouve1();
                $controleSousPeriodeBR = is_array($r) && array_key_exists('LIB01PARV', $r) && $r['LIB01PARV'] == 'O';
                if($ouvertureSousPeriode && $controleSousPeriodeBR){
                    $resultSousPer = SqlBr::ouvertureSousPeriode($dte_per, $info_entete_commande['CODE_STE'], 1)->Trouve1();
                    if(!$resultSousPer){      
                        Affichage::messageJS(trad("La sous-période à laquelle correspond la date d'effet n'est pas ouverte."));
                        $saisi_ok = false;
                    }
                }
            }
            else{                
                Affichage::messageJS(trad('La date de période est obligatoire, veuillez la renseigner.'));
                $saisi_ok = false;
            }
        }

        
        return $saisi_ok;
    }

    /**
     * Fonction permettant pour un login donné de savoir si toutes les lignes à réceptionner sont cochées ou non.
     *
     * @param string $login
     *            : Login de l'utilisateur connecté
     * @return boolean : 1 si toutes les lignes sont cochées sinon 0
     */
    public static function ISReceptionSolde(& $login)
    {
        $result = SqlBr::rqISReceptionSolde($login)->Trouve1();
        if (is_array($result) && array_key_exists('IS_CDE_SOLDE', $result))
            return $result['IS_CDE_SOLDE'];
        else
            return 0;
    }

    /**
     * Fonction retournant un booléen qui indique
     * qu'au moins une ligne sur le BR est réceptionnables (is_reception = vrai)
     */
    public static function &IsBREnregistrable(& $login)
    {
        $resultat = false;
        $result = SqlBr::rqISBREnregistrable($login)->Trouve1();
        if (is_array($result) && array_key_exists('nb', $result))
            if ($result['nb'] == 0)
                Affichage::messageJS(trad('Une des lignes au moins doit être sélectionnée pour réception.'));
            else
                $resultat = true;
        
        return $resultat;
    }

    /**
     * Fonction contrôlant les livraisons excédentaires pour le BR en cours d'un utilisateur donné
     *
     * @param string $login
     *            : Login de l'utilisateur
     * @param int $no_ligne
     *            : Numéro de la ligne a contrôler
     * @return array : Un tableau avec la liste des messages d'erreurs
     */
    public function ctrlQteMontant(& $login, $no_ligne = null)
    {
        $messageErreur = array();
        $messageAvert = array();
        
        // On récupère les infos de l'entête
        $brEntete = new BR_entete();
        $brEntete->getBR_entete($_SESSION['Session_Login']);
        
        // On fait attention aux arrondis, 4 chiffres après la virgule
        $precisionArrondi = Param::getPrecisionArrondi();
        $precisionArrondiMontant = Param::getNombreDeciamleMntTotal();
        
        $taux_liv_excedent = 0;
        $montant_liv_excedent = 0;
        $tauxConversion = 1.0;
        // On récupère le paramétrage sur le contrôle des livraisons exédentaires
        $isCtrlBrExedentaire = Param::isCtrlBrExedentaire();
        if ($isCtrlBrExedentaire) {
            // Le cas échéant, on va chercher les informations
            // DOSSIER 32661 : Prendre en compte le paramétrage du type de document avant le paramétrage général
            $CdeResult = SqlCde::rqGetEnteteCde($brEntete->getNo_cde())->Trouve1();
            $infoTypdoc = SqlInfo::rqGetTypesDocument($CdeResult['TYP_DOC'], true)->Trouve1();
            $taux_liv_excedent = $infoTypdoc['TXLIVEXCD'];
            $montant_liv_excedent = $infoTypdoc['MTLIVEXCD'];
            if($taux_liv_excedent == 0 && $montant_liv_excedent == 0){                
                $taux_liv_excedent = Param::getTauxMargeBrExedentaire();
                $montant_liv_excedent = Param::getMontantMargeBRExedentaire();
            }
            $tauxConversion = Param::getTauxConvDevSrcToDevDest($CdeResult['DEVISE'], Param::getDeviseBase());
        }
        
        if (! is_null($no_ligne)) {
            $BrLigne = new BR_ligne();
            $BrLigne->getLigneBRCreation($login, $no_ligne);
            $this->array_br_ligne[0] = $BrLigne;
        }
        
        /**
         * Attention en mode mdodification le RAL visualiser prend en compte la quantite cde
         */
        foreach ($this->array_br_ligne as & $ligne) {
            // On doit vérifier que les valeurs sont repectées pour la quantité ET le montant excédentaire
            // Pour peu que leur valeur soit <> 0

            // Pour chacune des lignes du BR
            $montant = $ligne->getMontantRec();
            $montant = round($montant, $precisionArrondiMontant);
            $ligne_cde = SqlCde::rqGetLigneCde($brEntete->getNo_cde(), $ligne->getNo_ligne_cde())->Trouve1();

            $calQteComm = $ligne_cde['QTE_COMM'];
            $calPURemise = $ligne_cde['PU_REMISE'];
            // Dossier 26462 : on tient compte du signe du PU
            $PURemisePositif = ($calPURemise == abs($calPURemise));
            $calRal = $ligne->getRal(); // 21820 NE SURTOUT PAS PRENDRE le ral de la commande car en cas de modif de BR il ne prend la quantité recu avec modification
            
            $testTauxOk = true;
            $testMontantOk = true;
            if ($isCtrlBrExedentaire && ($taux_liv_excedent > 0 || $montant_liv_excedent > 0)) {
                if ($ligne->isReceptionEnMontant()) {
       
                    $dejaLiv = sqlbr::rqDejaLivrerCde($ligne_cde)->Trouve1()['dejaLivre'];
                    $RAL = $calQteComm * abs($calPURemise) - $dejaLiv; 
                    
                    // Nous sommes sur une réception en montant
                    //$op1 = round(($calQteComm - $calRal) * abs($calPURemise) + $montant, $precisionArrondi);
                    $op1 = (int)$RAL + $montant;
                    $op2 = $calQteComm * abs($calPURemise);

                    if ($montant_liv_excedent > 0)
                    {
                        // Dossier 26462 : on tient compte du signe du PU
                        if (($montant + $dejaLiv > round($op2 + $montant_liv_excedent, $precisionArrondi))) 
                        {
                            $messageErreur[] = strBuild(trad('Ligne @1@ : le montant dépasse le montant restant à livrer et le montant de marge excédentaire.'), $ligne->getNo_ligne_cde());
                            $testMontantOk = false;
                        }
                    }
               
                    if ($taux_liv_excedent > 0)
                    {
                        $op2 *= 1 + $taux_liv_excedent/100;
                        if ($montant + $dejaLiv > round($op2, $precisionArrondi))
                         {
                            $messageErreur[] = strBuild(trad('Ligne @1@ : le montant dépasse le reste à livrer et le taux de marge autorisé.'), $ligne->getNo_ligne_cde());
                            $testTauxOk = false;
                        }
                    } 
                

                    // Dossier 26462 : on tient compte du signe du PU
                    if($testMontantOk != false && $testTauxOk != false)
                    {
                        if ($montant > $RAL)
                        {
                            $messageAvert[] = strBuild(trad('Ligne @1@ : le montant dépasse le montant restant à livrer, la livraison sera excédentaire.'), $ligne->getNo_ligne_cde());
                        }
                    }


      
                } else {
                    // Nous sommes sur une réception en quantité
                    // Si la quantité acceptée est supérieure à la quantité commandée exédentaire + reste à livrer : test KO
                    $op1 = ($calQteComm - $calRal) + $ligne->getQte_a();
                    $op2 = $calQteComm;
                    if (round($op1, $precisionArrondi) > round($op2, $precisionArrondi)) {
                        $messageAvert[] = strBuild(trad('Ligne @1@ : la quantité dépasse la quantité restant à livrer, la livraison sera excédentaire.'), $ligne->getNo_ligne_cde());
                    }
                    
                    if ($taux_liv_excedent > 0){
                        if (round($op1, $precisionArrondi) > round($calQteComm * (1 + $taux_liv_excedent/100), $precisionArrondi)) {
                            $testTauxOk = false;
                            $messageErreur[] = strBuild(trad('Ligne @1@ : la quantité dépasse le reste à livrer et le taux de marge autorisé.'), $ligne->getNo_ligne_cde());
                        }
                    }
                    if ($montant_liv_excedent > 0 && $testTauxOk) {
                        $op1 = round($op1 * abs($calPURemise) * $tauxConversion, $precisionArrondi);
                        $op2 = round($calQteComm * abs($calPURemise) * $tauxConversion + $montant_liv_excedent, $precisionArrondi);
                        // Dossier 26462 : on tient compte du signe du PU
                        // if ( ($PURemisePositif && ($op1 > $op2)) || (!$PURemisePositif && ($op1 < $op2))) {
                        if (($op1 > $op2)) {
                            $testMontantOk = false;
                            $messageErreur[] = strBuild(trad('Ligne @1@ : la quantité dépasse le reste à livrer et le montant de marge autorisé.'), $ligne->getNo_ligne_cde());
                        }
                    }
                }
            } else {
                // Pas de contrôle excédentaire OU les deux marges sont à 0
                if ($ligne->isReceptionEnMontant()) {
                    // Dossier 26462 : on tient compte du signe du PU
                    // DOSSIER 32834 : Ne plus tenir compte de la qté de reste à livrer mais faire la somme des montants des lignes de BR existantes, plus la ligne de BR en cours de saisie et comparer au montant de la ligne de commande
                    $MONTANT_RAL = $calPURemise * $calQteComm - sqlbr::rqDejaLivrerCde(['NO_CDE' => $brEntete->getNo_cde(), 'NO_PO' => $ligne->getNo_ligne_cde()])->Trouve1()['dejaLivre'];
                    $MONTANT_RAL = round($MONTANT_RAL, $precisionArrondiMontant);
                    if (($PURemisePositif && ($montant > $MONTANT_RAL)) || (! $PURemisePositif && ($montant < $MONTANT_RAL))) {
                        $messageErreur[] = strBuild(trad('Ligne @1@ : le montant dépasse le reste à livrer.'), $ligne->getNo_ligne_cde());
                        $testMontantOk = false;
                    }
                } else {
                    // Réception en quantité
                    $op1 = round(($calQteComm - $calRal + $ligne->getQte_a()) * $calPURemise, $precisionArrondi);
                    $op2 = round($calQteComm * $calPURemise, $precisionArrondi);
                    // Dossier 26462 : on tient compte du signe du PU
                    if (($PURemisePositif && ($op1 > $op2)) || (! $PURemisePositif && ($op1 < $op2))) {
                        $messageErreur[] = strBuild(trad('Ligne @1@ : la quantité dépasse le reste à livrer.'), $ligne->getNo_ligne_cde());
                        $testTauxOk = false;
                    }
                }
            }
            // Gestion des erreurs
            if ($testTauxOk && $testMontantOk)
                // Alors la ligne est déclarée valide
                $ligne->setQteAccepValide(1);
            else
                $ligne->setQteAccepValide(0);
        }
        
        return array(
            'Erreur' => $messageErreur,
            'Avert' => $messageAvert
        );
    }

    /**
     * Fonction réalisant le contrôle sur les quantités acceptées du BR et affichant à l'utilisateur les lignes non valides
     *
     * @param string $login
     *            : Login de l'utilisateur permettant d'indentifier le BR en cours de l'utilisateur
     * @param string $contexte
     *            : Contexte dans lequel l'utilisateur valide le BR
     * @return boolean : Retourne vrai si le contrôle est OK false, sinon
     */
    public function &ctrlQteAcceptee(& $login)
    {
        $message = '';
        
        // Si le contrôle sur la validité des quantités acceptées est négatif
        $resultatCtrl = $this->ctrlQteMontant($login);
        
        // if (!$this->isQteAccepteeValide($login))
        if (count($resultatCtrl['Erreur']) > 0)
            if (Param::isCtrlBrExedentaireBloquant())
                $message = trad('Une ou plusieurs lignes ont une valeur dépassant le reste à livrer et les excédents autorisés, veuillez modifier les quantités surlignées en rouge avant de valider le bon de réception.');
            else {
                $_SESSION['BR_LIVR_EXCEDENT_CONFIRM'] = true;
                $message = trad('Une ou plusieurs lignes ont une valeur dépassant le reste à livrer et les excédents autorisés, veuillez valider à nouveau le bon de réception pour confirmer.');
            }
        
        return $message;
    }

    /**
     * Fonction retournant un boolean indiquant si des factures sont associées sur un BR donné
     *
     * @param int $no_br
     *            : Numéro du BR
     * @return boolean : true si une ou plusieurs factures existent, sinon false
     */
    public static function isBapOnBr(& $no_br)
    {
        if (SqlBr::rqGetFacByBr($no_br)->TrouveTous())
            return true;
        else
            return false;
    }

    /**
     * Fonction permettant de tester si un BR donné peut être utilisé pour réalise un bon de retour
     *
     * @param int $num_br
     * @return boolean : True si ok pour bon de retour, false sinon.
     */
    public static function isBonReceptionPourBonRetour(& $num_br)
    {
        if (SqlBr::rqSelectBonReceptionPourBonRetour($num_br)->Trouve1())
            return true;
        else
            return false;
    }

    /**
     * Fonction initialisant la liste de toutes les directions présentent sur une societe
     * 
     * @param string $ste
     *            : societe dont on recherche les directions
     * @return void Spec 3011 - client 71 - Paramétrage fonction Liste chantiers
     */
    function getListAllRepartionBR(& $num_BR)
    {
        $this->listeRepartionBR = SqlBr::rqGetListAllRepartionBR($num_BR)->TrouveTous();
    }

    /**
     * fonction intégrant la liste des infos de répartitions de ligne de br dans le tableau de données XML
     */
    function buildXML_ListRepartionBR(&$xml_array, & $num_BR)
    {
        $tabUtilisateur = array();
        $this->getListAllRepartionBR($num_BR);
        $compteurUser = 0;
        
        // On parcours le tableau des ligne de Br
        $MailtoUSER = array();
        foreach ($this->listeRepartionBR as & $element) {
            
            // Variable pour la préparation du mail to
            $TexteSujet = trad('Livraison');
            $TexteElem = trad('Les éléments suivants ont été livrés :') . '%0A';
            
            // sur chaque ligne de Br on détermine l'utilisateur a contacter :
            // Priorité : Demandeur de la DA, Sinon le demandeur de la commande et sinon l'acheteur
            // On recupère également les informations utilisateur.
            if ($element['DEMDACODE'] != '') {
                $CodeRuptureUser = & $element['DEMDACODE'];
                $NomRuptureUser = & $element['DEMDANOM'];
                $TelRuptureUser = & $element['DEMDATEL'];
                $GSMRuptureUser = & $element['DEMDAGSM'];
                $MailRuptureUser = & $element['DEMDAMAIL'];
                $destinataire = & $element['DEMDAMAIL'];
            } elseif ($element['DEMCDECODE'] != '') {
                $CodeRuptureUser = & $element['DEMCDECODE'];
                $NomRuptureUser = & $element['DEMCDENOM'];
                $TelRuptureUser = & $element['DEMCDETEL'];
                $GSMRuptureUser = & $element['DEMCDEGSM'];
                $MailRuptureUser = & $element['DEMCDEMAIL'];
                $destinataire = & $element['DEMCDEMAIL'];
            } else {
                $CodeRuptureUser = & $element['ACHCODE'];
                $NomRuptureUser = & $element['ACHNOM'];
                $TelRuptureUser = & $element['ACHTEL'];
                $GSMRuptureUser = & $element['ACHGSM'];
                $MailRuptureUser = & $element['ACHMAIL'];
                $destinataire = & $element['ACHMAIL'];
            }
            
            if ($element['NO_DA'] != '' && $element['NO_DA'] != 0 && ! is_null($element['NO_DA']))
                $document = trad("Demande d'achat N° ") . $element['NO_DA'];
            else
                $document = trad('Commande N° ') . $element['NUM_CDE'];
            
            $Mailto = 'mailto:' . ($destinataire) . '?subject=' . ($TexteSujet) . '&body=' . ($TexteElem);
            $Mailto .= $document . ' : ';
            $Mailto .= $element['DESIGN'] . ' : ' . $element['QTE_ACCEP'] . ' ' . $element['UNITE'];
            
            // A chaque nouvelle ligne pour un même utilisateur, on ajoute dans le mail
            if (! array_key_exists($CodeRuptureUser, $MailtoUSER) || $MailtoUSER[$CodeRuptureUser] == '')
                $MailtoUSER[$CodeRuptureUser] = 'mailto:' . ($destinataire) . '?subject=' . ($TexteSujet) . '&body=' . ($TexteElem);
            else
                $MailtoUSER[$CodeRuptureUser] .= '%0A';
            
            $MailtoUSER[$CodeRuptureUser] .= $document . ' : ';
            $MailtoUSER[$CodeRuptureUser] .= $element['DESIGN'] . ' : ' . $element['QTE_ACCEP'] . ' ' . $element['UNITE'];
            
            // Si la ligne porte sur un nouvel utilisateur
            if (! in_array($CodeRuptureUser, $tabUtilisateur)) {
                // tableau qui contient les valeurs utilisateurs déjà rencontrés
                $tabUtilisateur[] = $CodeRuptureUser;
                $xml_array['utilisateur'][] = array(
                    'Code_user_rupture' => $CodeRuptureUser,
                    'Nom_user_rupture' => $NomRuptureUser,
                    'Tel_user_rupture' => $TelRuptureUser,
                    'GSM_user_rupture' => $GSMRuptureUser,
                    'Mail_user_rupture' => $MailRuptureUser
                );
                // tableau qui renvoi l'indice par rapport à un code utilisateur (POur la construction du tableau d'information)
                $reverso[$CodeRuptureUser] = $compteurUser;
                $compteurUser += 1;
            }
             
            // Mise à jour du mail à envoyer au niveau de l'entête (pour un utilisateur)
            $xml_array['utilisateur'][$reverso[$CodeRuptureUser]]['MAILTOUSER'] = $MailtoUSER[$CodeRuptureUser];
            
            $xml_array['utilisateur'][$reverso[$CodeRuptureUser]]['ligne'][] = array(
                '!NUM_BR' => & $element['NUM_BR'],
                '!NO_PO_BR' => & $element['NO_PO_BR'],
                '!NUM_CDE' => & $element['NUM_CDE'],
                '!NO_PO_CDE' => & $element['NO_PO_CDE'],
                '!NO_DA' => & $element['NO_DA'],
                '!CODE_ART' => & $element['CODE_ART'],
                '!DESIGN' => & $element['DESIGN'],
                '!DESIGN_COMP' => & $element['DESIGN_COMP'],
                '!QTE' => & $element['QTE_ACCEP'],
                '!UNITE' => & $element['UNITE'],
                '!DEMDACODE' => & $element['DEMDACODE'],
                '!DEMDANOM' => & $element['DEMDANOM'],
                '!DEMDATEL' => & $element['DEMDATEL'],
                '!DEMDAGSM' => & $element['DEMDAGSM'],
                '!DEMDAMAIL' => & $element['DEMDAMAIL'],
                '!ACHCODE' => & $element['ACHCODE'],
                '!ACHNOM' => & $element['ACHNOM'],
                '!ACHTEL' => & $element['ACHTEL'],
                '!ACHGSM' => & $element['ACHGSM'],
                '!ACHMAIL' => & $element['ACHMAIL'],
                '!DEMCDECODE' => & $element['DEMCDECODE'],
                '!DEMCDENOM' => & $element['DEMCDENOM'],
                '!DEMCDETEL' => & $element['DEMCDETEL'],
                '!DEMCDEGSM' => & $element['DEMCDEGSM'],
                '!DEMCDEMAIL' => & $element['DEMCDEMAIL'],
                '!CODE_USER' => $CodeRuptureUser,
                '!MAILTO' => $Mailto
            );
        }
    }
}