use crate::{
client::DocarooClient,
error::Result,
models::{PricingRequest, PricingResponse},
};
#[derive(Debug, Clone)]
pub struct PricingClient {
client: DocarooClient,
}
impl PricingClient {
pub(crate) fn new(client: DocarooClient) -> Self {
Self { client }
}
pub async fn get_in_network_rates(&self, request: PricingRequest) -> Result<PricingResponse> {
self.validate_pricing_request(&request)?;
let url = self.client.build_url("/pricing/in-network")?;
let response = self
.client
.http_client()
.post(url)
.json(&request)
.send()
.await?;
DocarooClient::handle_response(response).await
}
fn validate_pricing_request(&self, request: &PricingRequest) -> Result<()> {
use crate::error::DocarooError;
if request.npis.is_empty() {
return Err(DocarooError::InvalidRequest(
"At least one NPI must be provided".to_string(),
));
}
if request.npis.len() > 10 {
return Err(DocarooError::InvalidRequest(
"Maximum 10 NPIs allowed per request".to_string(),
));
}
for npi in &request.npis {
if npi.len() != 10 || !npi.chars().all(|c| c.is_ascii_digit()) {
return Err(DocarooError::InvalidRequest(format!(
"Invalid NPI format: '{}'. NPIs must be 10-digit numbers",
npi
)));
}
}
if request.condition_code.trim().is_empty() {
return Err(DocarooError::InvalidRequest(
"Condition code cannot be empty".to_string(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validate_pricing_request_valid() {
let client = DocarooClient::new("test-key");
let pricing_client = PricingClient::new(client);
let request = PricingRequest::builder()
.npis(vec!["1234567890".to_string()])
.condition_code("99214")
.build();
assert!(pricing_client.validate_pricing_request(&request).is_ok());
}
#[test]
fn test_validate_pricing_request_empty_npis() {
let client = DocarooClient::new("test-key");
let pricing_client = PricingClient::new(client);
let request = PricingRequest {
npis: vec![],
condition_code: "99214".to_string(),
plan_id: None,
code_type: None,
};
let result = pricing_client.validate_pricing_request(&request);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("At least one NPI must be provided"));
}
#[test]
fn test_validate_pricing_request_too_many_npis() {
let client = DocarooClient::new("test-key");
let pricing_client = PricingClient::new(client);
let npis: Vec<String> = (0..11).map(|i| format!("{:010}", i)).collect();
let request = PricingRequest {
npis,
condition_code: "99214".to_string(),
plan_id: None,
code_type: None,
};
let result = pricing_client.validate_pricing_request(&request);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Maximum 10 NPIs allowed"));
}
#[test]
fn test_validate_pricing_request_invalid_npi_format() {
let client = DocarooClient::new("test-key");
let pricing_client = PricingClient::new(client);
let request = PricingRequest::builder()
.npis(vec!["123".to_string()]) .condition_code("99214")
.build();
let result = pricing_client.validate_pricing_request(&request);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Invalid NPI format"));
}
}