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::{SafeDispatch, SafeVariant};
use crate::errors::SageResult;
use crate::wrappers::cpta::factories::FactoryEcritureIn;
use crate::wrappers::cpta::objects::{Devise, Journal};
use crate::wrappers::cpta::process::ErrorCollection;
use windows::Win32::System::Com::IDispatch;

/// Wrapper pour le processus de saisie de pièce comptable (IPMEncoder)
/// Ce processus permet de créer des pièces comptables équilibrées avec validation
/// avant enregistrement dans la base Sage.
///
/// # Flux d'utilisation
/// 1. Créer le processus via `CptaApplication::create_process_encoder()`
/// 2. Définir les propriétés globales (journal, date, pièce, intitulé)
/// 3. Créer les écritures via `factory_ecriture_in()?.create()`
/// 4. Valider avec `can_process()`
/// 5. Enregistrer avec `process()`
pub struct PMEncoder {
    pub dispatch: IDispatch,
}

impl PMEncoder {
    fn dispatch(&self) -> SafeDispatch<'_> {
        SafeDispatch::new(&self.dispatch)
    }

    // ==================== PROPRIÉTÉS GLOBALES ====================

    /// Définit si les écritures analytiques doivent être générées automatiquement
    pub fn set_analytique_auto(&self, auto: bool) -> SageResult<()> {
        let auto_variant = SafeVariant::Bool(auto);
        self.dispatch()
            .call_property_put("bAnalytiqueAuto", &[auto_variant])?;
        Ok(())
    }

    /// Récupère le paramètre de génération automatique des écritures analytiques
    pub fn analytique_auto(&self) -> SageResult<bool> {
        self.dispatch()
            .get_property_by_name("bAnalytiqueAuto")?
            .to_bool()
    }

    /// Définit si les échéances doivent être générées automatiquement
    pub fn set_multi_echeance_auto(&self, auto: bool) -> SageResult<()> {
        let auto_variant = SafeVariant::Bool(auto);
        self.dispatch()
            .call_property_put("bMultiEcheanceAuto", &[auto_variant])?;
        Ok(())
    }

    /// Récupère le paramètre de génération automatique des échéances
    pub fn multi_echeance_auto(&self) -> SageResult<bool> {
        self.dispatch()
            .get_property_by_name("bMultiEcheanceAuto")?
            .to_bool()
    }

    /// Définit le journal du processus
    /// Le journal est partagé par toutes les écritures de la pièce
    pub fn set_journal(&self, journal: &Journal) -> SageResult<()> {
        let journal_variant = SafeVariant::from_dispatch(journal.dispatch.clone());
        self.dispatch()
            .call_property_put("Journal", &[journal_variant])?;
        Ok(())
    }

    /// Récupère le journal du processus
    pub fn journal(&self) -> SageResult<Journal> {
        let variant = self.dispatch().get_property_by_name("Journal")?;
        let dispatch = variant.to_dispatch()?;
        Ok(Journal { dispatch })
    }

    /// Définit la date du processus (format ISO: YYYY-MM-DD)
    /// La date est partagée par toutes les écritures de la pièce
    pub fn set_date(&self, date: &str) -> SageResult<()> {
        let date_variant = SafeVariant::from_string(date);
        self.dispatch().call_property_put("Date", &[date_variant])?;
        Ok(())
    }

    /// Récupère la date du processus
    pub fn date(&self) -> SageResult<String> {
        self.dispatch().get_property_by_name("Date")?.to_string()
    }

    /// Définit la devise du processus
    pub fn set_devise(&self, devise: &Devise) -> SageResult<()> {
        let devise_variant = SafeVariant::from_dispatch(devise.dispatch.clone());
        self.dispatch()
            .call_property_put("Devise", &[devise_variant])?;
        Ok(())
    }

    /// Définit la parité de la devise
    pub fn set_ec_parite(&self, parite: f64) -> SageResult<()> {
        let parite_variant = SafeVariant::R8(parite);
        self.dispatch()
            .call_property_put("EC_Parite", &[parite_variant])?;
        Ok(())
    }

    /// Définit l'intitulé (propriété globale de la pièce)
    pub fn set_ec_intitule(&self, intitule: &str) -> SageResult<()> {
        let intitule_variant = SafeVariant::from_string(intitule);
        self.dispatch()
            .call_property_put("EC_Intitule", &[intitule_variant])?;
        Ok(())
    }

    /// Définit le numéro de pièce
    /// Généralement obtenu via `journal.next_ec_piece(date)`
    pub fn set_ec_piece(&self, piece: &str) -> SageResult<()> {
        let piece_variant = SafeVariant::from_string(piece);
        self.dispatch()
            .call_property_put("EC_Piece", &[piece_variant])?;
        Ok(())
    }

    /// Définit la référence de pièce
    pub fn set_ec_ref_piece(&self, ref_piece: &str) -> SageResult<()> {
        let ref_variant = SafeVariant::from_string(ref_piece);
        self.dispatch()
            .call_property_put("EC_RefPiece", &[ref_variant])?;
        Ok(())
    }

    /// Définit la référence
    pub fn set_ec_reference(&self, reference: &str) -> SageResult<()> {
        let ref_variant = SafeVariant::from_string(reference);
        self.dispatch()
            .call_property_put("EC_Reference", &[ref_variant])?;
        Ok(())
    }

    // ==================== FACTORY ÉCRITURES ====================

    /// Accède à la factory pour créer les écritures du processus
    /// Utilisez `create()` pour ajouter des écritures à la pièce
    pub fn factory_ecriture_in(&self) -> SageResult<FactoryEcritureIn> {
        let factory_variant = self.dispatch().get_property_by_name("FactoryEcritureIn")?;

        let factory_dispatch = factory_variant.to_dispatch()?;

        Ok(FactoryEcritureIn {
            dispatch: factory_dispatch,
        })
    }

    /// Liste des écritures créées (après Process)
    /// Retourne une collection variant des écritures enregistrées
    pub fn list_ecritures_out(&self) -> SageResult<SafeVariant> {
        self.dispatch().call_method_by_name("ListEcrituresOut", &[])
    }

    // ==================== PROPRIÉTÉS CALCULÉES (LECTURE SEULE) ====================

    /// Retourne la somme des montants au crédit
    pub fn credit(&self) -> SageResult<f64> {
        self.dispatch().get_property_by_name("Credit")?.to_f64()
    }

    /// Retourne la somme des montants au débit
    pub fn debit(&self) -> SageResult<f64> {
        self.dispatch().get_property_by_name("Debit")?.to_f64()
    }

    /// Retourne le solde des écritures du processus (Débit - Crédit)
    /// Un solde à 0 indique une pièce équilibrée
    pub fn solde(&self) -> SageResult<f64> {
        self.dispatch().get_property_by_name("Solde")?.to_f64()
    }

    // ==================== VALIDATION ET ENREGISTREMENT ====================

    /// Vérifie si le processus peut être validé
    /// Retourne true si la pièce est équilibrée et valide
    /// Retourne false si des erreurs existent (consultables via `errors()`)
    pub fn can_process(&self) -> SageResult<bool> {
        self.dispatch()
            .call_method_by_name("CanProcess", &[])?
            .to_bool()
    }

    /// Enregistre les écritures en base
    /// À appeler uniquement si `can_process()` retourne true
    /// Lève une erreur si la validation échoue
    pub fn process(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Process", &[])?;
        Ok(())
    }

    // ==================== GESTION DES ERREURS ====================

    /// Récupère la collection des erreurs de validation
    /// Utilisez cette méthode si `can_process()` retourne false
    pub fn errors(&self) -> SageResult<ErrorCollection> {
        let errors_variant = self.dispatch().get_property_by_name("Errors")?;
        let errors_dispatch = errors_variant.to_dispatch()?;

        Ok(ErrorCollection {
            dispatch: errors_dispatch,
        })
    }

    // ==================== MÉTHODES AVANCÉES ====================

    /// Ajoute automatiquement les écritures de tiers (échéances, etc.)
    /// Cette méthode génère les écritures d'échéances pour les comptes tiers
    pub fn add_tiers_part(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("AddTiersPart", &[])?;
        Ok(())
    }

    /// Équilibre automatiquement la pièce
    /// Génère une écriture de contrepartie pour équilibrer débit/crédit
    pub fn equilibrer(&self) -> SageResult<()> {
        self.dispatch().call_method_by_name("Equilibrer", &[])?;
        Ok(())
    }
}