1use crate::{
4 client::DocarooClient,
5 error::Result,
6 models::{PricingRequest, PricingResponse},
7};
8
9#[derive(Debug, Clone)]
11pub struct PricingClient {
12 client: DocarooClient,
13}
14
15impl PricingClient {
16 pub(crate) fn new(client: DocarooClient) -> Self {
18 Self { client }
19 }
20
21 pub async fn get_in_network_rates(&self, request: PricingRequest) -> Result<PricingResponse> {
70 self.validate_pricing_request(&request)?;
72
73 let url = self.client.build_url("/pricing/in-network")?;
75
76 let response = self
78 .client
79 .http_client()
80 .post(url)
81 .json(&request)
82 .send()
83 .await?;
84
85 DocarooClient::handle_response(response).await
87 }
88
89 fn validate_pricing_request(&self, request: &PricingRequest) -> Result<()> {
91 use crate::error::DocarooError;
92
93 if request.npis.is_empty() {
95 return Err(DocarooError::InvalidRequest(
96 "At least one NPI must be provided".to_string(),
97 ));
98 }
99
100 if request.npis.len() > 10 {
101 return Err(DocarooError::InvalidRequest(
102 "Maximum 10 NPIs allowed per request".to_string(),
103 ));
104 }
105
106 for npi in &request.npis {
108 if npi.len() != 10 || !npi.chars().all(|c| c.is_ascii_digit()) {
109 return Err(DocarooError::InvalidRequest(format!(
110 "Invalid NPI format: '{}'. NPIs must be 10-digit numbers",
111 npi
112 )));
113 }
114 }
115
116 if request.condition_code.trim().is_empty() {
118 return Err(DocarooError::InvalidRequest(
119 "Condition code cannot be empty".to_string(),
120 ));
121 }
122
123 Ok(())
124 }
125}
126
127#[cfg(test)]
128mod tests {
129 use super::*;
130
131 #[test]
132 fn test_validate_pricing_request_valid() {
133 let client = DocarooClient::new("test-key");
134 let pricing_client = PricingClient::new(client);
135
136 let request = PricingRequest::builder()
137 .npis(vec!["1234567890".to_string()])
138 .condition_code("99214")
139 .build();
140
141 assert!(pricing_client.validate_pricing_request(&request).is_ok());
142 }
143
144 #[test]
145 fn test_validate_pricing_request_empty_npis() {
146 let client = DocarooClient::new("test-key");
147 let pricing_client = PricingClient::new(client);
148
149 let request = PricingRequest {
150 npis: vec![],
151 condition_code: "99214".to_string(),
152 plan_id: None,
153 code_type: None,
154 };
155
156 let result = pricing_client.validate_pricing_request(&request);
157 assert!(result.is_err());
158 assert!(result
159 .unwrap_err()
160 .to_string()
161 .contains("At least one NPI must be provided"));
162 }
163
164 #[test]
165 fn test_validate_pricing_request_too_many_npis() {
166 let client = DocarooClient::new("test-key");
167 let pricing_client = PricingClient::new(client);
168
169 let npis: Vec<String> = (0..11).map(|i| format!("{:010}", i)).collect();
170 let request = PricingRequest {
171 npis,
172 condition_code: "99214".to_string(),
173 plan_id: None,
174 code_type: None,
175 };
176
177 let result = pricing_client.validate_pricing_request(&request);
178 assert!(result.is_err());
179 assert!(result
180 .unwrap_err()
181 .to_string()
182 .contains("Maximum 10 NPIs allowed"));
183 }
184
185 #[test]
186 fn test_validate_pricing_request_invalid_npi_format() {
187 let client = DocarooClient::new("test-key");
188 let pricing_client = PricingClient::new(client);
189
190 let request = PricingRequest::builder()
191 .npis(vec!["123".to_string()]) .condition_code("99214")
193 .build();
194
195 let result = pricing_client.validate_pricing_request(&request);
196 assert!(result.is_err());
197 assert!(result.unwrap_err().to_string().contains("Invalid NPI format"));
198 }
199}