vaultparser 0.3.0

A fast, pure-Rust library and visual tool for extracting tabular transaction ledgers from PDF bank statements
Documentation
use crate::config::ExtractionConfig;

/// Supported out-of-the-box bank statement templates.
///
/// Each preset contains standard column coordinates and label mappings
/// for common Indian banks.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BankPreset {
    /// HDFC Bank India statement template.
    Hdfc,
    /// State Bank of India (SBI) statement template.
    Sbi,
    /// Canara Bank statement template.
    Canara,
    /// Union Bank of India statement template.
    Union,
    /// UCO Bank statement template.
    Uco,
    /// Indian Bank statement template.
    Indian,
    /// H P State Co-operative Bank statement template.
    Hpscb,
    /// ICICI Bank statement template.
    Icici,
    /// Punjab National Bank (PNB) statement template.
    Pnb,
    /// Kotak Mahindra Bank statement template.
    Kotak,
    /// Axis Bank statement template.
    Axis,
    /// Bank of Baroda statement template.
    Bob,
    /// YES Bank statement template.
    Yes,
    /// IDFC FIRST Bank statement template.
    Idfc,
    /// IndusInd Bank statement template.
    Indusind,
}

impl BankPreset {
    /// Returns the human-readable display name of the bank preset.
    pub fn name(&self) -> &'static str {
        match self {
            Self::Hdfc => "HDFC Bank India",
            Self::Sbi => "State Bank of India (SBI)",
            Self::Canara => "Canara Bank",
            Self::Union => "Union Bank of India",
            Self::Uco => "UCO Bank",
            Self::Indian => "Indian Bank",
            Self::Hpscb => "H P State Co-operative Bank",
            Self::Icici => "ICICI Bank",
            Self::Pnb => "Punjab National Bank (PNB)",
            Self::Kotak => "Kotak Mahindra Bank",
            Self::Axis => "Axis Bank",
            Self::Bob => "Bank of Baroda",
            Self::Yes => "YES Bank",
            Self::Idfc => "IDFC FIRST Bank",
            Self::Indusind => "IndusInd Bank",
        }
    }

    /// Returns the pre-configured [`ExtractionConfig`] for the specific bank.
    ///
    /// # Examples
    /// ```
    /// use vaultparser::BankPreset;
    ///
    /// let config = BankPreset::Hdfc.config();
    /// assert!(config.filter_only_date);
    /// assert_eq!(config.col_mappings.len(), config.col_guides.len() + 1);
    /// ```
    pub fn config(&self) -> ExtractionConfig {
        let mut config = ExtractionConfig::default();
        match self {
            Self::Hdfc => {
                config.col_guides = vec![0.11, 0.42, 0.52, 0.62, 0.75, 0.88];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "skip".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
            }
            Self::Sbi => {
                config.col_guides = vec![0.10, 0.20, 0.52, 0.64, 0.76, 0.88];
                config.col_mappings = vec![
                    "date".to_string(),
                    "skip".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 15.0;
            }
            Self::Canara => {
                config.col_guides = vec![0.12, 0.48, 0.60, 0.74, 0.87];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
            }
            Self::Union => {
                config.col_guides = vec![0.11, 0.42, 0.52, 0.62, 0.75, 0.88];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "skip".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
            }
            Self::Uco => {
                config.col_guides = vec![0.12, 0.24, 0.60, 0.74, 0.87];
                config.col_mappings = vec![
                    "date".to_string(),
                    "reference".to_string(),
                    "description".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
            }
            Self::Indian => {
                config.col_guides = vec![0.08, 0.18, 0.45, 0.58, 0.71, 0.80];
                config.col_mappings = vec![
                    "date".to_string(),
                    "value_date".to_string(),
                    "description".to_string(),
                    "chq_no".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 15.0;
            }
            Self::Hpscb => {
                config.col_guides = vec![0.08, 0.16, 0.38, 0.41, 0.65, 0.74, 0.82];
                config.col_mappings = vec![
                    "s_no".to_string(),
                    "date".to_string(),
                    "value_date".to_string(),
                    "chq_no".to_string(),
                    "description".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 15.0;
            }
            Self::Icici => {
                config.col_guides = vec![0.08, 0.44, 0.55, 0.62, 0.88];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "chq_no".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Pnb => {
                config.col_guides = vec![0.14, 0.23, 0.33, 0.40, 0.47, 0.53];
                config.col_mappings = vec![
                    "date".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                    "skip".to_string(),
                    "chq_no".to_string(),
                    "description".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Kotak => {
                config.col_guides = vec![0.15, 0.44, 0.65, 0.79];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "debit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Axis => {
                config.col_guides = vec![0.12, 0.42, 0.55, 0.68, 0.82];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "chq_no".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Bob => {
                config.col_guides = vec![0.10, 0.20, 0.50, 0.65, 0.78, 0.88];
                config.col_mappings = vec![
                    "date".to_string(),
                    "value_date".to_string(),
                    "description".to_string(),
                    "chq_no".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 15.0;
            }
            Self::Yes => {
                config.col_guides = vec![0.12, 0.45, 0.58, 0.72, 0.85];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Idfc => {
                config.col_guides = vec![0.11, 0.40, 0.54, 0.68, 0.82];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "reference".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
            Self::Indusind => {
                config.col_guides = vec![0.12, 0.44, 0.56, 0.70, 0.84];
                config.col_mappings = vec![
                    "date".to_string(),
                    "description".to_string(),
                    "chq_no".to_string(),
                    "debit".to_string(),
                    "credit".to_string(),
                    "balance".to_string(),
                ];
                config.filter_only_date = true;
                config.y_tolerance = 12.0;
            }
        }
        config
    }

    /// Attempts to parse a case-insensitive string into a [`BankPreset`].
    /// Returns `None` if the name is unrecognized.
    ///
    /// # Examples
    /// ```
    /// use vaultparser::BankPreset;
    ///
    /// assert_eq!(BankPreset::from_str("hdfc"), Some(BankPreset::Hdfc));
    /// assert_eq!(BankPreset::from_str("HDFC"), Some(BankPreset::Hdfc));
    /// assert_eq!(BankPreset::from_str("nope"), None);
    /// ```
    #[allow(clippy::should_implement_trait)]
    pub fn from_str(s: &str) -> Option<Self> {
        match s.to_lowercase().as_str() {
            "hdfc" => Some(Self::Hdfc),
            "sbi" => Some(Self::Sbi),
            "canara" => Some(Self::Canara),
            "union" => Some(Self::Union),
            "uco" => Some(Self::Uco),
            "indian" => Some(Self::Indian),
            "hpscb" => Some(Self::Hpscb),
            "icici" => Some(Self::Icici),
            "pnb" => Some(Self::Pnb),
            "kotak" => Some(Self::Kotak),
            "axis" => Some(Self::Axis),
            "bob" | "baroda" => Some(Self::Bob),
            "yes" => Some(Self::Yes),
            "idfc" => Some(Self::Idfc),
            "indusind" => Some(Self::Indusind),
            _ => None,
        }
    }
}