objets_metier_rs 1.0.2

Bibliothèque Rust moderne et sûre pour l'API COM Objets Métier Sage 100c - Production Ready
use crate::com::{FromDispatch, FromDispatchNew, SafeDispatch, SafeVariant};
use crate::errors::SageResult;
use windows::Win32::System::Com::IDispatch;

/// Wrapper pour l'objet ModeleReglement de Sage 100c (IBOModeleReglement3)
///
/// Représente un modèle de conditions de paiement réutilisable permettant de définir
/// des échéances et des conditions de règlement standard.
pub struct ModeleReglement {
    pub dispatch: IDispatch,
}

impl ModeleReglement {
    /// Crée un SafeDispatch temporaire pour les appels
    fn dispatch(&self) -> SafeDispatch<'_> {
        SafeDispatch::new(&self.dispatch)
    }

    // ==================== IDENTIFICATION ====================

    /// Obtient l'intitulé du modèle de règlement
    pub fn mr_intitule(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("MR_Intitule", &[])?
            .to_string()
    }

    /// Définit l'intitulé du modèle de règlement
    pub fn set_mr_intitule(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("MR_Intitule", &[param])?;
        Ok(())
    }

    // ==================== TYPE ET STRUCTURE ====================

    /// Obtient le type de modèle de règlement
    /// 0 = Équilibré, 1 = Déséquilibré, 2 = Fin de mois
    pub fn mr_type(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("MR_Type", &[])?
            .to_i32()
    }

    /// Définit le type de modèle de règlement
    /// 0 = Équilibré, 1 = Déséquilibré, 2 = Fin de mois
    pub fn set_mr_type(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("MR_Type", &[param])?;
        Ok(())
    }

    /// Obtient le nombre de lignes d'échéance
    pub fn mr_nb_lignes(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("MR_NbLignes", &[])?
            .to_i32()
    }

    /// Définit le nombre de lignes d'échéance
    pub fn set_mr_nb_lignes(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("MR_NbLignes", &[param])?;
        Ok(())
    }

    // ==================== CONDITIONS ====================

    /// Obtient la condition de règlement
    /// 0 = Comptant, 1 = Jours nets, 2 = Jours fin de mois
    pub fn mr_condition(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("MR_Condition", &[])?
            .to_i32()
    }

    /// Définit la condition de règlement
    /// 0 = Comptant, 1 = Jours nets, 2 = Jours fin de mois
    pub fn set_mr_condition(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch()
            .call_property_put("MR_Condition", &[param])?;
        Ok(())
    }

    /// Obtient le nombre de jours de paiement
    pub fn mr_nb_jours(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("MR_NbJour", &[])?
            .to_i32()
    }

    /// Définit le nombre de jours de paiement
    pub fn set_mr_nb_jours(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("MR_NbJour", &[param])?;
        Ok(())
    }

    /// Obtient le jour de tombée (1-31)
    pub fn mr_jour(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("MR_Jour", &[])?
            .to_i32()
    }

    /// Définit le jour de tombée (1-31)
    pub fn set_mr_jour(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("MR_Jour", &[param])?;
        Ok(())
    }

    // ==================== OPTIONS ====================

    /// Indique si le calcul se fait en fin de mois
    pub fn mr_fin_mois(&self) -> SageResult<bool> {
        self.dispatch()
            .call_method_by_name("MR_FinMois", &[])?
            .to_bool()
    }

    /// Définit si le calcul se fait en fin de mois
    pub fn set_mr_fin_mois(&self, value: bool) -> SageResult<()> {
        let param = SafeVariant::from_bool(value);
        self.dispatch().call_property_put("MR_FinMois", &[param])?;
        Ok(())
    }

    /// Indique si le modèle prend en compte le jour "le" (date butoir)
    pub fn mr_le(&self) -> SageResult<bool> {
        self.dispatch().call_method_by_name("MR_Le", &[])?.to_bool()
    }

    /// Définit si le modèle prend en compte le jour "le"
    pub fn set_mr_le(&self, value: bool) -> SageResult<()> {
        let param = SafeVariant::from_bool(value);
        self.dispatch().call_property_put("MR_Le", &[param])?;
        Ok(())
    }

    // ==================== MÉTHODES IBIPersistObject ====================

    /// Enregistre l'objet dans la base de données
    pub fn write(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Write", &[])?;
        Ok(())
    }

    /// Lit l'objet depuis la base de données
    pub fn read(&self) -> SageResult<SafeVariant> {
        self.dispatch().call_method_by_name("Read", &[])
    }

    /// Supprime l'objet de la base de données
    pub fn remove(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Remove", &[])?;
        Ok(())
    }

    // ==================== MÉTHODES UTILITAIRES ====================

    /// Retourne une description formatée du modèle de règlement
    /// Format: "ModeleReglement [Intitulé] - Type: [Type], Lignes: [NbLignes]"
    pub fn description(&self) -> SageResult<String> {
        let intitule = self.mr_intitule()?;
        let type_val = self.mr_type()?;
        let nb_lignes = self.mr_nb_lignes()?;

        let type_str = match type_val {
            0 => "Équilibré",
            1 => "Déséquilibré",
            2 => "Fin de mois",
            _ => "Inconnu",
        };

        Ok(format!(
            "ModeleReglement {} - Type: {}, Lignes: {}",
            intitule, type_str, nb_lignes
        ))
    }

    /// Retourne une description de la condition de règlement
    pub fn condition_description(&self) -> SageResult<String> {
        let condition = self.mr_condition()?;
        let nb_jours = self.mr_nb_jours()?;

        let desc = match condition {
            0 => "Comptant".to_string(),
            1 => format!("{} jours nets", nb_jours),
            2 => format!("{} jours fin de mois", nb_jours),
            _ => "Condition inconnue".to_string(),
        };

        Ok(desc)
    }
}

impl FromDispatch for ModeleReglement {
    fn from_dispatch(dispatch: IDispatch) -> SageResult<Self> {
        Ok(ModeleReglement { dispatch })
    }
}

impl FromDispatchNew for ModeleReglement {
    fn from_dispatch_new(dispatch: IDispatch) -> SageResult<Self> {
        Ok(Self { dispatch })
    }
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_modele_reglement_documentation() {
        // Test de documentation - nécessite un environnement Sage pour s'exécuter

        // Utilisation typique :
        // let factory = app.factory_modele_reglement()?;
        // let modele = factory.read_intitule("30 jours fin de mois")?;
        //
        // println!("Modèle: {}", modele.mr_intitule()?);
        // println!("Type: {}", modele.mr_type()?);
        // println!("Nombre de lignes: {}", modele.mr_nb_lignes()?);
        // println!("Condition: {}", modele.condition_description()?);
        // println!("Jours: {}", modele.mr_nb_jours()?);
        //
        // // Création d'un nouveau modèle
        // let nouveau = factory.create()?;
        // nouveau.set_mr_intitule("60 jours nets")?;
        // nouveau.set_mr_type(0)?; // Équilibré
        // nouveau.set_mr_condition(1)?; // Jours nets
        // nouveau.set_mr_nb_jours(60)?;
        // nouveau.set_mr_nb_lignes(1)?;
        // nouveau.write()?;
    }
}