use chrono::NaiveDate;
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq, Eq)]
pub enum DocumentType {
#[serde(rename = "PASSPORT")]
Passport,
#[serde(rename = "BIRTH_CERTIFICATE")]
BirthCertificate,
#[serde(rename = "NATIONAL_ID")]
NationalId,
#[serde(rename = "DRIVERS_LICENSE")]
DriversLicense,
#[serde(rename = "VOTER_ID")]
VoterId,
#[serde(rename = "MILITARY_ID")]
MilitaryId,
#[serde(rename = "RESIDENCE_PERMIT")]
ResidencePermit,
#[serde(rename = "WORK_PERMIT")]
WorkPermit,
#[serde(other, rename = "OTHER")]
Other,
}
impl std::fmt::Display for DocumentType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DocumentType::Passport => write!(f, "PASSPORT"),
DocumentType::BirthCertificate => write!(f, "BIRTH_CERTIFICATE"),
DocumentType::NationalId => write!(f, "NATIONAL_ID"),
DocumentType::DriversLicense => write!(f, "DRIVERS_LICENSE"),
DocumentType::VoterId => write!(f, "VOTER_ID"),
DocumentType::MilitaryId => write!(f, "MILITARY_ID"),
DocumentType::ResidencePermit => write!(f, "RESIDENCE_PERMIT"),
DocumentType::WorkPermit => write!(f, "WORK_PERMIT"),
DocumentType::Other => write!(f, "OTHER"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct IdentityDocument {
pub document_type: DocumentType,
pub number: String,
pub issuing_country: Option<String>,
pub issuing_authority: Option<String>,
pub issue_date: Option<NaiveDate>,
pub expiry_date: Option<NaiveDate>,
pub verified: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_document_type_variants() {
let types = vec![
DocumentType::Passport,
DocumentType::BirthCertificate,
DocumentType::NationalId,
DocumentType::DriversLicense,
DocumentType::VoterId,
DocumentType::MilitaryId,
DocumentType::ResidencePermit,
DocumentType::WorkPermit,
DocumentType::Other,
];
for dt in &types {
let display = format!("{}", dt);
assert!(!display.is_empty(), "DocumentType Display should not be empty");
}
assert_eq!(format!("{}", DocumentType::Passport), "PASSPORT");
assert_eq!(format!("{}", DocumentType::DriversLicense), "DRIVERS_LICENSE");
assert_eq!(format!("{}", DocumentType::Other), "OTHER");
}
#[test]
fn test_document_serialization() {
let doc = IdentityDocument {
document_type: DocumentType::Passport,
number: "AB1234567".into(),
issuing_country: Some("US".into()),
issuing_authority: Some("State Dept".into()),
issue_date: Some(NaiveDate::from_ymd_opt(2020, 1, 15).unwrap()),
expiry_date: Some(NaiveDate::from_ymd_opt(2030, 1, 15).unwrap()),
verified: true,
};
let json = serde_json::to_string(&doc).expect("Serialization should succeed");
let deser: IdentityDocument = serde_json::from_str(&json).expect("Deserialization should succeed");
assert_eq!(deser.document_type, DocumentType::Passport);
assert_eq!(deser.number, "AB1234567");
assert_eq!(deser.issuing_country.as_deref(), Some("US"));
assert!(deser.verified);
assert_eq!(deser.issue_date, doc.issue_date);
assert_eq!(deser.expiry_date, doc.expiry_date);
}
}