Skip to main content

cima_rs/
models.rs

1use serde::{Deserialize, Serialize};
2
3/// Wrapper for paginated API responses
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct PaginatedResponse<T> {
6    #[serde(rename = "totalFilas")]
7    pub total_rows: u32,
8    #[serde(rename = "pagina")]
9    pub page: u32,
10    #[serde(rename = "tamanioPagina")]
11    pub page_size: u32,
12    #[serde(rename = "resultados")]
13    pub results: Vec<T>,
14}
15
16/// Authorization status of a medication or presentation
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct AuthorizationStatus {
19    /// Authorization date (Unix Epoch GMT+2:00)
20    #[serde(skip_serializing_if = "Option::is_none")]
21    pub aut: Option<i64>,
22    /// Suspension date (Unix Epoch GMT+2:00)
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub susp: Option<i64>,
25    /// Revocation date (Unix Epoch GMT+2:00)
26    #[serde(skip_serializing_if = "Option::is_none")]
27    pub rev: Option<i64>,
28}
29
30/// Generic item used in master data catalogs
31#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct MasterItem {
33    /// Numeric identifier
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub id: Option<i32>,
36    /// Alphanumeric identifier
37    #[serde(rename = "codigo", skip_serializing_if = "Option::is_none")]
38    pub code: Option<String>,
39    /// Name
40    #[serde(rename = "nombre")]
41    pub name: String,
42}
43
44/// Supply problem for a presentation
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct SupplyProblem {
47    /// National code
48    pub cn: String,
49    /// Presentation name
50    #[serde(rename = "nombre")]
51    pub name: String,
52    /// Start date (Unix Epoch GMT+2:00)
53    pub fini: i64,
54    /// Expected end date or resolution date (Unix Epoch GMT+2:00)
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub ffin: Option<i64>,
57    /// Observations
58    #[serde(rename = "observ", skip_serializing_if = "Option::is_none")]
59    pub observations: Option<String>,
60    /// Indicates if still active
61    #[serde(rename = "activo")]
62    pub active: bool,
63}
64
65/// Document section
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct Section {
68    /// Section number (up to 3 levels: "N.N.N")
69    #[serde(rename = "seccion")]
70    pub section: String,
71    /// Section title
72    #[serde(rename = "titulo")]
73    pub title: String,
74    /// Section order
75    #[serde(rename = "orden")]
76    pub order: i32,
77    /// Content in HTML format
78    #[serde(rename = "contenido", skip_serializing_if = "Option::is_none")]
79    pub content: Option<String>,
80}
81
82/// Document type
83#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
84#[repr(u8)]
85pub enum DocumentType {
86    /// Technical data sheet
87    #[serde(rename = "FichaTecnica")]
88    TechnicalSheet = 1,
89    /// Package leaflet
90    #[serde(rename = "Prospecto")]
91    PackageLeaflet = 2,
92    /// Public evaluation report
93    #[serde(rename = "InformePublico")]
94    PublicReport = 3,
95    /// Risk management plan
96    #[serde(rename = "PlanGestionRiesgos")]
97    RiskManagementPlan = 4,
98}
99
100/// Document associated with a medication
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct Document {
103    /// Document type
104    #[serde(rename = "tipo")]
105    pub doc_type: u8,
106    /// URL to access the document
107    pub url: String,
108    /// Indicates if available in HTML sections
109    #[serde(rename = "secc")]
110    pub has_sections: bool,
111    /// URL in HTML format (only if has_sections = true)
112    #[serde(rename = "urlHtml", skip_serializing_if = "Option::is_none")]
113    pub url_html: Option<String>,
114    /// Modification date (Unix Epoch GMT+2:00)
115    #[serde(rename = "fecha", skip_serializing_if = "Option::is_none")]
116    pub date: Option<i64>,
117}
118
119/// Safety or informative note
120#[derive(Debug, Clone, Serialize, Deserialize)]
121pub struct SafetyNote {
122    /// Note type (1: Safety Note)
123    #[serde(rename = "tipo")]
124    pub note_type: u8,
125    /// Note number
126    pub num: String,
127    /// Associated reference
128    #[serde(skip_serializing_if = "Option::is_none")]
129    pub r#ref: Option<String>,
130    /// Subject
131    #[serde(rename = "asunto")]
132    pub subject: String,
133    /// Publication date (Unix Epoch GMT+2:00)
134    #[serde(rename = "fecha")]
135    pub date: i64,
136    /// URL to access the note
137    pub url: String,
138}
139
140/// Informative material document
141#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct MaterialDocument {
143    /// Document title
144    #[serde(rename = "nombre")]
145    pub name: String,
146    /// Access URL
147    pub url: String,
148    /// Update date (Unix Epoch GMT+2:00)
149    #[serde(rename = "fecha")]
150    pub date: i64,
151}
152
153/// Safety informative material
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct SafetyMaterial {
156    /// List of documents for healthcare professionals
157    #[serde(rename = "listaDocsProfesional", default)]
158    pub professional_docs: Vec<MaterialDocument>,
159}
160
161/// Clinical description (VMP/VMPP)
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct ClinicalDescription {
164    /// VMP code
165    pub vmp: String,
166    /// VMP name
167    #[serde(rename = "vmpDesc")]
168    pub vmp_desc: String,
169    /// VMPP code
170    pub vmpp: String,
171    /// VMPP name
172    #[serde(rename = "vmppDesc")]
173    pub vmpp_desc: String,
174    /// Number of commercialized presentations
175    #[serde(rename = "presComerc")]
176    pub commercialized_presentations: i32,
177}
178
179/// ATC code
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct AtcCode {
182    /// ATC code
183    #[serde(rename = "codigo")]
184    pub code: String,
185    /// Descriptive name
186    #[serde(rename = "nombre")]
187    pub name: String,
188    /// ATC code level
189    #[serde(rename = "nivel")]
190    pub level: i32,
191}
192
193/// Active ingredient
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub struct ActiveIngredient {
196    /// Active ingredient ID
197    #[serde(skip_serializing_if = "Option::is_none")]
198    pub id: Option<i32>,
199    /// Identification code
200    #[serde(rename = "codigo", skip_serializing_if = "Option::is_none")]
201    pub code: Option<String>,
202    /// Name
203    #[serde(rename = "nombre")]
204    pub name: String,
205    /// Amount
206    #[serde(rename = "cantidad", skip_serializing_if = "Option::is_none")]
207    pub amount: Option<String>,
208    /// Unit
209    #[serde(rename = "unidad", skip_serializing_if = "Option::is_none")]
210    pub unit: Option<String>,
211    /// Display order
212    #[serde(rename = "orden", skip_serializing_if = "Option::is_none")]
213    pub order: Option<i32>,
214}
215
216/// Excipient
217#[derive(Debug, Clone, Serialize, Deserialize)]
218pub struct Excipient {
219    /// Excipient ID
220    #[serde(skip_serializing_if = "Option::is_none")]
221    pub id: Option<i32>,
222    /// Name
223    #[serde(rename = "nombre")]
224    pub name: String,
225    /// Amount
226    #[serde(rename = "cantidad", skip_serializing_if = "Option::is_none")]
227    pub amount: Option<String>,
228    /// Unit
229    #[serde(rename = "unidad", skip_serializing_if = "Option::is_none")]
230    pub unit: Option<String>,
231    /// Display order
232    #[serde(rename = "orden", skip_serializing_if = "Option::is_none")]
233    pub order: Option<i32>,
234}
235
236/// Medication photo
237#[derive(Debug, Clone, Serialize, Deserialize)]
238pub struct Photo {
239    /// Type: "materialas" (packaging material) or "formafarmac" (pharmaceutical form)
240    #[serde(rename = "tipo")]
241    pub photo_type: String,
242    /// Image URL
243    pub url: String,
244    /// Update date (Unix Epoch GMT+2:00)
245    #[serde(rename = "fecha", skip_serializing_if = "Option::is_none")]
246    pub date: Option<i64>,
247}
248
249/// Presentation of a medication (simplified view for listings)
250#[derive(Debug, Clone, Serialize, Deserialize)]
251pub struct PresentationSummary {
252    /// National code
253    pub cn: String,
254    /// Presentation name
255    #[serde(rename = "nombre")]
256    pub name: String,
257    /// Registration status
258    #[serde(rename = "estado")]
259    pub status: AuthorizationStatus,
260    /// Indicates if commercialized
261    #[serde(rename = "comerc")]
262    pub commercialized: bool,
263    /// Indicates if has supply problems
264    #[serde(skip_serializing_if = "Option::is_none")]
265    pub psum: Option<bool>,
266}
267
268/// Complete presentation
269#[derive(Debug, Clone, Serialize, Deserialize)]
270pub struct Presentation {
271    /// National code
272    pub cn: String,
273    /// Name
274    #[serde(rename = "nombre")]
275    pub name: String,
276    /// Status
277    #[serde(rename = "estado")]
278    pub status: AuthorizationStatus,
279    /// Indicates if commercialized
280    #[serde(rename = "comerc")]
281    pub commercialized: bool,
282    /// Indicates if has supply problems
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub psum: Option<bool>,
285}
286
287/// Medication (simplified view for listings)
288#[derive(Debug, Clone, Serialize, Deserialize)]
289pub struct MedicationSummary {
290    /// Registration number
291    pub nregistro: String,
292    /// Medication name
293    #[serde(rename = "nombre")]
294    pub name: String,
295    /// Holder laboratory
296    pub labtitular: String,
297    /// Registration status
298    #[serde(rename = "estado")]
299    pub status: AuthorizationStatus,
300    /// Prescription conditions
301    pub cpresc: String,
302    /// Indicates if has any commercialized presentation
303    #[serde(rename = "comerc", skip_serializing_if = "Option::is_none")]
304    pub commercialized: Option<bool>,
305    /// Indicates if requires prescription
306    #[serde(rename = "receta", skip_serializing_if = "Option::is_none")]
307    pub prescription_required: Option<bool>,
308    /// Indicates if affects driving
309    #[serde(rename = "conduc", skip_serializing_if = "Option::is_none")]
310    pub affects_driving: Option<bool>,
311    /// Indicates if has black triangle
312    #[serde(rename = "triangulo", skip_serializing_if = "Option::is_none")]
313    pub black_triangle: Option<bool>,
314    /// Indicates if orphan drug
315    #[serde(rename = "huerfano", skip_serializing_if = "Option::is_none")]
316    pub orphan: Option<bool>,
317    /// Indicates if biosimilar
318    #[serde(skip_serializing_if = "Option::is_none")]
319    pub biosimilar: Option<bool>,
320    /// Non-substitutable type
321    #[serde(rename = "nosustituible", skip_serializing_if = "Option::is_none")]
322    pub non_substitutable: Option<MasterItem>,
323    /// Indicates if has supply problems
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub psum: Option<bool>,
326    /// Indicates if registered by EMA
327    #[serde(skip_serializing_if = "Option::is_none")]
328    pub ema: Option<bool>,
329    /// Indicates if has notes
330    #[serde(rename = "notas", skip_serializing_if = "Option::is_none")]
331    pub has_notes: Option<bool>,
332    /// Indicates if has informative materials
333    #[serde(rename = "materialesInf", skip_serializing_if = "Option::is_none")]
334    pub has_materials: Option<bool>,
335    /// Associated documents
336    #[serde(default)]
337    pub docs: Vec<Document>,
338    /// Associated photos
339    #[serde(rename = "fotos", default)]
340    pub photos: Vec<Photo>,
341    /// Administration routes
342    #[serde(rename = "viasAdministracion", default)]
343    pub administration_routes: Vec<MasterItem>,
344    /// Pharmaceutical form
345    #[serde(rename = "formaFarmaceutica", skip_serializing_if = "Option::is_none")]
346    pub pharmaceutical_form: Option<MasterItem>,
347    /// Simplified pharmaceutical form
348    #[serde(
349        rename = "formaFarmaceuticaSimplificada",
350        skip_serializing_if = "Option::is_none"
351    )]
352    pub simplified_pharmaceutical_form: Option<MasterItem>,
353    /// Active ingredient dose
354    #[serde(skip_serializing_if = "Option::is_none")]
355    pub dosis: Option<String>,
356}
357
358/// Complete medication with all details
359#[derive(Debug, Clone, Serialize, Deserialize)]
360pub struct Medication {
361    /// Registration number
362    pub nregistro: String,
363    /// Medication name
364    #[serde(rename = "nombre")]
365    pub name: String,
366    /// Comma-separated list of active ingredients
367    pub pactivos: String,
368    /// Holder laboratory
369    pub labtitular: String,
370    /// Registration status
371    #[serde(rename = "estado")]
372    pub status: AuthorizationStatus,
373    /// Prescription conditions
374    pub cpresc: String,
375    /// Indicates if has any commercialized presentation
376    #[serde(rename = "comerc", skip_serializing_if = "Option::is_none")]
377    pub commercialized: Option<bool>,
378    /// Indicates if requires prescription
379    #[serde(rename = "receta", skip_serializing_if = "Option::is_none")]
380    pub prescription_required: Option<bool>,
381    /// Indicates if affects driving
382    #[serde(rename = "conduc", skip_serializing_if = "Option::is_none")]
383    pub affects_driving: Option<bool>,
384    /// Indicates if has black triangle
385    #[serde(rename = "triangulo", skip_serializing_if = "Option::is_none")]
386    pub black_triangle: Option<bool>,
387    /// Indicates if orphan drug
388    #[serde(rename = "huerfano", skip_serializing_if = "Option::is_none")]
389    pub orphan: Option<bool>,
390    /// Indicates if biosimilar
391    #[serde(skip_serializing_if = "Option::is_none")]
392    pub biosimilar: Option<bool>,
393    /// Indicates if registered by EMA
394    #[serde(skip_serializing_if = "Option::is_none")]
395    pub ema: Option<bool>,
396    /// Indicates if has supply problems
397    #[serde(skip_serializing_if = "Option::is_none")]
398    pub psum: Option<bool>,
399    /// Associated documents
400    #[serde(default)]
401    pub docs: Vec<Document>,
402    /// Associated photos
403    #[serde(rename = "fotos", default)]
404    pub photos: Vec<Photo>,
405    /// Indicates if has notes
406    #[serde(rename = "notas", skip_serializing_if = "Option::is_none")]
407    pub has_notes: Option<bool>,
408    /// Indicates if has informative materials
409    #[serde(rename = "materialesInf", skip_serializing_if = "Option::is_none")]
410    pub has_materials: Option<bool>,
411    /// ATC codes
412    #[serde(default)]
413    pub atcs: Vec<AtcCode>,
414    /// Active ingredients
415    #[serde(rename = "principiosActivos", default)]
416    pub active_ingredients: Vec<ActiveIngredient>,
417    /// Excipients
418    #[serde(rename = "excipientes", default)]
419    pub excipients: Vec<Excipient>,
420    /// Administration routes
421    #[serde(rename = "viasAdministracion", default)]
422    pub administration_routes: Vec<MasterItem>,
423    /// Non-substitutable type
424    #[serde(rename = "nosustituible", skip_serializing_if = "Option::is_none")]
425    pub non_substitutable: Option<MasterItem>,
426    /// Presentations
427    #[serde(rename = "presentaciones", default)]
428    pub presentations: Vec<PresentationSummary>,
429    /// Pharmaceutical form
430    #[serde(rename = "formaFarmaceutica", skip_serializing_if = "Option::is_none")]
431    pub pharmaceutical_form: Option<MasterItem>,
432    /// Simplified pharmaceutical form
433    #[serde(
434        rename = "formaFarmaceuticaSimplificada",
435        skip_serializing_if = "Option::is_none"
436    )]
437    pub simplified_pharmaceutical_form: Option<MasterItem>,
438    /// Active ingredient dose
439    #[serde(skip_serializing_if = "Option::is_none")]
440    pub dosis: Option<String>,
441}
442
443/// Change log record
444#[derive(Debug, Clone, Serialize, Deserialize)]
445pub struct ChangeRecord {
446    /// Medication registration number
447    pub nregistro: String,
448    /// Change date (Unix Epoch GMT+2:00)
449    #[serde(rename = "fecha")]
450    pub date: i64,
451    /// Change type: 1=New, 2=Deleted, 3=Modified
452    #[serde(rename = "tipoCambio")]
453    pub change_type: u8,
454    /// List of changes: "estado", "comerc", "prosp", "ft", "psum", "notasSeguridad", "matinf", "otros"
455    #[serde(rename = "cambios", default)]
456    pub changes: Vec<String>,
457}
458
459/// Master data type
460#[derive(Debug, Clone, Copy, PartialEq, Eq)]
461#[repr(u8)]
462pub enum MasterDataType {
463    ActiveIngredients = 1,
464    PharmaceuticalForms = 3,
465    AdministrationRoutes = 4,
466    Laboratories = 6,
467    AtcCodes = 7,
468    ActiveIngredientsSNOMED = 11,
469    SimplifiedPharmaceuticalFormsSNOMED = 13,
470    AdministrationRoutesSNOMED = 14,
471    Medications = 15,
472    CommercializedMedicationsSNOMED = 16,
473}
474
475impl MasterDataType {
476    pub fn as_u8(self) -> u8 {
477        self as u8
478    }
479}