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 Depot de Sage 100c (IBODepot)
///
/// Représente un dépôt de stockage avec ses propriétés et informations.
/// Un dépôt est un lieu physique ou logique où sont stockés les articles.
///
/// # Exemples
///
/// ```no_run
/// # use objets_metier_rs::wrappers::cial::CialApplication;
/// # fn main() -> Result<(), Box<dyn std::error::Error>> {
/// # let cial = CialApplication::new("Objets100c.CIAL")?;
/// # cial.set_name("D:\\Sage\\BIJOU.MAE")?;
/// # cial.open()?;
/// let factory_depot = cial.factory_depot()?;
/// let depot = factory_depot.read_intitule("Principal")?;
/// println!("Dépôt : {}", depot.de_intitule()?);
/// println!("Code : {}", depot.de_code()?);
/// # Ok(())
/// # }
/// ```
pub struct Depot {
    pub(crate) dispatch: IDispatch,
}

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

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

    /// Obtient l'intitulé du dépôt
    ///
    /// # Exemples
    ///
    /// ```no_run
    /// # use objets_metier_rs::wrappers::cial::objects::Depot;
    /// # fn example(depot: &Depot) -> Result<(), Box<dyn std::error::Error>> {
    /// let intitule = depot.de_intitule()?;
    /// println!("Intitulé : {}", intitule);
    /// # Ok(())
    /// # }
    /// ```
    pub fn de_intitule(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Intitule", &[])?
            .to_string()
    }

    /// Définit l'intitulé du dépôt
    pub fn set_de_intitule(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Intitule", &[param])?;
        Ok(())
    }

    /// Obtient le code du dépôt
    pub fn de_code(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Code", &[])?
            .to_string()
    }

    /// Définit le code du dépôt
    pub fn set_de_code(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Code", &[param])?;
        Ok(())
    }

    /// Obtient le compteur interne du dépôt
    pub fn de_no(&self) -> SageResult<i32> {
        self.dispatch().call_method_by_name("DE_No", &[])?.to_i32()
    }

    // ==================== ADRESSE ====================

    /// Obtient l'adresse du dépôt
    pub fn de_adresse(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Adresse", &[])?
            .to_string()
    }

    /// Définit l'adresse du dépôt
    pub fn set_de_adresse(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Adresse", &[param])?;
        Ok(())
    }

    /// Obtient le complément d'adresse du dépôt
    pub fn de_complement(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Complement", &[])?
            .to_string()
    }

    /// Définit le complément d'adresse du dépôt
    pub fn set_de_complement(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch()
            .call_property_put("DE_Complement", &[param])?;
        Ok(())
    }

    /// Obtient le code postal du dépôt
    pub fn de_code_postal(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_CodePostal", &[])?
            .to_string()
    }

    /// Définit le code postal du dépôt
    pub fn set_de_code_postal(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch()
            .call_property_put("DE_CodePostal", &[param])?;
        Ok(())
    }

    /// Obtient la ville du dépôt
    pub fn de_ville(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Ville", &[])?
            .to_string()
    }

    /// Définit la ville du dépôt
    pub fn set_de_ville(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Ville", &[param])?;
        Ok(())
    }

    /// Obtient le pays du dépôt
    pub fn de_pays(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Pays", &[])?
            .to_string()
    }

    /// Définit le pays du dépôt
    pub fn set_de_pays(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Pays", &[param])?;
        Ok(())
    }

    // ==================== CONTACT ====================

    /// Obtient le contact du dépôt
    pub fn de_contact(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Contact", &[])?
            .to_string()
    }

    /// Définit le contact du dépôt
    pub fn set_de_contact(&self, value: &str) -> SageResult<()> {
        let param = SafeVariant::from_string(value);
        self.dispatch().call_property_put("DE_Contact", &[param])?;
        Ok(())
    }

    /// Obtient le téléphone du dépôt
    pub fn de_telephone(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Telephone", &[])?
            .to_string()
    }

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

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

    /// Obtient le type de dépôt (0=Normal, 1=Principal, etc.)
    pub fn de_type(&self) -> SageResult<i32> {
        self.dispatch()
            .call_method_by_name("DE_Type", &[])?
            .to_i32()
    }

    /// Définit le type de dépôt
    pub fn set_de_type(&self, value: i32) -> SageResult<()> {
        let param = SafeVariant::from_i32(value);
        self.dispatch().call_property_put("DE_Type", &[param])?;
        Ok(())
    }

    /// Obtient l'email du dépôt
    pub fn de_email(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_EMail", &[])?
            .to_string()
    }

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

    /// Obtient le fax du dépôt
    pub fn de_telecopie(&self) -> SageResult<String> {
        self.dispatch()
            .call_method_by_name("DE_Telecopie", &[])?
            .to_string()
    }

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

    /// Indique si le dépôt est principal
    pub fn de_principal(&self) -> SageResult<bool> {
        let type_depot = self.de_type()?;
        Ok(type_depot == 1)
    }

    /// Indique si le dépôt est actif
    pub fn de_actif(&self) -> SageResult<bool> {
        self.dispatch()
            .call_method_by_name("DE_Sommeil", &[])?
            .to_bool()
            .map(|v| !v) // DE_Sommeil = true signifie inactif, donc on inverse
    }

    /// Active ou désactive le dépôt
    pub fn set_de_actif(&self, actif: bool) -> SageResult<()> {
        let param = SafeVariant::from_bool(!actif); // Inverse pour DE_Sommeil
        self.dispatch().call_property_put("DE_Sommeil", &[param])?;
        Ok(())
    }

    // ==================== MÉTHODES D'ÉCRITURE ====================

    /// Enregistre les modifications du dépôt dans la base de données
    ///
    /// # Exemples
    ///
    /// ```no_run
    /// # use objets_metier_rs::wrappers::cial::objects::Depot;
    /// # fn example(depot: &Depot) -> Result<(), Box<dyn std::error::Error>> {
    /// depot.set_de_intitule("Dépôt Sud")?;
    /// depot.set_de_ville("Lyon")?;
    /// depot.write()?;
    /// # Ok(())
    /// # }
    /// ```
    pub fn write(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Write", &[])?;
        Ok(())
    }

    /// Supprime le dépôt de la base de données
    ///
    /// ⚠️ Attention : Cette opération est irréversible
    pub fn remove(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Remove", &[])?;
        Ok(())
    }

    // ==================== MÉTHODES MÉTIER ====================

    /// Obtient l'adresse complète formatée du dépôt
    ///
    /// Retourne une adresse formatée sur plusieurs lignes
    pub fn get_adresse_complete(&self) -> SageResult<String> {
        let mut adresse = String::new();

        let addr = self.de_adresse()?;
        if !addr.is_empty() {
            adresse.push_str(&addr);
            adresse.push('\n');
        }

        let complement = self.de_complement()?;
        if !complement.is_empty() {
            adresse.push_str(&complement);
            adresse.push('\n');
        }

        let cp = self.de_code_postal()?;
        let ville = self.de_ville()?;
        if !cp.is_empty() || !ville.is_empty() {
            adresse.push_str(&format!("{} {}\n", cp, ville));
        }

        let pays = self.de_pays()?;
        if !pays.is_empty() {
            adresse.push_str(&pays);
        }

        Ok(adresse.trim().to_string())
    }

    /// Valide les données du dépôt avant enregistrement
    ///
    /// Vérifie que les champs obligatoires sont remplis
    pub fn validate(&self) -> SageResult<bool> {
        let intitule = self.de_intitule()?;
        if intitule.is_empty() {
            return Ok(false);
        }

        let code = self.de_code()?;
        if code.is_empty() {
            return Ok(false);
        }

        Ok(true)
    }

    /// Obtient le compteur interne (cbMarq) du dépôt
    pub fn cbmarq(&self) -> SageResult<i32> {
        self.dispatch().call_method_by_name("cbMarq", &[])?.to_i32()
    }
}

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

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

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_depot_structure() {
        // Test de documentation vérifiant que la structure compile
        // Ne s'exécute pas réellement car nécessite une connexion Sage
    }
}