mirror of
https://github.com/pcvolkmer/bzkf-rwdp-check.git
synced 2025-04-20 03:26:50 +00:00
Compare commits
No commits in common. "master" and "v0.2.0" have entirely different histories.
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@ -1,46 +0,0 @@
|
|||||||
name: Create release and upload assets
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
tags:
|
|
||||||
- 'v*'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
linuxbuild:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Run tests
|
|
||||||
run: cargo test --verbose
|
|
||||||
- run: make linux-package
|
|
||||||
- name: Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
with:
|
|
||||||
draft: 'true'
|
|
||||||
make_latest: 'true'
|
|
||||||
generate_release_notes: 'true'
|
|
||||||
files: |
|
|
||||||
*linux.tar.gz
|
|
||||||
windowsbuild:
|
|
||||||
runs-on: windows-latest
|
|
||||||
defaults:
|
|
||||||
run:
|
|
||||||
shell: bash
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Run tests
|
|
||||||
run: cargo test --verbose
|
|
||||||
- run: make win-package
|
|
||||||
- name: Release
|
|
||||||
uses: softprops/action-gh-release@v2
|
|
||||||
if: startsWith(github.ref, 'refs/tags/')
|
|
||||||
with:
|
|
||||||
draft: 'true'
|
|
||||||
make_latest: 'true'
|
|
||||||
generate_release_notes: 'true'
|
|
||||||
files: |
|
|
||||||
*win64.zip
|
|
22
.github/workflows/test.yml
vendored
22
.github/workflows/test.yml
vendored
@ -1,22 +0,0 @@
|
|||||||
name: "Run Tests"
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "master" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "master" ]
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Build
|
|
||||||
run: cargo build --verbose
|
|
||||||
- name: Run tests
|
|
||||||
run: cargo test --verbose
|
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "bzkf-rwdp-check"
|
name = "bzkf-rwdp-check"
|
||||||
version = "0.4.0"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
|
authors = ["Paul-Christian Volkmer <volkmer_p@ukw.de>"]
|
||||||
description = "Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform."
|
description = "Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform."
|
||||||
@ -11,11 +11,11 @@ clap = { version = "4.5", features = ["std", "help", "usage", "derive", "error-c
|
|||||||
console = "0.15"
|
console = "0.15"
|
||||||
csv = "1.3"
|
csv = "1.3"
|
||||||
dialoguer = "0.11"
|
dialoguer = "0.11"
|
||||||
itertools = "0.14"
|
itertools = "0.12"
|
||||||
mysql = "25.0"
|
mysql = "24.0"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
urlencoding = "2.1"
|
urlencoding = "2.1"
|
||||||
regex = "1.11"
|
regex = "1.10"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
3
Makefile
3
Makefile
@ -16,8 +16,7 @@ win-package: win-binary-x86_64
|
|||||||
cp target/x86_64-pc-windows-gnu/release/$(PROG_NAME).exe $(PROG_NAME)/
|
cp target/x86_64-pc-windows-gnu/release/$(PROG_NAME).exe $(PROG_NAME)/
|
||||||
cp README.md $(PROG_NAME)/
|
cp README.md $(PROG_NAME)/
|
||||||
cp LICENSE $(PROG_NAME)/
|
cp LICENSE $(PROG_NAME)/
|
||||||
# first try (linux) zip command, then powershell sub command to create ZIP file
|
zip $(PROG_NAME)-$(TAG)_win64.zip $(PROG_NAME)/*
|
||||||
zip $(PROG_NAME)-$(TAG)_win64.zip $(PROG_NAME)/* || powershell Compress-ARCHIVE $(PROG_NAME) $(PROG_NAME)-$(TAG)_win64.zip
|
|
||||||
rm -rf $(PROG_NAME) || true
|
rm -rf $(PROG_NAME) || true
|
||||||
|
|
||||||
.PHONY: linux-package
|
.PHONY: linux-package
|
||||||
|
42
README.md
42
README.md
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform.
|
Anwendung zur Durchführung einer Plausibilitätsprüfung anhand der Daten für die BZKF Real World Data Platform.
|
||||||
|
|
||||||
**Hinweis:** Dies ist eine Weiterführung des ursprünglichen
|
|
||||||
Projekts [bzkf-rwdp-check](https://github.com/CCC-MF/bzkf-rwdp-check)
|
|
||||||
|
|
||||||
## Aufbau der ETL-Strecke an den Standorten
|
## Aufbau der ETL-Strecke an den Standorten
|
||||||
|
|
||||||
Die Daten werden aus der Onkostar-Datenbank ausgelesen und in Apache-Kafka eingespeist.
|
Die Daten werden aus der Onkostar-Datenbank ausgelesen und in Apache-Kafka eingespeist.
|
||||||
@ -25,9 +22,6 @@ flowchart LR
|
|||||||
Die Anwendung gibt für die möglichen Quellen der Kennzahlen die Anzahl der _Conditions_, gruppiert nach ICD-10 Gruppen,
|
Die Anwendung gibt für die möglichen Quellen der Kennzahlen die Anzahl der _Conditions_, gruppiert nach ICD-10 Gruppen,
|
||||||
aus.
|
aus.
|
||||||
|
|
||||||
Unterstützt wird eien OPAL-CSV-Datei (wie für BZKF vorgesehen) und eine Onkostar-Datenbank, basierend auf MariaDB oder
|
|
||||||
MySQL.
|
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Kennzahlen aus der CSV-Datei
|
## Kennzahlen aus der CSV-Datei
|
||||||
@ -43,8 +37,8 @@ Die Anwendung gibt nun eine Liste der ICD-10-Gruppen mit Anzahl der _Conditions_
|
|||||||
|
|
||||||
## Kennzahlen aus der Onkostar-Datenbank
|
## Kennzahlen aus der Onkostar-Datenbank
|
||||||
|
|
||||||
Die Anzahl der _Conditions_, gruppiert nach ICD-10-Gruppe, kann auch mit dem Befehl `database` aus der
|
Die Anzahl der _Conditions_, gruppiert nach ICD-10-Gruppe, kann auch mit dem Befehl `database` aus der Onkostar-Datenbank
|
||||||
Onkostar-Datenbank abgerufen werden.
|
abgerufen werden.
|
||||||
|
|
||||||
```
|
```
|
||||||
bzkf-rwdp-check database --user me --year 2024
|
bzkf-rwdp-check database --user me --year 2024
|
||||||
@ -68,16 +62,6 @@ Der zusätzliche Parameter `--ignore-exports-since` ist optional.
|
|||||||
Wird er angegeben, werden keine Einträge mit Exportdatum ab diesem Datum verwendet.
|
Wird er angegeben, werden keine Einträge mit Exportdatum ab diesem Datum verwendet.
|
||||||
Dies eignet sich um nachträglich Zahlen zu einem bestimmten Datum zu ermitteln.
|
Dies eignet sich um nachträglich Zahlen zu einem bestimmten Datum zu ermitteln.
|
||||||
|
|
||||||
Der optionale Parameter `--include-extern` schließt Meldungen mit externer Diagnosestellung ein.
|
|
||||||
Diese sind normalerweise nicht enthalten.
|
|
||||||
Die Entscheidung, ob eine Meldung intern oder extern gemeldet wird, wird anhand der `Melder_ID` getroffen.
|
|
||||||
Enthält diese die Zeichenkette `9999` wird von einer externen Meldung ausgegangen.
|
|
||||||
|
|
||||||
Der optionale Parameter `--include-histo-zyto` schließt Meldungen mit Meldeanlass `histologhie_zytologie` ein.
|
|
||||||
Diese sind normalerweise ebenfalls nicht enthalten.
|
|
||||||
|
|
||||||
Mit dem optionalen Parameter `--schema-versions` werden die Angaben zudem noch oBDS-Schema-Version getrennt ausgegeben.
|
|
||||||
|
|
||||||
## Export aus der Onkostar-Datenbank
|
## Export aus der Onkostar-Datenbank
|
||||||
|
|
||||||
Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten
|
Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten
|
||||||
@ -89,32 +73,18 @@ Die Anwendung ist in der Lage, mit dem Befehl `export` die Spalten
|
|||||||
|
|
||||||
in eine CSV-Datei zum Abgleich mit der OPAL-CSV-Datei zu exportieren.
|
in eine CSV-Datei zum Abgleich mit der OPAL-CSV-Datei zu exportieren.
|
||||||
|
|
||||||
Hierbei gelten die gleichen Datenbank-Parameter wie
|
Hierbei gelten die gleichen Datenbank-Parameter wie unter [Kennzahlen aus der Onkostar-Datenbank](#kennzahlen-aus-der-onkostar-datenbank),
|
||||||
unter [Kennzahlen aus der Onkostar-Datenbank](#kennzahlen-aus-der-onkostar-datenbank), zusätzlich gibt es noch die
|
zusätzlich gibt es noch die folgenden Parameter:
|
||||||
folgenden Parameter:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
Options:
|
Options:
|
||||||
--pat-id Export mit Klartext-Patienten-ID
|
--pat-id Export mit Klartext-Patienten-ID
|
||||||
-o, --output <OUTPUT> Ausgabedatei
|
-o, --output <OUTPUT> Ausgabedatei
|
||||||
--xls-csv Export mit Trennzeichen ';' für Excel
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## Vergleich CSV-Datei für OPAL und Onkostar-Datenbank
|
## Vergleich CSV-Datei für OPAL und Onkostar-Datenbank
|
||||||
|
|
||||||
Die Anwendung kann auch die Conditions in der CSV-Datei mit der Onkostar-Datenbank direkt vergleichen.
|
Die Anwendung kann auch die Conditions in der CSV-Datei mit der Onkostar-Datenbank direkt vergleichen.
|
||||||
|
|
||||||
Hierzu kann der Befehl `compare` genutzt werden. Dieser verwendet alle Optionen für die Datenbank und die
|
Hierzu kann der Befehl `compare` genutzt werden. Dieser verwendet alle Optionen für die Datenbank und die Option `--file`
|
||||||
Option `--file` für die CSV-Datei und gibt eine Übersicht auf der Konsole aus.
|
für die CSV-Datei und gibt eine Übersicht auf der Konsole aus.
|
||||||
|
|
||||||
## Vergleich der XML-basierten LKR-Export-Protokolldatei mit der Datenbank
|
|
||||||
|
|
||||||
Mithilfe dieser Anwendung kann auch der aktuelle Inhalt der Datenbank gegen die LKR-Export-Protokolldatei für einen
|
|
||||||
Export verglichen werden.
|
|
||||||
|
|
||||||
Der Befehl `check-export` kann zusammen mit der Angabe der Protokolldatei (`--file`) und der Angabe des
|
|
||||||
Exports (`--package=...` bzw. `--export-package=...`) und den Optionen für den Datenbankzugriff ausgeführt werden.
|
|
||||||
|
|
||||||
Zur Überprüfung werden irrelevante Leerzeichen und Zeilenumbrüche entfernt und _Self-Closed-Tags_ ersetzt
|
|
||||||
(`<Meldeanlass />` => `<Meldeanlass></Meldeanlass>`),
|
|
||||||
da in Onkostar in der Datenbank und der LKR-Export-Protokolldatei verschiedene Formatierungen verwendet werden (können).
|
|
71
src/cli.rs
71
src/cli.rs
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,7 +20,6 @@
|
|||||||
|
|
||||||
use clap::{Parser, Subcommand};
|
use clap::{Parser, Subcommand};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(author, version, about)]
|
#[command(author, version, about)]
|
||||||
@ -35,7 +34,7 @@ pub enum SubCommand {
|
|||||||
#[command(about = "Ermittelt die Prüfwerte aus einem CSV-File für OPAL")]
|
#[command(about = "Ermittelt die Prüfwerte aus einem CSV-File für OPAL")]
|
||||||
OpalFile {
|
OpalFile {
|
||||||
#[arg(short, long, help = "CSV-File für Opal")]
|
#[arg(short, long, help = "CSV-File für Opal")]
|
||||||
file: PathBuf,
|
file: String,
|
||||||
},
|
},
|
||||||
#[command(about = "Ermittelt die Prüfwerte aus der Onkostar-Datenbank")]
|
#[command(about = "Ermittelt die Prüfwerte aus der Onkostar-Datenbank")]
|
||||||
Database {
|
Database {
|
||||||
@ -62,17 +61,6 @@ pub enum SubCommand {
|
|||||||
year: String,
|
year: String,
|
||||||
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
||||||
ignore_exports_since: Option<String>,
|
ignore_exports_since: Option<String>,
|
||||||
#[arg(long, help = "Ignoriere Meldungen, die nicht im oBDS 2.x Format sind")]
|
|
||||||
ignore_non_obds_2: bool,
|
|
||||||
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
|
|
||||||
include_extern: bool,
|
|
||||||
#[arg(
|
|
||||||
long,
|
|
||||||
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
|
|
||||||
)]
|
|
||||||
include_histo_zyto: bool,
|
|
||||||
#[arg(long, help = "Meldungen mit oBDS-Schema-version anzeigen")]
|
|
||||||
schema_versions: bool,
|
|
||||||
},
|
},
|
||||||
#[command(
|
#[command(
|
||||||
about = "Erstellt eine (reduzierte) CSV-Datei zum direkten Vergleich mit der OPAL-CSV-Datei"
|
about = "Erstellt eine (reduzierte) CSV-Datei zum direkten Vergleich mit der OPAL-CSV-Datei"
|
||||||
@ -100,22 +88,11 @@ pub enum SubCommand {
|
|||||||
#[arg(short = 'u', long, help = "Benutzername")]
|
#[arg(short = 'u', long, help = "Benutzername")]
|
||||||
user: String,
|
user: String,
|
||||||
#[arg(short = 'o', long, help = "Ausgabedatei")]
|
#[arg(short = 'o', long, help = "Ausgabedatei")]
|
||||||
output: PathBuf,
|
output: String,
|
||||||
#[arg(short = 'y', long, help = "Jahr der Diagnose")]
|
#[arg(short = 'y', long, help = "Jahr der Diagnose")]
|
||||||
year: String,
|
year: String,
|
||||||
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
||||||
ignore_exports_since: Option<String>,
|
ignore_exports_since: Option<String>,
|
||||||
#[arg(long, help = "Ignoriere Meldungen, die nicht im oBDS 2.x Format sind")]
|
|
||||||
ignore_non_obds_2: bool,
|
|
||||||
#[arg(long, help = "Export mit Trennzeichen ';' für Excel")]
|
|
||||||
xls_csv: bool,
|
|
||||||
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
|
|
||||||
include_extern: bool,
|
|
||||||
#[arg(
|
|
||||||
long,
|
|
||||||
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
|
|
||||||
)]
|
|
||||||
include_histo_zyto: bool,
|
|
||||||
},
|
},
|
||||||
#[command(about = "Abgleich zwischen CSV-Datei für OPAL und Onkostar-Datenbank")]
|
#[command(about = "Abgleich zwischen CSV-Datei für OPAL und Onkostar-Datenbank")]
|
||||||
Compare {
|
Compare {
|
||||||
@ -141,51 +118,11 @@ pub enum SubCommand {
|
|||||||
#[arg(short = 'u', long, help = "Benutzername")]
|
#[arg(short = 'u', long, help = "Benutzername")]
|
||||||
user: String,
|
user: String,
|
||||||
#[arg(short, long, help = "CSV-File für Opal")]
|
#[arg(short, long, help = "CSV-File für Opal")]
|
||||||
file: PathBuf,
|
file: String,
|
||||||
#[arg(short = 'y', long, help = "Jahr der Diagnose")]
|
#[arg(short = 'y', long, help = "Jahr der Diagnose")]
|
||||||
year: String,
|
year: String,
|
||||||
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
#[arg(long, value_parser = value_is_date, help = "Ignoriere LKR-Exporte seit Datum")]
|
||||||
ignore_exports_since: Option<String>,
|
ignore_exports_since: Option<String>,
|
||||||
#[arg(long, help = "Ignoriere Meldungen, die nicht im oBDS 2.x Format sind")]
|
|
||||||
ignore_non_obds_2: bool,
|
|
||||||
#[arg(long, help = "Meldungen mit externer Diagnose einschließen")]
|
|
||||||
include_extern: bool,
|
|
||||||
#[arg(
|
|
||||||
long,
|
|
||||||
help = "Meldungen mit Meldeanlass 'histologie_zytologie' einschließen"
|
|
||||||
)]
|
|
||||||
include_histo_zyto: bool,
|
|
||||||
},
|
|
||||||
#[command(about = "Abgleich zwischen LKR-Export-Protokoll und Onkostar-Datenbank")]
|
|
||||||
CheckExport {
|
|
||||||
#[arg(short = 'D', long, help = "Datenbank-Name", default_value = "onkostar")]
|
|
||||||
database: String,
|
|
||||||
#[arg(
|
|
||||||
short = 'h',
|
|
||||||
long,
|
|
||||||
help = "Datenbank-Host",
|
|
||||||
default_value = "localhost"
|
|
||||||
)]
|
|
||||||
host: String,
|
|
||||||
#[arg(short = 'P', long, help = "Datenbank-Host", default_value = "3306")]
|
|
||||||
port: u16,
|
|
||||||
#[arg(
|
|
||||||
short = 'p',
|
|
||||||
long,
|
|
||||||
help = "Passwort. Wenn nicht angegeben, wird danach gefragt"
|
|
||||||
)]
|
|
||||||
password: Option<String>,
|
|
||||||
#[arg(short = 'u', long, help = "Benutzername")]
|
|
||||||
user: String,
|
|
||||||
#[arg(short, long, help = "LKR-Export-Protokoll-Datei")]
|
|
||||||
file: PathBuf,
|
|
||||||
#[arg(
|
|
||||||
long,
|
|
||||||
alias = "export-package",
|
|
||||||
help = "Exportpaketnummer",
|
|
||||||
default_value = "0"
|
|
||||||
)]
|
|
||||||
package: u16,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -23,7 +23,6 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
pub struct Icd10GroupSize {
|
pub struct Icd10GroupSize {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub schema_version: Option<String>,
|
|
||||||
pub size: usize,
|
pub size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,12 +63,11 @@ impl Check {
|
|||||||
icd10_code: Self::map_icd_code(&record.icd10_code),
|
icd10_code: Self::map_icd_code(&record.icd10_code),
|
||||||
})
|
})
|
||||||
.sorted_by_key(|record| record.icd10_code.to_string())
|
.sorted_by_key(|record| record.icd10_code.to_string())
|
||||||
.chunk_by(|record| record.icd10_code.to_string())
|
.group_by(|record| record.icd10_code.to_string())
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(icd10, group)| (icd10, group.collect::<Vec<_>>()))
|
.map(|(icd10, group)| (icd10, group.collect::<Vec<_>>()))
|
||||||
.map(|record| Icd10GroupSize {
|
.map(|record| Icd10GroupSize {
|
||||||
name: record.0,
|
name: record.0,
|
||||||
schema_version: None,
|
|
||||||
size: record.1.len(),
|
size: record.1.len(),
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
@ -118,15 +116,3 @@ impl Check {
|
|||||||
.to_string()
|
.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::common::Check;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_map_icd10_code_as_expected() {
|
|
||||||
assert_eq!(Check::map_icd_code("D39.1"), "C56, D39.1");
|
|
||||||
assert_eq!(Check::map_icd_code("C00"), "C00-C14");
|
|
||||||
assert_eq!(Check::map_icd_code("F79.9"), "Other");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,29 +18,12 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use mysql::prelude::Queryable;
|
use mysql::prelude::Queryable;
|
||||||
use mysql::{params, Pool};
|
use mysql::{params, Pool};
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
use crate::common::{ExportData, Icd10GroupSize};
|
use crate::common::{ExportData, Icd10GroupSize};
|
||||||
use crate::resources::{EXPORTED_TO_LKR, EXPORT_QUERY, SQL_QUERY, SQL_QUERY_WITH_SCHEMA_VERSION};
|
use crate::resources::{EXPORT_QUERY, SQL_QUERY};
|
||||||
|
|
||||||
fn result_mapper() -> fn((String, String, usize)) -> Icd10GroupSize {
|
|
||||||
|(icd10_group, _, count)| Icd10GroupSize {
|
|
||||||
name: icd10_group,
|
|
||||||
schema_version: None,
|
|
||||||
size: count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result_mapper_with_schema_version() -> fn((String, String, usize)) -> Icd10GroupSize {
|
|
||||||
|(icd10_group, schema_version, count)| Icd10GroupSize {
|
|
||||||
name: icd10_group,
|
|
||||||
schema_version: Some(schema_version),
|
|
||||||
size: count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct DatabaseSource(String);
|
pub struct DatabaseSource(String);
|
||||||
|
|
||||||
@ -51,39 +34,20 @@ impl DatabaseSource {
|
|||||||
DatabaseSource(url)
|
DatabaseSource(url)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(
|
pub fn check(&self, year: &str, ignore_exports_since: &str) -> Result<Vec<Icd10GroupSize>, ()> {
|
||||||
&self,
|
|
||||||
year: &str,
|
|
||||||
ignore_exports_since: &str,
|
|
||||||
ignore_non_obds_2: bool,
|
|
||||||
include_extern: bool,
|
|
||||||
include_histo_zyto: bool,
|
|
||||||
schema_versions: bool,
|
|
||||||
) -> Result<Vec<Icd10GroupSize>, ()> {
|
|
||||||
let params = params! {
|
|
||||||
"year" => year,
|
|
||||||
"ignore_exports_since" => ignore_exports_since,
|
|
||||||
"ignore_non_obds_2" => if ignore_non_obds_2 { 1 } else { 0 },
|
|
||||||
"include_extern" => if include_extern { 1 } else { 0 },
|
|
||||||
"include_histo_zyto" => if include_histo_zyto { 1 } else { 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
match Pool::new(self.0.as_str()) {
|
match Pool::new(self.0.as_str()) {
|
||||||
Ok(pool) => {
|
Ok(pool) => {
|
||||||
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
|
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
|
||||||
return match schema_versions {
|
return match connection.exec_map(
|
||||||
true => match connection.exec_map(
|
SQL_QUERY,
|
||||||
SQL_QUERY_WITH_SCHEMA_VERSION,
|
params! {"year" => year, "ignore_exports_since" => ignore_exports_since},
|
||||||
params,
|
|(icd10_group, count)| Icd10GroupSize {
|
||||||
result_mapper_with_schema_version(),
|
name: icd10_group,
|
||||||
) {
|
size: count,
|
||||||
Ok(result) => Ok(result),
|
|
||||||
Err(_) => Err(()),
|
|
||||||
},
|
|
||||||
false => match connection.exec_map(SQL_QUERY, params, result_mapper()) {
|
|
||||||
Ok(result) => Ok(result),
|
|
||||||
Err(_) => Err(()),
|
|
||||||
},
|
},
|
||||||
|
) {
|
||||||
|
Ok(result) => Ok(result),
|
||||||
|
Err(_) => Err(()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -99,23 +63,14 @@ impl DatabaseSource {
|
|||||||
&self,
|
&self,
|
||||||
year: &str,
|
year: &str,
|
||||||
ignore_exports_since: &str,
|
ignore_exports_since: &str,
|
||||||
ignore_non_obds_2: bool,
|
|
||||||
use_pat_id: bool,
|
use_pat_id: bool,
|
||||||
include_extern: bool,
|
|
||||||
include_histo_zyto: bool,
|
|
||||||
) -> Result<Vec<ExportData>, ()> {
|
) -> Result<Vec<ExportData>, ()> {
|
||||||
match Pool::new(self.0.as_str()) {
|
match Pool::new(self.0.as_str()) {
|
||||||
Ok(pool) => {
|
Ok(pool) => {
|
||||||
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
|
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
|
||||||
return match connection.exec_map(
|
return match connection.exec_map(
|
||||||
EXPORT_QUERY,
|
EXPORT_QUERY,
|
||||||
params! {
|
params! {"year" => year, "ignore_exports_since" => ignore_exports_since},
|
||||||
"year" => year,
|
|
||||||
"ignore_exports_since" => ignore_exports_since,
|
|
||||||
"ignore_non_obds_2" => if ignore_non_obds_2 { 1 } else { 0 },
|
|
||||||
"include_extern" => if include_extern { 1 } else { 0 },
|
|
||||||
"include_histo_zyto" => if include_histo_zyto { 1 } else { 0 }
|
|
||||||
},
|
|
||||||
|(condition_id, icd_10_code, diagnosis_date, pat_id)| ExportData {
|
|(condition_id, icd_10_code, diagnosis_date, pat_id)| ExportData {
|
||||||
condition_id,
|
condition_id,
|
||||||
icd_10_code,
|
icd_10_code,
|
||||||
@ -137,30 +92,4 @@ impl DatabaseSource {
|
|||||||
|
|
||||||
Err(())
|
Err(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exported(&self, package: u16) -> Result<Vec<(String, String)>, ()> {
|
|
||||||
match Pool::new(self.0.as_str()) {
|
|
||||||
Ok(pool) => {
|
|
||||||
if let Ok(mut connection) = pool.try_get_conn(Duration::from_secs(3)) {
|
|
||||||
return match connection.exec_map(
|
|
||||||
EXPORTED_TO_LKR,
|
|
||||||
params! {
|
|
||||||
"export_id" => package,
|
|
||||||
},
|
|
||||||
|(id, xml_data)| (id, xml_data),
|
|
||||||
) {
|
|
||||||
Ok(result) => Ok(result),
|
|
||||||
Err(_) => {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(_) => {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
270
src/lkrexport.rs
270
src/lkrexport.rs
@ -1,270 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of bzkf-rwdp-check
|
|
||||||
*
|
|
||||||
* Copyright (C) 2024 the original author or authors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::str::FromStr;
|
|
||||||
|
|
||||||
use itertools::Itertools;
|
|
||||||
use regex::Regex;
|
|
||||||
|
|
||||||
pub struct LkrExportProtocolFile {
|
|
||||||
pub patients: Vec<Patient>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LkrExportProtocolFile {
|
|
||||||
pub fn parse_file(path: &Path) -> Result<LkrExportProtocolFile, ()> {
|
|
||||||
let xml_file_content = fs::read_to_string(path).map_err(|_| ())?;
|
|
||||||
Self::parse(&xml_file_content)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(content: &str) -> Result<LkrExportProtocolFile, ()> {
|
|
||||||
let re = Regex::new(r"(?s)(?<patient><Patient>(.*?)</Patient>)").unwrap();
|
|
||||||
|
|
||||||
if re.is_match(content) {
|
|
||||||
let patients = re
|
|
||||||
.find_iter(content)
|
|
||||||
.map(|m| Patient {
|
|
||||||
raw_value: m.as_str().to_string(),
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
return Ok(LkrExportProtocolFile { patients });
|
|
||||||
}
|
|
||||||
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn meldungen(&self) -> Vec<Meldung> {
|
|
||||||
self.patients
|
|
||||||
.iter()
|
|
||||||
.flat_map(|patient| patient.meldungen())
|
|
||||||
.collect_vec()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Patient {
|
|
||||||
pub raw_value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Patient {
|
|
||||||
pub fn meldungen(&self) -> Vec<Meldung> {
|
|
||||||
let re = Regex::new(r"(?s)(?<meldung><Meldung(.*?)</Meldung>)").unwrap();
|
|
||||||
|
|
||||||
if re.is_match(&self.raw_value) {
|
|
||||||
return re
|
|
||||||
.find_iter(&self.raw_value)
|
|
||||||
.map(|m| Meldung {
|
|
||||||
raw_value: m.as_str().to_string(),
|
|
||||||
})
|
|
||||||
.collect_vec();
|
|
||||||
}
|
|
||||||
vec![]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct Meldung {
|
|
||||||
pub raw_value: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FromStr for Meldung {
|
|
||||||
type Err = ();
|
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
||||||
Ok(Meldung {
|
|
||||||
raw_value: s.to_string(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(unused)]
|
|
||||||
impl Meldung {
|
|
||||||
pub fn id(&self) -> Option<String> {
|
|
||||||
let re = Regex::new(r#"Meldung_ID="(?<meldung_id>(.*?))""#).unwrap();
|
|
||||||
|
|
||||||
if re.is_match(&self.raw_value) {
|
|
||||||
let caps = re.captures(&self.raw_value).unwrap();
|
|
||||||
return Some(caps["meldung_id"].to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn icd10(&self) -> Option<String> {
|
|
||||||
let re = Regex::new(r"(?s)<Primaertumor_ICD_Code>(?<icd10>(.*?))</Primaertumor_ICD_Code>")
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
if re.is_match(&self.raw_value) {
|
|
||||||
let caps = re.captures(&self.raw_value).unwrap();
|
|
||||||
return Some(caps["icd10"].to_string());
|
|
||||||
}
|
|
||||||
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn database_id(&self) -> Option<String> {
|
|
||||||
match self.id() {
|
|
||||||
Some(id) => to_database_id(&id),
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sanitized_xml_string(&self) -> String {
|
|
||||||
let re = Regex::new(r"[\r|\n]+\s*").unwrap();
|
|
||||||
let content = re.replace_all(&self.raw_value, "").trim().to_string();
|
|
||||||
|
|
||||||
let re = Regex::new(r"<[^>]+/>").unwrap();
|
|
||||||
if re.is_match(&content) {
|
|
||||||
let mut c = content.to_string();
|
|
||||||
re.find_iter(&content)
|
|
||||||
.map(|m| m.as_str().to_string().replace('<', "").replace("/>", ""))
|
|
||||||
.for_each(|tag| {
|
|
||||||
c = c.replace(&format!("<{}/>", tag), &format!("<{}></{}>", tag, tag));
|
|
||||||
});
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_database_id(id: &str) -> Option<String> {
|
|
||||||
let re1 = Regex::new(r"^(?<id>[0-9A-F]+)").unwrap();
|
|
||||||
let re2 = Regex::new(r"(?<id>[0-9]+)$").unwrap();
|
|
||||||
|
|
||||||
if re1.is_match(id) {
|
|
||||||
match re1.find(id).map(|m| m.as_str().to_string()) {
|
|
||||||
Some(val) => match u64::from_str_radix(&val, 16) {
|
|
||||||
Ok(val) => Some(val.to_string()),
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
} else if re2.is_match(id) {
|
|
||||||
re2.find(id).map(|m| m.as_str().to_string())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use crate::lkrexport::{LkrExportProtocolFile, Meldung};
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_read_xml_file_content() {
|
|
||||||
let actual = LkrExportProtocolFile::parse(include_str!("../testdaten/testdaten_1.xml"));
|
|
||||||
|
|
||||||
assert!(actual.is_ok());
|
|
||||||
assert_eq!(actual.unwrap().patients.len(), 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldungen() {
|
|
||||||
let actual = LkrExportProtocolFile::parse(include_str!("../testdaten/testdaten_1.xml"));
|
|
||||||
|
|
||||||
assert!(actual.is_ok());
|
|
||||||
|
|
||||||
let patients = actual.unwrap().patients;
|
|
||||||
|
|
||||||
assert_eq!(patients[0].meldungen().len(), 1);
|
|
||||||
assert_eq!(patients[1].meldungen().len(), 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldung_id() {
|
|
||||||
let actual = LkrExportProtocolFile::parse(include_str!("../testdaten/testdaten_1.xml"));
|
|
||||||
|
|
||||||
assert!(actual.is_ok());
|
|
||||||
|
|
||||||
let patients = actual.unwrap().patients;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
patients[0].meldungen()[0].id(),
|
|
||||||
Some("TEST1727528".to_string())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
patients[1].meldungen()[0].id(),
|
|
||||||
Some("001A5D50-TEST".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldung_database_id() {
|
|
||||||
let actual = LkrExportProtocolFile::parse(include_str!("../testdaten/testdaten_1.xml"));
|
|
||||||
|
|
||||||
assert!(actual.is_ok());
|
|
||||||
|
|
||||||
let patients = actual.unwrap().patients;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
patients[0].meldungen()[0].database_id(),
|
|
||||||
Some("1727528".to_string())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
patients[1].meldungen()[0].database_id(),
|
|
||||||
Some("1727824".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldung_icd10() {
|
|
||||||
let actual = LkrExportProtocolFile::parse(include_str!("../testdaten/testdaten_1.xml"));
|
|
||||||
|
|
||||||
assert!(actual.is_ok());
|
|
||||||
|
|
||||||
let patients = actual.unwrap().patients;
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
patients[0].meldungen()[0].icd10(),
|
|
||||||
Some("C17.1".to_string())
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
patients[1].meldungen()[0].icd10(),
|
|
||||||
Some("C17.2".to_string())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldung_with_trimmed_margin() {
|
|
||||||
let meldung = Meldung {
|
|
||||||
raw_value: " <Test>\n <Test2>TestInhalt 3</Test2>\n</Test>\n".into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
meldung.sanitized_xml_string(),
|
|
||||||
"<Test><Test2>TestInhalt 3</Test2></Test>".to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn should_get_meldung_without_self_closing_tags() {
|
|
||||||
let meldung = Meldung {
|
|
||||||
raw_value:
|
|
||||||
" <Test>\n <Test2/>\n <Content>Test</Content>\n <Test3/>\n <Test2/>\n</Test>\n"
|
|
||||||
.into(),
|
|
||||||
};
|
|
||||||
|
|
||||||
assert_eq!(
|
|
||||||
meldung.sanitized_xml_string(),
|
|
||||||
"<Test><Test2></Test2><Content>Test</Content><Test3></Test3><Test2></Test2></Test>"
|
|
||||||
.to_string()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
300
src/main.rs
300
src/main.rs
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -18,23 +18,21 @@
|
|||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use console::{style, Term};
|
use console::{style, Term};
|
||||||
use csv::WriterBuilder;
|
use csv::Writer;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::cli::{Cli, SubCommand};
|
use crate::cli::{Cli, SubCommand};
|
||||||
use crate::common::{Check, DiffRecord, Icd10GroupSize};
|
use crate::common::{Check, DiffRecord, Icd10GroupSize};
|
||||||
use crate::database::DatabaseSource;
|
use crate::database::DatabaseSource;
|
||||||
use crate::lkrexport::{to_database_id, LkrExportProtocolFile, Meldung};
|
|
||||||
|
|
||||||
mod cli;
|
mod cli;
|
||||||
mod common;
|
mod common;
|
||||||
mod database;
|
mod database;
|
||||||
mod lkrexport;
|
|
||||||
mod opal;
|
mod opal;
|
||||||
mod resources;
|
mod resources;
|
||||||
|
|
||||||
@ -51,9 +49,9 @@ fn request_password_if_none(password: Option<String>) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sanitize_year(year: &str) -> String {
|
fn sanitize_year(year: String) -> String {
|
||||||
if year.len() == 4 {
|
if year.len() == 4 {
|
||||||
year.to_string()
|
year
|
||||||
} else {
|
} else {
|
||||||
format!("2{:0>3}", year)
|
format!("2{:0>3}", year)
|
||||||
}
|
}
|
||||||
@ -67,48 +65,26 @@ fn print_items(items: &[Icd10GroupSize]) {
|
|||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
items.iter().for_each(|item| {
|
items.iter().for_each(|item| {
|
||||||
let _ = term.write_line(&format!(
|
let _ = term.write_line(&format!("{:<20}={:>6}", item.name, item.size));
|
||||||
"{:<20} {:<6} ={:>6}",
|
|
||||||
item.name,
|
|
||||||
item.schema_version.as_ref().unwrap_or(&String::new()),
|
|
||||||
item.size
|
|
||||||
));
|
|
||||||
});
|
});
|
||||||
let sum: usize = items
|
let sum: usize = items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|item| item.name != "Other")
|
.filter(|item| item.name != "Other")
|
||||||
.map(|item| item.size)
|
.map(|item| item.size)
|
||||||
.sum();
|
.sum();
|
||||||
let _ = term.write_line(&style("─".repeat(35)).dim().to_string());
|
let _ = term.write_line(&style("─".repeat(27)).dim().to_string());
|
||||||
let _ = term.write_line(
|
let _ = term.write_line(
|
||||||
&style(format!(
|
&style(format!("{:<20}={:>6}", "Summe (C**.*/D**.*)", sum))
|
||||||
"{:<20} {:<6} ={:>6}",
|
|
||||||
"Summe (C**.*/D**.*)", "", sum
|
|
||||||
))
|
|
||||||
.dim()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
let sum: usize = items.iter().map(|item| item.size).sum();
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style(format!("{:<20} {:<6} ={:>6}", "Gesamtsumme", "", sum))
|
|
||||||
.dim()
|
.dim()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
let _ = term.write_line(&style("─".repeat(35)).dim().to_string());
|
let sum: usize = items.iter().map(|item| item.size).sum();
|
||||||
}
|
let _ = term.write_line(
|
||||||
|
&style(format!("{:<20}={:>6}", "Gesamtsumme", sum))
|
||||||
fn print_extern_notice(include_extern: bool) {
|
.dim()
|
||||||
let _ = Term::stdout().write_line(
|
.to_string(),
|
||||||
format!(
|
|
||||||
"{} Die Datenbankanfrage schließt Meldungen mit externer Diagnose {}.",
|
|
||||||
style("Hinweis:").bold().underlined(),
|
|
||||||
match include_extern {
|
|
||||||
true => style("ein").yellow(),
|
|
||||||
false => style("nicht ein (Standard)").green(),
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.as_str(),
|
|
||||||
);
|
);
|
||||||
|
let _ = term.write_line(&style("─".repeat(27)).dim().to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
@ -116,8 +92,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
match Cli::parse().cmd {
|
match Cli::parse().cmd {
|
||||||
SubCommand::OpalFile { file } => {
|
SubCommand::OpalFile { file } => {
|
||||||
let items =
|
let items = opal::OpalCsvFile::check(Path::new(&file))
|
||||||
opal::OpalCsvFile::check(file.as_path()).map_err(|_e| "Kann Datei nicht lesen")?;
|
.map_err(|_e| "Kann Datei nicht lesen")?;
|
||||||
|
|
||||||
print_items(&items);
|
print_items(&items);
|
||||||
}
|
}
|
||||||
@ -129,36 +105,23 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
user,
|
user,
|
||||||
year,
|
year,
|
||||||
ignore_exports_since,
|
ignore_exports_since,
|
||||||
ignore_non_obds_2,
|
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
schema_versions,
|
|
||||||
} => {
|
} => {
|
||||||
let password = request_password_if_none(password);
|
let password = request_password_if_none(password);
|
||||||
let year = sanitize_year(&year);
|
let year = sanitize_year(year);
|
||||||
|
|
||||||
let _ = term.write_line(
|
let _ = term.write_line(
|
||||||
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
||||||
.blue()
|
.blue()
|
||||||
.bright()
|
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let db = DatabaseSource::new(&database, &host, &password, port, &user);
|
let db = DatabaseSource::new(&database, &host, &password, port, &user);
|
||||||
let items = db
|
let items = db
|
||||||
.check(
|
.check(&year, &ignore_exports_since.unwrap_or("9999-12-31".into()))
|
||||||
&year,
|
|
||||||
&ignore_exports_since.unwrap_or("9999-12-31".into()),
|
|
||||||
ignore_non_obds_2,
|
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
schema_versions,
|
|
||||||
)
|
|
||||||
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
||||||
|
|
||||||
let _ = term.clear_last_lines(1);
|
let _ = term.clear_last_lines(1);
|
||||||
|
|
||||||
print_extern_notice(include_extern);
|
|
||||||
print_items(&items);
|
print_items(&items);
|
||||||
}
|
}
|
||||||
SubCommand::Export {
|
SubCommand::Export {
|
||||||
@ -171,18 +134,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
output,
|
output,
|
||||||
year,
|
year,
|
||||||
ignore_exports_since,
|
ignore_exports_since,
|
||||||
ignore_non_obds_2,
|
|
||||||
xls_csv,
|
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
} => {
|
} => {
|
||||||
let password = request_password_if_none(password);
|
let password = request_password_if_none(password);
|
||||||
let year = sanitize_year(&year);
|
let year = sanitize_year(year);
|
||||||
|
|
||||||
let _ = term.write_line(
|
let _ = term.write_line(
|
||||||
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
||||||
.blue()
|
.blue()
|
||||||
.bright()
|
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -191,23 +149,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
.export(
|
.export(
|
||||||
&year,
|
&year,
|
||||||
&ignore_exports_since.unwrap_or("9999-12-31".into()),
|
&ignore_exports_since.unwrap_or("9999-12-31".into()),
|
||||||
ignore_non_obds_2,
|
|
||||||
pat_id,
|
pat_id,
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
)
|
)
|
||||||
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
||||||
|
|
||||||
let _ = term.clear_last_lines(1);
|
let _ = term.clear_last_lines(1);
|
||||||
|
|
||||||
let writer_builder = &mut WriterBuilder::new();
|
let mut writer = Writer::from_path(Path::new(&output)).expect("writeable file");
|
||||||
let mut writer_builder = writer_builder.has_headers(true);
|
|
||||||
if xls_csv {
|
|
||||||
writer_builder = writer_builder.delimiter(b';');
|
|
||||||
}
|
|
||||||
let mut writer = writer_builder
|
|
||||||
.from_path(output.as_path())
|
|
||||||
.expect("writeable file");
|
|
||||||
|
|
||||||
items
|
items
|
||||||
.iter()
|
.iter()
|
||||||
@ -218,13 +166,11 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
"{} Conditions für das Jahr {} in Datei '{}' exportiert",
|
"{} Conditions für das Jahr {} in Datei '{}' exportiert",
|
||||||
items.len(),
|
items.len(),
|
||||||
year,
|
year,
|
||||||
output.to_str().unwrap_or_default()
|
output
|
||||||
))
|
))
|
||||||
.green()
|
.green()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
print_extern_notice(include_extern);
|
|
||||||
}
|
}
|
||||||
SubCommand::Compare {
|
SubCommand::Compare {
|
||||||
pat_id,
|
pat_id,
|
||||||
@ -236,17 +182,13 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
file,
|
file,
|
||||||
year,
|
year,
|
||||||
ignore_exports_since,
|
ignore_exports_since,
|
||||||
ignore_non_obds_2,
|
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
} => {
|
} => {
|
||||||
let password = request_password_if_none(password);
|
let password = request_password_if_none(password);
|
||||||
let year = sanitize_year(&year);
|
let year = sanitize_year(year);
|
||||||
|
|
||||||
let _ = term.write_line(
|
let _ = term.write_line(
|
||||||
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
&style(format!("Warte auf Daten für das Diagnosejahr {}...", year))
|
||||||
.blue()
|
.blue()
|
||||||
.bright()
|
|
||||||
.to_string(),
|
.to_string(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -255,21 +197,18 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
.export(
|
.export(
|
||||||
&year,
|
&year,
|
||||||
&ignore_exports_since.unwrap_or("9999-12-31".into()),
|
&ignore_exports_since.unwrap_or("9999-12-31".into()),
|
||||||
ignore_non_obds_2,
|
|
||||||
pat_id,
|
pat_id,
|
||||||
include_extern,
|
|
||||||
include_histo_zyto,
|
|
||||||
)
|
)
|
||||||
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
||||||
|
|
||||||
let _ = term.clear_last_lines(1);
|
let _ = term.clear_last_lines(1);
|
||||||
|
|
||||||
let csv_items =
|
let csv_items = opal::OpalCsvFile::export(Path::new(&file))
|
||||||
opal::OpalCsvFile::export(file.as_path()).map_err(|_e| "Kann Datei nicht lesen")?;
|
.map_err(|_e| "Kann Datei nicht lesen")?;
|
||||||
|
|
||||||
let mut not_in_csv = db_items
|
let mut not_in_csv = db_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&db_item| {
|
.filter(|db_item| {
|
||||||
!csv_items
|
!csv_items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|csv_item| &csv_item.condition_id)
|
.map(|csv_item| &csv_item.condition_id)
|
||||||
@ -277,14 +216,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
print_extern_notice(include_extern);
|
|
||||||
|
|
||||||
let _ = term.write_line(
|
let _ = term.write_line(
|
||||||
&style(format!(
|
&style(format!(
|
||||||
"{} Conditions aus der Datenbank für das Jahr {} - aber nicht in Datei '{}'",
|
"{} Conditions aus der Datenbank für das Jahr {} - aber nicht in Datei '{}'",
|
||||||
not_in_csv.len(),
|
not_in_csv.len(),
|
||||||
year,
|
year,
|
||||||
file.to_str().unwrap_or_default()
|
file
|
||||||
))
|
))
|
||||||
.green()
|
.green()
|
||||||
.to_string(),
|
.to_string(),
|
||||||
@ -299,7 +236,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
not_in_csv
|
not_in_csv
|
||||||
.iter()
|
.iter()
|
||||||
.for_each(|&item| match Check::is_relevant(&item.icd_10_code) {
|
.for_each(|item| match Check::is_relevant(&item.icd_10_code) {
|
||||||
true => {
|
true => {
|
||||||
let _ = term.write_line(&format!(
|
let _ = term.write_line(&format!(
|
||||||
"{:<64} {:<10} {:<5} {:<5} {}",
|
"{:<64} {:<10} {:<5} {:<5} {}",
|
||||||
@ -330,7 +267,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
|
|
||||||
let mut not_in_db = csv_items
|
let mut not_in_db = csv_items
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|&csv_item| {
|
.filter(|csv_item| {
|
||||||
!db_items
|
!db_items
|
||||||
.iter()
|
.iter()
|
||||||
.map(|db_item| &db_item.condition_id)
|
.map(|db_item| &db_item.condition_id)
|
||||||
@ -342,7 +279,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
&style(format!(
|
&style(format!(
|
||||||
"{} Conditions aus Datei '{}' - aber nicht in der Datenbank für das Jahr {}",
|
"{} Conditions aus Datei '{}' - aber nicht in der Datenbank für das Jahr {}",
|
||||||
not_in_db.len(),
|
not_in_db.len(),
|
||||||
file.to_str().unwrap_or_default(),
|
file,
|
||||||
year
|
year
|
||||||
))
|
))
|
||||||
.green()
|
.green()
|
||||||
@ -443,185 +380,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
));
|
));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
SubCommand::CheckExport {
|
|
||||||
database,
|
|
||||||
host,
|
|
||||||
password,
|
|
||||||
port,
|
|
||||||
user,
|
|
||||||
file,
|
|
||||||
package,
|
|
||||||
} => {
|
|
||||||
let password = request_password_if_none(password);
|
|
||||||
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style(format!(
|
|
||||||
"Warte auf Daten für den LKR-Export '{}'...",
|
|
||||||
package
|
|
||||||
))
|
|
||||||
.blue()
|
|
||||||
.bright()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let db = DatabaseSource::new(&database, &host, &password, port, &user);
|
|
||||||
|
|
||||||
let db_entries = db
|
|
||||||
.exported(package)
|
|
||||||
.map_err(|_e| "Fehler bei Zugriff auf die Datenbank")?;
|
|
||||||
|
|
||||||
let db_meldungen = db_entries
|
|
||||||
.iter()
|
|
||||||
.map(|entry| LkrExportProtocolFile::parse(&entry.1))
|
|
||||||
.filter(|entry| entry.is_ok())
|
|
||||||
.flat_map(|entry| entry.unwrap().meldungen())
|
|
||||||
.filter(|meldung| meldung.id().is_some())
|
|
||||||
.map(|meldung| (meldung.id().unwrap(), meldung))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let xml_meldungen = LkrExportProtocolFile::parse_file(file.as_path())
|
|
||||||
.map_err(|_e| "Fehler bei Zugriff auf die Protokolldatei")?
|
|
||||||
.meldungen()
|
|
||||||
.into_iter()
|
|
||||||
.filter(|meldung| meldung.id().is_some())
|
|
||||||
.map(|meldung| (meldung.id().unwrap(), meldung))
|
|
||||||
.collect::<HashMap<_, _>>();
|
|
||||||
|
|
||||||
let missing_xml_ids = db_meldungen
|
|
||||||
.keys()
|
|
||||||
.filter(|&key| !xml_meldungen.contains_key(key))
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
let _ = term.clear_last_lines(1);
|
|
||||||
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style(format!(
|
|
||||||
"{} Datenbankeinträge mit {} Meldungen abgerufen",
|
|
||||||
db_entries.len(),
|
|
||||||
db_meldungen.len()
|
|
||||||
))
|
|
||||||
.green()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
fn print_missing_ids(missing_ids: &[&String], term: &Term) {
|
|
||||||
missing_ids.iter().sorted().for_each(|&item| {
|
|
||||||
let _ = term.write_line(&format!(
|
|
||||||
"{} ({})",
|
|
||||||
item,
|
|
||||||
to_database_id(item).unwrap_or("?".into())
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if db_meldungen.len() != xml_meldungen.len() {
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style("\nNicht übereinstimmende Anzahl an Meldungen:")
|
|
||||||
.yellow()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
let _ = term.write_line(&format!(
|
|
||||||
"Datenbank: {:>10}\nProtokolldatei: {:>10}",
|
|
||||||
db_meldungen.len(),
|
|
||||||
xml_meldungen.len()
|
|
||||||
));
|
|
||||||
|
|
||||||
let missing_db_ids = xml_meldungen
|
|
||||||
.keys()
|
|
||||||
.filter(|&key| !db_meldungen.contains_key(key))
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
if !missing_db_ids.is_empty() {
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style("\nIn der Datenbank fehlende Meldungen:")
|
|
||||||
.yellow()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
print_missing_ids(&missing_db_ids, &term);
|
|
||||||
}
|
|
||||||
|
|
||||||
if !missing_xml_ids.is_empty() {
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style("\nIn der Protokolldatei fehlende Meldungen:")
|
|
||||||
.yellow()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
print_missing_ids(&missing_xml_ids, &term);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let multiple_meldung_entries = db_entries
|
|
||||||
.iter()
|
|
||||||
.map(|(lkr_meldung, meldung)| (lkr_meldung, LkrExportProtocolFile::parse(meldung)))
|
|
||||||
.filter_map(|(lkr_meldung, meldung)| {
|
|
||||||
if meldung.unwrap().meldungen().len() > 1 {
|
|
||||||
Some(lkr_meldung)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sorted()
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
if !multiple_meldung_entries.is_empty() {
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style("\nFolgende Einträge in `lkr_meldung_export` haben mehrere Meldungsinhalte in `xml_daten`:")
|
|
||||||
.yellow()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
multiple_meldung_entries.iter().for_each(|&item| {
|
|
||||||
let _ = term.write_line(&item.to_string());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
let different_content = db_meldungen
|
|
||||||
.iter()
|
|
||||||
.filter(|(id, _)| !missing_xml_ids.contains(id))
|
|
||||||
.filter(|(id, meldung)| {
|
|
||||||
xml_meldungen
|
|
||||||
.get(&id.to_string())
|
|
||||||
.unwrap_or(&Meldung {
|
|
||||||
raw_value: String::new(),
|
|
||||||
})
|
|
||||||
.sanitized_xml_string()
|
|
||||||
!= meldung.sanitized_xml_string()
|
|
||||||
})
|
|
||||||
.map(|(_, meldung)| meldung.id().unwrap_or("?".into()))
|
|
||||||
.collect_vec();
|
|
||||||
|
|
||||||
if !different_content.is_empty() {
|
|
||||||
let _ = term.write_line(
|
|
||||||
&style(&format!(
|
|
||||||
"\nFolgende {} Meldungen unterscheiden sich in der Datenbank und der Protokolldatei:",
|
|
||||||
different_content.len()
|
|
||||||
))
|
|
||||||
.yellow()
|
|
||||||
.to_string(),
|
|
||||||
);
|
|
||||||
|
|
||||||
let _ = term.write_line(
|
|
||||||
"Dies kann auch aufgrund der verwendeten XML-Encodierung auftreten und bedeutet nicht immer eine inhaltliche Abweichung."
|
|
||||||
);
|
|
||||||
|
|
||||||
different_content
|
|
||||||
.iter()
|
|
||||||
.sorted_by(|&id1, &id2| {
|
|
||||||
to_database_id(id1)
|
|
||||||
.unwrap_or_default()
|
|
||||||
.cmp(&to_database_id(id2).unwrap_or_default())
|
|
||||||
})
|
|
||||||
.for_each(|id| {
|
|
||||||
let _ = term.write_line(&format!(
|
|
||||||
"{} ({})",
|
|
||||||
id,
|
|
||||||
to_database_id(id).unwrap_or("?".into())
|
|
||||||
));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -33,21 +33,19 @@ FROM (
|
|||||||
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1) AS diagnosedatum,
|
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1) AS diagnosedatum,
|
||||||
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
|
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
|
||||||
FROM lkr_meldung_export lme
|
FROM lkr_meldung_export lme
|
||||||
|
JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1')
|
||||||
|
JOIN lkr_export le ON (le.id = lme.lkr_export)
|
||||||
WHERE lme.xml_daten LIKE '%ICD_Version%'
|
WHERE lme.xml_daten LIKE '%ICD_Version%'
|
||||||
AND lme.typ <> -1
|
|
||||||
AND lme.xml_daten NOT LIKE '%<Menge_Tumorkonferenz%'
|
|
||||||
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
||||||
AND (lme.xml_daten NOT LIKE '%histologie_zytologie%' OR 1 = :include_histo_zyto)
|
AND (lme.xml_daten LIKE '%<cTNM%' OR lme.xml_daten LIKE '%<pTNM%' OR lme.xml_daten LIKE '%<Menge_Histologie>%' OR lme.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%')
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//Meldende_Stelle') NOT LIKE '%9999%' OR 1 <= :include_extern)
|
AND le.exportiert_am < :ignore_exports_since
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//ADT_GEKID/@Schema_Version') LIKE '2.%' OR 1 = :ignore_non_obds_2)
|
|
||||||
) o1
|
) o1
|
||||||
LEFT OUTER JOIN (
|
LEFT OUTER JOIN (
|
||||||
|
|
||||||
SELECT DISTINCT
|
SELECT
|
||||||
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
||||||
CASE WHEN le.exportiert_am < :ignore_exports_since THEN MAX(versionsnummer) ELSE ~0 END AS max_version
|
MAX(versionsnummer) AS max_version
|
||||||
FROM lkr_meldung_export lme
|
FROM lkr_meldung_export lme
|
||||||
JOIN lkr_export le ON (lme.lkr_export = le.id)
|
|
||||||
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
||||||
GROUP BY cond_id ORDER BY cond_id
|
GROUP BY cond_id ORDER BY cond_id
|
||||||
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of bzkf-rwdp-check
|
|
||||||
*
|
|
||||||
* Copyright (C) 2024 the original author or authors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SELECT
|
|
||||||
CONVERT(id,char) AS id,
|
|
||||||
xml_daten
|
|
||||||
FROM lkr_meldung_export
|
|
||||||
WHERE typ <> -1
|
|
||||||
AND (lkr_export = :export_id OR (0 = :export_id AND lkr_export IN (SELECT MAX(lkr_export) FROM lkr_meldung_export)));
|
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -20,8 +20,4 @@
|
|||||||
|
|
||||||
pub const SQL_QUERY: &str = include_str!("query.sql");
|
pub const SQL_QUERY: &str = include_str!("query.sql");
|
||||||
|
|
||||||
pub const SQL_QUERY_WITH_SCHEMA_VERSION: &str = include_str!("query_with_schema_version.sql");
|
|
||||||
|
|
||||||
pub const EXPORT_QUERY: &str = include_str!("export.sql");
|
pub const EXPORT_QUERY: &str = include_str!("export.sql");
|
||||||
|
|
||||||
pub const EXPORTED_TO_LKR: &str = include_str!("exported-to-lkr.sql");
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of bzkf-rwdp-check
|
* This file is part of bzkf-rwdp-check
|
||||||
*
|
*
|
||||||
* Copyright (C) 2024 the original author or authors.
|
* Copyright (C) 2024 Comprehensive Cancer Center Mainfranken and contributors.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -107,35 +107,34 @@ SELECT CASE
|
|||||||
|
|
||||||
ELSE 'Other'
|
ELSE 'Other'
|
||||||
END AS ICD10_GROUP,
|
END AS ICD10_GROUP,
|
||||||
'' AS schema_version,
|
|
||||||
COUNT(*) as COUNT
|
COUNT(*) as COUNT
|
||||||
FROM (
|
FROM (
|
||||||
|
|
||||||
SELECT DISTINCT
|
SELECT DISTINCT
|
||||||
lme.lkr_meldung,
|
|
||||||
EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid,
|
EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid,
|
||||||
EXTRACTVALUE(lme.xml_daten, '//ADT_GEKID/@Schema_Version') AS schema_version,
|
|
||||||
lme.versionsnummer,
|
lme.versionsnummer,
|
||||||
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
||||||
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode,
|
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode,
|
||||||
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
|
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
|
||||||
FROM lkr_meldung_export lme
|
FROM lkr_meldung_export lme
|
||||||
|
JOIN lkr_meldung lm ON (lm.id = lme.lkr_meldung AND lme.typ <> '-1')
|
||||||
|
JOIN lkr_export le ON (le.id = lme.lkr_export)
|
||||||
WHERE lme.xml_daten LIKE '%ICD_Version%'
|
WHERE lme.xml_daten LIKE '%ICD_Version%'
|
||||||
AND lme.typ <> -1
|
|
||||||
AND lme.xml_daten NOT LIKE '%<Menge_Tumorkonferenz%'
|
|
||||||
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
||||||
AND (lme.xml_daten NOT LIKE '%histologie_zytologie%' OR 1 = :include_histo_zyto)
|
AND (lme.xml_daten LIKE '%<cTNM%' OR lme.xml_daten LIKE '%<pTNM%' OR lme.xml_daten LIKE '%<Menge_Histologie>%' OR lme.xml_daten LIKE '%<Menge_Weitere_Klassifikation>%')
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//Meldende_Stelle') NOT LIKE '%9999%' OR 1 <= :include_extern)
|
AND le.exportiert_am < :ignore_exports_since
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//ADT_GEKID/@Schema_Version') LIKE '2.%' OR 1 = :ignore_non_obds_2)
|
) o1
|
||||||
) o1
|
LEFT OUTER JOIN (
|
||||||
LEFT OUTER JOIN (
|
|
||||||
SELECT DISTINCT
|
SELECT
|
||||||
lme.lkr_meldung,
|
|
||||||
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
||||||
CASE WHEN STR_TO_DATE(EXTRACTVALUE(lme.xml_daten, '//Meldedatum'), '%d.%c.%Y') < :ignore_exports_since THEN MAX(versionsnummer) ELSE ~0 END AS max_version
|
MAX(versionsnummer) AS max_version
|
||||||
FROM lkr_meldung_export lme
|
FROM lkr_meldung_export lme
|
||||||
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
||||||
GROUP BY cond_id ORDER BY cond_id
|
GROUP BY cond_id ORDER BY cond_id
|
||||||
) o2
|
|
||||||
|
) o2
|
||||||
ON (o1.cond_id = o2.cond_id AND o1.versionsnummer < max_version)
|
ON (o1.cond_id = o2.cond_id AND o1.versionsnummer < max_version)
|
||||||
WHERE diagnosejahr = :year AND o2.cond_id IS NULL
|
WHERE diagnosejahr = :year AND o2.cond_id IS NULL
|
||||||
GROUP BY ICD10_GROUP;
|
GROUP BY ICD10_GROUP;
|
@ -1,141 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of bzkf-rwdp-check
|
|
||||||
*
|
|
||||||
* Copyright (C) 2024 the original author or authors.
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License along
|
|
||||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
SELECT CASE
|
|
||||||
WHEN condcodingcode LIKE 'C00%'
|
|
||||||
OR condcodingcode LIKE 'C01%'
|
|
||||||
OR condcodingcode LIKE 'C02%'
|
|
||||||
OR condcodingcode LIKE 'C03%'
|
|
||||||
OR condcodingcode LIKE 'C04%'
|
|
||||||
OR condcodingcode LIKE 'C05%'
|
|
||||||
OR condcodingcode LIKE 'C06%'
|
|
||||||
OR condcodingcode LIKE 'C07%'
|
|
||||||
OR condcodingcode LIKE 'C08%'
|
|
||||||
OR condcodingcode LIKE 'C09%'
|
|
||||||
OR condcodingcode LIKE 'C10%'
|
|
||||||
OR condcodingcode LIKE 'C11%'
|
|
||||||
OR condcodingcode LIKE 'C12%'
|
|
||||||
OR condcodingcode LIKE 'C13%'
|
|
||||||
OR condcodingcode LIKE 'C14%' THEN 'C00-C14'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C15%' THEN 'C15'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C16%' THEN 'C16'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C18%'
|
|
||||||
OR condcodingcode LIKE 'C19%'
|
|
||||||
OR condcodingcode LIKE 'C20%'
|
|
||||||
OR condcodingcode LIKE 'C21%' THEN 'C18-C21'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C22%' THEN 'C22'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C23%'
|
|
||||||
OR condcodingcode LIKE 'C24%' THEN 'C23-C24'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C25%' THEN 'C25'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C32%' THEN 'C32'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C33%'
|
|
||||||
OR condcodingcode LIKE 'C34%' THEN 'C33-C34'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C43%' THEN 'C43'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C50%'
|
|
||||||
OR condcodingcode LIKE 'D05%' THEN 'C50, D05'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C53%'
|
|
||||||
OR condcodingcode LIKE 'D06%' THEN 'C53, D06'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C54%'
|
|
||||||
OR condcodingcode LIKE 'C55%' THEN 'C54-C55'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C56%'
|
|
||||||
OR condcodingcode = 'D39.1' THEN 'C56, D39.1'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C61%' THEN 'C61'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C62%' THEN 'C62'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C64%' THEN 'C64'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C67%'
|
|
||||||
OR condcodingcode = 'D09.0'
|
|
||||||
OR condcodingcode = 'D41.4' THEN 'C67, D09.0, D41.4'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C70%'
|
|
||||||
OR condcodingcode LIKE 'C71%'
|
|
||||||
OR condcodingcode LIKE 'C72%' THEN 'C70-C72'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C73%' THEN 'C73'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C81%' THEN 'C81'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C82%'
|
|
||||||
OR condcodingcode LIKE 'C83%'
|
|
||||||
OR condcodingcode LIKE 'C84%'
|
|
||||||
OR condcodingcode LIKE 'C85%'
|
|
||||||
OR condcodingcode LIKE 'C86%'
|
|
||||||
OR condcodingcode LIKE 'C87%'
|
|
||||||
OR condcodingcode LIKE 'C88%'
|
|
||||||
OR condcodingcode LIKE 'C96%' THEN 'C82-C88, C96'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C90%' THEN 'C90'
|
|
||||||
|
|
||||||
WHEN condcodingcode LIKE 'C91%'
|
|
||||||
OR condcodingcode LIKE 'C92%'
|
|
||||||
OR condcodingcode LIKE 'C93%'
|
|
||||||
OR condcodingcode LIKE 'C94%'
|
|
||||||
OR condcodingcode LIKE 'C95%' THEN 'C91-C95'
|
|
||||||
|
|
||||||
ELSE 'Other'
|
|
||||||
END AS ICD10_GROUP,
|
|
||||||
schema_version,
|
|
||||||
COUNT(*) as COUNT
|
|
||||||
FROM (
|
|
||||||
SELECT DISTINCT
|
|
||||||
lme.lkr_meldung,
|
|
||||||
EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID') AS pid,
|
|
||||||
EXTRACTVALUE(lme.xml_daten, '//ADT_GEKID/@Schema_Version') AS schema_version,
|
|
||||||
lme.versionsnummer,
|
|
||||||
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
|
||||||
SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Primaertumor_ICD_Code'), ' ', 1) AS condcodingcode,
|
|
||||||
SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) AS diagnosejahr
|
|
||||||
FROM lkr_meldung_export lme
|
|
||||||
WHERE lme.xml_daten LIKE '%ICD_Version%'
|
|
||||||
AND lme.typ <> -1
|
|
||||||
AND lme.xml_daten NOT LIKE '%<Menge_Tumorkonferenz%'
|
|
||||||
AND SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
|
||||||
AND (lme.xml_daten NOT LIKE '%histologie_zytologie%' OR 1 = :include_histo_zyto)
|
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//Meldende_Stelle') NOT LIKE '%9999%' OR 1 <= :include_extern)
|
|
||||||
AND (EXTRACTVALUE(lme.xml_daten, '//ADT_GEKID/@Schema_Version') LIKE '2.%' OR 1 = :ignore_non_obds_2)
|
|
||||||
) o1
|
|
||||||
LEFT OUTER JOIN (
|
|
||||||
SELECT DISTINCT
|
|
||||||
lme.lkr_meldung,
|
|
||||||
SHA2(CONCAT('https://fhir.diz.uk-erlangen.de/identifiers/onkostar-xml-condition-id|', EXTRACTVALUE(lme.xml_daten, '//Patienten_Stammdaten/@Patient_ID'), 'condition', EXTRACTVALUE(lme.xml_daten, '//Diagnose/@Tumor_ID')), 256) AS cond_id,
|
|
||||||
CASE WHEN STR_TO_DATE(EXTRACTVALUE(lme.xml_daten, '//Meldedatum'), '%d.%c.%Y') < :ignore_exports_since THEN MAX(versionsnummer) ELSE ~0 END AS max_version
|
|
||||||
FROM lkr_meldung_export lme
|
|
||||||
WHERE SUBSTRING_INDEX(SUBSTRING_INDEX(EXTRACTVALUE(lme.xml_daten, '//Diagnosedatum'), ' ', 1), '.', -1) = :year
|
|
||||||
GROUP BY cond_id ORDER BY cond_id
|
|
||||||
) o2
|
|
||||||
ON (o1.cond_id = o2.cond_id AND o1.versionsnummer < max_version)
|
|
||||||
WHERE diagnosejahr = :year AND o2.cond_id IS NULL
|
|
||||||
GROUP BY ICD10_GROUP, schema_version;
|
|
@ -1,89 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ADT_GEKID xmlns="http://www.gekid.de/namespace" Schema_Version="2.2.3">
|
|
||||||
<Absender Absender_ID="TEST" Software_ID="ONKOSTAR" Installations_ID="2011">
|
|
||||||
<Absender_Bezeichnung>TEST</Absender_Bezeichnung>
|
|
||||||
<Absender_Anschrift>Musterstraße 1, 012345 Musterhausen</Absender_Anschrift>
|
|
||||||
</Absender>
|
|
||||||
<Menge_Patient>
|
|
||||||
<Patient>
|
|
||||||
<Patienten_Stammdaten Patient_ID="20001234">
|
|
||||||
<KrankenversichertenNr>E123456789</KrankenversichertenNr>
|
|
||||||
<KrankenkassenNr>123456789</KrankenkassenNr>
|
|
||||||
<Patienten_Nachname>Tester</Patienten_Nachname>
|
|
||||||
<Patienten_Titel></Patienten_Titel>
|
|
||||||
<Patienten_Vornamen>Patrick</Patienten_Vornamen>
|
|
||||||
<Patienten_Geburtsname>Tester</Patienten_Geburtsname>
|
|
||||||
<Patienten_Geschlecht>M</Patienten_Geschlecht>
|
|
||||||
<Patienten_Geburtsdatum>01.01.1980</Patienten_Geburtsdatum>
|
|
||||||
<Menge_Adresse>
|
|
||||||
<Adresse>
|
|
||||||
<Patienten_Strasse>Testweg</Patienten_Strasse>
|
|
||||||
<Patienten_Hausnummer>1</Patienten_Hausnummer>
|
|
||||||
<Patienten_Land>DE</Patienten_Land>
|
|
||||||
<Patienten_PLZ>01234</Patienten_PLZ>
|
|
||||||
<Patienten_Ort>Musterhausen</Patienten_Ort>
|
|
||||||
</Adresse>
|
|
||||||
</Menge_Adresse>
|
|
||||||
</Patienten_Stammdaten>
|
|
||||||
<Menge_Meldung>
|
|
||||||
<Meldung Meldung_ID="TEST1727528" Melder_ID="TEST">
|
|
||||||
<Meldedatum>11.06.2024</Meldedatum>
|
|
||||||
<Meldebegruendung>I</Meldebegruendung>
|
|
||||||
<Meldeanlass>statusaenderung</Meldeanlass>
|
|
||||||
<Tumorzuordnung Tumor_ID="1">
|
|
||||||
<Primaertumor_ICD_Code>C17.1</Primaertumor_ICD_Code>
|
|
||||||
<Primaertumor_ICD_Version>10 2015 GM</Primaertumor_ICD_Version>
|
|
||||||
<Diagnosedatum>10.06.2024</Diagnosedatum>
|
|
||||||
<Seitenlokalisation>T</Seitenlokalisation>
|
|
||||||
</Tumorzuordnung>
|
|
||||||
<Menge_Tumorkonferenz>
|
|
||||||
<Tumorkonferenz Tumorkonferenz_ID="1234567">
|
|
||||||
<Tumorkonferenz_Datum>11.06.2024</Tumorkonferenz_Datum>
|
|
||||||
<Tumorkonferenz_Typ>praeth</Tumorkonferenz_Typ>
|
|
||||||
</Tumorkonferenz>
|
|
||||||
</Menge_Tumorkonferenz>
|
|
||||||
</Meldung>
|
|
||||||
</Menge_Meldung>
|
|
||||||
</Patient>
|
|
||||||
<Patient>
|
|
||||||
<Patienten_Stammdaten Patient_ID="20004321">
|
|
||||||
<KrankenversichertenNr>E123456789</KrankenversichertenNr>
|
|
||||||
<KrankenkassenNr>123456789</KrankenkassenNr>
|
|
||||||
<Patienten_Nachname>Tester</Patienten_Nachname>
|
|
||||||
<Patienten_Titel></Patienten_Titel>
|
|
||||||
<Patienten_Vornamen>Patricia</Patienten_Vornamen>
|
|
||||||
<Patienten_Geburtsname>Tester</Patienten_Geburtsname>
|
|
||||||
<Patienten_Geschlecht>W</Patienten_Geschlecht>
|
|
||||||
<Patienten_Geburtsdatum>01.01.1980</Patienten_Geburtsdatum>
|
|
||||||
<Menge_Adresse>
|
|
||||||
<Adresse>
|
|
||||||
<Patienten_Strasse>Testweg</Patienten_Strasse>
|
|
||||||
<Patienten_Hausnummer>1</Patienten_Hausnummer>
|
|
||||||
<Patienten_Land>DE</Patienten_Land>
|
|
||||||
<Patienten_PLZ>01234</Patienten_PLZ>
|
|
||||||
<Patienten_Ort>Musterhausen</Patienten_Ort>
|
|
||||||
</Adresse>
|
|
||||||
</Menge_Adresse>
|
|
||||||
</Patienten_Stammdaten>
|
|
||||||
<Menge_Meldung>
|
|
||||||
<Meldung Meldung_ID="001A5D50-TEST" Melder_ID="TEST">
|
|
||||||
<Meldedatum>11.06.2024</Meldedatum>
|
|
||||||
<Meldebegruendung>I</Meldebegruendung>
|
|
||||||
<Meldeanlass>statusaenderung</Meldeanlass>
|
|
||||||
<Tumorzuordnung Tumor_ID="1">
|
|
||||||
<Primaertumor_ICD_Code>C17.2</Primaertumor_ICD_Code>
|
|
||||||
<Primaertumor_ICD_Version>10 2015 GM</Primaertumor_ICD_Version>
|
|
||||||
<Diagnosedatum>01.01.2024</Diagnosedatum>
|
|
||||||
<Seitenlokalisation>T</Seitenlokalisation>
|
|
||||||
</Tumorzuordnung>
|
|
||||||
<Menge_Tumorkonferenz>
|
|
||||||
<Tumorkonferenz Tumorkonferenz_ID="1234568">
|
|
||||||
<Tumorkonferenz_Datum>10.01.2024</Tumorkonferenz_Datum>
|
|
||||||
<Tumorkonferenz_Typ>praeth</Tumorkonferenz_Typ>
|
|
||||||
</Tumorkonferenz>
|
|
||||||
</Menge_Tumorkonferenz>
|
|
||||||
</Meldung>
|
|
||||||
</Menge_Meldung>
|
|
||||||
</Patient>
|
|
||||||
</Menge_Patient>
|
|
||||||
</ADT_GEKID>
|
|
Loading…
x
Reference in New Issue
Block a user