107 lines
3.6 KiB
Rust
107 lines
3.6 KiB
Rust
use rust_decimal::Decimal;
|
|
use chrono::NaiveDate;
|
|
use std::fmt;
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
pub struct BankTransaction {
|
|
/// Source ID (GoCardless transactionId)
|
|
pub internal_id: String,
|
|
/// Booking date
|
|
pub date: NaiveDate,
|
|
/// Amount in account currency
|
|
pub amount: Decimal,
|
|
/// Account currency code (e.g., EUR)
|
|
pub currency: String,
|
|
/// Original amount (if currency exchange occurred)
|
|
pub foreign_amount: Option<Decimal>,
|
|
/// Original currency code
|
|
pub foreign_currency: Option<String>,
|
|
/// Remittance info or description
|
|
pub description: String,
|
|
/// Counterparty name
|
|
pub counterparty_name: Option<String>,
|
|
/// Counterparty IBAN
|
|
pub counterparty_iban: Option<String>,
|
|
}
|
|
|
|
impl fmt::Debug for BankTransaction {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("BankTransaction")
|
|
.field("internal_id", &self.internal_id)
|
|
.field("date", &self.date)
|
|
.field("amount", &"[REDACTED]")
|
|
.field("currency", &self.currency)
|
|
.field("foreign_amount", &self.foreign_amount.as_ref().map(|_| "[REDACTED]"))
|
|
.field("foreign_currency", &self.foreign_currency)
|
|
.field("description", &"[REDACTED]")
|
|
.field("counterparty_name", &self.counterparty_name.as_ref().map(|_| "[REDACTED]"))
|
|
.field("counterparty_iban", &self.counterparty_iban.as_ref().map(|_| "[REDACTED]"))
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, PartialEq)]
|
|
pub struct Account {
|
|
pub id: String,
|
|
pub iban: String,
|
|
pub currency: String,
|
|
}
|
|
|
|
impl fmt::Debug for Account {
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
f.debug_struct("Account")
|
|
.field("id", &self.id)
|
|
.field("iban", &"[REDACTED]")
|
|
.field("currency", &self.currency)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use rust_decimal::Decimal;
|
|
|
|
#[test]
|
|
fn test_bank_transaction_debug_masks_sensitive_data() {
|
|
let tx = BankTransaction {
|
|
internal_id: "test-id".to_string(),
|
|
date: NaiveDate::from_ymd_opt(2023, 1, 1).unwrap(),
|
|
amount: Decimal::new(12345, 2), // 123.45
|
|
currency: "EUR".to_string(),
|
|
foreign_amount: Some(Decimal::new(67890, 2)), // 678.90
|
|
foreign_currency: Some("USD".to_string()),
|
|
description: "Test transaction".to_string(),
|
|
counterparty_name: Some("Test Counterparty".to_string()),
|
|
counterparty_iban: Some("DE1234567890".to_string()),
|
|
};
|
|
|
|
let debug_str = format!("{:?}", tx);
|
|
assert!(debug_str.contains("internal_id"));
|
|
assert!(debug_str.contains("date"));
|
|
assert!(debug_str.contains("currency"));
|
|
assert!(debug_str.contains("foreign_currency"));
|
|
assert!(debug_str.contains("[REDACTED]"));
|
|
assert!(!debug_str.contains("123.45"));
|
|
assert!(!debug_str.contains("678.90"));
|
|
assert!(!debug_str.contains("Test transaction"));
|
|
assert!(!debug_str.contains("Test Counterparty"));
|
|
assert!(!debug_str.contains("DE1234567890"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_account_debug_masks_iban() {
|
|
let account = Account {
|
|
id: "123".to_string(),
|
|
iban: "DE1234567890".to_string(),
|
|
currency: "EUR".to_string(),
|
|
};
|
|
|
|
let debug_str = format!("{:?}", account);
|
|
assert!(debug_str.contains("id"));
|
|
assert!(debug_str.contains("currency"));
|
|
assert!(debug_str.contains("[REDACTED]"));
|
|
assert!(!debug_str.contains("DE1234567890"));
|
|
}
|
|
}
|