objets_metier_rs 1.0.2

Bibliothèque Rust moderne et sûre pour l'API COM Objets Métier Sage 100c - Production Ready
//! Traits pour la lecture d'entités par clé spécifique
//!
//! Ce module définit des traits pour standardiser les méthodes de lecture par clé :
//! - `FactoryReadBy<K, T>` - Trait générique pour lecture par clé
//! - `FactoryReadByNumero` - Spécialisation pour lecture par numéro (i32)
//! - `FactoryReadByIntitule` - Spécialisation pour lecture par intitulé (String)
//! - `FactoryReadByCode` - Spécialisation pour lecture par code (String)

use crate::errors::SageResult;

/// Trait générique pour la lecture d'entités par clé
///
/// Ce trait fournit une interface commune pour récupérer une entité spécifique
/// à partir d'une clé (numéro, intitulé, code, etc.).
///
/// # Type Parameters
///
/// * `K` - Le type de la clé (i32, &str, etc.)
/// * `T` - Le type d'entité retourné
///
/// # Exemple
///
/// ```rust,ignore
/// use objets_metier_rs::wrappers::cpta::traits::FactoryReadBy;
///
/// fn lire_par_cle<F, K, T>(factory: &F, key: K) -> SageResult<T>
/// where
///     F: FactoryReadBy<K, T>,
/// {
///     factory.read_by(key)
/// }
/// ```
pub trait FactoryReadBy<K, T> {
    /// Lit une entité par sa clé
    ///
    /// # Arguments
    ///
    /// * `key` - La clé identifiant l'entité
    ///
    /// # Errors
    ///
    /// Retourne une erreur si :
    /// - L'entité n'existe pas
    /// - La connexion COM échoue
    /// - Une erreur de conversion se produit
    fn read_by(&self, key: K) -> SageResult<T>;

    /// Vérifie si une entité existe pour la clé donnée
    ///
    /// # Arguments
    ///
    /// * `key` - La clé à vérifier
    ///
    /// # Returns
    ///
    /// `true` si l'entité existe, `false` sinon
    ///
    /// # Errors
    ///
    /// Retourne une erreur si la vérification échoue
    fn exist_by(&self, key: K) -> SageResult<bool>;
}

/// Trait pour la lecture d'entités par numéro (i32)
///
/// Ce trait est une spécialisation de `FactoryReadBy` pour les entités
/// identifiées par un numéro entier (journaux, comptes, tiers, etc.).
///
/// # Exemple
///
/// ```rust,ignore
/// use objets_metier_rs::wrappers::cpta::traits::FactoryReadByNumero;
///
/// // Lire le journal numéro 1
/// let journal = factory_journal.read_numero(1)?;
///
/// // Vérifier si le compte 401000 existe
/// if factory_compte_g.exist_numero(401000)? {
///     println!("Le compte fournisseur existe");
/// }
/// ```
pub trait FactoryReadByNumero<T> {
    /// Lit une entité par son numéro
    ///
    /// # Arguments
    ///
    /// * `numero` - Le numéro de l'entité (ex: numéro de journal, de compte)
    ///
    /// # Errors
    ///
    /// Retourne une erreur si l'entité n'existe pas ou si la lecture échoue
    fn read_numero(&self, numero: i32) -> SageResult<T>;

    /// Vérifie si une entité existe pour le numéro donné
    ///
    /// # Arguments
    ///
    /// * `numero` - Le numéro à vérifier
    ///
    /// # Returns
    ///
    /// `true` si l'entité existe, `false` sinon
    fn exist_numero(&self, numero: i32) -> SageResult<bool>;
}

/// Trait pour la lecture d'entités par intitulé
///
/// Ce trait est une spécialisation de `FactoryReadBy` pour les entités
/// identifiées par un intitulé (texte descriptif).
///
/// # Exemple
///
/// ```rust,ignore
/// use objets_metier_rs::wrappers::cpta::traits::FactoryReadByIntitule;
///
/// // Lire le mode de règlement "Espèces"
/// let reglement = factory_reglement.read_intitule("Espèces")?;
///
/// // Vérifier si la banque "BNP Paribas" existe
/// if factory_banque.exist_intitule("BNP Paribas")? {
///     println!("La banque existe");
/// }
/// ```
pub trait FactoryReadByIntitule<T> {
    /// Lit une entité par son intitulé
    ///
    /// # Arguments
    ///
    /// * `intitule` - L'intitulé de l'entité
    ///
    /// # Errors
    ///
    /// Retourne une erreur si l'entité n'existe pas ou si la lecture échoue
    fn read_intitule(&self, intitule: &str) -> SageResult<T>;

    /// Vérifie si une entité existe pour l'intitulé donné
    ///
    /// # Arguments
    ///
    /// * `intitule` - L'intitulé à vérifier
    ///
    /// # Returns
    ///
    /// `true` si l'entité existe, `false` sinon
    fn exist_intitule(&self, intitule: &str) -> SageResult<bool>;
}

/// Trait pour la lecture d'entités par code
///
/// Ce trait est une spécialisation de `FactoryReadBy` pour les entités
/// identifiées par un code (ex: codes TVA, codes risque).
///
/// # Exemple
///
/// ```rust,ignore
/// use objets_metier_rs::wrappers::cpta::traits::FactoryReadByCode;
///
/// // Lire le code TVA "C20"
/// let taxe = factory_taxe.read_code("C20")?;
///
/// // Vérifier si le code risque "R001" existe
/// if factory_code_risque.exist_code("R001")? {
///     println!("Le code risque existe");
/// }
/// ```
pub trait FactoryReadByCode<T> {
    /// Lit une entité par son code
    ///
    /// # Arguments
    ///
    /// * `code` - Le code de l'entité
    ///
    /// # Errors
    ///
    /// Retourne une erreur si l'entité n'existe pas ou si la lecture échoue
    fn read_code(&self, code: &str) -> SageResult<T>;

    /// Vérifie si une entité existe pour le code donné
    ///
    /// # Arguments
    ///
    /// * `code` - Le code à vérifier
    ///
    /// # Returns
    ///
    /// `true` si l'entité existe, `false` sinon
    fn exist_code(&self, code: &str) -> SageResult<bool>;
}

// Implémentations automatiques de FactoryReadBy pour les traits spécialisés
impl<T, F> FactoryReadBy<i32, T> for F
where
    F: FactoryReadByNumero<T>,
{
    fn read_by(&self, key: i32) -> SageResult<T> {
        self.read_numero(key)
    }

    fn exist_by(&self, key: i32) -> SageResult<bool> {
        self.exist_numero(key)
    }
}

impl<'a, T, F> FactoryReadBy<&'a str, T> for F
where
    F: FactoryReadByIntitule<T>,
{
    fn read_by(&self, key: &'a str) -> SageResult<T> {
        self.read_intitule(key)
    }

    fn exist_by(&self, key: &'a str) -> SageResult<bool> {
        self.exist_intitule(key)
    }
}