use crate::api_client::CimaClient;
use crate::models::{Medication, MedicationSummary};
use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
#[derive(Debug, Default, Clone)]
pub struct SearchMedicationsParams {
pub name: Option<String>,
pub laboratory: Option<String>,
pub active_ingredient_1: Option<String>,
pub active_ingredient_2: Option<String>,
pub active_ingredient_1_id: Option<i32>,
pub active_ingredient_2_id: Option<i32>,
pub national_code: Option<String>,
pub atc: Option<String>,
pub registration_number: Option<String>,
pub active_ingredient_count: Option<i32>,
pub black_triangle: Option<u8>,
pub orphan: Option<u8>,
pub biosimilar: Option<u8>,
pub substitutable_type: Option<u8>,
pub vmp: Option<String>,
pub commercialized: Option<u8>,
pub authorized: Option<u8>,
pub prescription: Option<u8>,
pub narcotic: Option<u8>,
pub psychotropic: Option<u8>,
pub narcotic_or_psychotropic: Option<u8>,
pub page: Option<u32>,
}
impl SearchMedicationsParams {
pub fn new() -> Self {
Self::default()
}
pub(crate) fn to_query_params(&self) -> Vec<(&str, String)> {
let mut params = Vec::new();
if let Some(ref v) = self.name {
params.push(("nombre", v.clone()));
}
if let Some(ref v) = self.laboratory {
params.push(("laboratorio", v.clone()));
}
if let Some(ref v) = self.active_ingredient_1 {
params.push(("practiv1", v.clone()));
}
if let Some(ref v) = self.active_ingredient_2 {
params.push(("practiv2", v.clone()));
}
if let Some(v) = self.active_ingredient_1_id {
params.push(("idpractiv1", v.to_string()));
}
if let Some(v) = self.active_ingredient_2_id {
params.push(("idpractiv2", v.to_string()));
}
if let Some(ref v) = self.national_code {
params.push(("cn", v.clone()));
}
if let Some(ref v) = self.atc {
params.push(("atc", v.clone()));
}
if let Some(ref v) = self.registration_number {
params.push(("nregistro", v.clone()));
}
if let Some(v) = self.active_ingredient_count {
params.push(("npactiv", v.to_string()));
}
if let Some(v) = self.black_triangle {
params.push(("triangulo", v.to_string()));
}
if let Some(v) = self.orphan {
params.push(("huerfano", v.to_string()));
}
if let Some(v) = self.biosimilar {
params.push(("biosimilar", v.to_string()));
}
if let Some(v) = self.substitutable_type {
params.push(("sust", v.to_string()));
}
if let Some(ref v) = self.vmp {
params.push(("vmp", v.clone()));
}
if let Some(v) = self.commercialized {
params.push(("comerc", v.to_string()));
}
if let Some(v) = self.authorized {
params.push(("autorizados", v.to_string()));
}
if let Some(v) = self.prescription {
params.push(("receta", v.to_string()));
}
if let Some(v) = self.narcotic {
params.push(("estupefaciente", v.to_string()));
}
if let Some(v) = self.psychotropic {
params.push(("psicotropo", v.to_string()));
}
if let Some(v) = self.narcotic_or_psychotropic {
params.push(("estuopsico", v.to_string()));
}
if let Some(v) = self.page {
params.push(("pagina", v.to_string()));
}
params
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TechnicalSheetQuery {
#[serde(rename = "seccion")]
pub section: String,
#[serde(rename = "texto")]
pub text: String,
#[serde(rename = "contiene")]
pub contains: u8,
}
impl CimaClient {
pub async fn get_medication(
&self,
registration_number: Option<&str>,
national_code: Option<&str>,
) -> Result<Medication> {
let mut params = Vec::new();
if let Some(nr) = registration_number {
params.push(("nregistro", nr.to_string()));
}
if let Some(cn) = national_code {
params.push(("cn", cn.to_string()));
}
if params.is_empty() {
anyhow::bail!("Must provide either registration_number or national_code");
}
self.get_with_params("medicamento", ¶ms)
.await
.context("Failed to get medication")
}
pub async fn search_medications(
&self,
params: &SearchMedicationsParams,
) -> Result<crate::models::PaginatedResponse<MedicationSummary>> {
let query_params = params.to_query_params();
self.get_with_params("medicamentos", &query_params)
.await
.context("Failed to search medications")
}
pub async fn search_in_technical_sheet(
&self,
queries: &[TechnicalSheetQuery],
) -> Result<Vec<MedicationSummary>> {
self.post("buscarEnFichaTecnica", queries)
.await
.context("Failed to search in technical sheet")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_search_params_to_query() {
let params = SearchMedicationsParams {
name: Some("Paracetamol".to_string()),
black_triangle: Some(1),
page: Some(2),
..Default::default()
};
let query = params.to_query_params();
assert_eq!(query.len(), 3);
assert!(
query
.iter()
.any(|(k, v)| k == &"nombre" && v == "Paracetamol")
);
assert!(query.iter().any(|(k, v)| k == &"triangulo" && v == "1"));
assert!(query.iter().any(|(k, v)| k == &"pagina" && v == "2"));
}
#[test]
fn test_technical_sheet_query_serialization() {
let query = TechnicalSheetQuery {
section: "4.1".to_string(),
text: "cáncer".to_string(),
contains: 1,
};
let json = serde_json::to_string(&query).unwrap();
assert!(json.contains("4.1"));
assert!(json.contains("cáncer"));
}
}