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 Contact de Sage 100c (IBOContact3)
///
/// Représente une personne de contact chez un tiers (client/fournisseur).
/// Permet de gérer plusieurs contacts par tiers avec leurs coordonnées.
pub struct Contact {
    pub dispatch: IDispatch,
}

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

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

    /// Obtient le numéro interne du contact
    pub fn c_numero(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("C_Numero", &[])?
            .to_i32()
    }

    /// Obtient le code tiers rattaché
    pub fn c_tiers(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Tiers", &[])?
            .to_string()
    }

    /// Définit le code tiers rattaché
    pub fn set_c_tiers(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Tiers", &[param])?;
        Ok(())
    }

    /// Obtient la civilité (0=M., 1=Mme, 2=Mlle)
    pub fn c_civilite(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("C_Civilite", &[])?
            .to_i32()
    }

    /// Définit la civilité
    pub fn set_c_civilite(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("C_Civilite", &[param])?;
        Ok(())
    }

    /// Obtient le nom
    pub fn c_nom(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Nom", &[])?
            .to_string()
    }

    /// Définit le nom
    pub fn set_c_nom(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Nom", &[param])?;
        Ok(())
    }

    /// Obtient le prénom
    pub fn c_prenom(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Prenom", &[])?
            .to_string()
    }

    /// Définit le prénom
    pub fn set_c_prenom(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Prenom", &[param])?;
        Ok(())
    }

    // ==================== FONCTION ====================

    /// Obtient la fonction
    pub fn c_fonction(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Fonction", &[])?
            .to_string()
    }

    /// Définit la fonction
    pub fn set_c_fonction(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Fonction", &[param])?;
        Ok(())
    }

    /// Obtient le service
    pub fn c_service(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Service", &[])?
            .to_string()
    }

    /// Définit le service
    pub fn set_c_service(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Service", &[param])?;
        Ok(())
    }

    /// Indique si c'est le contact principal
    pub fn c_principal(&self) -> SageResult<bool> {
        self.dispatch()
            .call_method_by_name("C_Principal", &[])?
            .to_bool()
    }

    /// Définit si c'est le contact principal
    pub fn set_c_principal(&self, value: bool) -> SageResult<()> {
        let param = SafeVariant::from_bool(value);
        self.dispatch().call_property_put("C_Principal", &[param])?;
        Ok(())
    }

    // ==================== COORDONNÉES ====================

    /// Obtient le téléphone direct
    pub fn c_telephone(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Telephone", &[])?
            .to_string()
    }

    /// Définit le téléphone direct
    pub fn set_c_telephone(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Telephone", &[param])?;
        Ok(())
    }

    /// Obtient le mobile
    pub fn c_mobile(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Mobile", &[])?
            .to_string()
    }

    /// Définit le mobile
    pub fn set_c_mobile(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Mobile", &[param])?;
        Ok(())
    }

    /// Obtient l'email
    pub fn c_email(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Email", &[])?
            .to_string()
    }

    /// Définit l'email
    pub fn set_c_email(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Email", &[param])?;
        Ok(())
    }

    /// Obtient le fax
    pub fn c_fax(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Fax", &[])?
            .to_string()
    }

    /// Définit le fax
    pub fn set_c_fax(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("C_Fax", &[param])?;
        Ok(())
    }

    // ==================== INFORMATIONS COMPLÉMENTAIRES ====================

    /// Obtient la date de naissance (format "YYYYMMDD")
    pub fn c_date_naissance(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_DateNaissance", &[])?
            .to_string()
    }

    /// Définit la date de naissance
    pub fn set_c_date_naissance(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch()
            .call_property_put("C_DateNaissance", &[param])?;
        Ok(())
    }

    /// Obtient le commentaire
    pub fn c_commentaire(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("C_Commentaire", &[])?
            .to_string()
    }

    /// Définit le commentaire
    pub fn set_c_commentaire(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch()
            .call_property_put("C_Commentaire", &[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 contact
    pub fn description(&self) -> SageResult<String> {
        let civilite = self.c_civilite()?;
        let nom = self.c_nom()?;
        let prenom = self.c_prenom().unwrap_or_else(|_| String::new());

        let civilite_str = match civilite {
            0 => "M.",
            1 => "Mme",
            2 => "Mlle",
            _ => "",
        };

        let nom_complet = if prenom.is_empty() {
            format!("{} {}", civilite_str, nom)
        } else {
            format!("{} {} {}", civilite_str, prenom, nom)
        };

        Ok(nom_complet)
    }

    /// Retourne les coordonnées complètes
    pub fn coordonnees(&self) -> SageResult<String> {
        let tel = self.c_telephone().unwrap_or_else(|_| "N/A".to_string());
        let mobile = self.c_mobile().unwrap_or_else(|_| String::new());
        let email = self.c_email().unwrap_or_else(|_| "N/A".to_string());

        let mut result = format!("Tél: {}", tel);
        if !mobile.is_empty() {
            result.push_str(&format!(" - Mobile: {}", mobile));
        }
        result.push_str(&format!(" - Email: {}", email));

        Ok(result)
    }
}

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

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

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

        // Utilisation typique :
        // let factory = app.factory_contact()?;
        // let contact = factory.read_principal("CLIENT01")?;
        //
        // println!("Contact: {}", contact.description()?);
        // println!("Fonction: {}", contact.c_fonction()?);
        // println!("{}", contact.coordonnees()?);
    }
}