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 Analytique de Sage 100c (IBOAnalytique3)
///
/// Représente une section analytique (axe d'analyse) permettant de ventiler
/// les écritures comptables selon différents critères (projets, services, etc.)
pub struct Analytique {
    pub dispatch: IDispatch,
}

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

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

    /// Obtient le numéro de la section analytique
    pub fn a_numero(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("A_Numero", &[])?
            .to_string()
    }

    /// Définit le numéro de la section analytique
    pub fn set_a_numero(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("A_Numero", &[param])?;
        Ok(())
    }

    /// Obtient l'intitulé de la section analytique
    pub fn a_intitule(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("A_Intitule", &[])?
            .to_string()
    }

    /// Définit l'intitulé de la section analytique
    pub fn set_a_intitule(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("A_Intitule", &[param])?;
        Ok(())
    }

    // ==================== CLASSIFICATION ====================

    /// Obtient le type de section analytique
    /// 0 = Détail, 1 = Total
    pub fn a_type(&self) -> SageResult<i32> {
        self.dispatch().call_method_by_name("A_Type", &[])?.to_i32()
    }

    /// Définit le type de section analytique
    /// 0 = Détail, 1 = Total
    pub fn set_a_type(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("A_Type", &[param])?;
        Ok(())
    }

    /// Obtient le niveau hiérarchique de la section (0-9)
    pub fn a_niveau(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("A_Niveau", &[])?
            .to_i32()
    }

    /// Définit le niveau hiérarchique de la section
    pub fn set_a_niveau(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("A_Niveau", &[param])?;
        Ok(())
    }

    // ==================== COMPTE DE RATTACHEMENT ====================

    /// Obtient le compte général de rattachement
    pub fn a_compte_rattachement(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("A_CompteRattachement", &[])?
            .to_string()
    }

    /// Définit le compte général de rattachement
    pub fn set_a_compte_rattachement(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch()
            .call_property_put("A_CompteRattachement", &[param])?;
        Ok(())
    }

    // ==================== ÉTAT ====================

    /// Indique si la section analytique est active
    pub fn a_actif(&self) -> SageResult<bool> {
        self.dispatch()
            .call_method_by_name("A_Actif", &[])?
            .to_bool()
    }

    /// Définit si la section analytique est active
    pub fn set_a_actif(&self, value: bool) -> SageResult<()> {
        let param = SafeVariant::from_bool(value);
        self.dispatch().call_property_put("A_Actif", &[param])?;
        Ok(())
    }

    // ==================== PLAN ANALYTIQUE ====================

    /// Obtient le numéro du plan analytique (1-10)
    pub fn a_plan(&self) -> SageResult<i32> {
        self.dispatch().call_method_by_name("A_Plan", &[])?.to_i32()
    }

    /// Définit le numéro du plan analytique
    pub fn set_a_plan(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("A_Plan", &[param])?;
        Ok(())
    }

    // ==================== RUPTURE ET SAUT ====================

    /// Obtient le niveau de rupture
    pub fn a_rupture(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("A_Rupture", &[])?
            .to_i32()
    }

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

    /// Obtient le saut de ligne pour l'impression
    pub fn a_saut(&self) -> SageResult<i32> {
        self.dispatch().call_method_by_name("A_Saut", &[])?.to_i32()
    }

    /// Définit le saut de ligne pour l'impression
    pub fn set_a_saut(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("A_Saut", &[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 de la section analytique
    /// Format: "Analytique [Numéro] - [Intitulé] (Type: [Type], Niveau: [Niveau])"
    pub fn description(&self) -> SageResult<String> {
        let numero = self.a_numero()?;
        let intitule = self.a_intitule()?;
        let type_val = self.a_type()?;
        let niveau = self.a_niveau()?;

        let type_str = match type_val {
            0 => "Détail",
            1 => "Total",
            _ => "Inconnu",
        };

        Ok(format!(
            "Analytique {} - {} (Type: {}, Niveau: {})",
            numero, intitule, type_str, niveau
        ))
    }

    /// Retourne l'état de la section (Active/Inactive)
    pub fn etat(&self) -> SageResult<String> {
        let actif = self.a_actif()?;
        Ok(if actif {
            "Active".to_string()
        } else {
            "Inactive".to_string()
        })
    }
}

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

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

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

        // Utilisation typique :
        // let factory = app.factory_analytique()?;
        // let section = factory.read_numero("PRJ001")?;
        //
        // println!("Section: {}", section.a_intitule()?);
        // println!("Type: {}", section.a_type()?);
        // println!("Niveau: {}", section.a_niveau()?);
        // println!("Compte rattachement: {}", section.a_compte_rattachement()?);
        // println!("État: {}", section.etat()?);
        //
        // // Création d'une nouvelle section
        // let nouvelle = factory.create()?;
        // nouvelle.set_a_numero("SRV001")?;
        // nouvelle.set_a_intitule("Service Commercial")?;
        // nouvelle.set_a_type(0)?; // Détail
        // nouvelle.set_a_niveau(1)?;
        // nouvelle.set_a_plan(1)?;
        // nouvelle.set_a_actif(true)?;
        // nouvelle.write()?;
    }
}