#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BRCode {
pub payload_format_indicator: String,
pub point_of_initiation_method: Option<String>,
pub merchant_account_info: MerchantAccountInfo,
pub merchant_category_code: String,
pub transaction_currency: String,
pub transaction_amount: Option<String>,
pub country_code: String,
pub merchant_name: String,
pub merchant_city: String,
pub additional_data: Option<AdditionalData>,
pub crc16: String,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct MerchantAccountInfo {
pub gui: String,
pub pix_key: String,
pub description: Option<String>,
pub url: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct AdditionalData {
pub bill_number: Option<String>,
pub mobile_number: Option<String>,
pub store_label: Option<String>,
pub loyalty_number: Option<String>,
pub reference_label: Option<String>,
pub customer_label: Option<String>,
pub terminal_label: Option<String>,
pub purpose_of_transaction: Option<String>,
pub additional_consumer_data_request: Option<String>,
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum PixKeyType {
Uuid,
Email,
Phone,
Cpf,
Cnpj,
Random,
}
#[derive(Debug, Clone, PartialEq)]
pub struct EmvField {
pub tag: String,
pub length: usize,
pub value: String,
}
impl BRCode {
pub fn is_static(&self) -> bool {
self.point_of_initiation_method.as_deref() == Some("11")
}
pub fn is_dynamic(&self) -> bool {
self.point_of_initiation_method.as_deref() == Some("12")
}
pub fn pix_key_type(&self) -> PixKeyType {
classify_pix_key(&self.merchant_account_info.pix_key)
}
pub fn has_amount(&self) -> bool {
self.transaction_amount.is_some()
}
}
pub fn classify_pix_key(key: &str) -> PixKeyType {
if key.len() == 36 && key.chars().nth(8) == Some('-') && key.chars().nth(13) == Some('-') {
return PixKeyType::Uuid;
}
if key.contains('@') && key.contains('.') {
return PixKeyType::Email;
}
if key.starts_with("+55") && key.len() >= 13 {
return PixKeyType::Phone;
}
if key.len() == 11 && key.chars().all(|c| c.is_ascii_digit()) {
return PixKeyType::Cpf;
}
if key.len() == 14 && key.chars().all(|c| c.is_ascii_digit()) {
return PixKeyType::Cnpj;
}
PixKeyType::Random
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_pix_key_classification() {
assert_eq!(classify_pix_key("123e4567-e89b-12d3-a456-426614174000"), PixKeyType::Uuid);
assert_eq!(classify_pix_key("user@example.com"), PixKeyType::Email);
assert_eq!(classify_pix_key("+5511999999999"), PixKeyType::Phone);
assert_eq!(classify_pix_key("12345678901"), PixKeyType::Cpf);
assert_eq!(classify_pix_key("12345678000195"), PixKeyType::Cnpj);
assert_eq!(classify_pix_key("randomkey123"), PixKeyType::Random);
}
}