1use bon::Builder;
4use chrono::{DateTime, Utc};
5use serde::{Deserialize, Serialize};
6use std::collections::HashMap;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(rename_all = "SCREAMING-KEBAB-CASE")]
11pub enum CodeType {
12 #[serde(rename = "CPT")]
14 Cpt,
15 #[serde(rename = "NDC")]
17 Ndc,
18 #[serde(rename = "HCPCS")]
20 Hcpcs,
21 #[serde(rename = "RC")]
23 Rc,
24 #[serde(rename = "ICD")]
26 Icd,
27 #[serde(rename = "MS-DRG")]
29 MsDrg,
30 #[serde(rename = "R-DRG")]
32 RDrg,
33 #[serde(rename = "S-DRG")]
35 SDrg,
36 #[serde(rename = "APS-DRG")]
38 ApsDrg,
39 #[serde(rename = "AP-DRG")]
41 ApDrg,
42 #[serde(rename = "APR-DRG")]
44 AprDrg,
45 #[serde(rename = "APC")]
47 Apc,
48 #[serde(rename = "LOCAL")]
50 Local,
51 #[serde(rename = "EAPG")]
53 Eapg,
54 #[serde(rename = "HIPPS")]
56 Hipps,
57 #[serde(rename = "CDT")]
59 Cdt,
60 #[serde(rename = "CSTM-ALL")]
62 CstmAll,
63}
64
65impl Default for CodeType {
66 fn default() -> Self {
67 Self::Cpt
68 }
69}
70
71#[derive(Debug, Clone, Serialize, Builder)]
73#[serde(rename_all = "camelCase")]
74pub struct PricingRequest {
75 #[builder(into)]
78 pub npis: Vec<String>,
79
80 #[builder(into)]
82 pub condition_code: String,
83
84 #[serde(skip_serializing_if = "Option::is_none")]
86 #[builder(into)]
87 pub plan_id: Option<String>,
88
89 #[serde(skip_serializing_if = "Option::is_none")]
91 pub code_type: Option<CodeType>,
92}
93
94#[derive(Debug, Clone, Serialize, Builder)]
96#[serde(rename_all = "camelCase")]
97pub struct LikelihoodRequest {
98 #[builder(into)]
100 pub npis: Vec<String>,
101
102 #[builder(into)]
104 pub condition_code: String,
105
106 #[builder(into)]
108 pub code_type: String,
109}
110
111#[derive(Debug, Clone, Deserialize)]
113pub struct PricingResponse {
114 pub data: HashMap<String, Vec<RateData>>,
116 pub meta: PricingMeta,
118}
119
120#[derive(Debug, Clone, Deserialize)]
122pub struct LikelihoodResponse {
123 pub data: HashMap<String, LikelihoodData>,
125 pub meta: LikelihoodMeta,
127}
128
129#[derive(Debug, Clone, Deserialize)]
131#[serde(rename_all = "camelCase")]
132pub struct RateData {
133 pub code: String,
135 pub code_type: String,
137 pub negotiated_type: String,
139 pub min_rate: f64,
141 pub max_rate: f64,
143 pub avg_rate: f64,
145 pub instances: u32,
147}
148
149#[derive(Debug, Clone, Deserialize)]
151#[serde(rename_all = "camelCase")]
152pub struct LikelihoodData {
153 pub code: String,
155 pub code_type: String,
157 pub likelihood: f64,
159}
160
161#[derive(Debug, Clone, Deserialize)]
163#[serde(rename_all = "camelCase")]
164pub struct PricingMeta {
165 pub plan_id: String,
167 pub payer: String,
169 pub request_id: String,
171 pub timestamp: DateTime<Utc>,
173 pub processing_time_ms: u32,
175 pub in_network_records_count: u32,
177}
178
179#[derive(Debug, Clone, Deserialize)]
181#[serde(rename_all = "camelCase")]
182pub struct LikelihoodMeta {
183 pub request_id: String,
185 pub timestamp: DateTime<Utc>,
187 pub processing_time_ms: u32,
189 pub out_of_network_records_count: u32,
191}
192
193#[derive(Debug, Clone, Deserialize)]
195#[serde(rename_all = "camelCase")]
196pub struct ErrorResponse {
197 pub error: String,
199 pub message: String,
201 #[serde(skip_serializing_if = "Option::is_none")]
203 pub details: Option<serde_json::Value>,
204 #[serde(skip_serializing_if = "Option::is_none")]
206 pub request_id: Option<String>,
207 #[serde(skip_serializing_if = "Option::is_none")]
209 pub timestamp: Option<DateTime<Utc>>,
210}
211
212
213#[cfg(test)]
214mod tests {
215 use super::*;
216
217 #[test]
218 fn test_pricing_request_builder() {
219 let request = PricingRequest::builder()
220 .npis(vec![String::from("1043566623"), String::from("1972767655")])
221 .condition_code("99214")
222 .plan_id("942404110")
223 .code_type(CodeType::Cpt)
224 .build();
225
226 assert_eq!(request.npis.len(), 2);
227 assert_eq!(request.condition_code, "99214");
228 assert_eq!(request.plan_id, Some("942404110".to_string()));
229 assert_eq!(request.code_type, Some(CodeType::Cpt));
230 }
231
232 #[test]
233 fn test_likelihood_request_builder() {
234 let request = LikelihoodRequest::builder()
235 .npis(vec!["1487648176".to_string()])
236 .condition_code("99214")
237 .code_type("CPT")
238 .build();
239
240 assert_eq!(request.npis.len(), 1);
241 assert_eq!(request.condition_code, "99214");
242 assert_eq!(request.code_type, "CPT");
243 }
244
245 #[test]
246 fn test_code_type_serialization() {
247 let code_type = CodeType::Cpt;
248 let json = serde_json::to_string(&code_type).unwrap();
249 assert_eq!(json, r#""CPT""#);
250
251 let deserialized: CodeType = serde_json::from_str(&json).unwrap();
252 assert_eq!(deserialized, CodeType::Cpt);
253 }
254}