Implémentation du parsing des données issues de la lecture de la carte CPS (SSV_LireCartePS) #77

Open
florian_briand wants to merge 6 commits from feat/38-fsv-lire-carte-ps-parsing into feat/38-fsv-lire-config-parsing
4 changed files with 522 additions and 21 deletions
Showing only changes of commit c37b7f241d - Show all commits

View File

@ -58,6 +58,10 @@ pub enum DataGroup {
LireCartePS_Group1_Holder( LireCartePS_Group1_Holder(
#[deku(reader = "read_with_size(deku::reader, data_size as usize)")] #[deku(reader = "read_with_size(deku::reader, data_size as usize)")]
groups::ssv_lire_carte_ps::group_1_holder::Holder), groups::ssv_lire_carte_ps::group_1_holder::Holder),
#[deku(id = 2)]
LireCartePS_Group2_Situation(
#[deku(reader = "read_with_size(deku::reader, data_size as usize)")]
groups::ssv_lire_carte_ps::group_2_situation::Situation),
#[deku(id = 60)] #[deku(id = 60)]
LireConfig_Group60_ConfigHeader( LireConfig_Group60_ConfigHeader(
#[deku(reader = "read_with_size(deku::reader, data_size as usize)")] #[deku(reader = "read_with_size(deku::reader, data_size as usize)")]

View File

@ -21,6 +21,16 @@ where
.map_err(|e| DekuError::Parse(e.to_string().into())) .map_err(|e| DekuError::Parse(e.to_string().into()))
} }
/// # Extract raw bytes from a DataField, through a Vec<u8>
/// This function is used as deku map function to extract raw bytes
/// from a DataField
fn map_raw_from_data_field<T>(data_field: DataField) -> Result<T, DekuError>
where
T: From<Vec<u8>>,
{
Ok(data_field.data.into())
}
/// # Extract an enum id from a string /// # Extract an enum id from a string
/// Deku enums only supports numbers as id, and we usually extract strings /// Deku enums only supports numbers as id, and we usually extract strings
/// from data fields. This function is used as a context function to convert /// from data fields. This function is used as a context function to convert
@ -47,11 +57,11 @@ struct DataField {
#[deku_derive(DekuRead)] #[deku_derive(DekuRead)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
/// # Numeric string /// # Data field: Numeric string (x CN)
/// TODO: check if all the characters are numeric /// TODO: check if all the characters are numeric
pub struct NumericString( pub struct NumericString(
#[deku(map = "map_from_data_field")] #[deku(map = "map_from_data_field")]
String pub String
); );
impl From<&str> for NumericString { impl From<&str> for NumericString {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
@ -61,9 +71,10 @@ impl From<&str> for NumericString {
#[deku_derive(DekuRead)] #[deku_derive(DekuRead)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
/// # Data field: Alphanumeric string (x CA/CE)
pub struct AlphaNumericString( pub struct AlphaNumericString(
#[deku(map = "map_from_data_field")] #[deku(map = "map_from_data_field")]
String pub String
); );
impl From<&str> for AlphaNumericString { impl From<&str> for AlphaNumericString {
fn from(s: &str) -> Self { fn from(s: &str) -> Self {
@ -71,6 +82,22 @@ impl From<&str> for AlphaNumericString {
} }
} }
#[deku_derive(DekuRead)]
#[derive(Debug, Clone, PartialEq)]
/// # Data field: Raw bytes (x CB)
pub struct RawBytes(
#[deku(map = "map_raw_from_data_field")]
pub Vec<u8>
);
#[deku_derive(DekuRead)]
#[derive(Debug, Clone, PartialEq)]
/// # Data field: Raw byte (1 CB)
pub struct RawByte(
#[deku(map = "|x: DataField| -> Result<u8, DekuError> { Ok(x.data[0]) }")]
pub u8
);
#[deku_derive(DekuRead)] #[deku_derive(DekuRead)]
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
#[deku(endian = "big")] #[deku(endian = "big")]

View File

@ -1,15 +1,14 @@
//! # Structures de parsing des données de la fonction SSV_LireCartePS //! # Structures de parsing des données de la fonction SSV_LireCartePS
#![allow(clippy::explicit_auto_deref)] // False positive on ctx attributes when using extract_enum_id_from_str
use deku::deku_derive; use deku::deku_derive;
use crate::fsv_parsing::groups::NumericString; use crate::fsv_parsing::groups::{ extract_enum_id_from_str, AlphaNumericString, NumericString, RawByte };
/// # Titulaire /// # Titulaire
/// 1 occurence /// 1 occurence
pub mod group_1_holder { pub mod group_1_holder {
use crate::fsv_parsing::groups::{ extract_enum_id_from_str, AlphaNumericString };
use super::*; use super::*;
/// Groupe 1 - Titulaire /// Groupe 1 - Titulaire
@ -17,24 +16,24 @@ pub mod group_1_holder {
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct Holder { pub struct Holder {
#[deku(temp)] #[deku(temp)]
card_type_raw: NumericString, card_type_raw: NumericString, // Champ 1 : Type de carte PS (2 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*card_type_raw.0, 255)")] #[deku(ctx = "extract_enum_id_from_str::<u8>(&*card_type_raw.0, 255)")]
pub card_type: CardPSType, pub card_type: CardPSType,
#[deku(temp)] #[deku(temp)]
national_id_type_raw: NumericString, national_id_type_raw: NumericString, // Champ 2 : Type didentification nationale (1 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*national_id_type_raw.0, 255)")] #[deku(ctx = "extract_enum_id_from_str::<u8>(&*national_id_type_raw.0, 255)")]
pub national_id_type: NationalIDType, pub national_id_type: NationalIDType,
// TODO: handle national_id depending on national_id_type // TODO: handle national_id depending on national_id_type
pub national_id: AlphaNumericString, // /!\ CE and not CA pub national_id: AlphaNumericString, // /!\ CE and not CA - Champ 3 : N° didentification nationale (8-30 CE)
pub national_id_key: AlphaNumericString, pub national_id_key: AlphaNumericString, // Champ 4 : Clé du N° didentification nationale (1 CN)
#[deku(temp)] #[deku(temp)]
civility_code_raw: NumericString, civility_code_raw: NumericString, // Champ 5 : Code civilité (2 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*civility_code_raw.0, 255)")] #[deku(ctx = "extract_enum_id_from_str::<u8>(&*civility_code_raw.0, 255)")]
pub civility_code: CivilityCode, pub civility_code: CivilityCode,
pub holder_lastname: AlphaNumericString, // /!\ CE and not CA pub holder_lastname: AlphaNumericString, // /!\ CE and not CA - Champ 6 : Nom du PS (27 CE)
pub holder_firstname: AlphaNumericString, // /!\ CE and not CA pub holder_firstname: AlphaNumericString, // /!\ CE and not CA - Champ 7 : Prénom du PS (27 CE)
#[deku(temp)] #[deku(temp)]
category_card_size: u8, category_card_size: u8, // Champ 8 : Catégorie Carte (1 CA)
pub category_card: CategoryCard, pub category_card: CategoryCard,
} }
@ -180,10 +179,432 @@ pub mod group_1_holder {
} }
} }
/// # Situation
/// 1-16 occurences
pub mod group_2_situation {
use super::*;
/// Groupe 2 - Situation du PS
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
pub struct Situation {
pub id: RawByte, // Champ 1 : N° logique de la situation de facturation du PS (1 CB)
#[deku(temp)]
practice_mode_raw: NumericString, // Champ 2 : Mode dexercice (2 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*practice_mode_raw.0, 255)")]
pub practice_mode: PracticeMode,
// #[deku(temp)]
pub practice_status_raw: NumericString, // Champ 3 : Statut dexercice (3 CN)
// #[deku(ctx = "extract_enum_id_from_str::<u8>(&*practice_status_raw.0, 255)")]
// pub practice_status: PracticeStatus,
#[deku(temp)]
activity_sector_raw: NumericString, // Champ 4 : Secteur dactivité (3 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*activity_sector_raw.0, 255)")]
pub activity_sector: ActivitySector,
#[deku(temp)]
structure_id_type_raw: NumericString, // Champ 5 : Type didentification structure (1 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*structure_id_type_raw.0, 255)")]
pub structure_id_type: StructureIDType,
pub structure_id: AlphaNumericString, // Champ 6 : N° didentification structure (14 CA)
pub structure_id_key: NumericString, // Champ 7 : Clé du n° didentification structure (1 CN)
pub structure_name: AlphaNumericString, // Champ 8 : Raison sociale structure (40 CE)
pub ps_billing_number: NumericString, // Champ 9 : N° didentification de facturation du PS (8 CN)
pub ps_billing_number_key: NumericString, // Champ 10 : Clé du n° didentification de facturation du PS (1 CN)
pub ps_replacement_number: AlphaNumericString, // Champ 11 : N° didentification du PS remplaçant (30 CA) -- TODO OPTIONNEL
pub ps_replacement_number_key: NumericString, // Champ 12 : Clé du n° didentification du PS remplaçant (1 CN) -- TODO OPTIONNEL
#[deku(temp)]
convention_code_raw: NumericString, // Champ 13 : Code conventionnel (1 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*convention_code_raw.0, 255)")]
pub convention_code: ConventionCode,
#[deku(temp)]
specialty_code_raw: NumericString, // Champ 14 : Code spécialité (2 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*specialty_code_raw.0, 255)")]
pub specialty_code: SpecialtyCode,
// #[deku(temp)]
pub rate_zone_code_raw: NumericString, // Champ 15 : Code zone tarifaire (2 CN)
// #[deku(ctx = "extract_enum_id_from_str::<u8>(&*rate_zone_code_raw.0, 255)")]
// pub rate_zone_code: RateZoneCode, // CF p53-55 - Attribution complexe, dépendant du practice_status, du specialty_code et du convention_code
#[deku(temp)]
ik_zone_code_raw: NumericString, // Champ 16 : Code zone IK - Indemnité kilométrique (2 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*ik_zone_code_raw.0, 255)")]
pub ik_zone_code: IkZoneCode,
#[deku(temp)]
approval_code_1_raw: NumericString, // Champ 17 : Code agrément 1 (1 CN)
#[deku(ctx = "extract_enum_id_from_str::<u8>(&*approval_code_1_raw.0, 255)")]
pub approval_code_1: ApprovalCode,
pub approval_code_2_raw: NumericString, // Champ 18 : Code agrément 2 (1 CN) - Non utilisé pour le moment
pub approval_code_3_raw: NumericString, // Champ 19 : Code agrément 3 (1 CN) - Non utilisé pour le moment
pub invoice_signature_permission: NumericString, // Champ 20 : Habilitation à signer une facture (1 CN)
pub lot_signature_permission: NumericString, // Champ 21 : Habilitation à signer un lot (1 CN)
}
// Fields
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Mode d'exercice
pub enum PracticeMode {
#[deku(id = 0)]
Liberal, // Libéral, exploitant, commerçant
#[deku(id = 1)]
Salarie,
#[deku(id = 4)]
Remplacant,
#[deku(id = 7)]
Benevole,
}
//
// #[deku_derive(DekuRead)]
// #[derive(Debug, PartialEq)]
// #[deku(ctx = "id: u8", id = "id")]
// /// Statut d'exercice
// pub enum PracticeStatus {
// // Cf. TAB-Statuts géré par lANS
// }
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Secteur d'activité
pub enum ActivitySector {
#[deku(id = 10)]
EtablissementPublicDeSante, // Etablissement Public de santé
#[deku(id = 11)]
HopitauxMilitaires, // Hôpitaux Militaires
#[deku(id = 16)]
EtablissementPrivePSPH, // Etablissement Privé PSPH
#[deku(id = 17)]
EtablissementPriveNonPSPH, // Etablissement Privé Non PSPH
#[deku(id = 25)]
DispensaireDeSoins, // Dispensaire de soins
#[deku(id = 26)]
AutresStructuresDeSoinsArmee, // Autres structures de soins relevant du Service de santé des armées
#[deku(id = 31)]
CabinetIndividuel, // Cabinet individuel
#[deku(id = 32)]
CabinetDeGroupe, // Cabinet de Groupe
#[deku(id = 33)]
ExerciceEnSociete, // Exercice en Société
#[deku(id = 34)]
SecteurPrivePHTempsPlein, // Secteur privé PH temps plein
#[deku(id = 35)]
TransportSanitaire, // Transport sanitaire
#[deku(id = 37)]
EntrepriseDInterim, // Entreprise d'intérim
#[deku(id = 41)]
EtablissementDeSoinsEtPrevention, // Etablissement de Soins et Prévention
#[deku(id = 42)]
PreventionEtSoinsEnEntreprise, // Prévention. Et Soins en Entreprise
#[deku(id = 43)]
SanteScolaireEtUniversitaire, // Santé scolaire & universitaire
#[deku(id = 44)]
RecrutementEtGestionRH, // Recrutement & gestion RH
#[deku(id = 45)]
PMIPlanificationFamiliale, // P.M.I. Planification familiale
#[deku(id = 51)]
EtablissementPourHandicapes, // Etablissement pour Handicapés
#[deku(id = 52)]
ComMarketingConsultingMedia, // Com/Marketing/Consulting/Media
#[deku(id = 53)]
EtablissementPersonnesAgees, // Etablissement Personnes Agées
#[deku(id = 54)]
EtablissementAideALaFamille, // Etablissement Aide à la famille
#[deku(id = 55)]
EtablissementDEnseignement, // Etablissement d'enseignement
#[deku(id = 56)]
EtablissementsDeProtectionDeLEnfance, // Etablissements de protection de l'enfance
#[deku(id = 57)]
EtablissementsDHebergementEtDeReadaptation, // Etablissements d'hébergement et de réadaptation
#[deku(id = 58)]
Recherche, // Recherche
#[deku(id = 61)]
AssurancePrivee, // Assurance Privée
#[deku(id = 62)]
OrganismeDeSecuriteSociale, // Organisme de Sécurité Sociale
#[deku(id = 65)]
MinistereEtServicesDeconcentres, // Ministère & Serv. Déconcentrés
#[deku(id = 66)]
CollectivitesTerritoriales, // Collectivités Territoriales
#[deku(id = 68)]
AssoEtOrgaHumanitaire, // Asso et orga humanitaire
#[deku(id = 71)]
LABM, // LABM
#[deku(id = 75)]
AutreEtablissementSanitaire, // Autre établissement Sanitaire
#[deku(id = 81)]
ProdEtComGrosBienMed, // Prod. & Com. Gros Bien Med.
#[deku(id = 85)]
CommDetailDeBiensMedicaux, // Comm. Détail de biens médicaux
#[deku(id = 86)]
PharmacieDOfficine, // Pharmacie d'officine
#[deku(id = 87)]
CentreDeDialyse, // Centre de dialyse
#[deku(id = 88)]
ParaPharmacie, // Para-pharmacie
#[deku(id = 91)]
AutreSecteurDActivite, // Autre secteur d'activité
#[deku(id = 92)]
SecteurNonDefini, // Secteur non défini
#[deku(id = 93)]
CentreAntiCancer, // Centre anti-cancer
#[deku(id = 94)]
CentreDeTransfusionSanguine, // Centre de transfusion sanguine
#[deku(id = 95)]
ChaineDuMedicament, // Répart. Distrib. Fab. Exploit. Import Médicaments
#[deku(id = 96)]
IncendiesEtSecours, // Incendies et secours
#[deku(id = 97)]
EntreprisesIndustriellesNonPharma, // Entreprises industrielles et tertiaires hors industries pharmaceutiques
#[deku(id = 98)]
EntiteDUnTOM, // Entité d'un TOM
#[deku(id = 99)]
ChaineDuDispositifMedical, // Fab. Exploit. Import. Médicaments et Dispositifs Médicaux
}
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Type d'identification structure
pub enum StructureIDType {
#[deku(id = 0)]
ADELICabinet, // Id Cabinet ADELI
#[deku(id = 1)]
FINESS, // N° FINESS
#[deku(id = 2)]
SIREN, // N° SIREN
#[deku(id = 3)]
SIRET, // N° SIRET
#[deku(id = 4)]
RPPSCabinet, // Id Cabinet RPPS
}
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Code conventionnel
/// Dictionnaire des données FSV, p37
pub enum ConventionCode {
#[deku(id = 0)]
NonConventionne,
#[deku(id = 1)]
Conventionne,
#[deku(id = 2)]
ConventionneAvecDepassement,
#[deku(id = 3)]
ConventionneAvecHonorairesLibres,
}
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Code spécialité
/// Dictionnaire des données FSV, p43
pub enum SpecialtyCode {
#[deku(id = 1)]
MedecineGenerale, // Médecine générale
#[deku(id = 2)]
AnesthesieReanimation, // Anesthésie-Réanimation
#[deku(id = 3)]
Cardiologie, // Cardiologie
#[deku(id = 4)]
ChirurgieGenerale, // Chirurgie Générale
#[deku(id = 5)]
DermatoVenerologie, // Dermatologie et Vénérologie
#[deku(id = 6)]
Radiologie, // Radiologie
#[deku(id = 7)]
GynecologieObstetrique, // Gynécologie obstétrique
#[deku(id = 8)]
GastroEnterologieHepatologie, // Gastro-Entérologie et Hépatologie
#[deku(id = 9)]
MedecineInterne, // Médecine interne
#[deku(id = 10)]
NeuroChirurgie, // Neuro-Chirurgie
#[deku(id = 11)]
OtoRhinoLaryngologie, // Oto-Rhino-Laryngologie
#[deku(id = 12)]
Pediatrie, // Pédiatrie
#[deku(id = 13)]
Pneumologie, // Pneumologie
#[deku(id = 14)]
Rhumatologie, // Rhumatologie
#[deku(id = 15)]
Ophtalmologie, // Ophtalmologie
#[deku(id = 16)]
ChirurgieUrologique, // Chirurgie urologique
#[deku(id = 17)]
NeuroPsychiatrie, // Neuro-Psychiatrie
#[deku(id = 18)]
Stomatologie, // Stomatologie
#[deku(id = 19)]
ChirurgienDentiste, // Chirurgien dentiste
#[deku(id = 20)]
ReanimationMedicale, // Réanimation médicale
#[deku(id = 21)]
SageFemme, // Sage-femme
#[deku(id = 22)]
SpécialisteEnMGDiplome, // Spécialiste en médecine générale avec diplôme
#[deku(id = 23)]
SpécialisteEnMGReconnu, // Spécialiste en médecine générale reconnu par lOrdre
#[deku(id = 24)]
Infirmier, // Infirmier
#[deku(id = 25)]
Psychologue, // Psychologue
#[deku(id = 26)]
MasseurKinesitherapeute, // Masseur Kinésithérapeute
#[deku(id = 27)]
PedicurePodologue, // Pédicure Podologue
#[deku(id = 28)]
Orthophoniste, // Orthophoniste
#[deku(id = 29)]
Orthoptiste, // Orthoptiste
#[deku(id = 30)]
LaboAnalysesMedicales, // Laboratoire d'analyses médicales
#[deku(id = 31)]
ReeducationReadaptationFonctionnelle, // Rééducation Réadaptation fonctionnelle
#[deku(id = 32)]
Neurologie, // Neurologie
#[deku(id = 33)]
Psychiatrie, // Psychiatrie
#[deku(id = 34)]
Geriatrie, // Gériatrie
#[deku(id = 35)]
Nephrologie, // Néphrologie
#[deku(id = 36)]
ChirurgieDentaireSpecialiteODF, // Chirurgie Dentaire spécialité O.D.F
#[deku(id = 37)]
AnatomoCytoPathologie, // Anatomo-Cyto-Pathologie
#[deku(id = 38)]
MedecinBiologiste, // Médecin biologiste
#[deku(id = 39)]
LaboPolyvalent, // Laboratoire polyvalent
#[deku(id = 40)]
LaboAnatomoCytoPathologique, // Laboratoire danatomo-cyto-pathologique
#[deku(id = 41)]
ChirurgieOrthopediqueTraumatologie, // Chirurgie Orthopédique et Traumatologie
#[deku(id = 42)]
EndocrinologieMetabolisme, // Endocrinologie et Métabolisme
#[deku(id = 43)]
ChirurgieInfantile, // Chirurgie infantile
#[deku(id = 44)]
ChirurgieMaxilloFaciale, // Chirurgie maxillo-faciale
#[deku(id = 45)]
ChirurgieMaxilloFacialeStomatologie, // Chirurgie maxillo-faciale et stomatologie
#[deku(id = 46)]
ChirurgiePlastiqueReconstructriceEsthetique, // Chirurgie plastique reconstructrice et esthétique
#[deku(id = 47)]
ChirurgieThoraciqueCardioVasculaire, // Chirurgie thoracique et cardio-vasculaire
#[deku(id = 48)]
ChirurgieVasculaire, // Chirurgie vasculaire
#[deku(id = 49)]
ChirurgieVisceraleDigestive, // Chirurgie viscérale et digestive
#[deku(id = 50)]
PharmacieDOfficine, // Pharmacie dofficine
#[deku(id = 51)]
PharmacieMutualiste, // Pharmacie Mutualiste
#[deku(id = 53)]
ChirurgienDentisteSpecialiteCO, // Chirurgien dentiste spécialité C.O.
#[deku(id = 54)]
ChirurgienDentisteSpecialiteMBD, // Chirurgien dentiste spécialité M.B.D.
#[deku(id = 60)]
PrestataireDeTypeSociete, // Prestataire de type société
#[deku(id = 61)]
PrestataireArtisan, // Prestataire artisan
#[deku(id = 62)]
PrestataireDeTypeAssociation, // Prestataire de type association
#[deku(id = 63)]
Orthesiste, // Orthésiste
#[deku(id = 64)]
Opticien, // Opticien
#[deku(id = 65)]
Audioprothesiste, // Audioprothésiste
#[deku(id = 66)]
EpithesisteOculariste, // Épithésiste Oculariste
#[deku(id = 67)]
PodoOrthesiste, // Podo-orthésiste
#[deku(id = 68)]
Orthoprothesiste, // Orthoprothésiste
#[deku(id = 69)]
ChirurgieOrale, // Chirurgie orale
#[deku(id = 70)]
GynecologieMedicale, // Gynécologie médicale
#[deku(id = 71)]
Hematologie, // Hématologie
#[deku(id = 72)]
MedecineNucleaire, // Médecine nucléaire
#[deku(id = 73)]
OncologieMedicale, // Oncologie médicale
#[deku(id = 74)]
OncologieRadiotherapique, // Oncologie radiothérapique
#[deku(id = 75)]
PsychiatrieEnfantAdolescent, // Psychiatrie de lenfant et de ladolescent
#[deku(id = 76)]
Radiotherapie, // Radiothérapie
#[deku(id = 77)]
Obstetrique, // Obstétrique
#[deku(id = 78)]
GenetiqueMedicale, // Génétique médicale
#[deku(id = 79)]
ObstetriqueGynecologieMedicale, // Obstétrique et Gynécologie médicale
#[deku(id = 80)]
SantePubliqueMedecineSociale, // Santé publique et médecine sociale
#[deku(id = 81)]
MaladiesInfectieusesTropicales, // Médecine des Maladies infectieuses et tropicales
#[deku(id = 82)]
MedecineLegaleExpertisesMedicales, // Médecine légale et expertises médicales
#[deku(id = 83)]
MedecineDurgence, // Médecine durgence
#[deku(id = 84)]
MedecineVasculaire, // Médecine vasculaire
#[deku(id = 85)]
Allergologie, // Allergologie
#[deku(id = 86)]
IPA, // Infirmier exerçant en Pratiques Avancées (IPA)
}
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Code zone IK - Indemnité kilométrique
/// Dictionnaire des données FSV, p44
pub enum IkZoneCode {
#[deku(id = 0)]
PasDIndemniteKilometrique, // Pas d'indemnité kilométrique
#[deku(id = 1)]
IndemniteKilometriquePlaine, // Indemnité kilométrique plaine
#[deku(id = 2)]
IndemniteKilometriqueMontagne, // Indemnité kilométrique montagne
}
#[deku_derive(DekuRead)]
#[derive(Debug, PartialEq)]
#[deku(ctx = "id: u8", id = "id")]
/// Code agrément
/// Dictionnaire des données FSV, p44
pub enum ApprovalCode {
#[deku(id = 0)]
PasAgrementRadio, // Pas d'agrément radio
#[deku(id = 1)]
AgrementDOuDDASS, // Agrément D ou DDASS
#[deku(id = 2)]
AgrementABCEF, // Agrément A, B, C, E, F
#[deku(id = 3)]
AgrementGHJ, // Agrément G, H, J
#[deku(id = 4)]
AgrementK, // Agrément K
#[deku(id = 5)]
AgrementL, // Agrément L
#[deku(id = 6)]
AgrementM, // Agrément M
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use deku::DekuContainerRead as _; use deku::DekuContainerRead as _;
use group_1_holder::{CardPSType, CategoryCard, CivilityCode, NationalIDType}; use group_1_holder::{CardPSType, CategoryCard, CivilityCode, NationalIDType};
use group_2_situation::{ActivitySector, ApprovalCode, ConventionCode, IkZoneCode, PracticeMode, SpecialtyCode, StructureIDType};
use crate::fsv_parsing::blocks::BlockHeader; use crate::fsv_parsing::blocks::BlockHeader;
@ -223,7 +644,7 @@ mod tests {
1, // Type d'identification structure, 1 CN 1, // Type d'identification structure, 1 CN
49, 49,
9, // N° d'identification structure, 14 CA 9, // N° d'identification structure, 14 CA
48, 66, 48, 50, 52, 54, 50, 56, 54, 48, 66, 48, 50, 52, 54, 50, 56, 54, // 0B0246286
1, // Clé du N° d'identification structure, 1 CN 1, // Clé du N° d'identification structure, 1 CN
54, 54,
34, // Raison sociale structure, 40 CE 34, // Raison sociale structure, 40 CE
@ -232,7 +653,7 @@ mod tests {
32, 82, 79, 85, 84, 73, 69, 82, 69, 50, 32, 82, 79, 85, 84, 73, 69, 82, 69, 50,
52, 54, 50, 56, 52, 54, 50, 56,
8, // N° d'identification de facturation du PS, 8 CN 8, // N° d'identification de facturation du PS, 8 CN
48, 48, 50, 48, 57, 51, 54, 56, 48, 48, 50, 48, 57, 51, 54, 56, // 00209368
1, // Clé du N° d'identification de facturation du PS, 1 CN 1, // Clé du N° d'identification de facturation du PS, 1 CN
48, 48,
0, // N° d'identification du PS remplaçant, 30 CA 0, // N° d'identification du PS remplaçant, 30 CA
@ -255,7 +676,7 @@ mod tests {
1, // Habilitation à signer une Facture // 1 CN 1, // Habilitation à signer une Facture // 1 CN
49, 49,
1, // Habilitation à signer un lot // 1 CN 1, // Habilitation à signer un lot // 1 CN
49 49,
]; ];
} }
@ -269,7 +690,7 @@ mod tests {
#[test] #[test]
fn test_group_1_holder() { fn test_group_1_holder() {
env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging // env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging
let offset = 3*8; let offset = 3*8;
let (_rest, holder) = group_1_holder::Holder::from_bytes((data::BUFFER, offset)).unwrap(); let (_rest, holder) = group_1_holder::Holder::from_bytes((data::BUFFER, offset)).unwrap();
assert_eq!(holder.card_type, CardPSType::CPS, "Card type"); assert_eq!(holder.card_type, CardPSType::CPS, "Card type");
@ -281,4 +702,32 @@ mod tests {
assert_eq!(holder.holder_firstname.0, "GILBERT", "Holder Firstname"); assert_eq!(holder.holder_firstname.0, "GILBERT", "Holder Firstname");
assert_eq!(holder.category_card, CategoryCard::Unknown, "Category card"); assert_eq!(holder.category_card, CategoryCard::Unknown, "Category card");
} }
#[test]
fn test_group_2_situation() {
// env_logger::init(); // Uncomment and run with RUST_LOG=trace for deku debugging
let offset = 3*8 + 53*8 + 3*8;
let (_rest, situation) = group_2_situation::Situation::from_bytes((data::BUFFER, offset)).unwrap();
assert_eq!(situation.id.0, 1, "ID");
assert_eq!(situation.practice_mode, PracticeMode::Liberal, "Practice mode");
assert_eq!(situation.practice_status_raw.0, "1", "Practice status raw");
assert_eq!(situation.activity_sector, ActivitySector::PharmacieDOfficine, "Activity sector");
assert_eq!(situation.structure_id_type, StructureIDType::FINESS, "Structure ID type");
assert_eq!(situation.structure_id.0, "0B0246286", "Structure ID");
assert_eq!(situation.structure_id_key.0, "6", "Structure ID key");
assert_eq!(situation.structure_name.0, "PHARMACIE DE LA GARE ROUTIERE24628", "Structure name");
assert_eq!(situation.ps_billing_number.0, "00209368", "PS billing number");
assert_eq!(situation.ps_billing_number_key.0, "0", "PS billing number key");
assert_eq!(situation.ps_replacement_number.0, "", "PS replacement number");
assert_eq!(situation.ps_replacement_number_key.0, "0", "PS replacement number key");
assert_eq!(situation.convention_code, ConventionCode::Conventionne, "Convention code");
assert_eq!(situation.specialty_code, SpecialtyCode::PharmacieDOfficine, "Specialty code");
assert_eq!(situation.rate_zone_code_raw.0, "10", "Rate zone code raw");
assert_eq!(situation.ik_zone_code, IkZoneCode::PasDIndemniteKilometrique, "IK zone code");
assert_eq!(situation.approval_code_1, ApprovalCode::PasAgrementRadio, "Approval code 1");
assert_eq!(situation.approval_code_2_raw.0, "0", "Approval code 2 raw");
assert_eq!(situation.approval_code_3_raw.0, "0", "Approval code 3 raw");
assert_eq!(situation.invoice_signature_permission.0, "1", "Invoice signature permission");
assert_eq!(situation.lot_signature_permission.0, "1", "Lot signature permission");
}
} }

View File

@ -158,7 +158,7 @@ mod tests {
use utils::config::load_config; use utils::config::load_config;
use anyhow::{bail, Result}; use anyhow::{bail, Result};
use crate::fsv_parsing::blocks::DataGroup; use crate::fsv_parsing::{blocks::DataGroup, groups::ssv_lire_carte_ps::{group_1_holder::CardPSType, group_2_situation::{PracticeMode, SpecialtyCode}}};
use super::*; use super::*;
@ -184,11 +184,32 @@ mod tests {
} }
#[test] #[test]
#[ignore="WARNING: Read the card with PIN 1234 - Risk of blocking the card"] #[ignore="
WARNING: Read the card with PIN 1234 - Risk of blocking the card
WARNING: This test will only work with GILBERT's PHARMOFFICE card (titulaire kit pharmacie)
"]
fn test_read_professional_card_good_pin() -> Result<()> { fn test_read_professional_card_good_pin() -> Result<()> {
let lib = setup::init()?; let lib = setup::init()?;
let pin_code = "1234"; let pin_code = "1234";
lib.read_professional_card(pin_code)?; let cps_blocks = lib.read_professional_card(pin_code)?;
// Check the first group is the holder group
let holder_group = cps_blocks.blocks.first().unwrap();
assert_eq!(holder_group.header.group_id.0, 1);
let holder_content = match &holder_group.content {
DataGroup::LireCartePS_Group1_Holder(content) => { content },
_ => bail!("Wrong group type"),
};
assert_eq!(holder_content.card_type, CardPSType::CPS, "Card type");
assert_eq!(holder_content.holder_firstname.0, "GILBERT", "Holder firstname");
// Check the second group is a situation group
let situation_group = cps_blocks.blocks.get(1).unwrap();
assert_eq!(situation_group.header.group_id.0, 2);
let situation_content = match &situation_group.content {
DataGroup::LireCartePS_Group2_Situation(content) => { content },
_ => bail!("Wrong group type"),
};
assert_eq!(situation_content.practice_mode, PracticeMode::Liberal, "Practice mode");
assert_eq!(situation_content.specialty_code, SpecialtyCode::PharmacieDOfficine, "Specialty code");
Ok(()) Ok(())
} }