diff --git a/.gitignore b/.gitignore index 7f06374a..6d16126f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ /captures .externalNativeBuild .cxx +repo Jenkinsfile Nightly.Jenkinsfile @@ -24,3 +25,5 @@ ci-overrides.properties nexus-init.gradle.kts documentation-internal android/src/androidTest +technical_requirements_report.html +keystore diff --git a/LICENSE b/LICENSE index 90ff2aec..4addc737 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2023 gematik GmbH +Copyright (c) 2024 gematik GmbH Licensed under the EUPL, Version 1.2 or – as soon they will be approved by the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 7aada13b..567c70c9 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,9 @@ +# Release 1.16.1 +- Added Invoice correction function for private health insurance customers +- Optimized performance +- UX improvements +- Bug fixes + # Release 1.14.0 - Allow devices without NFC to authenticate using 3rd party health insurance apps - Lots of bugfixes diff --git a/android/build.gradle.kts b/android/build.gradle.kts index d7b13c52..6c29309b 100644 --- a/android/build.gradle.kts +++ b/android/build.gradle.kts @@ -14,6 +14,8 @@ plugins { id("com.jaredsburrows.license") id("de.gematik.ti.erp.dependencies") id("com.google.android.libraries.mapsplatform.secrets-gradle-plugin") + id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") + id("shot") } val VERSION_CODE: String by overriding() @@ -49,7 +51,7 @@ android { versionName = VERSION_NAME testApplicationId = "de.gematik.ti.erp.app.test.test" - testInstrumentationRunner = TEST_INSTRUMENTATION_ORCHESTRATOR + testInstrumentationRunner = "com.karumi.shot.ShotTestRunner" testInstrumentationRunnerArguments += "clearPackageData" to "true" testInstrumentationRunnerArguments += "useTestStorageService" to "true" } @@ -75,7 +77,7 @@ android { dependencyCheck { analyzers.assemblyEnabled = false - + suppressionFile = "${project.rootDir}" + "/config/dependency-check/suppressions.xml" formats = listOf(Format.HTML, Format.XML) scanConfigurations = configurations.filter { it.name.startsWith("api") || @@ -189,13 +191,18 @@ android { compose.android.useAndroidX = true compose.android.androidxVersion = app.composeVersion +shot { + tolerance = 0.15 // Tests pass if less than 0,15% of the pixels differ + applicationId = "de.gematik.ti.erp.app" + runInstrumentation = true +} + dependencies { implementation(project(":common")) testImplementation(project(":common")) implementation(kotlin("stdlib")) implementation(kotlin("reflect")) testImplementation(kotlin("test")) - implementation("com.tom-roush:pdfbox-android:2.0.27.0") { exclude(group = "org.bouncycastle") } @@ -209,7 +216,7 @@ dependencies { implementation(coroutines("core")) implementation(coroutines("android")) implementation(coroutines("play-services")) - compileOnly(datetime) + implementation(datetime) testCompileOnly(datetime) } android { @@ -270,6 +277,9 @@ dependencies { implementation(retrofit2KotlinXSerialization) implementation(okhttp3("okhttp")) implementation(okhttp3("logging-interceptor")) + // Work around vulnerable Okio version 3.1.0 (CVE-2023-3635). + // Can be removed as soon as Retrofit releases a new version >2.9.0. + implementation(okio) androidTestImplementation(okhttp3("okhttp")) } @@ -324,6 +334,7 @@ dependencies { } composeTest { androidTestImplementation(ui) + debugImplementation(uiManifest) androidTestImplementation(junit4) } networkTest { diff --git a/android/src/debug/AndroidManifest.xml b/android/src/debug/AndroidManifest.xml index 91ae69c1..f5c241a6 100644 --- a/android/src/debug/AndroidManifest.xml +++ b/android/src/debug/AndroidManifest.xml @@ -1,5 +1,8 @@ - + diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt index 29d6c76a..668a2a40 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/data/DebugSettingsData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt index 3b67ab44..3bc733f5 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugLoadingButton.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt index ef2f9ef9..8289d239 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugPKV.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt index 9c8c9626..5c123ee8 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt index adac553d..2bb62a48 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenNavigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt index d90fa0ba..ee454dc3 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt index 57722637..45b7a327 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/debug/ui/DebugSettingsViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/di/EndpointHelper.kt b/android/src/debug/java/de/gematik/ti/erp/app/di/EndpointHelper.kt index d6a5edd6..944a9d39 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/di/EndpointHelper.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/di/EndpointHelper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/debug/java/de/gematik/ti/erp/app/utils/compose/DebugCommon.kt b/android/src/debug/java/de/gematik/ti/erp/app/utils/compose/DebugCommon.kt index 2ba0be20..c32a33ea 100644 --- a/android/src/debug/java/de/gematik/ti/erp/app/utils/compose/DebugCommon.kt +++ b/android/src/debug/java/de/gematik/ti/erp/app/utils/compose/DebugCommon.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml index 02c602c2..0bdb7e6d 100644 --- a/android/src/main/AndroidManifest.xml +++ b/android/src/main/AndroidManifest.xml @@ -1,6 +1,7 @@ + xmlns:tools="http://schemas.android.com/tools" + package="de.gematik.ti.erp.app.test"> diff --git a/android/src/main/assets/data_terms.html b/android/src/main/assets/data_terms.html index 20b41557..2d2d80be 100644 --- a/android/src/main/assets/data_terms.html +++ b/android/src/main/assets/data_terms.html @@ -2,135 +2,145 @@ - Datenschutzerklaerung-E-Rezept-App - + Datenschutzerklärung-E-Rezept-App +

Datenschutzerklärung

-

(Stand: Dezember 2022)

-

Die E-Rezept-App ist die offizielle App zum E-Rezept in Deutschland. Die gematik gibt die App als Nationale Agentur für Digitale Medizin im Auftrag des Gesetzgebers heraus. Die gematik ist auch für den Datenschutz der App verantwortlich.

+

Weitere Informationen

+

Das offizielle Informationsangebot der gematik zum E-Rezept in Deutschland finden Sie unter www.das-e-rezept-fuer-deutschland.de. Dort erhalten Sie verständlich aufbereitete Informationen und Antworten auf häufig gestellte Fragen zum E-Rezept.

-

1. Über diese Datenschutzerklärung

+

1. Über diese Datenschutzerklärung

-

In dieser Datenschutzerklärung informieren wir Sie über die Datenverarbeitung durch die E- Rezept-App. Wir bemühen uns um eine verständliche Darstellung der technischen Abläufe. Sollte uns das einmal nicht gelungen sein, lassen Sie es uns bitte wissen. Unsere Kontaktdaten finden Sie unter Ansprechpartner.

+

In dieser Datenschutzerklärung informieren wir Sie über die Datenverarbeitung durch die E-Rezept-App. Wir bemühen uns um eine verständliche Darstellung der technischen Abläufe. Sollte uns das einmal nicht gelungen sein, lassen Sie es uns bitte wissen. Unsere Kontaktdaten finden Sie unter Ansprechpartner.

-

Diese Datenschutzerklärung gilt nicht für die Dienste von anderen Anbietern, die die zentralen Systeme des E-Rezepts bereitstellen. Zu diesen Diensten zählen der Rezeptdienst, der Identitätsdienst und das Apothekenverzeichnis. Informationen zu den verantwortlichen Anbietern dieser Dienste finden Sie unter Weitere Verantwortliche.

+

Diese Datenschutzerklärung gilt nicht für die Dienste von anderen Anbietern, die die zentralen Systeme des E-Rezepts bereitstellen. Zu diesen Diensten zählen der Rezeptdienst, der Identitätsdienst und das Apothekenverzeichnis. Informationen zu den verantwortlichen Anbietern dieser Dienste finden Sie unter Weitere Verantwortliche.

-

2. Wozu dient diese App?

+

2. Wozu dient diese App?

-

Wenn Sie von Ihrem Arzt oder Ihrer Ärztin ein elektronisches Rezept bekommen, wird es verschlüsselt im Rezeptdienst gespeichert. Der Rezeptdienst ist der zentrale Rezeptspeicher im deutschen Gesundheitsnetz. Mit der E-Rezept-App können Sie sicher auf den Rezeptdienst zugreifen, um E-Rezepte zu empfangen, zu verwalten und Apotheken zuzuweisen.

+

Wenn Sie von Ihrem Arzt oder Ihrer Ärztin ein elektronisches Rezept bekommen, wird es verschlüsselt im Rezeptdienst gespeichert. Der Rezeptdienst ist der zentrale Rezeptspeicher im deutschen Gesundheitsnetz. Mit der E-Rezept-App können Sie sicher auf den Rezeptdienst zugreifen und E-Rezepte empfangen, verwalten und einlösen.

-

3. Ist die Nutzung der App freiwillig?

+

3. Ist die Nutzung der App freiwillig?

-

Ja, die Nutzung der E-Rezept-App ist freiwillig. Sie sind auch nicht verpflichtet, bestimmte Daten in der App anzugeben oder sich anzumelden. Wenn Sie sich nicht anmelden, können Sie die App jedoch nur zum Scannen und Vorzeigen von Rezeptcodes in der Apotheke nutzen.

+

Ja, die Nutzung der E-Rezept-App ist freiwillig. Sie sind auch nicht verpflichtet, bestimmte Daten in der App anzugeben oder sich anzumelden. Wenn Sie sich nicht anmelden, können Sie jedoch nicht alle Funktionen der App nutzen.

-

4. Wie und wozu werden Ihre Daten verarbeitet?

+

4. Wie und wozu werden Ihre Daten verarbeitet?

-

4.1 Profile einrichten

+

4.1 Profile einrichten

Sie müssen mindestens ein „Profil“ einrichten.

    -
  • Die Daten zum Profil werden nur auf Ihrem Gerät gespeichert.
  • -
  • Der Profilname dient der übersichtlichen Anzeige. Er ist frei wählbar.
  • -
  • Sie können mehrere Profile einrichten, um E-Rezepte für Angehörige zu verwalten.
  • +
  • Die Daten zum Profil werden nur auf Ihrem Gerät gespeichert.
  • +
  • Der Profilname dient der übersichtlichen Anzeige. Er ist frei wählbar.
  • +
  • Sie können mehrere Profile einrichten, um E-Rezepte für Angehörige zu verwalten.
-

4.2 Anmelden am Rezeptdienst

+

4.2 Anmelden am Rezeptdienst

-

Nur die Patientin/der Patient (bzw. eine Vertretungsperson), die verordnende Arztpraxis und die einlösende Apotheke dürfen auf die Daten im Rezeptdienst zugreifen dürfen. Für jeden Zugriff auf Ihre Daten im Rezeptdienst muss daher die Identität nachgewiesen werden, um die Zugriffsberechtigung zu überprüfen. Zuständig für diese Identitätsprüfung ist der Identitätsdienst. Informationen zum Anbieter dieses Dienstes finden Sie unter Weitere Verantwortliche.

+

Nur die Patientin/der Patient (bzw. eine Vertretungsperson), die verordnende Arztpraxis und die einlösende Apotheke dürfen auf die Daten im Rezeptdienst zugreifen. Für jeden Zugriff auf Ihre Daten im Rezeptdienst muss daher die Identität nachgewiesen werden, um die Zugriffsberechtigung zu überprüfen. Zuständig für diese Identitätsprüfung ist der Identitätsdienst. Informationen zum Anbieter dieses Dienstes finden Sie unter Weitere Verantwortliche.

Sie können Ihre Identität mit Ihrer elektronischen Gesundheitskarte (eGK) und Ihrer ePA-App nachweisen:

    -
  • Wenn Sie sich der eGK anmelden, wird das digitale Authentifizierungszertifikat auf dem Chip kontaktlos (per NFC) ausgelesen und an den Identitätsdienst übertragen. Ihre Einwilligung erteilen Sie durch die Eingabe der PIN. Das Authentifizierungszertifikat enthält Ihre Versichertenstammdaten (z. B. Name und Ihre Versichertennummer) und gilt als elektronischer Identitätsnachweis. Sobald der Identitätsdienst das Authentifizierungszertifikat geprüft und Ihre Identität bestätigt hat, stellt er der E-Rezept-App einen Zugangsschlüssel (Token) aus. Mit diesem kann sich die E-Rezept-App am Rezeptdienst anmelden.
  • -
  • Wenn Sie sich mit der ePA-App anmelden, müssen Sie zunächst Ihre Krankenkasse auswählen, damit die E-Rezept-App sich mit der „richtigen“ ePA-App verbinden kann. Die Liste der Krankenkassen ruft die E-Rezept-App vom Identitätsdienst ab. Nachdem Sie Ihre Identitätsdaten über Ihre ePA-App mit der E-Rezept-App geteilt haben, leitet diese die Daten an den Identitätsdienst zur Prüfung weiter. Wenn Ihre Identität bestätigt werden kann, stellt der Identitätsdienst der E-Rezept-App den Zugangsschlüssel (Token) zur Anmeldung am Rezeptdienst aus.
  • +
  • Wenn Sie sich der eGK anmelden, wird das digitale Authentifizierungszertifikat auf dem Chip kontaktlos (per NFC) ausgelesen und an den Identitätsdienst übertragen. Ihre Einwilligung erteilen Sie durch die Eingabe der PIN. Das Authentifizierungszertifikat enthält Ihre Versichertenstammdaten (z. B. Name und Ihre Versichertennummer) und gilt als elektronischer Identitätsnachweis. Sobald der Identitätsdienst das Authentifizierungszertifikat geprüft und Ihre Identität bestätigt hat, stellt er der E-Rezept-App einen Zugangsschlüssel (Token) aus. Mit diesem kann sich die E-Rezept-App am Rezeptdienst anmelden.
  • +
  • Wenn Sie sich mit der ePA-App anmelden, müssen Sie zunächst Ihre Krankenkasse auswählen, damit die E-Rezept-App sich mit der „richtigen“ ePA-App verbinden kann. Die Liste der Krankenkassen ruft die E-Rezept-App vom Identitätsdienst ab. Nachdem Sie Ihre Identitätsdaten über Ihre ePA-App mit der E-Rezept-App geteilt haben, leitet diese die Daten an den Identitätsdienst zur Prüfung weiter. Wenn Ihre Identität bestätigt werden kann, stellt der Identitätsdienst der E-Rezept-App den Zugangsschlüssel (Token) zur Anmeldung am Rezeptdienst aus.

Nach der Anmeldung werden Ihre im Rezeptdienst gespeicherten E-Rezepte und Abgabeinformationen heruntergeladen und zusätzlich auf Ihrem Gerät gespeichert.

Wenn Sie Ihre E-Rezepte über die E-Rezept-App verwalten, werden Ihre Aktivitäten an den Rezeptdienst übertragen und dort umgesetzt. Zu diesen Aktivitäten gehören beispielsweise die Vergabe von Zugriffsrechten und das Löschen von E-Rezepten.

-

4.3 Zugangsdaten speichern

+

4.3 Zugangsdaten speichern

Wenn Sie angemeldet sind, können Sie für zukünftige Anmeldungen die Funktion „Zugangsdaten speichern“ aktivieren. In einem geschützten Bereich Ihres Geräts werden dann die Zugangsdaten – bestehend aus PIN, CAN, Authentifizierungszertifikat und Zugangsschlüssel (Token) – gespeichert, so dass sie erneut verwendet werden können. Diese Funktion kann nur aktiviert werden, wenn Ihr Smartphone über einen sicheren Mechanismus für den Zugriffsschutz von Apps verfügt. Diese Voraussetzung erfüllen aktuell Apple iPhones mit Touch ID oder Face ID und Android-Geräte mit „Strongbox Keymaster“-Sicherheitsmodul.

-

4.4 Rezeptcodes scannen

+

4.4 Rezeptcodes scannen und einlösen

+ +

Wenn Sie einen Rezeptcode speichern und über die App bei einer Apotheke einlösen wollen, müssen Sie ihn zunächst mit der Kamera scannen. Beim Scannen wird eine elektronische Kopie des Rezeptcodes erzeugt. Dieser Arbeitsschritt findet ausschließlich auf Ihrem Gerät statt, das heißt es wird keine Internetverbindung benötigt. Anschließend können Sie das E-Rezept per App bei einer Apotheke einlösen:

+ +
    +
  • Wenn Sie am Rezeptdienst angemeldet sind und das E-Rezept per App einer Apotheke zur Einlösung zuweisen, wird dies im Rezeptdienst dokumentiert und der Rezeptstatus auf „in Einlösung“ geändert. Die Apotheke erhält dann das Zugriffsrecht für das im Rezeptdienst gespeicherte E-Rezept. Eine direkte Kommunikation zwischen App und Apotheke erfolgt dabei nicht. Sie können den aktuellen Bearbeitungsstatus, der vom Rezeptdienst verwaltet wird, jederzeit in der App einsehen.
  • +
  • Wenn Sie nicht am Rezeptdienst angemeldet sind, können Sie den Rezeptcode zusammen mit Ihren weiteren Bestelldaten (etwa ob Sie das Medikament abholen oder geliefert bekommen möchten) direkt an die Apotheke übermitteln. Die App kommuniziert in diesem Fall direkt mit dem Kommunikationssystem Ihrer Apotheke. Der Rezeptdienst ist an dieser Kommunikation nicht beteiligt und wird daher nicht über die Bestellung informiert. Zu Ihrer Übersicht wird das übermittelte E-Rezept in der Bestellübersicht Ihrer App als „gesendet“ gekennzeichnet. Die Zugangsdaten für das Kommunikationssystem der Apotheke erhält die App vom Apotheken-Verzeichnis.
  • +
+ +Hinweis für Android-Geräte: -

Wenn Sie einen Rezeptcode speichern wollen, müssen Sie ihn mit der Kamera scannen. Beim Scannen wird eine elektronische Kopie des Rezeptcodes erzeugt. Dieser Arbeitsschritt findet ausschließlich auf Ihrem Gerät statt, das heißt es wird keine Internetverbindung benötigt.

+

Um Rezeptcodes auch unter ungünstigen Bedingungen (z. B. schlechte Kameraauflösung oder Lichtverhältnisse) fehlerfrei scannen zu können, nutzt die App mit Ihrer Zustimmung eine spezielle Schnittstelle (Barcode Scanning API von Google ML Kit). Diese Schnittstelle ist Bestandteil der Google Play Services, die auf Ihrem Gerät bereits installiert sind. Das Kamerabild wird dabei ausschließlich auf Ihrem Gerät analysiert. Wie bei allen Android-Geräten mit Google Play Services behält sich Google jedoch vor, bestimmte bei der Nutzung der Schnittstelle anfallende Nutzungs- und Gerätedaten (bei ML Kit z. B.: Hersteller, Gerätemodell, Betriebssystemversion, Hardware, Mobilfunkbetreiber, Zeitzone, Spracheinstellungen, IP-Adresse, App-Version, Konfiguration von ML Kit, Anzahl der Scanvorgänge, Fehlermeldungen) innerhalb des Betriebssystems zu protokollieren und zur Weiterentwicklung der Schnittstelle an einen Google-Server zu übermitteln. Dabei kann nicht ausgeschlossen werden, dass diese Daten in ein Drittland (z. B. USA) übermittelt werden, siehe An wen werden Ihre Daten weitergegeben. Sie können Ihre Zustimmung zu der Nutzung des Google ML Kit jederzeit widerrufen, indem Sie die Kamera-Berechtigung der E-Rezept-App in den Android-Einstellungen deaktivieren. Weitere Informationen finden Sie in den Hinweisen von Google zu ML Kit und in der Google Datenschutzerklärung.

-

Hinweis für Android-Geräte: -Um Rezeptcodes auch unter ungünstigen Bedingungen (z. B. schlechte Kameraauflösung oder Lichtverhältnisse) fehlerfrei scannen zu können, nutzt die App mit Ihrer Zustimmung eine spezielle Schnittstelle (Barcode Scanning API von Google ML Kit). Diese Schnittstelle ist Bestandteil der Google Play Services, die auf Ihrem Gerät bereits installiert sind. Das Kamerabild wird dabei ausschließlich auf Ihrem Gerät analysiert. Wie bei allen Android-Geräten mit Google Play Services behält sich Google jedoch vor, bestimmte bei der Nutzung der Schnittstelle anfallende Nutzungs- und Gerätedaten (bei ML Kit z. B.: Hersteller, Gerätemodell, Betriebssystemversion, Hardware, Mobilfunkbetreiber, Zeitzone, Spracheinstellungen, IP-Adresse, App-Version, Konfiguration von ML Kit, Anzahl der Scanvorgänge, Fehlermeldungen) innerhalb des Betriebssystems zu protokollieren und zur Weiterentwicklung der Schnittstelle an einen Google-Server zu übermitteln. Dabei kann nicht ausgeschlossen werden, dass diese Daten in ein Drittland (z. B. USA) übermittelt werden, siehe An wen werden Ihre Daten weitergegeben. Sie können Ihre Zustimmung zu der Nutzung des Google ML Kit jederzeit widerrufen, indem Sie die Kamera-Berechtigung der E-Rezept-App in den Android-Einstellungen deaktivieren.

+

4.5 Apothekensuche

-

Weitere Informationen finden Sie in den Hinweisen von Google zu ML Kit und in der Google Datenschutzerklärung.

+

Bei Verwendung der Apothekensuche werden Ihre Suchkriterien (z. B. Adressen oder Standortdaten) an das Apotheken-Verzeichnis übermittelt. Das Apotheken-Verzeichnis stellt der App daraufhin eine Liste mit den zu den Suchkriterien passenden Apotheken bereit.

-

4.5 Apothekensuche

+

4.6 Mitteilungen an Apotheken

-

Bei Verwendung der Apothekensuche werden Ihre Suchkriterien (z. B. Adressen oder Standortdaten) an das Apotheken-Verzeichnis übermittelt.

+

Die E-Rezept-App ermöglicht eine direkte verschlüsselte und vertrauliche Kommunikation zwischen Ihnen und Apotheken.

-

4.6 Mitteilungen an Apotheken

+

Wenn Sie am Rezeptdienst angemeldet sind, läuft die Kommunikation mit der Apotheke über den Rezeptdienst, der die Mitteilungen auch archiviert. Die App lädt die Mitteilungen vom Rezeptdienst und speichert sie auf Ihrem Gerät, so dass Sie auch ohne Anmeldung den aktuellen Stand sehen können. Weder der Anbieter des Rezeptdienstes noch die gematik haben Einblick in die ausgetauschten Mitteilungen.

-

Die E-Rezept-App ermöglicht eine direkte Kommunikation zwischen Ihnen und Apotheken. Die Kommunikation läuft verschlüsselt und vertraulich über den Rezeptdienst, der die Mitteilungen auch archiviert. Weder der Anbieter des Rezeptdienstes noch die gematik haben Einblick in die ausgetauschten Mitteilungen. Die E-Rezept-App lädt die Mitteilungen vom Rezeptdienst und speichert sie auf Ihrem Gerät, so dass Sie auch ohne Anmeldung den aktuellen Stand sehen können.

+

Wenn Sie nicht am Rezeptdienst angemeldet sind, können Sie über die App Mitteilungen direkt an das Kommunikationssystem Ihrer Apotheke senden. Die Zugangsdaten für das Kommunikationssystem erhält die App vom Apotheken-Verzeichnis. Der Rezeptdienst ist an der Kommunikation nicht beteiligt. Bitte beachten Sie: Um Mitteilungen empfangen und Mitteilungsverläufe einsehen zu können, müssen Sie sich am Rezeptdienst anmelden.

-

4.7 Sicherheitsfunktionen

+

4.7 Sicherheitsfunktionen

-

(7.a) Verbundene Geräte

+

(a) Verbundene Geräte

-

Die Funktion „Zugangsdaten speichern“ kann auf mehreren Geräten aktiviert werden. Jedes Gerät, auf dem Sie diese Funktion aktiviert ist, wird als „verbundenes Gerät“ bezeichnet. Alle verbundenen Geräte werden zentral auf dem Identitätsdienst verwaltet. Hierzu überträgt die E-Rezept-App Geräteinformationen zur eindeutigen Unterscheidbarkeit an den Identitätsdienst: Hersteller, Gerätemodell, Gerätename, Betriebssystemversion und Gerätename (z. B. „Annas iPhone“). Damit Sie den Überblick behalten, können Sie im Bereich „Einstellungen“ unter „Verbundene Geräte“ sehen, auf welchen Geräten Sie Ihre Zugangsdaten gespeichert haben.

+

Die Funktion „Zugangsdaten speichern“ kann auf mehreren Geräten aktiviert werden. Jedes Gerät, auf dem Sie diese Funktion aktiviert ist, wird als „verbundenes Gerät“ bezeichnet. Alle verbundenen Geräte werden zentral auf dem Identitätsdienst verwaltet. Hierzu überträgt die E-Rezept-App Geräteinformationen zur eindeutigen Unterscheidbarkeit an den Identitätsdienst: Hersteller, Gerätemodell, Gerätename, Betriebssystemversion und Gerätename (z. B. „Annas iPhone“). Damit Sie den Überblick behalten, können Sie im Bereich „Einstellungen“ unter „Verbundene Geräte“ sehen, auf welchen Geräten Sie Ihre Zugangsdaten gespeichert haben.

Wenn Sie ein verbundenes Gerät abmelden möchten, können Sie dies auf dem betreffenden oder einem anderen verbundenen Gerät erledigen. Die auf dem abgemeldeten Gerät gespeicherten Zugangsdaten und die auf dem Identitätsdienst erfassten Geräteinformationen werden dann gelöscht.

Bitte beachten Sie: Wenn ein verbundenes Gerätemodell oder dessen Betriebsversion als unsicher eingestuft werden sollte, kann der Identitätsdienst das betreffende Gerät abmelden. Dabei werden die auf dem Identitätsdienst gespeicherten Geräteinformationen und der Zugangsschlüssel des Geräts gelöscht. Sie können sich auf dem abgemeldeten Gerät dann erneut am Rezeptdienst anmelden, sofern das Sicherheitsproblem durch ein Update des Betriebssystems beseitigt worden ist.

-

(7.b) Integritätsprüfungen

+

(b) Integritätsprüfungen

-

Smartphones können mit einem manipulierten Betriebssystem betrieben werden (sogenanntes „Jailbreaken“ oder „Rooten“). Nicht jeder betroffene Nutzer ist sich bewusst, dass sein Betriebssystem manipuliert worden ist (z. B. bei gebraucht gekauften Geräten) und welche Sicherheitsrisiken damit einhergehen. Bei jedem Start der E-Rezept-App wird daher eine technische Prüfung des Betriebssystems durchgeführt. Werden Hinweise auf eine Manipulation erkannt, wird eine Warnung angezeigt. Sie können die App anschließend auf eigenes Risiko ohne Einschränkungen weiternutzen.

+

Smartphones können mit einem manipulierten Betriebssystem betrieben werden (sogenanntes „Jailbreaken“ oder „Rooten“). Nicht jeder betroffene Nutzer ist sich bewusst, dass sein Betriebssystem manipuliert worden ist (z. B. bei gebraucht gekauften Geräten) und welche Sicherheitsrisiken damit einhergehen. Bei jedem Start der E-Rezept-App wird daher eine technische Prüfung des Betriebssystems durchgeführt. Werden Hinweise auf eine Manipulation erkannt, wird eine Warnung angezeigt. Sie können die App anschließend auf eigenes Risiko ohne Einschränkungen weiternutzen.

-

Für die Jailbreak-Erkennung auf Apple-Geräten prüft die E-Rezept-App den Gerätespeicher auf Hinweise von Apps, die nur auf Geräten mit Jailbreak installiert werden können (z. B. Cydia-App).

+

Für die Jailbreak-Erkennung auf Apple-Geräten prüft die E-Rezept-App den Gerätespeicher auf Hinweise von Apps, die nur auf Geräten mit Jailbreak installiert werden können (z. B. Cydia-App).

-

Für die Root-Erkennung auf Android-Geräten wird eine Sicherheitsfunktion des Betriebssystems genutzt. Hierzu generiert die App eine Zufallszahl sowie Informationen zur E-Rezept-App (z. B. Version) und übergibt sie an eine spezielle Schnittstelle Ihres Betriebssystems (SafetyNet Attestation API). Diese Schnittstelle ist Bestandteil der Google Play Services, die auf Ihrem Gerät bereits installiert sind (siehe Rezeptcodes scannen). Google untersucht dann anhand der nur ihm zugänglichen Informationen zu Ihrem Gerät und der App, ob das Betriebssystem manipuliert wurde und teilt der E-Rezept-App das Prüfungsergebnis mit.

+

Für die Root-Erkennung auf Android-Geräten wird eine Sicherheitsfunktion des Betriebssystems genutzt. Hierzu generiert die App eine Zufallszahl sowie Informationen zur E-Rezept-App (z. B. Version) und übergibt sie an eine spezielle Schnittstelle Ihres Betriebssystems (SafetyNet Attestation API). Diese Schnittstelle ist Bestandteil der Google Play Services, die auf Ihrem Gerät bereits installiert sind (siehe Rezeptcodes scannen). Google untersucht dann anhand der nur ihm zugänglichen Informationen zu Ihrem Gerät und der App, ob das Betriebssystem manipuliert wurde und teilt der E-Rezept-App das Prüfungsergebnis mit.

Weiterhin wird vor jeder Anmeldung am Rezeptdienst die Echtheit der App geprüft. Die Echtheitsprüfung dient dazu, festzustellen, ob Ihre Version der E-Rezept-App manipuliert oder gefälscht worden („unecht“) ist. Wenn Hinweise auf eine unechte App gefunden werden, kann sie sich nicht am Rezeptdienst anmelden. Sofern die E-Rezept-App auf einem verbundenen Gerät läuft, wird dieses getrennt und die unechte App abgemeldet. Für die Echtheitsprüfung nutzt die E-Rezept-App die Sicherheitsfunktionen Ihres Betriebssystems. Dies sind auf Apple-Geräten der Apple App Attest Service und auf Android-Geräten der SafetyNet App Attestation Service.

-

(7.c) App-Zugriffssperre

+

(c) App-Zugriffssperre

-

Um unbefugte Zugriffe auf Ihre E-Rezept-App zu erschweren, kann sie nach jedem Schließen automatisch gesperrt werden. Bei jedem Öffnen muss sie dann zunächst entsperrt werden. Je nachdem, über welche Sicherheitsausstattung Ihr Smartphone verfügt, stehen Kennwort- basierte und biometrische Verfahren zur Verfügung. -Bitte beachten Sie: Wenn Sie die Funktion „Zugangsdaten speichern“ aktivieren, wird automatisch auch die App-Sperre aktiviert.

+

Um unbefugte Zugriffe auf Ihre E-Rezept-App zu erschweren, kann sie nach jedem Schließen automatisch gesperrt werden. Bei jedem Öffnen muss sie dann zunächst entsperrt werden. Je nachdem, über welche Sicherheitsausstattung Ihr Smartphone verfügt, stehen Kennwort-basierte und biometrische Verfahren zur Verfügung.

-

Wenn Sie den Kennwortschutz aktivieren, wird Ihr Kennwort während der Einrichtung lokal auf ausreichende Stärke geprüft. Das Kennwort wird nur auf Ihrem Gerät gespeichert. -Bei Nutzung eines biometrischen Verfahrens werden die Sicherheitsfunktionen Ihres Smartphones verwendet. Die E-Rezept-App erhält dabei keine biometrischen Daten, sondern nur das Ergebnis der biometrischen Prüfung durch Ihr Betriebssystem.

+

Bitte beachten Sie: Wenn Sie die Funktion „Zugangsdaten speichern“ aktivieren, wird automatisch auch die App-Sperre aktiviert.

-

4.8 Push-Benachrichtigungen

+

Wenn Sie den Kennwortschutz aktivieren, wird Ihr Kennwort während der Einrichtung lokal auf ausreichende Stärke geprüft. Das Kennwort wird nur auf Ihrem Gerät gespeichert.

-

Sie können sich per Push-Benachrichtigung über Mitteilungen von Apotheken oder neue E-Rezepte informieren lassen. Dazu registriert sich Ihr Smartphone bei dem Push-Dienst Ihres Betriebssystems. Folgende Push-Dienste werden genutzt: Firebase Cloud Messaging (Android), Apple Push Notification (Apple), Huawei Push Kit (Huawei).

+

Bei Nutzung eines biometrischen Verfahrens werden die Sicherheitsfunktionen Ihres Smartphones verwendet. Die E-Rezept-App erhält dabei keine biometrischen Daten, sondern nur das Ergebnis der biometrischen Prüfung durch Ihr Betriebssystem.

+ +

4.8 Push-Benachrichtigungen

+ +

In künftigen Versionen der App können Sie sich per Push-Benachrichtigung über Mitteilungen von Apotheken oder neue E-Rezepte informieren lassen. Dazu registriert sich Ihr Smartphone bei dem Push-Dienst Ihres Betriebssystems. Folgende Push-Dienste werden genutzt: Firebase Cloud Messaging (Android), Apple Push Notification (Apple), Huawei Push Kit (Huawei).

Der jeweilige Push-Dienst übergibt der E-Rezept-App eine Push-Kennung. Die Push-Kennung wird dann von der E-Rezept-App an den Rezeptdienst übermittelt. Soll eine Push-Nachricht an Sie versendet werden, schickt der Rezeptdienst einen Hinweis mit Ihrer Push-Kennung an den genutzten Push-Dienst, der diesen dann an Ihr Smartphone weiterleitet. Die Mitteilung der Apotheke bleibt dabei auf dem Rezeptdienst und wird erst geladen, wenn Sie die E-Rezept-App öffnen.

-

4.9 Nutzungsanalyse

+

4.9 Nutzungsanalyse

-

Wenn Sie der Nutzungsanalyse zustimmen, erfasst die gematik auf Basis Ihrer Einwilligung Informationen über Ihr Gerät und darüber, wie die App verwendet wird (z.B. Art, Version und Hersteller des Gerätes und des Betriebssystems, die Art und den Umfang der Nutzung und Bedienung der einzelnen App-Funktionen). Die Nutzungsdaten werden anonymisiert gespeichert. Ihre Einwilligung können Sie jederzeit widerrufen, indem Sie die Nutzungsanalyse in den Einstellungen deaktivieren. Ihre Nutzungsdaten werden dann nicht mehr an die gematik übertragen. Weitere Hinweise erhalten Sie vor dem Aktivieren der Nutzungsanalyse in der E-Rezept-App.

+

Wenn Sie die Nutzungsanalyse erlauben, werden allgemeine Nutzungsdaten (z.B. Art und den Umfang der Nutzung und Bedienung der App-Funktionen) und Angaben zur verwendeten Hard - und Software (z.B. Art, Version und Hersteller des Gerätes und des Betriebssystems) sowie gewählte Einstellungen (z.B. Spracheinstellung) übermittelt. Die Nutzungsdaten werden ausschließlich anonymisiert ausgewertet. Ihre Einwilligung können Sie jederzeit widerrufen, indem Sie die Nutzungsanalyse in den Einstellungen deaktivieren. Ihre Nutzungsdaten werden dann nicht mehr an die gematik übertragen. Weitere Hinweise erhalten Sie vor dem Aktivieren der Nutzungsanalyse in der E-Rezept-App.

-

5. An wen werden Ihre Daten weitergegeben?

+

5. An wen werden Ihre Daten weitergegeben?

Wenn Sie der Nutzungsanalyse zugestimmt haben, übermittelt die App Ihre Nutzungsdaten auf Basis Ihrer Einwilligung an den technischen Dienstleister der gematik für die Nutzungsanalyse (Content Square GmbH).

-

Im Übrigen hat die gematik keinen Zugriff auf die auf Ihrem Gerät gespeicherten Daten. An andere Anbieter und sonstige Dritte gibt die App Ihre Daten nur im unter Wie und wozu werden Ihre Daten verarbeitet? beschriebenen Umfang weiter.

+

Im Übrigen hat die gematik keinen Zugriff auf die auf Ihrem Gerät gespeicherten Daten. An andere Anbieter und sonstige Dritte gibt die App Ihre Daten nur im unter Wie und wozu werden Ihre Daten verarbeitet? beschriebenen Umfang weiter.

-

Weder die E-Rezept-App noch die Anbieter des Rezeptdienstes, des Identitätsdienstes oder des Apothekenverzeichnisses übermitteln Ihre Daten in Länder, in denen kein angemessenes Datenschutzniveau besteht und europäische Datenschutzrechte eventuell nicht durchgesetzt werden (sogenannte Drittländer, z. B. USA).

+

Weder die E-Rezept-App noch die Anbieter des Rezeptdienstes, des Identitätsdienstes oder des Apotheken-Verzeichnisses übermitteln Ihre Daten in Länder, in denen kein angemessenes Datenschutzniveau besteht und europäische Datenschutzrechte eventuell nicht durchgesetzt werden (sogenannte Drittländer, z. B. USA).

Wir weisen Sie jedoch darauf hin, dass durch die Nutzung der E-Rezept-App auf Seiten Ihres Betriebssystems Nutzungsdaten anfallen. Die Hersteller der Betriebssysteme behalten sich teilweise vor, diese Daten zu protokollieren und auszuwerten. Dabei kann es auch zu einer Übermittlung von Geräte- und Nutzungsdaten in die USA oder ein anderes Drittland kommen. Insoweit besteht die Möglichkeit, dass Sicherheitsbehörden im Drittland auf die übermittelten Daten beim Hersteller zugreifen und diese auswerten, beispielsweise indem sie Daten mit anderen Informationen über Sie verknüpfen.

-

6. Wann werden Ihre Daten gelöscht?

+

6. Wann werden Ihre Daten gelöscht?

Die gematik speichert keine personenbezogenen Daten von Nutzern der E-Rezept-App. Seitens der gematik ist daher keine Löschung notwendig oder möglich.

-

Die auf Ihrem Gerät gespeicherten Rezeptdaten, Rezeptcodes und Mitteilungen können Sie in der App selbst löschen. Bitte beachten Sie, dass gelöschte E-Rezepte erneut auf Ihrem Gerät gespeichert werden, sobald Sie die Rezeptansicht aktualisieren. Dies können Sie verhindern, indem Sie die E-Rezepte auch im Rezeptdienst löschen. Die E-Rezepte im Rezeptdienst werden automatisch nach 100 Tagen ab Ausstellung oder letzter Statusänderung gelöscht (§ 360 Abs. 11 SGB V).

+

Die auf Ihrem Gerät gespeicherten Rezeptdaten, Rezeptcodes und Mitteilungen können Sie in der App selbst löschen. Bitte beachten Sie, dass gelöschte E-Rezepte erneut auf Ihrem Gerät gespeichert werden, sobald Sie die Rezeptansicht aktualisieren. Dies können Sie verhindern, indem Sie die E-Rezepte auch im Rezeptdienst löschen. Die E-Rezepte im Rezeptdienst werden automatisch nach 100 Tagen ab Ausstellung oder letzter Statusänderung gelöscht (§ 360 Abs. 11 SGB V).

-

Zugriffsprotokolle im Rezeptdienst werden nicht auf Ihrem Gerät gespeichert und können nicht gelöscht werden. Sie werden nach drei Jahren automatisch im Rezeptdienst gelöscht (§ 309 SGB V).

+

Zugriffsprotokolle im Rezeptdienst werden nicht auf Ihrem Gerät gespeichert und können nicht gelöscht werden. Sie werden nach drei Jahren automatisch im Rezeptdienst gelöscht (§ 309 SGB V).

Wenn Sie ein Profil löschen, werden alle damit zusammenhängenden Daten einschließlich der vom Rezeptdienst heruntergeladenen Daten und der gespeicherten Zugangsdaten gelöscht. Die gespeicherten Zugangsdaten werden auch gelöscht, wenn Sie „Zugangsdaten speichern“ deaktivieren.

@@ -138,36 +148,35 @@

6. Wann werden Ihre Daten gelöscht?

Die Deinstallation der E-Rezept-App bewirkt die Löschung sämtlicher von der E-Rezept-App auf Ihrem Gerät gespeicherten Daten.

-

7. Ihre Datenschutzrechte

- -

Bezüglich der mit Ihrer Einwilligung an die gematik übermittelten Nutzungsdaten stehen Ihnen gegenüber der gematik die Rechte auf Auskunft (Art. 15 DSGVO), Berichtigung (Art. 16 DSGVO), Löschung (Art. 17 DSGVO), Einschränkung der Verarbeitung (Art. 18 DSGVO) sowie Datenübertragbarkeit (Art. 20 DSGVO) zu. Sie haben auch das Recht, Ihre Einwilligung zu widerrufen (siehe hierzu unter Nutzungsanalyse). Bitte beachten Sie, dass die gematik Ihre Nutzungsdaten in anonymisierter Form speichert. Eine Zuordnung dieser Daten zu Ihrer Person ist nicht mehr möglich, so dass die oben genannten Datenschutzrechte keine Anwendung mehr finden (Art. 11 Abs. 2 DSGVO, § 308 SGB V).

+

7. Ihre Datenschutzrechte

-

Sie haben außerdem das Recht, sich bei einer Datenschutz-Aufsichtsbehörde zu beschweren. Die für die gematik zuständige Datenschutz-Aufsichtsbehörde ist der Bundesbeauftragte für den Datenschutz und die Informationsfreiheit.

+

Bezüglich der mit Ihrer Einwilligung an die gematik übermittelten Nutzungsdaten stehen Ihnen gegenüber der gematik die Rechte auf Auskunft (Art. 15 DSGVO), Berichtigung (Art. 16 DSGVO), Löschung (Art. 17 DSGVO), Einschränkung der Verarbeitung (Art. 18 DSGVO) sowie Datenübertragbarkeit (Art. 20 DSGVO) zu. Sie haben auch das Recht, Ihre Einwilligung zu widerrufen (siehe hierzu unter Nutzungsanalyse). Bitte beachten Sie, dass die gematik Ihre Nutzungsdaten in anonymisierter Form speichert. Eine Zuordnung dieser Daten zu Ihrer Person ist nicht mehr möglich, so dass die oben genannten Datenschutzrechte keine Anwendung mehr finden (Art. 11 Abs. 2 DSGVO, § 308 SGB V). Sie haben außerdem das Recht, sich bei einer Datenschutz-Aufsichtsbehörde zu beschweren. Die für die gematik zuständige Datenschutz-Aufsichtsbehörde ist der Bundesbeauftragte für den Datenschutz und die Informationsfreiheit.

-

8. Weitere Verantwortliche

+

8. Weitere Verantwortliche

Für die folgenden Dienste sind gemäß § 307 Abs. 4 SGB V die jeweiligen Anbieter datenschutzrechtlich verantwortlich:

    -
  • Rezeptdienst: IBM Deutschland GmbH, IBM-Allee 1, 71139 Ehningen
  • -
  • Identitätsdienst: Research Industrial Systems Engineering (RISE) Forschungs-, Entwicklungs- und Großprojektberatung GmbH, Concorde Business Park F, 2320 Schwechat, Österreich
  • -
  • Apothekenverzeichnis: Deutscher Apothekerverband e.V., Heidestraße 7, 10557 Berlin
  • +
  • Rezeptdienst: IBM Deutschland GmbH, IBM-Allee 1, 71139 Ehningen
  • +
  • Identitätsdienst: Research Industrial Systems Engineering (RISE) Forschungs-, Entwicklungs- und Großprojektberatung GmbH, Concorde Business Park F, 2320 Schwechat, Österreich
  • +
  • Apothekenverzeichnis: Deutscher Apothekerverband e.V., Heidestraße 7, 10557 Berlin
-

9. Ansprechpartner

+

9. Ansprechpartner

-

Die Kontaktdaten der gematik können Sie dem Impressum entnehmen. Weitere Kontaktmöglichkeiten finden Sie in den Einstellungen unter „Kontakt“.

+

Die Kontaktdaten der gematik können Sie dem Impressum entnehmen. Weitere Kontaktmöglichkeiten finden Sie in den Einstellungen unter „Kontakt“.

-

Bei Fragen zum Datenschutz oder zu Ihren Datenschutzrechten im Zusammenhang mit dieser App können Sie sich an den Datenschutzbeauftragten der gematik wenden.

- -

Sie erreichen ihn

+

Bei Fragen zum Datenschutz oder zu Ihren Datenschutzrechten im Zusammenhang mit dieser App können Sie sich an den Datenschutzbeauftragten der gematik wenden. Sie erreichen ihn

Bei Fragen zum Gesundheitsnetz (Telematikinfrastruktur) und insbesondere zu den datenschutzrechtlichen Verantwortlichkeiten der beteiligten Anbieter können Sie sich an den Datenschutzlotsen der gematik wenden: https://www.gematik.de/datensicherheit/datenschutzlotse

+ +

Stand: Juni 2023

+ - + \ No newline at end of file diff --git a/android/src/main/java/de/gematik/ti/erp/app/App.kt b/android/src/main/java/de/gematik/ti/erp/app/App.kt index 3b0b0346..cb4bbbc7 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/App.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/App.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/LegalNoticeScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/LegalNoticeScreen.kt index b7255ea7..d5bad335 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/LegalNoticeScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/LegalNoticeScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -52,11 +52,10 @@ import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.canHandleIntent -import de.gematik.ti.erp.app.utils.compose.createToastShort import de.gematik.ti.erp.app.utils.compose.handleIntent import de.gematik.ti.erp.app.utils.compose.provideEmailIntent import de.gematik.ti.erp.app.utils.compose.providePhoneIntent -import java.util.* +import de.gematik.ti.erp.app.utils.compose.shortToast @Composable fun LegalNoticeWithScaffold(navigation: NavHostController) { @@ -212,7 +211,7 @@ fun EmailContact( if (canHandleIntent(intent, context.packageManager)) { context.startActivity(intent) } else { - createToastShort(context, noEmailClientText) + context.shortToast(noEmailClientText) } } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/MainActivity.kt b/android/src/main/java/de/gematik/ti/erp/app/MainActivity.kt index 2c194051..634eeea2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/MainActivity.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/MainActivity.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -262,6 +262,11 @@ class MainActivity : AppCompatActivity(), DIAware { } } + @Requirement( + "O.Arch_10#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "If an update is required, the user is prompted to update via Google´s InAppUpdate function" + ) private suspend fun checkAppUpdate() { if (checkVersionUseCase.isUpdateRequired()) { val appUpdateManager = AppUpdateManagerFactory.create(this) diff --git a/android/src/main/java/de/gematik/ti/erp/app/MessageConversionException.kt b/android/src/main/java/de/gematik/ti/erp/app/MessageConversionException.kt index 91375851..cf7f7f9c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/MessageConversionException.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/MessageConversionException.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/Navigation.kt index 33849a0f..d9d98c69 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/TestTags.kt b/android/src/main/java/de/gematik/ti/erp/app/TestTags.kt index 95c1abec..0c15a54c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/TestTags.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/TestTags.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -188,7 +188,9 @@ object TestTag { val PickUpOptionButton by tagName() val CourierDeliveryOptionButton by tagName() - val OnlineDeliveryOptionButton by tagName() + val MailDeliveryOptionButton by tagName() + + val ComposeToast by tagName() } object OrderPrescriptionSelection { diff --git a/android/src/main/java/de/gematik/ti/erp/app/TestWrapper.kt b/android/src/main/java/de/gematik/ti/erp/app/TestWrapper.kt index 36d97449..b7ea67ec 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/TestWrapper.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/TestWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/VisibleDebugTree.kt b/android/src/main/java/de/gematik/ti/erp/app/VisibleDebugTree.kt index 95b1460b..b183a3b3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/VisibleDebugTree.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/VisibleDebugTree.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/analytics/Analytics.kt b/android/src/main/java/de/gematik/ti/erp/app/analytics/Analytics.kt index ccdd0743..4ab69cd1 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/analytics/Analytics.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/analytics/Analytics.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -64,6 +64,13 @@ class Analytics( sourceSpecification = "gemSpec_eRp_FdV", rationale = "Only screen names and data like error states are transmitted." ) + @Requirement( + "O.Purp_2#5", + "O.Purp_4#1", + "O.Data_6#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "User interaction analytics trigger records data only if user opt-in is given." + ) fun trackScreen(screenName: String) { if (analyticsAllowed.value) { Contentsquare.send(screenName) @@ -114,6 +121,11 @@ class Analytics( sourceSpecification = "gemSpec_eRp_FdV", rationale = "Enable analytics" ) + @Requirement( + "O.Purp_5#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Enable usage analytics." + ) fun allowAnalytics() { _analyticsAllowed.value = true @@ -131,6 +143,11 @@ class Analytics( sourceSpecification = "gemSpec_eRp_FdV", rationale = "Disable analytics" ) + @Requirement( + "O.Purp_5#6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Disable usage analytics." + ) fun disallowAnalytics() { _analyticsAllowed.value = false diff --git a/android/src/main/java/de/gematik/ti/erp/app/analytics/usecase/AnalyticsUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/analytics/usecase/AnalyticsUseCase.kt index 19e87b87..600feccb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/analytics/usecase/AnalyticsUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/analytics/usecase/AnalyticsUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt b/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt index 47e20090..8ef9b496 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt index 0c9b122d..c09aaec9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/attestation/usecase/IntegrityUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,6 +23,7 @@ import android.util.Base64 import com.google.android.play.core.integrity.IntegrityManagerFactory import com.google.android.play.core.integrity.IntegrityTokenRequest import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.secureRandomInstance import de.gematik.ti.erp.app.vau.toLowerCaseHex @@ -45,7 +46,19 @@ private const val RequiredSaltLength = 32 class IntegrityUseCase( private val context: Context ) { - + @Requirement( + "O.Arch_6#1", + "O.Resi_2#1", + "O.Resi_3#1", + "O.Resi_4#1", + "O.Resi_5#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "In the release process, the app is signed and the signed app bundle is uploaded to the store. " + + "An altered application can only run on a jailbroken device. We are using Googles Integrity API " + + "to detect jailbreaked devices. If a user is using a jailbroken device, may it be known or unknown, " + + "we display a security alert so a user can make an informed decision to use or " + + "not use the application.." + ) fun runIntegrityAttestation(): Flow = flow { val salt = provideSalt() val ourNonce = generateNonce(salt, nonceData()) @@ -62,6 +75,12 @@ class IntegrityUseCase( val token = tokenResponse.token() + @Requirement( + "O.Cryp_1#6", + "O.Cryp_4#6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" + ) val decryptionKeyBytes: ByteArray = Base64.decode(BuildKonfig.INTEGRITY_API_KEY, Base64.DEFAULT) diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/CardUnlockModule.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/CardUnlockModule.kt index 3fd73682..0fe466ae 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/CardUnlockModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/CardUnlockModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt index 6c8129b9..3487406d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/model/UnlockEgkNavigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt index cc75e614..72d2b482 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgKComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -45,6 +45,7 @@ import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.analytics.TrackNavigationChanges import de.gematik.ti.erp.app.card.model.command.UnlockMethod import de.gematik.ti.erp.app.cardunlock.model.UnlockEgkNavigation @@ -316,6 +317,12 @@ private fun CardAccessNumberScreen( private val PUKLengthRange = 8..8 +@Requirement( + "O.Purp_2#4", + "O.Data_6#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "PUK is used for unlock eGK." +) @Composable private fun PersonalUnblockingKeyScreen( personalUnblockingKey: String, diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkController.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkController.kt index f8c5a491..35c90aeb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkDialog.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkDialog.kt index 598b2cc2..5992dc20 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkDialog.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/ui/UnlockEgkDialog.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/usecase/UnlockEgkUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/usecase/UnlockEgkUseCase.kt index 05650bef..98f9853b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardunlock/usecase/UnlockEgkUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardunlock/usecase/UnlockEgkUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/CardWallModule.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/CardWallModule.kt index 12736584..39fe149a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/CardWallModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/CardWallModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/domain/biometric/Biometric.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/domain/biometric/Biometric.kt index d468ffbb..15454796 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/domain/biometric/Biometric.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/domain/biometric/Biometric.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -37,6 +37,11 @@ fun isDeviceSupportsBiometric(biometricMode: Int) = when (biometricMode) { sourceSpecification = "gemSpec_IDP_Frontend", rationale = "Check for support of BIOMETRIC_STRONG." ) +@Requirement( + "O.Biom_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check whether at least one biometric reference is available." +) fun deviceStrongBiometricStatus(context: Context): Int { val biometricManager = BiometricManager.from(context) return biometricManager.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) @@ -50,6 +55,12 @@ fun deviceStrongBiometricStatus(context: Context): Int { sourceSpecification = "gemSpec_IDP_Frontend", rationale = "Check for availability of strongbox." ) +@Requirement( + "O.Biom_2#2", + "O.Biom_3#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for availability of strongbox." +) fun hasDeviceStrongBox(context: Context) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { context.packageManager.hasSystemFeature(PackageManager.FEATURE_STRONGBOX_KEYSTORE) diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/Authentication.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/Authentication.kt index ee6203a7..1d8425ef 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/Authentication.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/Authentication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/ExternalAuthPrompt.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/ExternalAuthPrompt.kt index 96d0c404..4f29f686 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/ExternalAuthPrompt.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/ExternalAuthPrompt.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/HealthCardPrompt.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/HealthCardPrompt.kt index ee97c732..3f2bca82 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/HealthCardPrompt.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/HealthCardPrompt.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -212,10 +212,14 @@ class HealthCardPromptAuthenticator( "A_19937", "A_20079", "A_20605#1", - "GS-A_5542", sourceSpecification = "gemSpec_eRp_FdV", rationale = "Propagates IDP auth states to the user." ) + @Requirement( + "GS-A_5542#1", + sourceSpecification = "gemSpec_Krypt", + rationale = "Propagates IDP auth states to the user." + ) private fun AuthenticationState.emitAuthState() { when { isInProgress() -> { diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/MiniCardWallController.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/MiniCardWallController.kt index 72ddc7d4..67554aa0 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/MiniCardWallController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/MiniCardWallController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/SecureHardwarePrompt.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/SecureHardwarePrompt.kt index f6a4d0b5..22f254ba 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/SecureHardwarePrompt.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/mini/ui/SecureHardwarePrompt.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardChannel.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardChannel.kt index 936dfd9e..40ff4cf2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardChannel.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardSecureChannel.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardSecureChannel.kt index 5076ee38..de94194a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardSecureChannel.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcCardSecureChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcHealthCard.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcHealthCard.kt index a56ce345..34676afa 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcHealthCard.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/model/nfc/card/NfcHealthCard.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/AltPairing.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/AltPairing.kt index 3c85c284..444e8c07 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/AltPairing.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/AltPairing.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -78,12 +78,22 @@ class AltPairingProvider( sourceSpecification = "gemSpec_IDP_Frontend", rationale = "Initialize biometric authentication for strongbox backed devices." ) + @Requirement( + "O.Biom_1#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Initialize biometric authentication for strongbox backed devices." + ) @RequiresApi(Build.VERSION_CODES.P) suspend fun initializeAndPrompt(): AuthResult = suspendCancellableCoroutine { continuation -> val aliasOfSecureElementEntry = ByteArray(KeyStoreAliasKeySize).apply { secureRandomInstance().nextBytes(this) } + @Requirement( + "O.Biom_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The app uses the Android keystore to evaluate the biometric authentication" + ) val keyPairGenerator = KeyPairGenerator.getInstance( KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore" @@ -93,6 +103,12 @@ class AltPairingProvider( Base64.toBase64String(aliasOfSecureElementEntry), KeyProperties.PURPOSE_SIGN ).apply { + @Requirement( + "O.Biom_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Biometric secured private keys are invalid whenever the biometrics setup changes. " + + "Invalidates biometry after changes" + ) setInvalidatedByBiometricEnrollment(true) setUserAuthenticationRequired(true) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { @@ -101,6 +117,12 @@ class AltPairingProvider( // Android will throw a `KeyPermanentlyInvalidatedException`. Later on if the user restarts // the phone, the key is permanently invalidated and the actual `UserNotAuthenticatedException` // is thrown. + @Requirement( + "O.Biom_2#3", + "O.Biom_3#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Require Biometric STRONG." + ) setUserAuthenticationParameters(KeyTimeout, KeyProperties.AUTH_BIOMETRIC_STRONG) } setIsStrongBoxBacked(true) diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAccessNumber.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAccessNumber.kt index a924795c..e3f7b76c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAccessNumber.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAccessNumber.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -46,6 +46,7 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.pharmacy.ui.scrollOnFocus import de.gematik.ti.erp.app.theme.AppTheme @@ -58,6 +59,12 @@ import de.gematik.ti.erp.app.utils.compose.annotatedLinkStringLight const val EXPECTED_CAN_LENGTH = 6 +@Requirement( + "O.Purp_2#2", + "O.Data_6#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "CAN is used for eGK connection." +) @Composable fun CardAccessNumber( onClickLearnMore: () -> Unit, diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAnimation.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAnimation.kt index 71b27f7e..857a73fc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAnimation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAnimation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAuthDialog.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAuthDialog.kt index 0a3107e5..deee2328 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAuthDialog.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallAuthDialog.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt index 79fc2887..639a7108 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -78,6 +78,7 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.cardunlock.ui.UnlockEgKScreen import de.gematik.ti.erp.app.cardwall.domain.biometric.deviceStrongBiometricStatus @@ -234,6 +235,14 @@ fun CardWallScreen( onClickNoPinReceived = { navController.navigate(CardWallNavigation.OrderHealthCard.path()) } ) { val deviceSupportsBiometric = isDeviceSupportsBiometric(biometricMode) + + @Requirement( + "O.Biom_2#1", + "O.Biom_3#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Only if device has strongbox, the user can select authentication with " + + "biometric prompt" + ) val deviceSupportsStrongbox = hasDeviceStrongBox(context) if (deviceSupportsBiometric && deviceSupportsStrongbox @@ -276,6 +285,13 @@ fun CardWallScreen( } NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Biom_1", + "O.Biom_8", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Authentication via biometrics is only possible in combination with " + + "successful authentication via eGK + PIN." + ) AlternativeOptionInfoScreen( onCancel = onBack, onAccept = { @@ -369,6 +385,12 @@ fun CardWallScreen( } } +@Requirement( + "O.Purp_2#3", + "O.Data_6#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "PIN is used for eGK connection." +) @Composable fun PersonalIdentificationNumberScreen( navMode: NavigationMode, diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallController.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallController.kt index b755114f..3d578642 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcInstructionScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcInstructionScreen.kt index ccc796b1..7408a48d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcInstructionScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcInstructionScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcPositionState.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcPositionState.kt index 1d0e8c75..fd480606 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcPositionState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallNfcPositionState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallScaffold.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallScaffold.kt index 48789453..654a8a07 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallScaffold.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -50,6 +50,7 @@ import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.theme.AppTheme @@ -61,6 +62,11 @@ import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.SpacerXLarge +@Requirement( + "O.Auth_3#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Selection of Authentication with health card or insurance App" +) @Composable fun CardWallIntroScaffold( onNext: () -> Unit, diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallSecret.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallSecret.kt index 87e1251b..ad10b57e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallSecret.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/CardWallSecret.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -54,6 +54,7 @@ import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.pharmacy.ui.scrollOnFocus import de.gematik.ti.erp.app.theme.AppTheme @@ -156,6 +157,13 @@ fun CardWallSecretScreen( } } +@Requirement( + "O.Data_10", + "O.Data_11", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Password fields using the keyboard type numberPassword. Copying the content is not possible " + + "with this type. Autocorrect is disallowed. It`s not possible to disable third party keyboards." +) @Composable fun SecretInputField( modifier: Modifier, @@ -166,7 +174,8 @@ fun SecretInputField( label: String, next: (String) -> Unit ) { - val secretRegex = """^\d{0,${secretRange.last}}$""".toRegex() + val secretRegexString = "^\\d{0,${secretRange.last}}$" + val secretRegex = secretRegexString.toRegex() var secretVisible by remember { mutableStateOf(false) } OutlinedTextField( @@ -228,7 +237,8 @@ fun ConformationSecretInputField( isConsistent: Boolean, next: (String) -> Unit ) { - val secretRegex = """^\d{0,${secretRange.last}}$""".toRegex() + val secretRegexString = "^\\d{0,${secretRange.last}}$" + val secretRegex = secretRegexString.toRegex() var secretVisible by remember { mutableStateOf(false) } OutlinedTextField( @@ -266,7 +276,7 @@ fun ConformationSecretInputField( } }, keyboardActions = KeyboardActions { - if (isConsistent) { + if (isConsistent && secret.length in secretRange) { next(secret) } }, diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListScreen.kt index 974b58a0..1b108b50 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListViewModel.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListViewModel.kt index 65509eed..20549201 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListViewModel.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/ExternalAuthenticatorListViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt index b334bcfc..055a765a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/ui/model/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/AuthenticationUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/AuthenticationUseCase.kt index 6ddb5ce3..fa66f2e1 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/AuthenticationUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/AuthenticationUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallLoadNfcPositionUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallLoadNfcPositionUseCase.kt index 6fb8ae61..4a771ad2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallLoadNfcPositionUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallLoadNfcPositionUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallUseCase.kt index f5bbc4f7..053ead58 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/CardWallUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/MiniCardWallUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/MiniCardWallUseCase.kt index 8e2494f2..9c97163a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/MiniCardWallUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/MiniCardWallUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/model/NfcPositionUseCaseData.kt b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/model/NfcPositionUseCaseData.kt index dd63727e..14ad84c9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/model/NfcPositionUseCaseData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/cardwall/usecase/model/NfcPositionUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/core/AppScopedCache.kt b/android/src/main/java/de/gematik/ti/erp/app/core/AppScopedCache.kt index 8ca8c208..853eab17 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/core/AppScopedCache.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/core/AppScopedCache.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/core/IntentHandler.kt b/android/src/main/java/de/gematik/ti/erp/app/core/IntentHandler.kt index 7c356e2b..c882a9fc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/core/IntentHandler.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/core/IntentHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,6 +23,7 @@ import android.content.Intent import android.net.Uri import androidx.compose.runtime.Stable import androidx.compose.runtime.staticCompositionLocalOf +import de.gematik.ti.erp.app.Requirement import io.github.aakira.napier.Napier import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.receiveAsFlow @@ -40,6 +41,11 @@ class IntentHandler(private val context: Context) { val shareIntent = shareChannel.receiveAsFlow() + @Requirement( + "O.Source_1#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "External application calls via Universal Linking" + ) suspend fun propagateIntent(intent: Intent) { intent.data?.let { val value = it.toString() diff --git a/android/src/main/java/de/gematik/ti/erp/app/core/MainComposable.kt b/android/src/main/java/de/gematik/ti/erp/app/core/MainComposable.kt index 75b03c21..a0fdac9e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/core/MainComposable.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/core/MainComposable.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt b/android/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt index 52080151..94bc9fb9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/di/AllModules.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/di/NetworkModule.kt b/android/src/main/java/de/gematik/ti/erp/app/di/NetworkModule.kt index 755170fc..96afccef 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/di/NetworkModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/di/NetworkModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -60,11 +60,7 @@ class AuditEventFilteredHttpLoggingInterceptor( private val loggingInterceptor: HttpLoggingInterceptor ) : Interceptor { override fun intercept(chain: Interceptor.Chain): Response = - if ("AuditEvent" in chain.request().url.encodedPath) { - chain.proceed(chain.request()) - } else { - loggingInterceptor.intercept(chain) - } + loggingInterceptor.intercept(chain) } class NapierLogger(tagSuffix: String? = null) : HttpLoggingInterceptor.Logger { @@ -93,9 +89,6 @@ const val JsonFhirConverterFactoryTag = "JsonFhirConverterFactoryTag" "A_20529-01", "A_20606", "A_20608", - "GS-A_5035", - "GS-A_4387", - "GS-A_4385", "A_20607", "A_20609", "A_20617-01#1", @@ -103,6 +96,13 @@ const val JsonFhirConverterFactoryTag = "JsonFhirConverterFactoryTag" sourceSpecification = "gemSpec_eRp_FdV", rationale = "Any connection to the IDP or the ERP service uses this configuration." ) +@Requirement( + "GS-A_5035", + "GS-A_4387", + "GS-A_4385", + sourceSpecification = "gemSpec_Krypt", + rationale = "Any connection to the IDP or the ERP service uses this configuration." +) @OptIn(ExperimentalSerializationApi::class) val networkModule = DI.Module("Network Module") { bindInstance { @@ -115,6 +115,23 @@ val networkModule = DI.Module("Network Module") { bindSingleton(JsonFhirConverterFactoryTag) { instance().asConverterFactory("application/json+fhir".toMediaType()) } + @Requirement( + "O.Ntwk_1#2", + "O.Ntwk_2#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Bind the connection specification." + ) + @Requirement( + "O.Ntwk_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use OkHttp for network communication" + ) + @Requirement( + "GS-A_5322", + sourceSpecification = "gemSpec_Krypt", + rationale = "We initialize our okhttp client as singleton. Thus, we support TLS resumption, it is handled by " + + "okhttp. See https://square.github.io/okhttp/4.x/okhttp/okhttp3/-connection/ for more details." + ) bindSingleton { OkHttpClient.Builder() .connectTimeout( @@ -275,7 +292,7 @@ val networkModule = DI.Module("Network Module") { } @Requirement( - "A_20206", + "A_20206-01", "A_17322", "A_18464", "A_18467", @@ -284,6 +301,25 @@ val networkModule = DI.Module("Network Module") { sourceSpecification = "gemSpec_eRp_FdV", rationale = "Any connection initiated by the app uses TLS 1.2 or higher." ) +@Requirement( + "GS-A_4357-2#1", + "GS-A_4361-2#1", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Cipher Suites regarding sha256WithRsaEncryption are listed below, see RSA specific cipher suites." +) +@Requirement( + "O.Ntwk_1#1", + "O.Ntwk_2#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Any connection initiated by the app uses TLS 1.2 or higher." +) +@Requirement( + "GS-A_5035#1", + "GS-A_4385#1", + "GS-A_4387#1", + sourceSpecification = "gemSpec_Krypt", + rationale = "Any connection initiated by the app uses TLS 1.2 or higher." +) private fun getConnectionSpec(): List = ConnectionSpec .Builder(ConnectionSpec.RESTRICTED_TLS) .tlsVersions( diff --git a/android/src/main/java/de/gematik/ti/erp/app/di/RealmModule.kt b/android/src/main/java/de/gematik/ti/erp/app/di/RealmModule.kt index e10e16b2..fc7c0cc7 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/di/RealmModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/di/RealmModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -50,7 +50,28 @@ const val RealmDatabaseSecurePreferencesTag = "RealmDatabaseSecurePreferences" "A_19186", "A_20184#2", sourceSpecification = "gemSpec_eRp_FdV", - rationale = "Only encrypted SharedPreferences and an encrypted database are used to store data." + rationale = "Only encrypted SharedPreferences and an encrypted database are used to store data. " + + "It is not possible to create backups from within the app. If this is triggered externally, " + + "we use an encrypted database and encrypted preferences. The access keys are stored in the encrypted " + + "shared preferences" +) +@Requirement( + "O.Arch_2#1", + "O.Arch_4#1", + "O.Data_2", + "O.Data_3", + "O.Data_14", + "O.Data_15#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Only encrypted SharedPreferences and an encrypted database are used to store data. " + + "It is not possible to create backups from within the app. If this is triggered externally, " + + "we use an encrypted database and encrypted preferences. The access keys are stored in the encrypted " + + "shared preferences" +) +@Requirement( + "O.Source_2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Database access is done via prepared statements featured by Realm Database." ) val realmModule = DI.Module("realmModule") { bindSingleton(RealmDatabaseSecurePreferencesTag) { @@ -104,6 +125,11 @@ private fun generatePassPhrase(): String { return Base64.encode(passPhrase) } +@Requirement( + "O.Data_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Database access is done via prepared statements featured by Realm Database." +) private fun storePassPhrase( securePrefs: SharedPreferences, passPhrase: String diff --git a/android/src/main/java/de/gematik/ti/erp/app/featuretoggle/FeatureToggleManager.kt b/android/src/main/java/de/gematik/ti/erp/app/featuretoggle/FeatureToggleManager.kt index 8eece414..1e8f303e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/featuretoggle/FeatureToggleManager.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/featuretoggle/FeatureToggleManager.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/idp/IdpModule.kt b/android/src/main/java/de/gematik/ti/erp/app/idp/IdpModule.kt index d0d5726c..26b11461 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/idp/IdpModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/idp/IdpModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/interceptor/HeadersInterceptor.kt b/android/src/main/java/de/gematik/ti/erp/app/interceptor/HeadersInterceptor.kt index 16758928..18731a7a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/interceptor/HeadersInterceptor.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/interceptor/HeadersInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/license/model/LicenseModels.kt b/android/src/main/java/de/gematik/ti/erp/app/license/model/LicenseModels.kt index 9c8a81c4..a9040727 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/license/model/LicenseModels.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/license/model/LicenseModels.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/license/ui/LicenseScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/license/ui/LicenseScreen.kt index d030af8f..45cf68c7 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/license/ui/LicenseScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/license/ui/LicenseScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -40,6 +40,7 @@ import androidx.compose.ui.text.buildAnnotatedString import androidx.compose.ui.text.font.FontStyle import androidx.compose.ui.tooling.preview.Preview import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.license.model.License import de.gematik.ti.erp.app.license.model.LicenseEntry import de.gematik.ti.erp.app.license.model.parseLicenses @@ -62,6 +63,17 @@ fun rememberLicenses(): List { } } +@Requirement( + "O.Purp_7#1", + "O.Arch_7", + "O.Source_10", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Dependencies are only included if really necessary. " + + "We think about including only sub packages, but as most dependencies are very small, " + + "this is hardly used. We are using proguard for removing unused dependency functionality." + + "By default, Stack Smashing Protection is active." + + "A vulnerability analysis on 3rd party libraries is carried out using Owasp Dependency Check." +) @Composable fun LicenseScreen( navigationMode: NavigationBarMode = NavigationBarMode.Back, diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/FastTrackComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/FastTrackComponents.kt index fcb3fa6d..45730fa3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/FastTrackComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/FastTrackComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -27,6 +27,7 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.remember import androidx.compose.ui.res.stringResource import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.core.LocalIntentHandler import de.gematik.ti.erp.app.idp.usecase.IdpUseCase import de.gematik.ti.erp.app.utils.compose.AcceptDialog @@ -44,6 +45,11 @@ class FastTrackHandler( /** * Handles an incoming intent. Returns `true` if the intent could be handled. */ + @Requirement( + "O.Plat_10#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "handle incoming intent" + ) @Suppress("TooGenericExceptionCaught") suspend fun handle(value: String): Boolean = try { diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt index 09d371b7..e804bdd9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/InsecureDeviceScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -67,6 +67,15 @@ import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall import kotlinx.coroutines.launch import java.util.Locale +@Requirement( + "O.Arch_6#3", + "O.Resi_2#3", + "O.Resi_3#3", + "O.Resi_4#3", + "O.Resi_5#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Show integrity warning." +) @Requirement( "A_21574", sourceSpecification = "gemSpec_IDP_Frontend", diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt index 1e6adddf..78c0e25a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenBottomSheetContentState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -47,6 +47,7 @@ import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.input.ImeAction +import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp @@ -163,6 +164,7 @@ fun MainScreenBottomSheetContentState( } } ) + is MainScreenBottomSheetContentState.EditProfileName -> ProfileSheetContent( profilesController = profilesController, @@ -170,6 +172,7 @@ fun MainScreenBottomSheetContentState( profileToEdit = profileToRename, onCancel = onCancel ) + is MainScreenBottomSheetContentState.AddProfile -> ProfileSheetContent( profilesController = profilesController, @@ -238,15 +241,17 @@ fun ProfileSheetContent( value = textValue, singleLine = true, onValueChange = { - val name = sanitizeProfileName(it.trimStart()) + val isNotExistingText = textValue.trim() != profileToEdit?.name + val isNotExistingName = profilesState.containsProfileWithName(textValue) + val name = it.trimStart().sanitizeProfileName() textValue = name - duplicated = textValue.trim() != profileToEdit?.name && - profilesState.containsProfileWithName(textValue) + duplicated = isNotExistingText && isNotExistingName }, keyboardOptions = KeyboardOptions( autoCorrect = true, keyboardType = KeyboardType.Text, - imeAction = ImeAction.Done + imeAction = ImeAction.Done, + capitalization = KeyboardCapitalization.Sentences ), keyboardActions = KeyboardActions { if (!duplicated && textValue.isNotEmpty()) { diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenComponents.kt index 6404008c..8593adb1 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -89,6 +89,7 @@ import androidx.navigation.navOptions import de.gematik.ti.erp.app.BuildConfig import de.gematik.ti.erp.app.LegalNoticeWithScaffold import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.analytics.TrackNavigationChanges import de.gematik.ti.erp.app.analytics.TrackPopUps @@ -114,7 +115,7 @@ import de.gematik.ti.erp.app.prescription.ui.PrescriptionScreen import de.gematik.ti.erp.app.prescription.ui.PrescriptionServiceState import de.gematik.ti.erp.app.prescription.ui.RefreshedState import de.gematik.ti.erp.app.prescription.ui.ScanScreen -import de.gematik.ti.erp.app.prescription.ui.rememberPrescriptionState +import de.gematik.ti.erp.app.prescription.ui.rememberPrescriptionsController import de.gematik.ti.erp.app.profiles.ui.EditProfileScreen import de.gematik.ti.erp.app.profiles.ui.LocalProfileHandler import de.gematik.ti.erp.app.profiles.ui.ProfileImageCropper @@ -148,6 +149,374 @@ import kotlinx.coroutines.withContext private const val BottomBarBadgeOffsetX = -5 private const val BottomBarBadgeOffsetY = 5 +@Requirement( + "A_19178", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "see documentation-internal/security/mstg.adoc" +) +@Requirement( + "A_19983", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "All used services except our analytics framework are permitted and attested by the Gematik and " + + "under the TI monitoring. The usage of our analytics framework is not under our control, but we " + + "exclusively send data to it and receive none." +) +@Requirement( + "A_19979", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "We use external services: The Apothekenverzeichnis and our analytics framework. " + + "During the communication with the pharmacy, there will be data shared via a prescription code. " + + "The requirement to this feature is described in gemSpec_eRp_FdV section 5.2.3.10 and 5.2.3.11." + + "Our analytics framework does not use medical personal data, see DSFA section 5.6 " + + "Verarbeitungsvorgang 4: Rezepte einlösen" +) +@Requirement( + "A_19182", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "In order to minimize the risk of unknown vulnerabilities in dependencies, we use different measures:" + + "- We develop according to Security by Design Principles (see E-Rezept-App - SSDLC.pdf - Section " + + "Richtlinien, Vorgaben und Best Practices)" + + "- We train our engineers focussing on secure design and coding best practices " + + "(see Sicherheitsschulungen.pdf)" + + "- We publish our Code on Github and use a bug bounty program (https://www.gematik.de/datensicherheit -> " + + "Coordinated Vulnerability Disclosure Program)" +) +@Requirement( + "GS-A_5526", + sourceSpecification = "gemSpec_Krypt", + rationale = "Renegotiation is disabled by default in BoringSSL:\n" + + "'https://boringssl.googlesource.com/boringssl/+/9f69f139ed1088daabb6525f0c9c34d1e89688f7/PORTING.md" + + "#:~:text=TLS%20renegotiation&text=Renegotiation%20is%20an%20extremely%20problematic," + + "rejects%20peer%20renegotiations%20by%20default.'" +) +@Requirement( + "O.Arch_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We implement an SSDLC" +) +@Requirement( + "O.Arch_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "All cryptography is specified by gemSpec_Krypt in corporation with BSI" +) +@Requirement( + "O.Arch_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Authentication and Authorization are not handled by the App itself. It rather takes place in the " + + "IDP respectively the Relying Party. All communication is done with trustworhty backends, which is ensured" + + "by certificate pinning." +) +@Requirement( + "O.Arch_8", + "O.Plat_11", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Webviews only display local content that is delivered together with the application. " + + "Javascript is disabled, linking and loading other content is disabled. " + + "All website open the system browser." +) +@Requirement( + "O.Source_5", + "O.Source_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Secure deletion in memory is not possible with the technologies used, since automatic memory " + + "management is used. If there are errors in establishing the connection, the request is aborted. " + + "Access to sensitive data in the backend is only possible after successful authentication." +) +@Requirement( + "O.Source_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Automatic memory management is used in which the application cannot influence write and read access." +) +@Requirement( + "O.TrdP_1", + "O.TrdP_2", + "O.TrdP_3", + "O.TrdP_4", + "O.TrdP_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use a dependency check that is evaluated cyclically. All libraries are source code dependencies" + + "The dependencies are checked for vulnerabilities as part of the SAST/SCA checks. " + + "We are currently in the evaluation phase for a new tool due to the discontinuation of " + + "Microfocus Fortify. We also use the Owasp dependency check in the build pipeline." +) +@Requirement( + "O.TrdP_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We do not share sensitive data with third parties. Se data usages within `Purp_8` and `O.Arch_2" +) +@Requirement( + "O.TrdP_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "See `O.Source_1` and `O.Arch_6." +) +@Requirement( + "O.Cryp_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Private keys for encryption are either created and stored within the key store or stored " + + "within the eGK. As encryption for Server communication is done ephemeral via ECDH-ES, no static " + + "private keys on client side are necessary." +) +@Requirement( + "O.Cryp_2", + "O.Cryp_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "All cryptographics are defined within `gemSpec_Krypt`. The document was created together with BSI." +) +@Requirement( + "O.Cryp_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use Brainpool256R1 and AES256, see usages in O.Cryp_1 to O.Cryp_4" +) +@Requirement( + "O.Auth_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Our authentication concept is described in the following repository: https://github.com/gematik/" + + "api-erp/blob/master/docs/authentisieren.adoc We have more detailed diagrams regarding the context " + + "of the authentication in the SIS: Authentication on the central IDP: " + + "E-Rezept-App-Authentifizierungskonzept.pdf" + + "Authentication via Fast Track: E-Rezept-App-Authentifizierungskonzept_Fast_Track.pdf" +) +@Requirement( + "O.Auth_2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There is no client side separation of authentication and authorization. " + + "The authentication takes place at the identity provider, the authorization is realized by the Fachdienst" +) +@Requirement( + "O.Auth_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "One way to connect to the FD ist to login by using the eGK. To login with the eGK, the card, " + + "a CAN and a PIN is needed. The other way is to use a insurance company provided app. " + + "These apps must implement a second factor as well. " + + "See all `CardWall` prefixed files for all implementation details." +) +@Requirement( + "O.Auth_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There is no step up from always using 2nd factor authentication. Tokens have short lifetimes " + + "of 12h (server defined) SSO-Tokens and 5min Access-Tokens." +) +@Requirement( + "O.Auth_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "A Audit Log for every FD access is available in each user profile." +) +@Requirement( + "O.Auth_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There are not passwords to guess for server login within our application. " + + "Only eGK login is directly available within the application. The users application password is not " + + "delayed, as any user with PIN access would have access to the unencrypted file system as well." +) +@Requirement( + "O.Auth_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Token invalidation happens after 12 hours. If a user is still active, a reauthentication via eGK, " + + "Biometrics or Insurance App is necessary. " + + "Each meaning the posession and or knowledge of the needed user input." +) +@Requirement( + "O.Auth_10", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Authentication via eGK cannot be altered, as the physical card cannot be modified without " + + "authentication (e.g. PIN change). See gemSpec_COS for details. Adding a authentication key that " + + "is secured via biometrics (labeld as \"save login\" within the cardwall) enforces a new " + + "authentication via eGK on server side." +) +@Requirement( + "O.Auth_12", + "O.Data_19", + "O.Plat_4", + "O.Plat_5", + "O.Plat_8", + "O.Plat_9", + "O.Resi_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "unused" +) +@Requirement( + "O.Plat_16", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Since we implement the \"security-by-default\" principle, we don't have additional security " + + "measures which the user can use to increase the security level. All measures are built-in." +) +@Requirement( + "O.Pass_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There is no protocol for the application password within the application. " +) +@Requirement( + "O.Sess_1", "O.Sess_2", "O.Sess_3", "O.Sess_4", "O.Sess_5", "O.Sess_6", "O.Sess_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "not applicable" +) +@Requirement( + "O.Paid_1", "O.Paid_2", "O.Paid_3", "O.Paid_4", "O.Paid_5", "O.Paid_6", "O.Paid_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The app does not offer any purchases." +) +@Requirement( + "O.Tokn_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "For long-lived tokens, the token is stored in the secured realm database. Ephemeral tokens, " + + "such as those used in the biometric pairing process, do not persist and only remain in memory." +) +@Requirement( + "O.Tokn_2", + "O.Tokn_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The token is created by the backend, we have no means of manipulating the content." +) +@Requirement( + "O.Tokn_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The token is created by the IDP and signed there. We have not valid signing identity " + + "within the application to sign the token." +) +@Requirement( + "O.Tokn_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "A Section within User Profiles contains all tokens for that profile on the device." +) +@Requirement( + "O.Data_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Secure deletion in memory is not possible with the technologies used, since automatic memory " + + "management is used. Ephemeral private keys are released as soon as they are no longer needed" +) +@Requirement( + "O.Purp_2", + "O.Data_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Collected data is sparse and use case related as required." +) +@Requirement( + "O.Purp_8", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The purpose of data usage is described in section 4 and 5 of the Data Terms. " + + "Interfaces to external services can be found in the following package: " + + "common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/*" +) +@Requirement( + "O.Purp_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The purposes are described in the data terms in sections 4 and 5. " + + "All data presented are necessary besides the display of the tokens by the IDP. " + + "However, these are presented in the app due to O.Token_5." +) +@Requirement( + "O.Data_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Private data is not initially created by the application. Only additional information, such as " + + "redeeming or deleting prescriptions create data. The created data is kept on the FD." +) +@Requirement( + "O.Data_12", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There is no API that allows extraction of biometric data." +) +@Requirement( + "O.Data_15", + sourceSpecification = "BSI-eRp-ePA", + rationale = "All user data is stored in the private data area of the app and thus, cannot be accessed by another " + + "app. Furthermore, we have only encrypted data stored on the device. This excludes the health data from the " + + "backend, which can be accessed with legitimate authentication from other devices as well." +) +@Requirement( + "O.Data_16", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Storing application data is not possible." +) +@Requirement( + "O.Data_17", + "O.Data_18", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Uninstalling the app will delete all data stored by the e-prescription app on the device. By " + + "default, files that created on internal storage are accessible only to the app. Android implements " + + "this protection by default. The user may choose to manually logout or delete profiles before app deletion." +) +@Requirement( + "O.Ntwk_4", + "O.Ntwk_7", + "O.Resi_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "See network_security_config and AndroidManifest.xml for settings and pinned domains," + + " no exceptions are made" +) +@Requirement( + "O.Ntwk_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "By using OkHttp-Client handles that within the application." +) +@Requirement( + "O.Ntwk_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The server uses extended validation certificates to ensure maximum authenticity." +) +@Requirement( + "O.Ntwk_8", + "O.Ntwk_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "see results of backend system assessment." +) +@Requirement( + "O.Plat_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We test for device security at startup and show a dialog if the device is not secured." +) +@Requirement( + "O.Plat_2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "See AndroidManifest.xml for all accessed entitlements." +) +@Requirement( + "O.Plat_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use the platform dialoges for this." +) +@Requirement( + "O.Plat_6", + "O.Plat_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Implemented by the OS Sandboxing." +) +@Requirement( + "O.Plat_10", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Interprocesscommunication is implemented using Universal Linking. Current use cases are limited " + + "to login with insurance company apps. No sensitive data is transferred, the actual payload is decided " + + "by the server." +) +@Requirement( + "O.Plat_12", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use the platform dialoges for this." +) +@Requirement( + "O.Resi_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The application guides the user through the onboarding process and suggests the user the most " + + "secure mechanisms available on this device." +) +@Requirement( + "O.Resi_8", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Does not make sense. This Project is an open source project." +) +@Requirement( + "O.Resi_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use API keys that are assigned to fixed app versions at the backend service. " + + "We also have minimum requirements for the supported platform versions. " + + "There are minimum supported API levels, currently >= 24" +) +@Requirement( + "O.Resi_10", + sourceSpecification = "BSI-eRp-ePA", + rationale = "There are persistent data in the app, which means that the app is temporarily resilient to the " + + "unavailability of the backend service. As soon as data is persisted on the device, it can be " + + "accessed again even after local disruptions." +) @Suppress("LongMethod") @Composable fun MainScreen( @@ -180,6 +549,12 @@ fun MainScreen( } composable(MainNavigationScreens.DataProtection.route) { NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Arch_8#2", + "O.Plat_11#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Webview containing local html without javascript" + ) WebViewScreen( title = stringResource(R.string.onb_data_consent), onBack = { navController.popBackStack() }, @@ -200,6 +575,11 @@ fun MainScreen( ScanScreen(mainNavController = navController) } composable(MainNavigationScreens.Prescriptions.route) { + @Requirement( + "O.Plat_1#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for insecure Devices on MainScreen." + ) MainScreenWithScaffold( mainNavController = navController, onDeviceIsInsecure = { @@ -229,6 +609,11 @@ fun MainScreen( ) } composable(MainNavigationScreens.InsecureDeviceScreen.route) { + @Requirement( + "O.Plat_1#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "insecure Devices warning." + ) InsecureDeviceScreen( stringResource(id = R.string.insecure_device_title), painterResource(id = R.drawable.laptop_woman_yellow), @@ -321,6 +706,12 @@ fun MainScreen( } composable(MainNavigationScreens.Terms.route) { NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Arch_8#3", + "O.Plat_11#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Webview containing local html without javascript" + ) WebViewScreen( title = stringResource(R.string.onb_terms_of_use), onBack = { navController.popBackStack() }, @@ -337,6 +728,12 @@ fun MainScreen( } composable(MainNavigationScreens.DataProtection.route) { NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Arch_8#4", + "O.Plat_11#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Webview containing local html without javascript" + ) WebViewScreen( title = stringResource(R.string.onb_data_consent), onBack = { navController.popBackStack() }, @@ -456,10 +853,13 @@ fun MainScreen( composable( MainNavigationScreens.Archive.route ) { - val prescriptionState = rememberPrescriptionState() + val prescriptionController = rememberPrescriptionsController() NavigationAnimation(mode = navigationMode) { - ArchiveScreen(prescriptionState = prescriptionState, navController = navController) { + ArchiveScreen( + prescriptionsController = prescriptionController, + navController = navController + ) { navController.popBackStack() } } @@ -494,7 +894,21 @@ private fun MainScreenWithScaffold( currentBottomNavigationRoute?.destination?.route == MainNavigationScreens.Prescriptions.route } } + @Requirement( + "O.Plat_1#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for insecure Devices on MainScreen." + ) CheckInsecureDevice(onDeviceIsInsecure) + @Requirement( + "O.Arch_6#2", + "O.Resi_2#2", + "O.Resi_3#2", + "O.Resi_4#2", + "O.Resi_5#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check device integrity." + ) CheckDeviceIntegrity(mainScreenController, mainNavController) val scaffoldState = rememberScaffoldState() val scope = rememberCoroutineScope() @@ -702,11 +1116,11 @@ private fun MainScreenBottomNavHost( startDestination = MainNavigationScreens.Prescriptions.path() ) { composable(MainNavigationScreens.Prescriptions.route) { - val prescriptionState = rememberPrescriptionState() + val prescriptionsController = rememberPrescriptionsController() PrescriptionScreen( navController = mainNavController, onClickAvatar = onClickAvatar, - prescriptionState = prescriptionState, + prescriptionsController = prescriptionsController, mainScreenController = mainScreenController, onElevateTopBar = onElevateTopBar, onClickArchive = onClickArchive @@ -733,7 +1147,10 @@ private fun MainScreenBottomNavHost( } @Composable -private fun CheckDeviceIntegrity(mainScreenController: MainScreenController, mainNavController: NavController) { +private fun CheckDeviceIntegrity( + mainScreenController: MainScreenController, + mainNavController: NavController +) { LaunchedEffect(Unit) { if (BuildConfig.DEBUG) { return@LaunchedEffect @@ -759,6 +1176,11 @@ private fun CheckInsecureDevice(onDeviceIsInsecure: () -> Unit) { if (BuildConfig.DEBUG) { return@LaunchedEffect } + @Requirement( + "O.Plat_1#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Navigate to insecure Devices warning." + ) withContext(Dispatchers.Main) { if (settingsController.showInsecureDevicePrompt.first()) { onDeviceIsInsecure() diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenController.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenController.kt index dac7ab0d..b43f786a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenNavigationScreens.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenNavigationScreens.kt index f23349d5..9c3b4954 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenNavigationScreens.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenNavigationScreens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenSnackbar.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenSnackbar.kt index 54078611..e940f864 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenSnackbar.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/MainScreenSnackbar.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/OrderSuccessHandler.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/OrderSuccessHandler.kt index 1c61272c..6436a91a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/OrderSuccessHandler.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/OrderSuccessHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ProfileChips.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ProfileChips.kt index a96800ef..6116bf16 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ProfileChips.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ProfileChips.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RedeemButton.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RedeemButton.kt index 2d0be287..f29fe34f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RedeemButton.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RedeemButton.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RefreshScaffold.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RefreshScaffold.kt index 5ce90e76..841fc1fa 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RefreshScaffold.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/RefreshScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt index 0b11f311..884e1cda 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/ToolTip.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/TopBars.kt b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/TopBars.kt index 760f84ad..60d501bb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/TopBars.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/mainscreen/ui/TopBars.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingAppAuthentication.kt b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingAppAuthentication.kt index bdd29e7c..6e81104e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingAppAuthentication.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingAppAuthentication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt index f405276a..ac7aeb80 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -93,8 +93,8 @@ import de.gematik.ti.erp.app.utils.compose.SecondaryButton import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.SpacerXXLarge -import de.gematik.ti.erp.app.utils.compose.createToastShort import de.gematik.ti.erp.app.utils.compose.navigationModeState +import de.gematik.ti.erp.app.utils.compose.shortToast import de.gematik.ti.erp.app.utils.compose.visualTestTag import de.gematik.ti.erp.app.webview.URI_DATA_TERMS import de.gematik.ti.erp.app.webview.URI_TERMS_OF_USE @@ -206,6 +206,14 @@ fun OnboardingScreen( } composable(OnboardingNavigationScreens.TermsOfUse.route) { NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Purp_1#1", + "O.Arch_8#5", + "O.Plat_11#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Display terms of use as part of the onboarding." + + "Webview containing local html without javascript" + ) WebViewScreen( modifier = Modifier.testTag(TestTag.Onboarding.TermsOfUseScreen), title = stringResource(R.string.onb_terms_of_use), @@ -216,6 +224,14 @@ fun OnboardingScreen( } composable(OnboardingNavigationScreens.DataProtection.route) { NavigationAnimation(mode = navigationMode) { + @Requirement( + "O.Purp_1#2", + "O.Arch_8#6", + "O.Plat_11#6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Display data privacy as part of the onboarding. " + + "Webview containing local html without javascript." + ) WebViewScreen( modifier = Modifier.testTag(TestTag.Onboarding.DataProtectionScreen), title = stringResource(R.string.onb_data_consent), @@ -350,7 +366,7 @@ private fun OnboardingPages( onAllowAnalytics = { allow -> if (!allow) { onAllowTracking(false) - createToastShort(context, disAllowToast) + context.shortToast(disAllowToast) } else { navController.navigate(OnboardingNavigationScreens.Analytics.path()) } @@ -462,6 +478,11 @@ private fun OnboardingWelcome( } } +@Requirement( + "O.Purp_3#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "User information and acceptance/deny for analytics usage" +) @Composable private fun OnboardingPageAnalytics( allowAnalytics: Boolean, @@ -529,6 +550,8 @@ private fun OnboardingPageAnalytics( @Requirement( "A_19184", "A_20194", + "A_19980", + "A_19981", sourceSpecification = "gemSpec_eRp_FdV", rationale = "Displays terms of service and privacy statement to the user." ) @@ -576,6 +599,18 @@ private fun OnboardingPageTerms( SpacerMedium() } item { + @Requirement( + "O.Purp_3#1", + "O.Arch_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Display data protection as part of the onboarding" + ) + @Requirement( + "A_19980#1", + "A_19981#1", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Display data protection as part of the onboarding" + ) SecondaryButton( modifier = Modifier.fillMaxWidth().testTag(TestTag.Onboarding.DataTerms.OpenDataProtectionButton), onClick = { @@ -587,6 +622,11 @@ private fun OnboardingPageTerms( SpacerMedium() } item { + @Requirement( + "O.Purp_3#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Display terms of use as part of the onboarding" + ) SecondaryButton( modifier = Modifier.fillMaxWidth().testTag(TestTag.Onboarding.DataTerms.OpenTermsOfUseButton), onClick = { @@ -598,6 +638,11 @@ private fun OnboardingPageTerms( SpacerXXLarge() } item { + @Requirement( + "O.Purp_3#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "User acceptance for terms of use and dar´ta protection as part of the onboarding" + ) DataTermsToggle( accepted = accepted, onCheckedChange = { @@ -633,6 +678,13 @@ private fun AnalyticsToggle( onCheckedChange = onCheckedChange ) +@Requirement( + "A_19980#2", + "A_19981#2", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "The user is informed and required to accept this information via the data protection statement. " + + "Related data and services are listed in sections 5." +) @Composable private fun DataTermsToggle( accepted: Boolean, diff --git a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingScaffold.kt b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingScaffold.kt index 87f882f1..0eeaebbc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingScaffold.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/onboarding/ui/OnboardingScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/OderHealthCardModule.kt b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/OderHealthCardModule.kt index 5bb57bbd..27a560c3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/OderHealthCardModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/OderHealthCardModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt index 4f7af1ba..97df8e6e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -450,9 +450,9 @@ private fun ContactInsurance( else -> item { ContactMethodRow( - phone = null, + phone = it.healthCardAndPinPhone, url = it.pinUrl, - mail = it.healthCardAndPinMail, + mail = if (!it.subjectPinMail.isNullOrEmpty()) it.healthCardAndPinMail else null, company = it, option = healthCardOrderState.selectedOption ) diff --git a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt index 2b30be08..6b150e09 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/ui/HealthCardOrderState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCase.kt index cd87a0a1..9696d7e2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/model/HealthInsuranceCompany.kt b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/model/HealthInsuranceCompany.kt index e9e391cf..b189ed18 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/model/HealthInsuranceCompany.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orderhealthcard/usecase/model/HealthInsuranceCompany.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/MessagesModule.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/MessagesModule.kt index a43c932d..07282f14 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/MessagesModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/MessagesModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationLocalDataSource.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationLocalDataSource.kt index 8f72c764..222e053f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationLocalDataSource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationRepository.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationRepository.kt index e4810575..8408adbc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationRepository.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/CommunicationRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheLocalDataSource.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheLocalDataSource.kt index fce11bf3..c4fedc4c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheLocalDataSource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheRemoteDataSource.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheRemoteDataSource.kt index d4e7dc04..56e342ce 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheRemoteDataSource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/repository/PharmacyCacheRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/MessageSheets.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/MessageSheets.kt index 65975551..98138f57 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/MessageSheets.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/MessageSheets.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -52,14 +52,14 @@ import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.orders.usecase.model.OrderUseCaseData -import de.gematik.ti.erp.app.redeem.ui.createBitMatrix -import de.gematik.ti.erp.app.redeem.ui.drawDataMatrix import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.PrimaryButtonSmall import de.gematik.ti.erp.app.utils.compose.SpacerLarge import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.createBitMatrix +import de.gematik.ti.erp.app.utils.compose.drawDataMatrix import kotlinx.datetime.TimeZone import kotlinx.datetime.toJavaLocalDateTime import kotlinx.datetime.toLocalDateTime diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderEmptyScreens.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderEmptyScreens.kt index ba11fca6..b34448c0 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderEmptyScreens.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderEmptyScreens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderScreen.kt index 0692594d..37e06cc9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/ui/OrderScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCase.kt index 9677d603..bc8ee708 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/model/OrderUseCaseData.kt b/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/model/OrderUseCaseData.kt index 0195d8b0..4adab963 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/model/OrderUseCaseData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/orders/usecase/model/OrderUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyModule.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyModule.kt index 130ce3ce..17422a9d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,13 +18,14 @@ package de.gematik.ti.erp.app.pharmacy +import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import de.gematik.ti.erp.app.pharmacy.repository.PharmacyLocalDataSource import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRemoteDataSource -import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository +import de.gematik.ti.erp.app.pharmacy.repository.DefaultPharmacyRepository import de.gematik.ti.erp.app.pharmacy.repository.ShippingContactRepository -import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyOverviewUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyDirectRedeemUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyMapsUseCase +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyOverviewUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacySearchUseCase import org.kodein.di.DI import org.kodein.di.bindProvider @@ -33,7 +34,7 @@ import org.kodein.di.instance val pharmacyModule = DI.Module("pharmacyModule") { bindProvider { PharmacyRemoteDataSource(instance(), instance()) } bindProvider { PharmacyLocalDataSource(instance()) } - bindProvider { PharmacyRepository(instance(), instance(), instance()) } + bindProvider { DefaultPharmacyRepository(instance(), instance(), instance()) } bindProvider { ShippingContactRepository(instance(), instance()) } bindProvider { PharmacyDirectRedeemUseCase(instance()) } bindProvider { PharmacyMapsUseCase(instance(), instance(), instance()) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt new file mode 100644 index 00000000..b9262614 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyTestModule.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ +package de.gematik.ti.erp.app.pharmacy + +import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository +import de.gematik.ti.erp.app.pharmacy.repository.PharmacyLocalDataSource +import de.gematik.ti.erp.app.pharmacy.repository.PharmacyMockRepository +import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRemoteDataSource +import de.gematik.ti.erp.app.pharmacy.repository.ShippingContactRepository +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyDirectRedeemUseCase +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyMapsUseCase +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyOverviewUseCase +import de.gematik.ti.erp.app.pharmacy.usecase.PharmacySearchUseCase +import org.kodein.di.DI +import org.kodein.di.bindProvider +import org.kodein.di.instance + +val pharmacyTestModule = DI.Module("pharmacyTestModule") { + bindProvider { PharmacyRemoteDataSource(instance(), instance()) } + bindProvider { PharmacyLocalDataSource(instance()) } + bindProvider { ShippingContactRepository(instance(), instance()) } + bindProvider { PharmacyDirectRedeemUseCase(instance()) } + bindProvider { PharmacyMapsUseCase(instance(), instance(), instance()) } + bindProvider { PharmacySearchUseCase(instance(), instance(), instance(), instance(), instance()) } + bindProvider { PharmacyOverviewUseCase(instance(), instance()) } + + bindProvider { PharmacyMockRepository() } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Details.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Details.kt deleted file mode 100644 index 2c357daa..00000000 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Details.kt +++ /dev/null @@ -1,617 +0,0 @@ -/* - * Copyright (c) 2023 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -@file:Suppress("TooManyFunctions") - -package de.gematik.ti.erp.app.pharmacy.ui - -import android.content.Context -import android.content.Intent -import android.net.Uri -import androidx.compose.foundation.Image -import androidx.compose.foundation.background -import androidx.compose.foundation.clickable -import androidx.compose.foundation.interaction.MutableInteractionSource -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.IntrinsicSize -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.fillMaxHeight -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.size -import androidx.compose.foundation.rememberScrollState -import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.foundation.text.ClickableText -import androidx.compose.foundation.verticalScroll -import androidx.compose.material.Icon -import androidx.compose.material.MaterialTheme -import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.setValue -import androidx.compose.runtime.remember -import androidx.compose.ui.Alignment -import androidx.compose.ui.Modifier -import androidx.compose.ui.platform.LocalContext -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.painterResource -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.AnnotatedString -import androidx.compose.ui.text.SpanStyle -import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.unit.dp -import androidx.compose.material.icons.rounded.Star -import androidx.compose.material.icons.rounded.StarBorder -import androidx.compose.runtime.LaunchedEffect -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.rememberCoroutineScope -import androidx.compose.ui.draw.alpha -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.painter.Painter -import androidx.compose.ui.hapticfeedback.HapticFeedbackType -import androidx.compose.ui.platform.LocalHapticFeedback -import androidx.compose.ui.platform.testTag -import androidx.compose.ui.semantics.Role -import androidx.compose.ui.text.style.TextOverflow -import de.gematik.ti.erp.app.R -import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.fhir.model.Location -import de.gematik.ti.erp.app.fhir.model.OpeningHours -import de.gematik.ti.erp.app.fhir.model.isOpenToday -import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData -import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData -import de.gematik.ti.erp.app.theme.AppTheme -import de.gematik.ti.erp.app.theme.PaddingDefaults -import de.gematik.ti.erp.app.utils.compose.AcceptDialog -import de.gematik.ti.erp.app.utils.compose.HintTextActionButton -import de.gematik.ti.erp.app.utils.compose.SpacerTiny -import de.gematik.ti.erp.app.utils.compose.SpacerMedium -import de.gematik.ti.erp.app.utils.compose.SpacerSmall -import de.gematik.ti.erp.app.utils.compose.SpacerXXLarge -import de.gematik.ti.erp.app.utils.compose.TertiaryButton -import de.gematik.ti.erp.app.utils.compose.canHandleIntent -import de.gematik.ti.erp.app.utils.compose.createToastShort -import de.gematik.ti.erp.app.utils.compose.handleIntent -import de.gematik.ti.erp.app.utils.compose.provideEmailIntent -import de.gematik.ti.erp.app.utils.compose.providePhoneIntent -import kotlinx.coroutines.launch -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toJavaLocalTime -import kotlinx.datetime.toLocalDateTime -import java.time.format.DateTimeFormatter -import java.time.format.FormatStyle -import java.time.format.TextStyle -import java.util.Locale - -@Composable -fun PharmacyDetailsSheetContent( - orderState: PharmacyOrderState, - pharmacy: PharmacyUseCaseData.Pharmacy, - onClickOrder: (PharmacyUseCaseData.Pharmacy, PharmacyScreenData.OrderOption) -> Unit -) { - val context = LocalContext.current - - val scrollState = rememberScrollState() - val controller = rememberPharmacyController() - val scope = rememberCoroutineScope() - - val hasRedeemableTasks = orderState.hasRedeemableTasks - var showNoRedeemableTasksDialog by remember { mutableStateOf(false) } - - val onClickOrderFn = { pharmacy: PharmacyUseCaseData.Pharmacy, option: PharmacyScreenData.OrderOption -> - if (!hasRedeemableTasks.value) { - showNoRedeemableTasksDialog = true - } else { - onClickOrder(pharmacy, option) - } - } - - if (showNoRedeemableTasksDialog) { - AcceptDialog( - header = stringResource(R.string.pharmacy_order_no_prescriptions_title), - info = stringResource(R.string.pharmacy_order_no_prescriptions_desc), - acceptText = stringResource(R.string.ok), - onClickAccept = { - showNoRedeemableTasksDialog = false - } - ) - } - - Column( - modifier = Modifier - .padding(horizontal = PaddingDefaults.Medium, vertical = PaddingDefaults.Large) - .verticalScroll(scrollState) - .fillMaxWidth() - .testTag(TestTag.PharmacySearch.OrderOptions.Content), - horizontalAlignment = Alignment.CenterHorizontally - ) { - Row { - Column( - modifier = Modifier - .weight(1f) - .clickable( - role = Role.Button, - indication = null, - interactionSource = remember { MutableInteractionSource() } - ) { - pharmacy.location?.let { - navigateWithGoogleMaps(context, it) ?: launchMaps(context, it) - } - } - ) { - Text( - text = pharmacy.name, - style = AppTheme.typography.h6, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - SpacerTiny() - Text( - text = pharmacy.singleLineAddress(), - style = AppTheme.typography.subtitle2, - color = MaterialTheme.colors.secondary, - maxLines = 2, - overflow = TextOverflow.Ellipsis - ) - } - val isMarkedAsFavorite by produceState(false, pharmacy) { - controller.isPharmacyInFavorites(pharmacy).collect { - value = it - } - } - SpacerMedium() - FavoriteStarButton( - isMarked = isMarkedAsFavorite, - modifier = Modifier, - onChange = { - scope.launch { - if (it) { - controller.markPharmacyAsFavorite(pharmacy) - } else { - controller.unmarkPharmacyAsFavorite(pharmacy) - } - } - } - ) - } - SpacerXXLarge() - - OrderSelection( - orderState = orderState, - pharmacy = pharmacy, - onClickOrder = onClickOrderFn - ) - - SpacerXXLarge() - - PharmacyInfo(pharmacy) - } -} - -private const val NrOfAllOrderOptions = 3 - -@Composable -private fun OrderSelection( - pharmacy: PharmacyUseCaseData.Pharmacy, - onClickOrder: (PharmacyUseCaseData.Pharmacy, PharmacyScreenData.OrderOption) -> Unit, - orderState: PharmacyOrderState -) { - val scope = rememberCoroutineScope() - var directRedeemEnabled by remember { - mutableStateOf(false) - } - - LaunchedEffect(Unit) { - scope.launch { - directRedeemEnabled = orderState.profile.lastAuthenticated == null - } - } - val directPickUpServiceAvailable = directRedeemEnabled && pharmacy.contacts.pickUpUrl.isNotEmpty() - val pickUpServiceVisible = - pharmacy.pickupServiceAvailable() || directPickUpServiceAvailable - val pickupServiceEnabled = directPickUpServiceAvailable || - !directRedeemEnabled && pharmacy.pickupServiceAvailable() - - val directDeliveryServiceAvailable = directRedeemEnabled && pharmacy.contacts.deliveryUrl.isNotEmpty() - val deliveryServiceVisible = - directDeliveryServiceAvailable || pharmacy.deliveryServiceAvailable() - val deliveryServiceEnabled = directDeliveryServiceAvailable || - !directRedeemEnabled && pharmacy.deliveryServiceAvailable() - - val directOnlineServiceAvailable = directRedeemEnabled && pharmacy.contacts.onlineServiceUrl.isNotEmpty() - val onlineServiceVisible = - pharmacy.onlineServiceAvailable() || directOnlineServiceAvailable - val onlineServiceEnabled = directOnlineServiceAvailable || - !directRedeemEnabled && pharmacy.onlineServiceAvailable() - - val nrOfServices = remember(pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible) { - listOf(pickUpServiceVisible, deliveryServiceVisible, onlineServiceVisible).count { it } - } - val isSingle = nrOfServices == 1 - val isLarge = nrOfServices != NrOfAllOrderOptions - - Row( - horizontalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium), - modifier = Modifier.height(IntrinsicSize.Min) - ) { - val orderModifier = Modifier.weight(weight = 0.5f).fillMaxHeight() - if (pickUpServiceVisible) { - OrderButton( - modifier = orderModifier.testTag(TestTag.PharmacySearch.OrderOptions.PickUpOptionButton), - enabled = pickupServiceEnabled, - onClick = { onClickOrder(pharmacy, PharmacyScreenData.OrderOption.PickupService) }, - isLarge = isLarge, - text = stringResource(R.string.pharmacy_order_opt_collect), - image = painterResource(R.drawable.pharmacy_small) - ) - } - - if (deliveryServiceVisible) { - OrderButton( - modifier = orderModifier.testTag(TestTag.PharmacySearch.OrderOptions.CourierDeliveryOptionButton), - enabled = deliveryServiceEnabled, - onClick = { onClickOrder(pharmacy, PharmacyScreenData.OrderOption.CourierDelivery) }, - isLarge = isLarge, - text = stringResource(R.string.pharmacy_order_opt_delivery), - image = painterResource(R.drawable.delivery_car_small) - ) - } - if (onlineServiceVisible) { - OrderButton( - modifier = orderModifier - .testTag(TestTag.PharmacySearch.OrderOptions.OnlineDeliveryOptionButton), - enabled = onlineServiceEnabled, - onClick = { onClickOrder(pharmacy, PharmacyScreenData.OrderOption.MailDelivery) }, - isLarge = isLarge, - text = stringResource(R.string.pharmacy_order_opt_mail), - image = painterResource(R.drawable.truck_small) - ) - } - - if (isSingle) { - Spacer(Modifier.weight(weight = 0.5f)) - } - } -} - -@Suppress("MagicNumber") -@Composable -private fun OrderButton( - modifier: Modifier, - enabled: Boolean, - isLarge: Boolean = true, - text: String, - image: Painter, - onClick: () -> Unit -) { - val context = LocalContext.current - val shape = RoundedCornerShape(16.dp) - val connectText = stringResource(R.string.connect_for_pharmacy_service) - Column( - modifier = modifier - .background(AppTheme.colors.neutral100, shape) - .clip(shape) - .clickable( - role = Role.Button, - onClick = { - if (enabled) { - onClick() - } else { - createToastShort(context, connectText) - } - } - ) - .padding(PaddingDefaults.Medium) - .alpha( - if (enabled) { - 1f - } else { 0.3f } - ) - ) { - val imgModifier = if (isLarge) { - Modifier.align(Alignment.End) - } else { - Modifier.align(Alignment.CenterHorizontally) - } - Image(image, null, modifier = imgModifier) - SpacerTiny() - - val txtModifier = if (isLarge) { - Modifier.align(Alignment.Start) - } else { - Modifier.align(Alignment.CenterHorizontally) - } - Text(text, modifier = txtModifier, style = AppTheme.typography.subtitle2) - } -} - -@Composable -private fun FavoriteStarButton( - isMarked: Boolean, - modifier: Modifier = Modifier, - onChange: (Boolean) -> Unit -) { - val color = if (isMarked) { - AppTheme.colors.yellow500 - } else { - AppTheme.colors.primary600 - } - - val icon = if (isMarked) { - Icons.Rounded.Star - } else { - Icons.Rounded.StarBorder - } - - val addedText = stringResource(R.string.pharmacy_detals_added_to_favorites) - val removedText = stringResource(R.string.pharmacy_detalls_removed_from_favorites) - - val context = LocalContext.current - val haptic = LocalHapticFeedback.current - - TertiaryButton( - modifier = modifier.size(56.dp), - onClick = { - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - onChange(!isMarked) - createToastShort( - context, - if (!isMarked) { - addedText - } else { - removedText - } - ) - }, - contentPadding = PaddingValues(PaddingDefaults.Medium) - ) { - Icon( - icon, - contentDescription = null, - tint = color - ) - } -} - -@Composable -private fun PharmacyInfo(pharmacy: PharmacyUseCaseData.Pharmacy) { - Column { - pharmacy.openingHours?.let { - if (it.isNotEmpty()) { - PharmacyOpeningHours(it) - } - SpacerMedium() - } - Text( - text = stringResource(R.string.legal_notice_contact_header), - style = AppTheme.typography.h6 - ) - SpacerMedium() - val context = LocalContext.current - PharmacyPhoneContact(context, pharmacy.contacts.phone) - SpacerMedium() - PharmacyEmailContact(context = context, pharmacy.contacts.mail) - SpacerMedium() - if (pharmacy.contacts.url.isNotEmpty()) { - PharmacyWebSite(pharmacy.contacts.url) - SpacerMedium() - } - SpacerMedium() - DataInfoSection(modifier = Modifier.align(Alignment.End)) - } -} - -@Composable -private fun PharmacyOpeningHours(openingHours: OpeningHours) { - val dateTimeFormatter = remember { DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) } - - Column { - Text( - text = stringResource(R.string.pharm_detail_opening_hours), - style = AppTheme.typography.h6 - ) - - SpacerMedium() - - val sortedOpeningHours = OpeningHours(openingHours.toSortedMap(compareBy { it })) - - for (h in sortedOpeningHours) { - val (day, hours) = h - val now = remember { Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) } - val isOpenToday = remember(now) { h.isOpenToday(now) } - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.SpaceBetween - ) { - Text( - text = day.getDisplayName(TextStyle.FULL, Locale.getDefault()), - fontWeight = if (isOpenToday) FontWeight.Medium else null - ) - Column( - horizontalAlignment = Alignment.End - ) { - for (hour in hours.sortedBy { it.openingTime }) { - val opens = hour.openingTime?.toJavaLocalTime()?.format(dateTimeFormatter) ?: "" - val closes = hour.closingTime?.toJavaLocalTime()?.format(dateTimeFormatter) ?: "" - val text = "$opens - $closes" - val isOpenNow = - remember(now) { hour.isOpenAt(now.time) && isOpenToday } - when { - isOpenNow -> - Text( - text = text, - color = AppTheme.colors.green600, - fontWeight = FontWeight.Medium - ) - - isOpenToday -> - Text( - text = text, - color = AppTheme.colors.neutral600, - fontWeight = FontWeight.Medium - ) - - else -> - Text( - text = text, - color = AppTheme.colors.neutral600 - ) - } - } - } - } - SpacerMedium() - } - } -} - -@Composable -private fun PharmacyPhoneContact(context: Context, phone: String) { - Label( - text = phone, - label = stringResource(R.string.pres_detail_organization_label_telephone), - onClick = { - context.handleIntent(providePhoneIntent(it)) - } - ) -} - -@Composable -private fun PharmacyEmailContact(context: Context, mail: String) { - Label( - text = mail, - label = stringResource(R.string.pres_detail_organization_label_email), - onClick = { - val intent = provideEmailIntent(it) - if (canHandleIntent(intent, context.packageManager)) { - context.startActivity(intent) - } - } - ) -} - -@Composable -private fun DataInfoSection(modifier: Modifier) { - val uriHandler = LocalUriHandler.current - val uriPharmacyPortal = stringResource(R.string.pharmacy_detail_pharmacy_portal_uri) - val uriFaq = stringResource(R.string.pharmacy_detail_data_info_faqs_uri) - val textPharmacyPortal = stringResource(R.string.pharmacy_detail_data_info_domain) - val infoText = stringResource(R.string.pharmacy_detail_data_info) - val start = infoText.indexOf(textPharmacyPortal) - val end = start + textPharmacyPortal.length - val styledText = with(AnnotatedString.Builder()) { - append(infoText) - addStringAnnotation( - tag = "URL", - annotation = uriPharmacyPortal, - start = start, - end = end - ) - addStyle( - SpanStyle(color = AppTheme.colors.primary600), - start, - end - ) - toAnnotatedString() - } - ClickableText( - modifier = modifier - .fillMaxWidth(), - text = styledText, - style = AppTheme.typography.body2l, - onClick = { - styledText - .getStringAnnotations("URL", it, it) - .firstOrNull()?.let { stringAnnotation -> - uriHandler.openUri(stringAnnotation.item) - } - } - ) - SpacerSmall() - Row(modifier = modifier) { - HintTextActionButton(text = stringResource(R.string.pharmacy_detail_data_info_btn)) { - uriHandler.openUri(uriFaq) - } - } -} - -@Composable -private fun PharmacyWebSite(url: String) { - val uriHandler = LocalUriHandler.current - Label( - text = url, - label = stringResource(R.string.pharm_detail_website), - onClick = { - uriHandler.openUri(it) - } - ) -} - -@Composable -private fun Label( - text: String, - label: String, - onClick: (String) -> Unit -) { - Column( - modifier = Modifier - .clickable { - onClick(text) - } - .fillMaxWidth() - ) { - Text( - text = text, - style = AppTheme.typography.body1, - color = AppTheme.colors.primary600 - ) - SpacerTiny() - Text( - text = label, - style = AppTheme.typography.body2l - ) - } -} - -private fun launchMaps(context: Context, location: Location) { - val gmmIntentUri = Uri.parse("geo:${location.latitude},${location.longitude}?z=16") - val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) - mapIntent.resolveActivity(context.packageManager)?.let { - context.startActivity(mapIntent) - } -} - -private fun navigateWithGoogleMaps( - context: Context, - location: Location -): Any? { - val gmmIntentUri = - Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${location.latitude},${location.longitude}") - val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) - mapIntent.setPackage("com.google.android.apps.maps") - return mapIntent.resolveActivity(context.packageManager)?.let { - context.startActivity(mapIntent) - } -} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/EditShippingContactScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/EditShippingContactScreen.kt index d63aeaad..0c8d6be2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/EditShippingContactScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/EditShippingContactScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -52,6 +52,7 @@ import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.max import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData import de.gematik.ti.erp.app.pharmacy.ui.model.addressSupplementInputField import de.gematik.ti.erp.app.pharmacy.ui.model.cityInputField @@ -76,6 +77,12 @@ const val StringLengthLimit = 100 const val MinPhoneLength = 4 const val PostalCodeLength = 5 +@Requirement( + "O.Purp_2#6", + "O.Data_6#6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Contact information is collected when needed for redeeming." +) @Suppress("LongMethod") @Composable fun EditShippingContactScreen( diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/FavoriteStarButton.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/FavoriteStarButton.kt new file mode 100644 index 00000000..8444b30e --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/FavoriteStarButton.kt @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pharmacy.ui + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.Star +import androidx.compose.material.icons.rounded.StarBorder +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.hapticfeedback.HapticFeedbackType +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalHapticFeedback +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.TertiaryButton +import de.gematik.ti.erp.app.utils.compose.shortToast + +@Composable +internal fun FavoriteStarButton( + isMarked: Boolean, + modifier: Modifier = Modifier, + onChange: (Boolean) -> Unit +) { + val color = if (isMarked) { + AppTheme.colors.yellow500 + } else { + AppTheme.colors.primary600 + } + + val icon = if (isMarked) { + Icons.Rounded.Star + } else { + Icons.Rounded.StarBorder + } + + val addedText = stringResource(R.string.pharmacy_detals_added_to_favorites) + val removedText = stringResource(R.string.pharmacy_detalls_removed_from_favorites) + + val context = LocalContext.current + val haptic = LocalHapticFeedback.current + + TertiaryButton( + modifier = modifier.size(56.dp), + onClick = { + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + onChange(!isMarked) + context.shortToast( + when { + !isMarked -> addedText + else -> removedText + } + ) + }, + contentPadding = PaddingValues(PaddingDefaults.Medium) + ) { + Icon( + icon, + contentDescription = null, + tint = color + ) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Favorites.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Favorites.kt index 9f0cca41..8dd930a3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Favorites.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Favorites.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsOverview.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsOverview.kt index c6147167..a770c3fd 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsOverview.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsOverview.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -300,7 +300,7 @@ fun MapsOverview( ) is PharmacySearchSheetContentState.PharmacySelected -> - PharmacyDetailsSheetContent( + PharmacyBottomSheetDetails( orderState = orderState, pharmacy = (sheetState.content as PharmacySearchSheetContentState.PharmacySelected).pharmacy, diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsSnackbar.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsSnackbar.kt index 50e9bb32..4f9cc614 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsSnackbar.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/MapsSnackbar.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt index e3708855..39e4742a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -186,7 +186,7 @@ fun PharmacyNavigation( searchController = pharmacySearchController, onBack = { orderState.onResetPharmacySelection() - navController.popBackStack() + navController.navigate(PharmacyNavigationScreens.StartSearch.path()) }, onClickMaps = { scope.launch(Dispatchers.Main) { diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderOverview.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderOverview.kt index ead6084e..09c8b455 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderOverview.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderOverview.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt new file mode 100644 index 00000000..ccc2dbb5 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/OrderSelection.kt @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pharmacy.ui + +import androidx.compose.animation.AnimatedVisibility +import androidx.compose.foundation.Image +import androidx.compose.foundation.background +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.IntrinsicSize +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.alpha +import androidx.compose.ui.draw.clip +import androidx.compose.ui.graphics.painter.Painter +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.painterResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.TestTag +import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.SpacerTiny +import de.gematik.ti.erp.app.utils.compose.shortToast +import kotlinx.coroutines.launch + +private const val MAX_OPTIONS = 3 + +@Composable +internal fun OrderSelection( + pharmacy: PharmacyUseCaseData.Pharmacy, + orderState: PharmacyOrderState, + onOrderClicked: (PharmacyUseCaseData.Pharmacy, PharmacyScreenData.OrderOption) -> Unit +) { + val scope = rememberCoroutineScope() + var directRedeemEnabled by remember { + mutableStateOf(false) + } + val directRedeemUrlsNotPresent = ( + pharmacy.contacts.pickUpUrl.isEmpty() && + pharmacy.contacts.deliveryUrl.isEmpty() && + pharmacy.contacts.onlineServiceUrl.isEmpty() + ) + + LaunchedEffect(Unit) { + scope.launch { + directRedeemEnabled = orderState.profile.lastAuthenticated == null + } + } + val directPickUpServiceAvailable = + directRedeemEnabled && pharmacy.contacts.pickUpUrl.isNotEmpty() + val pickUpServiceVisible = + pharmacy.contacts.pickUpUrl.isNotEmpty() || directRedeemUrlsNotPresent + val pickupServiceEnabled = directPickUpServiceAvailable || + !directRedeemEnabled && pharmacy.pickupServiceAvailable() + + val directDeliveryServiceAvailable = + directRedeemEnabled && pharmacy.contacts.deliveryUrl.isNotEmpty() + val deliveryServiceVisible = directDeliveryServiceAvailable || + pharmacy.contacts.deliveryUrl.isNotEmpty() || + (directRedeemUrlsNotPresent && pharmacy.deliveryServiceAvailable()) + val deliveryServiceEnabled = directDeliveryServiceAvailable || + !directRedeemEnabled && pharmacy.deliveryServiceAvailable() + + val directOnlineServiceAvailable = + directRedeemEnabled && pharmacy.contacts.onlineServiceUrl.isNotEmpty() + val mailDeliveryVisible = directOnlineServiceAvailable || + pharmacy.contacts.onlineServiceUrl.isNotEmpty() || + (directRedeemUrlsNotPresent && pharmacy.onlineServiceAvailable()) + val onlineServiceEnabled = directOnlineServiceAvailable || + !directRedeemEnabled && pharmacy.onlineServiceAvailable() + + val nrOfServices = remember(pickUpServiceVisible, deliveryServiceVisible, mailDeliveryVisible) { + listOf(pickUpServiceVisible, deliveryServiceVisible, mailDeliveryVisible).count { it } + } + val isSingle = nrOfServices == 1 + val isLarge = nrOfServices != MAX_OPTIONS + + Row( + horizontalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium), + modifier = Modifier.height(IntrinsicSize.Min) + ) { + val orderModifier = Modifier + .weight(weight = 0.5f) + .fillMaxHeight() + if (pickUpServiceVisible) { + OrderButton( + modifier = orderModifier.testTag(TestTag.PharmacySearch.OrderOptions.PickUpOptionButton), + isServiceEnabled = pickupServiceEnabled, + onClick = { + onOrderClicked( + pharmacy, + PharmacyScreenData.OrderOption.PickupService + ) + }, + isLarge = isLarge, + text = stringResource(R.string.pharmacy_order_opt_collect), + image = painterResource(R.drawable.pharmacy_small) + ) + } + + if (deliveryServiceVisible) { + OrderButton( + modifier = orderModifier.testTag(TestTag.PharmacySearch.OrderOptions.CourierDeliveryOptionButton), + isServiceEnabled = deliveryServiceEnabled, + onClick = { + onOrderClicked( + pharmacy, + PharmacyScreenData.OrderOption.CourierDelivery + ) + }, + isLarge = isLarge, + text = stringResource(R.string.pharmacy_order_opt_delivery), + image = painterResource(R.drawable.delivery_car_small) + ) + } + if (mailDeliveryVisible) { + OrderButton( + modifier = orderModifier + .testTag(TestTag.PharmacySearch.OrderOptions.MailDeliveryOptionButton), + isServiceEnabled = onlineServiceEnabled, + onClick = { onOrderClicked(pharmacy, PharmacyScreenData.OrderOption.MailDelivery) }, + isLarge = isLarge, + text = stringResource(R.string.pharmacy_order_opt_mail), + image = painterResource(R.drawable.truck_small) + ) + } + + if (isSingle) { + Spacer(Modifier.weight(weight = 0.5f)) + } + } +} + +@Suppress("MagicNumber") +@Composable +private fun OrderButton( + modifier: Modifier, + isServiceEnabled: Boolean, + isLarge: Boolean = true, + text: String, + image: Painter, + onClick: () -> Unit +) { + val shape = RoundedCornerShape(16.dp) + val serviceDisabledText = stringResource(R.string.connect_for_pharmacy_service) + var showToast by remember { mutableStateOf(false) } + + // set the toast to be false on every recomposition + LaunchedEffect(showToast) { + showToast = false + } + + Column( + modifier = modifier + .background(AppTheme.colors.neutral100, shape) + .clip(shape) + .clickable( + role = Role.Button, + onClick = { + when { + isServiceEnabled -> onClick() + else -> showToast = true + } + } + ) + .padding(PaddingDefaults.Medium) + .alpha( + when { + isServiceEnabled -> 1f + else -> 0.3f + } + ) + ) { + val imgModifier = when { + isLarge -> Modifier.align(Alignment.End) + else -> Modifier.align(Alignment.CenterHorizontally) + } + Image(image, null, modifier = imgModifier) + SpacerTiny() + + val txtModifier = when { + isLarge -> Modifier.align(Alignment.Start) + else -> Modifier.align(Alignment.CenterHorizontally) + } + Text(text, modifier = txtModifier, style = AppTheme.typography.subtitle2) + } + + AnimatedVisibility(showToast) { + shortToast(serviceDisabledText) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyBottomSheetDetails.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyBottomSheetDetails.kt new file mode 100644 index 00000000..bc3bcc82 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyBottomSheetDetails.kt @@ -0,0 +1,241 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +@file:Suppress("TooManyFunctions") + +package de.gematik.ti.erp.app.pharmacy.ui + +import android.content.Context +import android.content.Intent +import android.net.Uri +import androidx.compose.foundation.clickable +import androidx.compose.foundation.interaction.MutableInteractionSource +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll +import androidx.compose.material.MaterialTheme +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.LocalUriHandler +import androidx.compose.ui.platform.testTag +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.semantics.Role +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.SpanStyle +import androidx.compose.ui.text.style.TextOverflow +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.TestTag +import de.gematik.ti.erp.app.fhir.model.Location +import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.compose.AcceptDialog +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerTiny +import de.gematik.ti.erp.app.utils.compose.SpacerXXLarge +import de.gematik.ti.erp.app.utils.compose.canHandleIntent +import de.gematik.ti.erp.app.utils.compose.handleIntent +import de.gematik.ti.erp.app.utils.compose.provideEmailIntent +import de.gematik.ti.erp.app.utils.compose.providePhoneIntent +import kotlinx.coroutines.launch + +@Composable +fun PharmacyBottomSheetDetails( + orderState: PharmacyOrderState, + pharmacy: PharmacyUseCaseData.Pharmacy, + pharmacyPortalUri: String = stringResource(R.string.pharmacy_detail_pharmacy_portal_uri), + pharmacyPortalText: String = stringResource(R.string.pharmacy_detail_data_info_domain), + infoText: String = stringResource(R.string.pharmacy_detail_data_info), + faqUri: String = stringResource(R.string.pharmacy_detail_data_info_faqs_uri), + onClickOrder: (PharmacyUseCaseData.Pharmacy, PharmacyScreenData.OrderOption) -> Unit +) { + val context = LocalContext.current + val uriHandler = LocalUriHandler.current + val scrollState = rememberScrollState() + val controller = rememberPharmacyController() + val scope = rememberCoroutineScope() + val styledText = buildStyledTextForPharmacy( + infoText = infoText, + pharmacyPortalUri = pharmacyPortalUri, + start = infoText.indexOf(pharmacyPortalText), + end = infoText.indexOf(pharmacyPortalText) + pharmacyPortalText.length + ) + val hasRedeemableTasks = orderState.hasRedeemableTasks + var showNoRedeemableTasksDialog by remember { mutableStateOf(false) } + + if (showNoRedeemableTasksDialog) { + AcceptDialog( + header = stringResource(R.string.pharmacy_order_no_prescriptions_title), + info = stringResource(R.string.pharmacy_order_no_prescriptions_desc), + acceptText = stringResource(R.string.ok), + onClickAccept = { + showNoRedeemableTasksDialog = false + } + ) + } + Column( + modifier = Modifier + .padding(horizontal = PaddingDefaults.Medium, vertical = PaddingDefaults.Large) + .verticalScroll(scrollState) + .fillMaxWidth() + .testTag(TestTag.PharmacySearch.OrderOptions.Content), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Row { + Column( + modifier = Modifier + .weight(1f) + .clickable( + role = Role.Button, + indication = null, + interactionSource = remember { MutableInteractionSource() } + ) { + pharmacy.location?.let { + navigateWithGoogleMaps(context, it) ?: launchMaps(context, it) + } + } + ) { + Text( + text = pharmacy.name, + style = AppTheme.typography.h6, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + SpacerTiny() + Text( + text = pharmacy.singleLineAddress(), + style = AppTheme.typography.subtitle2, + color = MaterialTheme.colors.secondary, + maxLines = 2, + overflow = TextOverflow.Ellipsis + ) + } + val isMarkedAsFavorite by produceState(false, pharmacy) { + controller.isPharmacyInFavorites(pharmacy).collect { value = it } + } + SpacerMedium() + FavoriteStarButton( + isMarked = isMarkedAsFavorite, + modifier = Modifier, + onChange = { + scope.launch { + if (it) { + controller.markPharmacyAsFavorite(pharmacy) + } else { + controller.unmarkPharmacyAsFavorite(pharmacy) + } + } + } + ) + } + SpacerXXLarge() + OrderSelection( + orderState = orderState, + pharmacy = pharmacy, + onOrderClicked = { pharmacy: PharmacyUseCaseData.Pharmacy, option: PharmacyScreenData.OrderOption -> + if (!hasRedeemableTasks.value) { + showNoRedeemableTasksDialog = true + } else { + onClickOrder(pharmacy, option) + } + } + ) + SpacerXXLarge() + PharmacyContact( + openingHours = pharmacy.openingHours, + phone = pharmacy.contacts.phone, + mail = pharmacy.contacts.mail, + url = pharmacy.contacts.url, + detailedInfoText = styledText, + onPhoneClicked = { context.handleIntent(providePhoneIntent(it)) }, + onMailClicked = { emailAddress -> + val intent = provideEmailIntent(emailAddress) + if (canHandleIntent(intent, context.packageManager)) { + context.startActivity(intent) + } else { + // Should we do something here? + } + }, + onUrlClicked = { url -> uriHandler.openUri(url) }, + onTextClicked = { + styledText + .getStringAnnotations("URL", it, it) + .firstOrNull()?.let { stringAnnotation -> + uriHandler.openUri(stringAnnotation.item) + } + }, + onHintClicked = { uriHandler.openUri(faqUri) } + ) + } +} + +@Composable +private fun buildStyledTextForPharmacy( + infoText: String, + pharmacyPortalUri: String, + start: Int, + end: Int +) = with(AnnotatedString.Builder()) { + append(infoText) + addStringAnnotation( + tag = "URL", + annotation = pharmacyPortalUri, + start = start, + end = end + ) + addStyle( + SpanStyle(color = AppTheme.colors.primary600), + start, + end + ) + toAnnotatedString() +} + +private fun launchMaps(context: Context, location: Location) { + val gmmIntentUri = Uri.parse("geo:${location.latitude},${location.longitude}?z=16") + val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) + mapIntent.resolveActivity(context.packageManager)?.let { + context.startActivity(mapIntent) + } +} + +private fun navigateWithGoogleMaps( + context: Context, + location: Location +): Any? { + val gmmIntentUri = + Uri.parse("https://www.google.com/maps/dir/?api=1&destination=${location.latitude},${location.longitude}") + val mapIntent = Intent(Intent.ACTION_VIEW, gmmIntentUri) + mapIntent.setPackage("com.google.android.apps.maps") + return mapIntent.resolveActivity(context.packageManager)?.let { + context.startActivity(mapIntent) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyContact.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyContact.kt new file mode 100644 index 00000000..e223901b --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyContact.kt @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pharmacy.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.text.ClickableText +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.font.FontWeight +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.fhir.model.OpeningHours +import de.gematik.ti.erp.app.fhir.model.isOpenToday +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.utils.compose.HintTextActionButton +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.SpacerTiny +import de.gematik.ti.erp.app.utils.compose.Title +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toJavaLocalTime +import kotlinx.datetime.toLocalDateTime +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle +import java.time.format.TextStyle +import java.util.Locale + +@Composable +internal fun PharmacyContact( + openingHours: OpeningHours?, + phone: String, + mail: String, + url: String, + detailedInfoText: AnnotatedString, + onPhoneClicked: (String) -> Unit, + onMailClicked: (String) -> Unit, + onUrlClicked: (String) -> Unit, + onTextClicked: (Int) -> Unit, + onHintClicked: () -> Unit +) { + Column { + openingHours?.let { + if (it.isNotEmpty()) { + PharmacyOpeningHours(it) + } + SpacerMedium() + } + if (phone.isNotEmpty() || mail.isNotEmpty() || url.isNotEmpty()) { + Title(text = stringResource(id = R.string.legal_notice_contact_header)) + SpacerMedium() + } + if (phone.isNotEmpty()) { + ContactLabel( + text = phone, + label = stringResource(R.string.pres_detail_organization_label_telephone), + onClick = onPhoneClicked + ) + SpacerMedium() + } + if (mail.isNotEmpty()) { + ContactLabel( + text = mail, + label = stringResource(R.string.pres_detail_organization_label_email), + onClick = onMailClicked + ) + SpacerMedium() + } + if (url.isNotEmpty()) { + ContactLabel( + text = url, + label = stringResource(R.string.pharm_detail_website), + onClick = onUrlClicked + ) + SpacerMedium() + } + SpacerMedium() + DataInfoSection( + modifier = Modifier.align(Alignment.End), + detailedInfoText = detailedInfoText, + onTextClicked = onTextClicked, + onHintClicked = onHintClicked + ) + } +} + +@Composable +private fun PharmacyOpeningHours(openingHours: OpeningHours) { + val dateTimeFormatter = remember { DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) } + + Column { + Text( + text = stringResource(R.string.pharm_detail_opening_hours), + style = AppTheme.typography.h6 + ) + + SpacerMedium() + + val sortedOpeningHours = OpeningHours(openingHours.toSortedMap(compareBy { it })) + + for (h in sortedOpeningHours) { + val (day, hours) = h + val now = + remember { Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) } + val isOpenToday = remember(now) { h.isOpenToday(now) } + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceBetween + ) { + Text( + text = day.getDisplayName(TextStyle.FULL, Locale.getDefault()), + fontWeight = if (isOpenToday) FontWeight.Medium else null + ) + Column( + horizontalAlignment = Alignment.End + ) { + for (hour in hours.sortedBy { it.openingTime }) { + val opens = + hour.openingTime?.toJavaLocalTime()?.format(dateTimeFormatter) ?: "" + val closes = + hour.closingTime?.toJavaLocalTime()?.format(dateTimeFormatter) ?: "" + val text = "$opens - $closes" + val isOpenNow = + remember(now) { hour.isOpenAt(now.time) && isOpenToday } + when { + isOpenNow -> + Text( + text = text, + color = AppTheme.colors.green600, + fontWeight = FontWeight.Medium + ) + + isOpenToday -> + Text( + text = text, + color = AppTheme.colors.neutral600, + fontWeight = FontWeight.Medium + ) + + else -> + Text( + text = text, + color = AppTheme.colors.neutral600 + ) + } + } + } + } + SpacerMedium() + } + } +} + +@Composable +private fun DataInfoSection( + modifier: Modifier, + detailedInfoText: AnnotatedString, + onTextClicked: (Int) -> Unit, + onHintClicked: () -> Unit +) { + ClickableText( + modifier = modifier + .fillMaxWidth(), + text = detailedInfoText, + style = AppTheme.typography.body2l, + onClick = onTextClicked + ) + SpacerSmall() + Row(modifier = modifier) { + HintTextActionButton( + text = stringResource(R.string.pharmacy_detail_data_info_btn), + onClick = onHintClicked + ) + } +} + +@Composable +private fun ContactLabel( + text: String, + label: String, + onClick: (String) -> Unit +) { + Column( + modifier = Modifier + .clickable { + onClick(text) + } + .fillMaxWidth() + ) { + Text( + text = text, + style = AppTheme.typography.body1, + color = AppTheme.colors.primary600 + ) + SpacerTiny() + Text( + text = label, + style = AppTheme.typography.body2l + ) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyController.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyController.kt index 79daea7a..37797b1c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyOrderState.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyOrderState.kt index 92c07650..db7ff605 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyOrderState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyOrderState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyResultCard.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyResultCard.kt new file mode 100644 index 00000000..2953417b --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyResultCard.kt @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pharmacy.ui + +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.size +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.KeyboardArrowRight +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.fhir.model.DeliveryPharmacyService +import de.gematik.ti.erp.app.fhir.model.LocalPharmacyService +import de.gematik.ti.erp.app.fhir.model.OnlinePharmacyService +import de.gematik.ti.erp.app.fhir.model.OpeningHours +import de.gematik.ti.erp.app.fhir.model.PharmacyContacts +import de.gematik.ti.erp.app.fhir.model.PickUpPharmacyService +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData.Pharmacy +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.utils.compose.LightDarkPreview +import de.gematik.ti.erp.app.utils.compose.SpacerMedium +import kotlinx.datetime.Clock +import kotlinx.datetime.TimeZone +import kotlinx.datetime.toLocalDateTime + +@Composable +internal fun PharmacyResultCard( + modifier: Modifier, + pharmacy: Pharmacy, + onClick: () -> Unit +) { + Row( + modifier = Modifier + .clickable(onClick = onClick) + .then(modifier), + verticalAlignment = Alignment.CenterVertically + ) { + val distanceTxt = pharmacy.distance?.let { distance -> + formattedDistance(distance) + } + + PharmacyImagePlaceholder(Modifier) + SpacerMedium() + Column(modifier = Modifier.weight(1f)) { + Text( + pharmacy.name, + style = AppTheme.typography.subtitle1 + ) + + Text( + pharmacy.singleLineAddress(), + style = AppTheme.typography.body2l, + modifier = Modifier, + overflow = TextOverflow.Ellipsis, + maxLines = 1 + ) + + val pharmacyLocalServices = + pharmacy.provides.find { it is LocalPharmacyService } as LocalPharmacyService + val now = + remember { Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) } + + if (pharmacyLocalServices.isOpenAt(now)) { + val text = if (pharmacyLocalServices.isAllDayOpen(now.dayOfWeek)) { + stringResource(R.string.search_pharmacy_continuous_open) + } else { + stringResource( + R.string.search_pharmacy_open_until, + requireNotNull(pharmacyLocalServices.openUntil(now)).toString() + ) + } + Text( + text, + style = AppTheme.typography.subtitle2l, + color = AppTheme.colors.green600 + ) + } else { + val text = + pharmacyLocalServices.opensAt(now)?.let { + stringResource( + R.string.search_pharmacy_opens_at, + it.toString() + ) + } + if (text != null) { + Text( + text, + style = AppTheme.typography.subtitle2l, + color = AppTheme.colors.yellow600 + ) + } + } + } + + SpacerMedium() + + if (distanceTxt != null) { + Text( + distanceTxt, + style = AppTheme.typography.body2l, + modifier = Modifier + .align(Alignment.CenterVertically), + textAlign = TextAlign.End + ) + } + Icon( + Icons.Rounded.KeyboardArrowRight, + null, + tint = AppTheme.colors.neutral400, + modifier = Modifier + .size(24.dp) + .align(Alignment.CenterVertically) + ) + } +} + +@LightDarkPreview +@Composable +internal fun PharmacyResultCardPreview() { + AppTheme { + PharmacyResultCard( + modifier = Modifier, + pharmacy = Pharmacy( + id = "pharmacy-id", + name = "2Königen-Aptheke", + address = "Ostwall 97, 47798 Krefeld", + location = null, + distance = null, + contacts = PharmacyContacts( + phone = "12345678", + mail = "pharmacy@mail.com", + url = "https://pharmacy.com", + pickUpUrl = "https://pharmacy.pickup.com/code123", + deliveryUrl = "https://pharmacy.delivery.com/code123", + onlineServiceUrl = "https://pharmacy.online.com/code123" + ), + provides = listOf( + DeliveryPharmacyService( + name = "delivery-service", + openingHours = OpeningHours(openingTime = mapOf()) + ), + OnlinePharmacyService(name = "online-service"), + PickUpPharmacyService(name = "pickup-service"), + LocalPharmacyService( + name = "local-service", + openingHours = OpeningHours(openingTime = mapOf()) + ) + ), + openingHours = OpeningHours(openingTime = mapOf()), + telematikId = "telematikId" + ), + onClick = {} + ) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchController.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchController.kt index 473a1efb..e1e65765 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -42,6 +42,7 @@ import androidx.paging.map import com.google.android.gms.location.LocationRequest import com.google.android.gms.location.LocationServices import com.google.android.gms.tasks.CancellationTokenSource +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.fhir.model.DeliveryPharmacyService import de.gematik.ti.erp.app.fhir.model.Location import de.gematik.ti.erp.app.fhir.model.isOpenAt @@ -50,6 +51,7 @@ import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyMapsUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacyOverviewUseCase import de.gematik.ti.erp.app.pharmacy.usecase.PharmacySearchUseCase import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData.LocationMode import de.gematik.ti.erp.app.prescription.ui.PrescriptionServiceState import de.gematik.ti.erp.app.prescription.ui.catchAndTransformRemoteExceptions import kotlinx.coroutines.CoroutineScope @@ -121,38 +123,9 @@ class PharmacySearchController( searchUseCase.searchPharmacies(searchData) .map { pagingData -> - if (searchData.locationMode is PharmacyUseCaseData.LocationMode.Enabled) { - pagingData.map { - it.copy( - distance = it.location?.minus(searchData.locationMode.location) - ) - } - } else { - pagingData - }.filter { pharmacy -> - if (searchData.filter.deliveryService) { - when { - searchData.filter.deliveryService && - pharmacy.provides.any { it is DeliveryPharmacyService } -> true - - else -> false - } - } else { - true - } - }.filter { - if (searchData.filter.openNow) { - when { - it.openingHours == null -> false - it.openingHours.isOpenAt( - Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - ) -> true - else -> false - } - } else { - true - } - } + pagingData.map { it.updateDistanceForEnabledLocation(searchData.locationMode) } + .filter { it.providesDeliveryService(searchData.filter.deliveryService) } + .filter { it.hasOpeningHours(searchData.filter.openNow) } }.cachedIn(coroutineScope) } .onEach { @@ -178,40 +151,13 @@ class PharmacySearchController( val pharmacies = mapsUseCase.searchPharmacies(searchData) - if (searchData.locationMode is PharmacyUseCaseData.LocationMode.Enabled) { - pharmacies.map { - it.copy( - distance = it.location?.minus(searchData.locationMode.location) - ) - } - } else { - pharmacies - }.filter { pharmacy -> - if (searchData.filter.deliveryService) { - when { - searchData.filter.deliveryService && - pharmacy.provides.any { it is DeliveryPharmacyService } -> true - - else -> false - } - } else { - true + pharmacies + .map { it.updateDistanceForEnabledLocation(searchData.locationMode) } + .filter { it.providesDeliveryService(searchData.filter.deliveryService) } + .filter { it.hasOpeningHours(searchData.filter.openNow) } + .also { + emit(State.Pharmacies(it)) } - }.filter { - if (searchData.filter.openNow) { - when { - it.openingHours == null -> false - it.openingHours.isOpenAt( - Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) - ) -> true - else -> false - } - } else { - true - } - }.also { - emit(State.Pharmacies(it)) - } }.catchAndTransformRemoteExceptions() } .onEach { @@ -252,14 +198,14 @@ class PharmacySearchController( } val locationMode = currentLocation?.let { - PharmacyUseCaseData.LocationMode.Enabled(it, radiusInMeter) - } ?: PharmacyUseCaseData.LocationMode.Disabled + LocationMode.Enabled(it, radiusInMeter) + } ?: LocationMode.Disabled val locationError = if (location == null && filter.nearBy) { when { !hasLocationServiceEnabled -> SearchQueryResult.NoLocationServicesEnabled !hasLocationPermission -> SearchQueryResult.NoLocationPermission - locationMode == PharmacyUseCaseData.LocationMode.Disabled -> SearchQueryResult.NoLocationFound + locationMode == LocationMode.Disabled -> SearchQueryResult.NoLocationFound else -> null } } else { @@ -272,13 +218,11 @@ class PharmacySearchController( } else -> { + val isNearBy = locationMode is LocationMode.Enabled && location == null searchChannelFlow.emit( PharmacyUseCaseData.SearchData( name = name, - filter = filter.copy( - nearBy = locationMode is PharmacyUseCaseData.LocationMode.Enabled && - location == null - ), + filter = filter.copy(nearBy = isNearBy), locationMode = locationMode ) ) @@ -313,6 +257,27 @@ class PharmacySearchController( suspend fun findPharmacyByTelematikIdState( telematikId: String ) = flowOf(pharmacyOverviewUseCase.searchPharmacyByTelematikId(telematikId)) + + private fun PharmacyUseCaseData.Pharmacy.updateDistanceForEnabledLocation(locationMode: LocationMode) = + when (locationMode) { + is LocationMode.Enabled -> copy(distance = location?.minus(locationMode.location)) + else -> this + } + + private fun PharmacyUseCaseData.Pharmacy.providesDeliveryService(isDeliveryServiceFiltered: Boolean) = + when { + isDeliveryServiceFiltered -> provides.any { it is DeliveryPharmacyService } + else -> true + } + + private fun PharmacyUseCaseData.Pharmacy.hasOpeningHours(isOpenNow: Boolean) = + if (isOpenNow) { + openingHours?.isOpenAt( + Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) + ) ?: false + } else { + true + } } private fun isLocationServiceEnabled(context: Context): Boolean { @@ -377,6 +342,11 @@ val locationPermissions = arrayOf( Manifest.permission.ACCESS_COARSE_LOCATION ) +@Requirement( + "O.Plat_3#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "platform dialog for ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION" +) private fun anyLocationPermissionGranted(context: Context) = locationPermissions.any { ContextCompat.checkSelfPermission( @@ -398,6 +368,6 @@ object PharmacySearchStateData { val defaultSearchData = PharmacyUseCaseData.SearchData( name = "", filter = PharmacyUseCaseData.Filter(), - locationMode = PharmacyUseCaseData.LocationMode.Disabled + locationMode = LocationMode.Disabled ) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchOverview.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchOverview.kt index a161b003..63f988eb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchOverview.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchOverview.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,6 +19,7 @@ package de.gematik.ti.erp.app.pharmacy.ui import android.net.Uri +import android.os.Build import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable @@ -180,7 +181,7 @@ fun PharmacyOverviewScreen( ) is PharmacySearchSheetContentState.PharmacySelected -> - PharmacyDetailsSheetContent( + PharmacyBottomSheetDetails( orderState = orderState, pharmacy = (sheetState.content as PharmacySearchSheetContentState.PharmacySelected) .pharmacy, @@ -215,7 +216,8 @@ private fun OverviewContent( val context = LocalContext.current val isGoogleApiAvailable by remember { mutableStateOf( - GoogleApiAvailability.getInstance() + Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && + GoogleApiAvailability.getInstance() .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS ) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchScreen.kt index 5333178d..45313731 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacySearchScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -70,7 +70,6 @@ import androidx.compose.material.TextFieldDefaults import androidx.compose.material.icons.Icons import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.Close -import androidx.compose.material.icons.rounded.KeyboardArrowRight import androidx.compose.material.icons.rounded.Map import androidx.compose.material.icons.rounded.Tune import androidx.compose.material.rememberScaffoldState @@ -95,7 +94,6 @@ import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import androidx.compose.ui.window.DialogProperties import androidx.navigation.NavHostController @@ -110,7 +108,6 @@ import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.analytics.trackPharmacySearchPopUps import de.gematik.ti.erp.app.analytics.trackScreenUsingNavEntry import de.gematik.ti.erp.app.core.LocalAnalytics -import de.gematik.ti.erp.app.fhir.model.LocalPharmacyService import de.gematik.ti.erp.app.pharmacy.ui.model.PharmacyScreenData import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import de.gematik.ti.erp.app.pharmacyId @@ -125,9 +122,6 @@ import de.gematik.ti.erp.app.utils.compose.SpacerSmall import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch -import kotlinx.datetime.Clock -import kotlinx.datetime.TimeZone -import kotlinx.datetime.toLocalDateTime import java.text.DecimalFormat private const val OneKilometerInMeter = 1000 @@ -206,7 +200,7 @@ fun NoLocationServicesDialog( } @Composable -private fun PharmacySearchInputfield( +private fun PharmacySearchInputField( modifier: Modifier, onBack: () -> Unit, isLoading: Boolean, @@ -468,96 +462,7 @@ fun FilterSheetContent( } } -@Composable -private fun PharmacyResultCard( - modifier: Modifier, - pharmacy: PharmacyUseCaseData.Pharmacy, - onClick: () -> Unit -) { - Row( - modifier = Modifier - .clickable(onClick = onClick) - .then(modifier), - verticalAlignment = Alignment.CenterVertically - ) { - val distanceTxt = pharmacy.distance?.let { distance -> - formattedDistance(distance) - } - - PharmacyImagePlaceholder(Modifier) - SpacerMedium() - Column(modifier = Modifier.weight(1f)) { - Text( - pharmacy.name, - style = AppTheme.typography.subtitle1 - ) - - Text( - pharmacy.singleLineAddress(), - style = AppTheme.typography.body2l, - modifier = Modifier, - overflow = TextOverflow.Ellipsis, - maxLines = 1 - ) - - val pharmacyLocalServices = pharmacy.provides.find { it is LocalPharmacyService } as LocalPharmacyService - val now = remember { Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()) } - - if (pharmacyLocalServices.isOpenAt(now)) { - val text = if (pharmacyLocalServices.isAllDayOpen(now.dayOfWeek)) { - stringResource(R.string.search_pharmacy_continuous_open) - } else { - stringResource( - R.string.search_pharmacy_open_until, - requireNotNull(pharmacyLocalServices.openUntil(now)).toString() - ) - } - Text( - text, - style = AppTheme.typography.subtitle2l, - color = AppTheme.colors.green600 - ) - } else { - val text = - pharmacyLocalServices.opensAt(now)?.let { - stringResource( - R.string.search_pharmacy_opens_at, - it.toString() - ) - } - if (text != null) { - Text( - text, - style = AppTheme.typography.subtitle2l, - color = AppTheme.colors.yellow600 - ) - } - } - } - - SpacerMedium() - - if (distanceTxt != null) { - Text( - distanceTxt, - style = AppTheme.typography.body2l, - modifier = Modifier - .align(Alignment.CenterVertically), - textAlign = TextAlign.End - ) - } - Icon( - Icons.Rounded.KeyboardArrowRight, - null, - tint = AppTheme.colors.neutral400, - modifier = Modifier - .size(24.dp) - .align(Alignment.CenterVertically) - ) - } -} - -private fun formattedDistance(distanceInMeters: Double): String { +internal fun formattedDistance(distanceInMeters: Double): String { val f = DecimalFormat() return if (distanceInMeters < OneKilometerInMeter) { f.maximumFractionDigits = 0 @@ -662,17 +567,9 @@ fun PharmacySearchResultScreen( ) } - val loadState = searchPagingItems.loadState val isLoading by remember { derivedStateOf { - searchController.isLoading || listOf(loadState.prepend, loadState.append, loadState.refresh) - .any { - when (it) { - is LoadState.NotLoading -> false // initial ui only loading indicator - is LoadState.Loading -> true - else -> false - } - } + searchController.isLoading } } @@ -719,7 +616,7 @@ fun PharmacySearchResultScreen( ) { innerPadding -> Column(Modifier.padding(innerPadding)) { SpacerMedium() - PharmacySearchInputfield( + PharmacySearchInputField( modifier = Modifier.testTag(TestTag.PharmacySearch.TextSearchField), onBack = onBack, isLoading = isLoading, @@ -803,7 +700,7 @@ fun PharmacySearchResultScreen( ) is PharmacySearchSheetContentState.PharmacySelected -> - PharmacyDetailsSheetContent( + PharmacyBottomSheetDetails( orderState = orderState, pharmacy = (sheetState.content as PharmacySearchSheetContentState.PharmacySelected).pharmacy, diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PrescriptionSelection.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PrescriptionSelection.kt index a947fb31..245cc020 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PrescriptionSelection.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/PrescriptionSelection.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -50,7 +50,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.fhir.parser.toFormattedDate +import de.gematik.ti.erp.app.utils.toFormattedDate import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import de.gematik.ti.erp.app.prescriptionId import de.gematik.ti.erp.app.prescriptionIds diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemErrorMessage.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemErrorMessage.kt index a5c1dc71..2595de37 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemErrorMessage.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemErrorMessage.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemPrescriptionsController.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemPrescriptionsController.kt index 09c6ddd1..e794bd4a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemPrescriptionsController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/RedeemPrescriptionsController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -22,6 +22,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Stable import androidx.compose.runtime.remember import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.api.ApiCallException import de.gematik.ti.erp.app.cardwall.mini.ui.Authenticator import de.gematik.ti.erp.app.core.LocalAuthenticator @@ -97,6 +98,12 @@ class RedeemPrescriptionsController( contact = contact ).cancellable().first() + @Requirement( + "A_22778", + "A_22779", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Start Redeem without TI." + ) suspend fun orderPrescriptionsDirectly( orderId: UUID, prescriptions: List, @@ -112,6 +119,11 @@ class RedeemPrescriptionsController( contact = contact ).cancellable().first() + @Requirement( + "GS-A_5542#2", + sourceSpecification = "gemSpec_Krypt", + rationale = "Errors from the protocol are handled and delegated." + ) private fun orderPrescriptionsDirectlyFlow( orderId: UUID, prescriptions: List, @@ -131,7 +143,7 @@ class RedeemPrescriptionsController( .map { prescription -> val message = DirectCommunicationMessage( - version = "2", + version = 2, supplyOptionsType = when (redeemOption) { PharmacyScreenData.OrderOption.PickupService -> RemoteRedeemOption.Local.type PharmacyScreenData.OrderOption.CourierDelivery -> RemoteRedeemOption.Delivery.type @@ -206,6 +218,11 @@ class RedeemPrescriptionsController( State.Ordered(orderId.toString(), results) }.flowOn(dispatchers.IO) + @Requirement( + "GS-A_5542#3", + sourceSpecification = "gemSpec_Krypt", + rationale = "Errors from the protocol are handled and delegated." + ) private fun orderPrescriptionsFlow( profileId: ProfileIdentifier, orderId: UUID, diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/VideoContent.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/VideoContent.kt index e233d493..bcae78c2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/VideoContent.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/VideoContent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/ContactInputFields.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/ContactInputFields.kt index cba77a73..87d5d48b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/ContactInputFields.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/ContactInputFields.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt index ebfd3a97..a2bf3c27 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/PharmacyScreenData.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/PharmacyScreenData.kt index 25bcf056..f6254896 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/PharmacyScreenData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/ui/model/PharmacyScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacySearchUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacySearchUseCase.kt index 3b954102..c380df06 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacySearchUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacySearchUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -26,26 +26,27 @@ import androidx.paging.PagingState import de.gematik.ti.erp.app.DispatchProvider import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.fhir.model.CommunicationPayload -import de.gematik.ti.erp.app.fhir.model.LocalPharmacyService -import de.gematik.ti.erp.app.fhir.model.Pharmacy import de.gematik.ti.erp.app.fhir.model.createCommunicationDispenseRequest import de.gematik.ti.erp.app.pharmacy.model.PharmacyData import de.gematik.ti.erp.app.pharmacy.model.shippingContact import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import de.gematik.ti.erp.app.pharmacy.repository.ShippingContactRepository +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.PharmacyInitialResultsPerPage +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.PharmacyNextResultsPerPage +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.mapToUseCasePharmacies import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import de.gematik.ti.erp.app.prescription.repository.PrescriptionRepository import de.gematik.ti.erp.app.prescription.repository.RemoteRedeemOption import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase -import kotlin.math.max import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.map import java.util.UUID +import kotlin.math.max // can't be modified; the backend will always return 80 entries on the first page const val PharmacyInitialResultsPerPage = 80 @@ -244,7 +245,7 @@ class PharmacySearchUseCase( accessCode = order.accessCode, recipientTID = pharmacyTelematikId, payload = CommunicationPayload( - version = "1", + version = 1, supplyOptionsType = redeemOption.type, name = contact.name, address = listOf(contact.line1, contact.line2, contact.postalCode, contact.city), @@ -268,20 +269,3 @@ class PharmacySearchUseCase( deliveryInformation = contact.deliveryInformation.trim() ) } - -fun List.mapToUseCasePharmacies(): List = - map { pharmacy -> - PharmacyUseCaseData.Pharmacy( - id = pharmacy.id, - name = pharmacy.name, - address = pharmacy.address.let { - "${it.lines.joinToString()}\n${it.postalCode} ${it.city}" - }, - location = pharmacy.location, - distance = null, - contacts = pharmacy.contacts, - provides = pharmacy.provides, - openingHours = (pharmacy.provides.find { it is LocalPharmacyService } as LocalPharmacyService).openingHours, - telematikId = pharmacy.telematikId - ) - } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/PkvModule.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/PkvModule.kt index 147c659f..eca116a0 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/PkvModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/PkvModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ConsentController.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ConsentController.kt index 0d0ace5f..2f7dd6a8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ConsentController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ConsentController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDetailsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDetailsScreen.kt index 2038b2ec..a048be33 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDetailsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDetailsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDialogues.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDialogues.kt index 8511bd7d..89a8ddcb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDialogues.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceDialogues.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceInformationScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceInformationScreen.kt index 8506cf20..fc063ecc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceInformationScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceInformationScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -30,13 +30,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Button -import androidx.compose.material.DropdownMenu -import androidx.compose.material.DropdownMenuItem -import androidx.compose.material.Icon -import androidx.compose.material.IconButton import androidx.compose.material.Text -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -49,8 +43,6 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource -import androidx.compose.ui.unit.DpOffset -import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.invoice.model.InvoiceData @@ -73,7 +65,8 @@ fun InvoiceInformationScreen( taskId: String, onBack: () -> Unit, onClickShowMore: () -> Unit, - onClickSubmit: () -> Unit + onClickCorrectInvoiceLocally: (String) -> Unit, + onClickSubmit: (String) -> Unit ) { val listState = rememberLazyListState() val scaffoldState = rememberScaffoldState() @@ -119,16 +112,21 @@ fun InvoiceInformationScreen( invoice?.let { InvoiceDetailBottomBar( it.invoice.totalBruttoAmount, - onClickSubmit = onClickSubmit + onClickSubmit = { onClickSubmit(it.taskId) } ) } }, listState = listState, actions = { Row { - InvoicesDetailThreeDotMenu( - onClickDelete = { showDeleteInvoiceAlert = true } - ) + invoice?.let { invoice -> + InvoiceThreeDotMenu( + invoice.taskId, + onClickShareInvoice = { onClickSubmit(invoice.taskId) }, + onClickRemoveInvoice = { showDeleteInvoiceAlert = true }, + onClickCorrectInvoiceLocally = { onClickCorrectInvoiceLocally(invoice.taskId) } + ) + } } }, onBack = onBack @@ -218,31 +216,3 @@ fun InvoiceMedicationHeader(invoice: InvoiceData.PKVInvoice) { val medicationInfo = joinMedicationInfo(invoice.medicationRequest) Text(text = medicationInfo, style = AppTheme.typography.h5) } - -@Composable -fun InvoicesDetailThreeDotMenu(onClickDelete: () -> Unit) { - var expanded by remember { mutableStateOf(false) } - - IconButton( - onClick = { expanded = true } - ) { - Icon(Icons.Rounded.MoreVert, null, tint = AppTheme.colors.neutral600) - } - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - offset = DpOffset(24.dp, 0.dp) - ) { - DropdownMenuItem( - onClick = { - onClickDelete() - expanded = false - } - ) { - Text( - text = stringResource(R.string.invoice_detail_delete), - color = AppTheme.colors.red600 - ) - } - } -} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceLocalCorrectionScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceLocalCorrectionScreen.kt new file mode 100644 index 00000000..92737218 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceLocalCorrectionScreen.kt @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pkv.ui + +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides +import androidx.compose.foundation.layout.asPaddingValues +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.rememberLazyListState +import androidx.compose.material.Text +import androidx.compose.material.TextButton +import androidx.compose.material.rememberScaffoldState +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.style.TextAlign +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.core.LocalActivity +import de.gematik.ti.erp.app.invoice.model.InvoiceData +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.ForceBrightness +import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.DataMatrix +import de.gematik.ti.erp.app.utils.compose.SpacerLarge +import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.createBitMatrix + +@Composable +fun InvoiceLocalCorrectionScreen( + invoicesController: InvoicesController, + taskId: String, + onBack: () -> Unit +) { + val listState = rememberLazyListState() + val scaffoldState = rememberScaffoldState() + + val invoice by produceState(null) { + invoicesController.detailState(taskId).collect { + value = it + } + } + + val matrix = remember(invoice) { + invoice?.dmcPayload?.let { + createBitMatrix(it) + } + } + + val activity = LocalActivity.current + activity.ForceBrightness() + + AnimatedElevationScaffold( + modifier = Modifier + .imePadding(), + topBarTitle = "", + navigationMode = null, + scaffoldState = scaffoldState, + listState = listState, + actions = { + TextButton( + onClick = onBack + ) { + Text(stringResource(R.string.invoice_correct_done)) + } + }, + onBack = onBack + ) { innerPadding -> + + LazyColumn( + modifier = Modifier + .fillMaxSize().padding(innerPadding), + contentPadding = WindowInsets.navigationBars.only(WindowInsetsSides.Bottom).asPaddingValues(), + state = listState + ) { + item { + Text( + modifier = Modifier.padding(PaddingDefaults.Medium).fillMaxWidth(), + textAlign = TextAlign.Center, + style = AppTheme.typography.subtitle1, + text = stringResource(R.string.invoice_correction_info) + ) + } + matrix?.let { + item { + DataMatrix( + modifier = Modifier + .padding(PaddingDefaults.Medium) + .fillMaxWidth(), + matrix = matrix + ) + } + } + item { + SpacerLarge() + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + style = AppTheme.typography.subtitle1, + text = stringResource(R.string.invoice_correction) + ) + SpacerSmall() + Text( + modifier = Modifier.fillMaxWidth(), + textAlign = TextAlign.Center, + style = AppTheme.typography.body2l, + text = invoice?.medicationRequest?.medication?.name() ?: "" + ) + } + } + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceOverviewScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceOverviewScreen.kt deleted file mode 100644 index a9f24bd5..00000000 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceOverviewScreen.kt +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2023 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -package de.gematik.ti.erp.app.pkv.ui - -import androidx.compose.foundation.layout.Arrangement -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.rememberLazyListState -import androidx.compose.material.Text -import androidx.compose.material.rememberScaffoldState -import androidx.compose.runtime.Composable -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.produceState -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue -import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource -import de.gematik.ti.erp.app.R -import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.invoice.model.InvoiceData -import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.theme.PaddingDefaults -import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold -import de.gematik.ti.erp.app.utils.compose.NavigationBarMode -import de.gematik.ti.erp.app.utils.compose.visualTestTag - -import de.gematik.ti.erp.app.utils.compose.LabeledText -import de.gematik.ti.erp.app.utils.compose.TertiaryButton - -@Composable -fun InvoiceOverviewScreen( - selectedProfile: ProfilesUseCaseData.Profile, - taskId: String, - onBack: () -> Unit, - onClickShowMore: () -> Unit, - onClickSubmit: () -> Unit -) { - val listState = rememberLazyListState() - val scaffoldState = rememberScaffoldState() - val invoicesController = rememberInvoicesController(profileId = selectedProfile.id) - val invoice by produceState(null) { - invoicesController.detailState(taskId).collect { - value = it - } - } - var showDeleteInvoiceAlert by remember { mutableStateOf(false) } - - AnimatedElevationScaffold( - modifier = Modifier - .imePadding() - .visualTestTag(TestTag.Profile.InvoicesDetailScreen), - topBarTitle = "", - navigationMode = NavigationBarMode.Back, - scaffoldState = scaffoldState, - bottomBar = { - invoice?.let { - InvoiceDetailBottomBar( - it.invoice.totalBruttoAmount, - onClickSubmit = onClickSubmit - ) - } - }, - listState = listState, - actions = { - Row { - InvoicesDetailThreeDotMenu( - onClickDelete = { showDeleteInvoiceAlert = true } - ) - } - }, - onBack = onBack - ) { innerPadding -> - - LazyColumn( - modifier = Modifier - .fillMaxSize() - .padding( - top = PaddingDefaults.Medium + innerPadding.calculateTopPadding(), - bottom = PaddingDefaults.Medium + innerPadding.calculateBottomPadding(), - start = PaddingDefaults.Medium, - end = PaddingDefaults.Medium - ), - state = listState, - verticalArrangement = Arrangement.spacedBy(PaddingDefaults.Medium) - ) { - invoice?.let { - item { - InvoiceMedicationHeader(it) - } - item { - LabeledText( - description = stringResource(R.string.invoice_prescribed_by), - content = it.practitioner.name - ) - } - item { - LabeledText( - description = stringResource(R.string.invoice_redeemed_in), - content = it.pharmacyOrganization.name - ) - } - item { - LabeledText( - description = stringResource(R.string.invoice_redeemed_on), - content = it.whenHandedOver?.formattedString() - ) - } - item { - Row( - modifier = Modifier.fillMaxWidth(), - horizontalArrangement = Arrangement.Center - ) { - TertiaryButton(onClick = onClickShowMore) { - Text(text = stringResource(R.string.invoice_show_more)) - } - } - } - } - } - } -} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceThreeDotMenu.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceThreeDotMenu.kt new file mode 100644 index 00000000..4859ce37 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoiceThreeDotMenu.kt @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pkv.ui + +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.material.DropdownMenu +import androidx.compose.material.DropdownMenuItem +import androidx.compose.material.Icon +import androidx.compose.material.IconButton +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.KeyboardArrowDown +import androidx.compose.material.icons.outlined.KeyboardArrowRight +import androidx.compose.material.icons.rounded.MoreVert +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.unit.DpOffset +import androidx.compose.ui.unit.dp +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.utils.compose.SpacerSmall + +@Composable +fun InvoiceThreeDotMenu( + taskId: String, + onClickShareInvoice: (String) -> Unit, + onClickRemoveInvoice: (String) -> Unit, + onClickCorrectInvoiceLocally: (String) -> Unit +) { + var isMenuExpanded by remember { mutableStateOf(false) } + var isDropDownExpanded by remember { mutableStateOf(false) } + + IconButton( + onClick = { isMenuExpanded = true } + ) { + Icon(Icons.Rounded.MoreVert, null, tint = AppTheme.colors.neutral600) + } + DropdownMenu( + expanded = isMenuExpanded, + onDismissRequest = { isMenuExpanded = false }, + offset = DpOffset(24.dp, 0.dp) + ) { + DropdownMenuItem( + onClick = { + onClickShareInvoice(taskId) + isMenuExpanded = false + } + ) { + Text( + text = stringResource(R.string.invoice_header_share) + ) + } + if (isDropDownExpanded) { + SpacerSmall() + } + DropdownMenuItem( + onClick = { + isDropDownExpanded = !isDropDownExpanded + } + ) { + Column { + val arrow = when (isDropDownExpanded) { + true -> Icons.Outlined.KeyboardArrowDown + false -> Icons.Outlined.KeyboardArrowRight + } + Row(verticalAlignment = Alignment.CenterVertically) { + Text(text = stringResource(R.string.invoice_menu_correct_invoice)) + SpacerSmall() + Icon(arrow, null, tint = AppTheme.colors.neutral400) + } + + if (isDropDownExpanded) { + DropdownMenuItem(onClick = { + onClickCorrectInvoiceLocally(taskId) + isMenuExpanded = false + }) { + Text( + text = stringResource(R.string.invoice_menu_correct_invoice_locally), + style = AppTheme.typography.subtitle1 + ) + } + DropdownMenuItem(onClick = {}) { + Text( + text = stringResource(R.string.invoice_menu_correct_invoice_online), + style = AppTheme.typography.subtitle1l + ) + } + } + } + } + DropdownMenuItem( + onClick = { + onClickRemoveInvoice(taskId) + isMenuExpanded = false + } + ) { + Text( + text = stringResource(R.string.invoice_header_delete), + color = AppTheme.colors.red600 + ) + } + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesController.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesController.kt index a9200cd5..69a1020f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -26,7 +26,7 @@ import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.api.ApiCallException import de.gematik.ti.erp.app.cardwall.mini.ui.Authenticator import de.gematik.ti.erp.app.core.LocalAuthenticator -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import de.gematik.ti.erp.app.invoice.model.InvoiceData import de.gematik.ti.erp.app.invoice.model.PkvHtmlTemplate import de.gematik.ti.erp.app.invoice.usecase.InvoiceUseCase diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesScreen.kt index 55b7e5ef..289a1571 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/InvoicesScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -43,7 +43,6 @@ import androidx.compose.foundation.lazy.LazyItemScope import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Button import androidx.compose.material.Divider import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem @@ -54,6 +53,7 @@ import androidx.compose.material.ScaffoldState import androidx.compose.material.SnackbarHost import androidx.compose.material.Text import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.KeyboardArrowRight import androidx.compose.material.icons.rounded.MoreVert import androidx.compose.material.pullrefresh.PullRefreshIndicator import androidx.compose.material.pullrefresh.pullRefresh @@ -90,6 +90,7 @@ import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.ConnectBottomBar import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall @@ -104,14 +105,12 @@ import kotlinx.datetime.toJavaLocalDateTime import kotlinx.datetime.toLocalDateTime import java.time.format.DateTimeFormatter -@Suppress("LongMethod") @Composable fun InvoicesScreen( onBack: () -> Unit, selectedProfile: ProfilesUseCaseData.Profile, onShowCardWall: () -> Unit, onClickInvoice: (String) -> Unit, - onClickShare: (String) -> Unit, invoicesController: InvoicesController ) { val listState = rememberLazyListState() @@ -191,7 +190,9 @@ fun InvoicesScreen( }, bottomBar = { if (!ssoTokenValid) { - ConnectBottomBar { + ConnectBottomBar( + infoText = stringResource(R.string.invoices_connect_info) + ) { scope.launch { refreshPrescriptionsController.refresh( profileId = selectedProfile.id, @@ -227,12 +228,7 @@ fun InvoicesScreen( scaffoldState.snackbarHostState.showSnackbar(it) } }, - onDeleteInvoice = { - invoiceToDeleteTaskID = it - showDeleteInvoiceAlert = true - }, - onClickInvoice = onClickInvoice, - onClickShare = onClickShare + onClickInvoice = onClickInvoice ) } } @@ -338,9 +334,7 @@ private fun RefreshInvoicesContent( ssoTokenValid: Boolean, consentGranted: Boolean, onRefreshInvoicesError: (String) -> Unit, - onDeleteInvoice: (String) -> Unit, - onClickInvoice: (String) -> Unit, - onClickShare: (String) -> Unit + onClickInvoice: (String) -> Unit ) { val scope = rememberCoroutineScope() val context = LocalContext.current @@ -380,9 +374,7 @@ private fun RefreshInvoicesContent( Invoices( listState = listState, invoicesController = invoicesController, - onDeleteInvoice = onDeleteInvoice, - onClickInvoice = onClickInvoice, - onClickShare = onClickShare + onClickInvoice = onClickInvoice ) } } @@ -420,55 +412,11 @@ fun InvoicesHeaderThreeDotMenu(consentGranted: Boolean, onClickRevokeConsent: () } } -@Composable -fun InvoiceThreeDotMenu( - taskId: String, - onClickShareInvoice: (String) -> Unit, - onClickRemoveInvoice: (String) -> Unit -) { - var expanded by remember { mutableStateOf(false) } - - IconButton( - onClick = { expanded = true } - ) { - Icon(Icons.Rounded.MoreVert, null, tint = AppTheme.colors.neutral600) - } - DropdownMenu( - expanded = expanded, - onDismissRequest = { expanded = false }, - offset = DpOffset(24.dp, 0.dp) - ) { - DropdownMenuItem( - onClick = { - onClickShareInvoice(taskId) - expanded = false - } - ) { - Text( - text = stringResource(R.string.invoice_header_share) - ) - } - DropdownMenuItem( - onClick = { - onClickRemoveInvoice(taskId) - expanded = false - } - ) { - Text( - text = stringResource(R.string.invoice_header_delete), - color = AppTheme.colors.red600 - ) - } - } -} - @Composable fun Invoices( listState: LazyListState, invoicesController: InvoicesController, - onClickInvoice: (String) -> Unit, - onDeleteInvoice: (String) -> Unit, - onClickShare: (String) -> Unit + onClickInvoice: (String) -> Unit ) { val invoiceState by invoicesController.state @@ -514,8 +462,6 @@ fun Invoices( Invoice( invoice = invoice, formattedDate = formattedDate, - onDeleteInvoice = onDeleteInvoice, - onClickShare = onClickShare, onClickInvoice = onClickInvoice ) Divider(modifier = Modifier.padding(start = PaddingDefaults.Medium)) @@ -532,8 +478,6 @@ fun Invoices( private fun Invoice( invoice: InvoiceData.PKVInvoice, formattedDate: String, - onDeleteInvoice: (String) -> Unit, - onClickShare: (String) -> Unit, onClickInvoice: (String) -> Unit ) { Row( @@ -572,12 +516,8 @@ private fun Invoice( text = invoice.invoice.totalBruttoAmount.currencyString() + " " + invoice.invoice.currency ) } - Row(modifier = Modifier, horizontalArrangement = Arrangement.End) { - InvoiceThreeDotMenu( - invoice.taskId, - onClickShareInvoice = onClickShare, - onClickRemoveInvoice = onDeleteInvoice - ) + Row(modifier = Modifier.padding(horizontal = PaddingDefaults.Medium), horizontalArrangement = Arrangement.End) { + Icon(Icons.Outlined.KeyboardArrowRight, null, tint = AppTheme.colors.neutral400) } } } @@ -652,30 +592,3 @@ fun LazyItemScope.InvoicesEmptyScreen() { ) } } - -@Composable -fun ConnectBottomBar(onClickConnect: () -> Unit) { - Row( - modifier = Modifier - .fillMaxWidth() - .background( - color = AppTheme.colors.primary100 - ), - horizontalArrangement = Arrangement.SpaceBetween, - verticalAlignment = Alignment.CenterVertically - ) { - Text( - text = stringResource(R.string.invoices_connect_info), - modifier = Modifier - .padding(PaddingDefaults.Medium) - .weight(1f), - style = AppTheme.typography.body2 - ) - Button( - onClick = onClickConnect, - modifier = Modifier.padding(end = PaddingDefaults.Medium) - ) { - Text(text = stringResource(R.string.invoices_connect_btn)) - } - } -} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ShareInformationScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ShareInformationScreen.kt index 93b07e4f..43922955 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ShareInformationScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/ui/ShareInformationScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pkv/usecase/CreatePdf.kt b/android/src/main/java/de/gematik/ti/erp/app/pkv/usecase/CreatePdf.kt index 02731f95..f2118dfc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pkv/usecase/CreatePdf.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/pkv/usecase/CreatePdf.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt index 41ddc528..3cc78828 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/PrescriptionModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -24,6 +24,8 @@ import de.gematik.ti.erp.app.prescription.repository.RemoteDataSource import de.gematik.ti.erp.app.prescription.ui.TwoDCodeProcessor import de.gematik.ti.erp.app.prescription.ui.TwoDCodeScanner import de.gematik.ti.erp.app.prescription.ui.TwoDCodeValidator +import de.gematik.ti.erp.app.prescription.usecase.GetActivePrescriptionsUseCase +import de.gematik.ti.erp.app.prescription.usecase.GetArchivedPrescriptionsUseCase import de.gematik.ti.erp.app.prescription.usecase.PrescriptionUseCase import de.gematik.ti.erp.app.prescription.usecase.RefreshPrescriptionUseCase import org.kodein.di.DI @@ -39,5 +41,7 @@ val prescriptionModule = DI.Module("prescriptionModule") { bindSingleton { PrescriptionRepository(instance(), instance(), instance()) } bindSingleton { RemoteDataSource(instance()) } bindSingleton { PrescriptionUseCase(instance(), instance(), instance()) } - bindSingleton { RefreshPrescriptionUseCase(instance(), instance(), instance(), instance()) } + bindSingleton { RefreshPrescriptionUseCase(instance(), instance(), instance()) } + bindProvider { GetActivePrescriptionsUseCase(instance()) } + bindProvider { GetArchivedPrescriptionsUseCase(instance()) } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/AccidentInformation.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/AccidentInformation.kt index 16549ca7..3ab2e388 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/AccidentInformation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/AccidentInformation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeletePrescriptions.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeletePrescriptions.kt index e8332fe1..80c3e48e 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeletePrescriptions.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeletePrescriptions.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeleteSnackbar.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeleteSnackbar.kt index ac3fa202..70155dc4 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeleteSnackbar.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DeleteSnackbar.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DetailNavController.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DetailNavController.kt index 9d1dfbd3..625e94ce 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DetailNavController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/DetailNavController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/InfoSheet.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/InfoSheet.kt index c7badeb4..b069e829 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/InfoSheet.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/InfoSheet.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -152,7 +152,7 @@ fun PrescriptionDetailInfoSheetContent( infoContent.prescription.authoredOn } Column { - DateRange(start = start, end = infoContent.prescription.acceptUntil ?: start) + DateRange(start = start, end = infoContent.prescription.acceptUntil?.minus(1.days) ?: start) SpacerSmall() Text( stringResource(R.string.pres_details_exp_valid_info_accept), @@ -162,13 +162,13 @@ fun PrescriptionDetailInfoSheetContent( SpacerMedium() DateRange( start = remember { - infoContent.prescription.acceptUntil?.plus(1.days) ?: start + infoContent.prescription.acceptUntil ?: start }, - end = infoContent.prescription.expiresOn ?: start + end = infoContent.prescription.expiresOn?.minus(1.days) ?: start ) SpacerSmall() Text( - stringResource(R.string.pres_details_exp_valid_info_expires), + stringResource(R.string.pres_details_exp_valid_info_expiry_time), style = AppTheme.typography.body2l ) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/IngredientScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/IngredientScreen.kt index a2cabd15..4d6e77b2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/IngredientScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/IngredientScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/MedicationOverviewScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/MedicationOverviewScreen.kt index 61110f37..968a57b4 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/MedicationOverviewScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/MedicationOverviewScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/OrganizationScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/OrganizationScreen.kt index 5e4fff34..fec71584 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/OrganizationScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/OrganizationScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PatientScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PatientScreen.kt index f2666095..1a78efc5 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PatientScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PatientScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriberScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriberScreen.kt index 36829b61..44e7d7f3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriberScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriberScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt index 186a274c..841c280b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -91,6 +91,7 @@ import de.gematik.ti.erp.app.analytics.trackScreenUsingNavEntry import de.gematik.ti.erp.app.core.LocalAnalytics import de.gematik.ti.erp.app.core.LocalAuthenticator import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionData +import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionData.scannedPrescriptionIndex import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionDetailsNavigationScreens import de.gematik.ti.erp.app.prescription.model.SyncedTaskData import de.gematik.ti.erp.app.prescription.ui.DirectAssignmentChip @@ -624,9 +625,9 @@ private fun onClickEmergencyFee( private fun emergencyFeeText(emergencyFee: Boolean) = if (emergencyFee) { // false - emergencyFee fee is to be paid by the insured (default value) // true - emergencyFee fee is not to be paid by the insured but by the payer - stringResource(R.string.pres_detail_no) + stringResource(R.string.pres_detail_noctu_no) } else { - stringResource(R.string.pres_detail_yes) + stringResource(R.string.pres_detail_noctu_yes) } @Composable @@ -851,7 +852,7 @@ private fun ScannedPrescriptionOverview( horizontalAlignment = Alignment.CenterHorizontally ) { Text( - stringResource(R.string.pres_details_scanned_prescription), + stringResource(R.string.pres_details_scanned_prescription) + " " + scannedPrescriptionIndex, style = AppTheme.typography.h5, textAlign = TextAlign.Center ) diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailsController.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailsController.kt index e774d03d..32fe12f4 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailsController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/PrescriptionDetailsController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt index e63c6517..daa31f30 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SharePrescriptionController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -34,7 +34,7 @@ import de.gematik.ti.erp.app.prescription.usecase.PrescriptionUseCase import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.ui.LocalProfileHandler import de.gematik.ti.erp.app.userauthentication.ui.AuthenticationModeAndMethod -import de.gematik.ti.erp.app.utils.compose.createToastShort +import de.gematik.ti.erp.app.utils.compose.shortToast import io.github.aakira.napier.Napier import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.collectLatest @@ -170,13 +170,13 @@ fun SharePrescriptionHandler( intentHandler.shareIntent.collect { intent -> when (controller.handle(intent)) { SharePrescriptionController.HandleResult.TaskAlreadyExists -> - createToastShort(context, taskExists) + context.shortToast(taskExists) SharePrescriptionController.HandleResult.TaskSaved -> - createToastShort(context, taskAdded) + context.shortToast(taskAdded) SharePrescriptionController.HandleResult.Failure -> - createToastShort(context, otherFailure) + context.shortToast(otherFailure) } } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SyncedMedicationDetailScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SyncedMedicationDetailScreen.kt index 79bf2852..cd5ae7d2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SyncedMedicationDetailScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/SyncedMedicationDetailScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -41,7 +41,7 @@ import androidx.compose.ui.semantics.semantics import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.medicationCategory import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionData import de.gematik.ti.erp.app.prescription.model.SyncedTaskData diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt index 18b9fdd6..dd661485 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/TechnicalInformation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt index b3223e72..6e52f7b3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/PrescriptionData.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/PrescriptionData.kt index a7ef9368..715f66d8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/PrescriptionData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/detail/ui/model/PrescriptionData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -26,6 +26,8 @@ import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import kotlinx.datetime.Instant object PrescriptionData { + var scannedPrescriptionIndex: Int = 0 + sealed interface Prescription { val profileId: ProfileIdentifier val taskId: String diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/mapper/PrescriptionMapper.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/mapper/PrescriptionMapper.kt new file mode 100644 index 00000000..d8e6b02c --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/mapper/PrescriptionMapper.kt @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.prescription.mapper + +import de.gematik.ti.erp.app.prescription.model.ScannedTaskData.ScannedTask +import de.gematik.ti.erp.app.prescription.model.SyncedTaskData.SyncedTask +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription + +internal fun ScannedTask.toPrescription() = Prescription.ScannedPrescription( + taskId = taskId, + scannedOn = scannedOn, + redeemedOn = redeemedOn, + communications = communications +) + +internal fun SyncedTask.toPrescription() = Prescription.SyncedPrescription( + taskId = taskId, + isIncomplete = isIncomplete, + name = medicationName(), + organization = practitioner.name ?: organization.name ?: "", + authoredOn = authoredOn, + redeemedOn = redeemedOn(), + expiresOn = expiresOn, + acceptUntil = acceptUntil, + state = state(), + isDirectAssignment = isDirectAssignment(), + prescriptionChipInformation = Prescription.PrescriptionChipInformation( + isPartOfMultiplePrescription = medicationRequest + .multiplePrescriptionInfo.indicator, + numerator = medicationRequest.multiplePrescriptionInfo + .numbering?.numerator?.value, + denominator = medicationRequest.multiplePrescriptionInfo + .numbering?.denominator?.value, + start = medicationRequest.multiplePrescriptionInfo.start + ) +) + +@JvmName("filterScannedNonActiveTasks") +internal fun List.filterNonActiveTasks() = + filter { it.redeemedOn != null } + +@JvmName("filterScannedActiveTasks") +internal fun List.filterActiveTasks() = + filter { it.redeemedOn == null } + +@JvmName("filterSyncedNonActiveTasks") +internal fun List.filterNonActiveTasks() = filter { !it.isActive() } + +@JvmName("filterSyncedActiveTasks") +internal fun List.filterActiveTasks() = filter { it.isActive() } + +internal fun List.sortByExpiredDateAndAuthoredDate() = + sortedWith(compareBy { it.expiresOn }.thenBy { it.authoredOn }) + +internal fun List.groupByHospitalsOrDoctors() = + groupBy { it.practitioner.name ?: it.organization.name } + +internal fun Map>.flatMapToPrescriptions() = + flatMap { (_, tasks) -> tasks.map(SyncedTask::toPrescription) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/KBVCodeMapping.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/KBVCodeMapping.kt index 80180cd9..99212d21 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/KBVCodeMapping.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/KBVCodeMapping.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt index c5b83c39..8e439416 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt index 2f4db896..193a9abc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -51,10 +51,10 @@ class PrescriptionRepository( } fun scannedTasks(profileId: ProfileIdentifier) = - localDataSource.loadScannedTasks(profileId).flowOn(dispatchers.IO) + localDataSource.loadScannedTasks(profileId) fun syncedTasks(profileId: ProfileIdentifier) = - localDataSource.loadSyncedTasks(profileId).flowOn(dispatchers.IO) + localDataSource.loadSyncedTasks(profileId) suspend fun redeemPrescription( profileId: ProfileIdentifier, diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt index 5881d00e..b2b452c2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ArchiveScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ArchiveScreen.kt index 6cff13fd..87648648 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ArchiveScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ArchiveScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -34,7 +34,8 @@ import androidx.navigation.NavController import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.mainscreen.ui.MainNavigationScreens -import de.gematik.ti.erp.app.prescription.usecase.model.PrescriptionUseCaseData +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription.ScannedPrescription +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription.SyncedPrescription import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.NavigationBarMode @@ -45,7 +46,11 @@ import kotlinx.datetime.toLocalDateTime import java.time.format.DateTimeFormatter @Composable -fun ArchiveScreen(prescriptionState: PrescriptionState, navController: NavController, onBack: () -> Unit) { +fun ArchiveScreen( + prescriptionsController: PrescriptionsController, + navController: NavController, + onBack: () -> Unit +) { val listState = rememberLazyListState() AnimatedElevationScaffold( topBarTitle = stringResource(R.string.archive_screen_title), @@ -53,73 +58,73 @@ fun ArchiveScreen(prescriptionState: PrescriptionState, navController: NavContro onBack = onBack, navigationMode = NavigationBarMode.Back ) { - val state by prescriptionState.state + val archivedPrescriptions by prescriptionsController.archivedPrescriptionsState LazyColumn( - modifier = Modifier.fillMaxSize().testTag(TestTag.Prescriptions.Archive.Content), + modifier = Modifier + .fillMaxSize() + .testTag(TestTag.Prescriptions.Archive.Content), state = listState, horizontalAlignment = Alignment.CenterHorizontally ) { item { SpacerXXLarge() } - state?.let { - it.redeemedPrescriptions.forEachIndexed { index, prescription -> - item(key = "prescription-${prescription.taskId}") { - val previousPrescriptionRedeemedOn = - it.redeemedPrescriptions.getOrNull(index - 1) - ?.redeemedOrExpiredOn() - ?.toLocalDateTime(TimeZone.currentSystemDefault()) + archivedPrescriptions.forEachIndexed { index, prescription -> + item(key = "prescription-${prescription.taskId}") { + val previousPrescriptionRedeemedOn = + archivedPrescriptions.getOrNull(index - 1) + ?.redeemedOrExpiredOn() + ?.toLocalDateTime(TimeZone.currentSystemDefault()) - val redeemedOn = prescription.redeemedOrExpiredOn() - .toLocalDateTime(TimeZone.currentSystemDefault()) + val redeemedOn = prescription.redeemedOrExpiredOn() + .toLocalDateTime(TimeZone.currentSystemDefault()) - val yearChanged = remember { - previousPrescriptionRedeemedOn?.year != redeemedOn.year - } - - if (yearChanged) { - val instantOfArchivedPrescription = remember { - val dateFormatter = DateTimeFormatter.ofPattern("yyyy") - redeemedOn.toJavaLocalDateTime().format(dateFormatter) - } + val yearChanged = remember { + previousPrescriptionRedeemedOn?.year != redeemedOn.year + } - Text( - text = instantOfArchivedPrescription, - style = AppTheme.typography.h6, - modifier = Modifier - .fillMaxWidth() - .then(CardPaddingModifier) - ) + if (yearChanged) { + val instantOfArchivedPrescription = remember { + val dateFormatter = DateTimeFormatter.ofPattern("yyyy") + redeemedOn.toJavaLocalDateTime().format(dateFormatter) } - when (prescription) { - is PrescriptionUseCaseData.Prescription.Scanned -> - LowDetailMedication( - modifier = CardPaddingModifier, - prescription, - 0, - onClick = { - navController.navigate( - MainNavigationScreens.PrescriptionDetail.path( - taskId = prescription.taskId - ) + Text( + text = instantOfArchivedPrescription, + style = AppTheme.typography.h6, + modifier = Modifier + .fillMaxWidth() + .then(CardPaddingModifier) + ) + } + + when (prescription) { + is ScannedPrescription -> + LowDetailMedication( + modifier = CardPaddingModifier, + prescription, + 0, + onClick = { + navController.navigate( + MainNavigationScreens.PrescriptionDetail.path( + taskId = prescription.taskId ) - } - ) + ) + } + ) - is PrescriptionUseCaseData.Prescription.Synced -> - FullDetailMedication( - prescription, - modifier = CardPaddingModifier, - onClick = { - navController.navigate( - MainNavigationScreens.PrescriptionDetail.path( - taskId = prescription.taskId - ) + is SyncedPrescription -> + FullDetailMedication( + prescription, + modifier = CardPaddingModifier, + onClick = { + navController.navigate( + MainNavigationScreens.PrescriptionDetail.path( + taskId = prescription.taskId ) - } - ) - } + ) + } + ) } } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreenTemplate.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreenTemplate.kt index e144f94a..5a6a4fda 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreenTemplate.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreenTemplate.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreens.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreens.kt index 66e546a8..7fac5f75 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreens.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/EmptyScreens.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt index e53e8f8f..b21055e9 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MainScreenAvatar.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitInformationScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitInformationScreen.kt index a6c187b2..6de91089 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitInformationScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitInformationScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt index 7ffcb958..5c525489 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/MlKitIntroScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreenComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreenComponents.kt index 40906d5c..13865901 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreenComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreenComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -69,15 +69,16 @@ import androidx.navigation.NavController import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag -import de.gematik.ti.erp.app.fhir.parser.toFormattedDate import de.gematik.ti.erp.app.mainscreen.ui.MainNavigationScreens import de.gematik.ti.erp.app.mainscreen.ui.MainScreenController import de.gematik.ti.erp.app.mainscreen.ui.RefreshScaffold +import de.gematik.ti.erp.app.prescription.detail.ui.model.PrescriptionData.scannedPrescriptionIndex import de.gematik.ti.erp.app.prescription.model.SyncedTaskData -import de.gematik.ti.erp.app.prescription.ui.model.PrescriptionScreenData import de.gematik.ti.erp.app.prescription.ui.model.SentOrCompletedPhrase import de.gematik.ti.erp.app.prescription.ui.model.sentOrCompleted -import de.gematik.ti.erp.app.prescription.usecase.model.PrescriptionUseCaseData.Prescription +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription.ScannedPrescription +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription.SyncedPrescription import de.gematik.ti.erp.app.prescriptionId import de.gematik.ti.erp.app.profiles.ui.LocalProfileHandler import de.gematik.ti.erp.app.profiles.ui.ProfileHandler @@ -91,11 +92,12 @@ import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.SpacerXXLarge import de.gematik.ti.erp.app.utils.compose.TertiaryButton -import de.gematik.ti.erp.app.utils.compose.annotatedPluralsResource import de.gematik.ti.erp.app.utils.compose.annotatedStringResource import de.gematik.ti.erp.app.utils.compose.dateString import de.gematik.ti.erp.app.utils.compose.dateWithIntroductionString import de.gematik.ti.erp.app.utils.compose.timeString +import de.gematik.ti.erp.app.utils.toFormattedDate +import de.gematik.ti.erp.app.utils.toStartOfDayInUTC import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlinx.datetime.TimeZone @@ -110,7 +112,7 @@ const val TWO_DAYS_LEFT = 2L @Composable fun PrescriptionScreen( navController: NavController, - prescriptionState: PrescriptionState, + prescriptionsController: PrescriptionsController, mainScreenController: MainScreenController, onClickAvatar: () -> Unit, onClickArchive: () -> Unit, @@ -140,7 +142,7 @@ fun PrescriptionScreen( onShowCardWall = onShowCardWall ) { onRefresh -> Prescriptions( - prescriptionState = prescriptionState, + prescriptionsController = prescriptionsController, onClickRefresh = { onRefresh(true, MutatePriority.UserInput) }, @@ -180,19 +182,21 @@ val CardPaddingModifier = Modifier @Composable private fun Prescriptions( - prescriptionState: PrescriptionState, + prescriptionsController: PrescriptionsController, navController: NavController, onClickRefresh: () -> Unit, onClickAvatar: () -> Unit, onClickArchive: () -> Unit, onElevateTopBar: (Boolean) -> Unit ) { - val state by prescriptionState.state + val activePrescriptions by prescriptionsController.activePrescriptionsState + val archivedPrescriptions by prescriptionsController.archivedPrescriptionsState PrescriptionsContent( onClickRefresh = onClickRefresh, onClickAvatar = onClickAvatar, - state = state, + activePrescriptions = activePrescriptions, + isArchiveEmpty = archivedPrescriptions.isEmpty(), navController = navController, onElevateTopBar = onElevateTopBar, onClickArchive = onClickArchive @@ -206,7 +210,8 @@ private fun PrescriptionsContent( onClickRefresh: () -> Unit, onClickAvatar: () -> Unit, onClickArchive: () -> Unit, - state: PrescriptionScreenData.State, + activePrescriptions: List, + isArchiveEmpty: Boolean, navController: NavController, onElevateTopBar: (Boolean) -> Unit ) { @@ -230,7 +235,7 @@ private fun PrescriptionsContent( horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.Top ) { - if (state.prescriptions.isNotEmpty()) { + if (activePrescriptions.isNotEmpty()) { item { SpacerXXLarge() ProfileConnectionSection(onClickAvatar, onClickRefresh) @@ -238,13 +243,13 @@ private fun PrescriptionsContent( } prescriptionContent( - state = state, + activePrescriptions = activePrescriptions, navController = navController ) } else { emptyContent(profileHandler, onClickRefresh, onClickAvatar) } - if (state.redeemedPrescriptions.isNotEmpty()) { + if (!isArchiveEmpty) { item { SpacerLarge() TextButton( @@ -297,7 +302,10 @@ fun LazyListScope.emptyContent( } else { item { SpacerLarge() - Text(stringResource(R.string.mainscreen_empty_content_header), style = AppTheme.typography.subtitle1) + Text( + stringResource(R.string.mainscreen_empty_content_header), + style = AppTheme.typography.subtitle1 + ) } item { SpacerMedium() @@ -315,14 +323,14 @@ fun LazyListScope.emptyContent( private fun LazyListScope.prescriptionContent( navController: NavController, - state: PrescriptionScreenData.State + activePrescriptions: List ) { - val prescriptionsIndices = processPrescriptionsDayIndices(state.prescriptions) + val prescriptionsIndices = processPrescriptionsDayIndices(activePrescriptions) - state.prescriptions.forEach { prescription -> + activePrescriptions.forEach { prescription -> item(key = "prescription-${prescription.taskId}") { when (prescription) { - is Prescription.Synced -> + is SyncedPrescription -> FullDetailMedication( prescription, modifier = CardPaddingModifier, @@ -335,12 +343,14 @@ private fun LazyListScope.prescriptionContent( } ) - is Prescription.Scanned -> { + is ScannedPrescription -> { LowDetailMedication( modifier = CardPaddingModifier, prescription, prescriptionsIndices.getOrDefault(prescription.taskId, 1), onClick = { + scannedPrescriptionIndex = + prescriptionsIndices.getOrDefault(prescription.taskId, 1) navController.navigate( MainNavigationScreens.PrescriptionDetail.path( taskId = prescription.taskId @@ -355,11 +365,11 @@ private fun LazyListScope.prescriptionContent( } private fun processPrescriptionsDayIndices(prescriptions: List): Map { - var previousPrescription: Prescription.Scanned? = null + var previousPrescription: ScannedPrescription? = null var dayIndex = 1 val indexedPrescriptions = mutableMapOf() - prescriptions.filterIsInstance().forEach { + prescriptions.filterIsInstance().forEach { val current = it.scannedOn.toFormattedDate() val prev = previousPrescription?.scannedOn?.toFormattedDate() if (current == prev) dayIndex++ else dayIndex = 1 @@ -390,44 +400,58 @@ fun readyPrescriptionStateInfo( append(stringResource(R.string.prescription_item_expiration_only_today)) } - acceptDaysLeft in ONE_DAY_LEFT..TWO_DAYS_LEFT -> buildAnnotatedString { + acceptDaysLeft == ONE_DAY_LEFT -> buildAnnotatedString { + appendInlineContent( + id = "warningAmber", + alternateText = stringResource(R.string.prescription_item_warning_amber) + ) + append(stringResource(R.string.prescription_item_accept_only_tomorrow)) + } + + expiryDaysLeft == ONE_DAY_LEFT -> buildAnnotatedString { + appendInlineContent( + id = "warningAmber", + alternateText = stringResource(R.string.prescription_item_warning_amber) + ) + append( + stringResource(R.string.prescription_item_expiration_only_tomorrow) + ) + } + + acceptDaysLeft == TWO_DAYS_LEFT -> buildAnnotatedString { appendInlineContent( id = "warningAmber", alternateText = stringResource(R.string.prescription_item_warning_amber) ) append( - annotatedPluralsResource( - R.plurals.prescription_item_accept_days, - acceptDaysLeft.toInt(), + annotatedStringResource( + R.string.prescription_item_two_accept_days_left, AnnotatedString(acceptDaysLeft.toString()) ) ) } - expiryDaysLeft in ONE_DAY_LEFT..TWO_DAYS_LEFT -> buildAnnotatedString { + expiryDaysLeft == TWO_DAYS_LEFT -> buildAnnotatedString { appendInlineContent( id = "warningAmber", alternateText = stringResource(R.string.prescription_item_warning_amber) ) append( - annotatedPluralsResource( - R.plurals.prescription_item_expiration_days_new, - expiryDaysLeft.toInt(), + annotatedStringResource( + R.string.prescription_item_two_expiration_days_left, AnnotatedString(expiryDaysLeft.toString()) ) ) } - acceptDaysLeft > TWO_DAYS_LEFT -> annotatedPluralsResource( - R.plurals.prescription_item_accept_days, - 1 + acceptDaysLeft.toInt(), - AnnotatedString((1 + acceptDaysLeft).toString()) + acceptDaysLeft > TWO_DAYS_LEFT -> annotatedStringResource( + R.string.prescription_item_accept_days_left, + AnnotatedString((acceptDaysLeft).toString()) ) - expiryDaysLeft > TWO_DAYS_LEFT -> annotatedPluralsResource( - R.plurals.prescription_item_expiration_days_new, - 1 + expiryDaysLeft.toInt(), - AnnotatedString((1 + expiryDaysLeft).toString()) + expiryDaysLeft > TWO_DAYS_LEFT -> annotatedStringResource( + R.string.prescription_item_expiration_days_left, + AnnotatedString((expiryDaysLeft).toString()) ) else -> null @@ -469,8 +493,10 @@ fun PrescriptionStateInfo( } is SyncedTaskData.SyncedTask.Ready -> { - val expiryDaysLeft = remember { (state.expiresOn - now).inWholeDays } - val acceptDaysLeft = remember { (state.acceptUntil - now).inWholeDays } + val expiryDaysLeft = + remember { (state.expiresOn - now.toStartOfDayInUTC()).inWholeDays } + val acceptDaysLeft = + remember { (state.acceptUntil - now.toStartOfDayInUTC()).inWholeDays } val text = readyPrescriptionStateInfo(acceptDaysLeft, expiryDaysLeft) @@ -507,7 +533,10 @@ fun PrescriptionStateInfo( is SyncedTaskData.SyncedTask.Expired -> { Text( - dateWithIntroductionString(R.string.pres_detail_medication_expired_on, state.expiredOn), + dateWithIntroductionString( + R.string.pres_detail_medication_expired_on, + state.expiredOn + ), style = AppTheme.typography.body2, textAlign = textAlign ) @@ -523,8 +552,19 @@ fun PrescriptionStateInfo( } @Composable -private fun sentOrCompletedPhrase(lastModified: Instant, now: Instant, completed: Boolean = false): String = - when (val phrase = sentOrCompleted(lastModified = lastModified, now = now, completed = completed)) { +private fun sentOrCompletedPhrase( + lastModified: Instant, + now: Instant, + completed: Boolean = false +): String = + when ( + val phrase = + sentOrCompleted( + lastModified = lastModified, + now = now, + completed = completed + ) + ) { SentOrCompletedPhrase.RedeemedJustNow -> stringResource(R.string.received_now) SentOrCompletedPhrase.SentJustNow -> stringResource(R.string.sent_now) @@ -568,7 +608,7 @@ private fun sentOrCompletedPhrase(lastModified: Instant, now: Instant, completed @OptIn(ExperimentalMaterialApi::class) @Composable fun FullDetailMedication( - prescription: Prescription.Synced, + prescription: SyncedPrescription, modifier: Modifier = Modifier, onClick: () -> Unit ) { @@ -596,7 +636,8 @@ fun FullDetailMedication( Row(modifier = Modifier.padding(PaddingDefaults.Medium)) { Column(modifier = Modifier.weight(1f)) { val medicationName = - prescription.name ?: stringResource(R.string.prescription_medication_default_name) + prescription.name + ?: stringResource(R.string.prescription_medication_default_name) Text( modifier = Modifier.testTag(TestTag.Prescriptions.FullDetailPrescriptionName), @@ -633,9 +674,9 @@ fun FullDetailMedication( } } } - if (prescription.multiplePrescriptionState.isPartOfMultiplePrescription) { - prescription.multiplePrescriptionState.numerator?.let { numerator -> - prescription.multiplePrescriptionState.denominator?.let { denominator -> + if (prescription.prescriptionChipInformation.isPartOfMultiplePrescription) { + prescription.prescriptionChipInformation.numerator?.let { numerator -> + prescription.prescriptionChipInformation.denominator?.let { denominator -> SpacerSmall() NumeratorChip(numerator, denominator) } @@ -660,7 +701,7 @@ fun FullDetailMedication( @Composable fun LowDetailMedication( modifier: Modifier = Modifier, - prescription: Prescription.Scanned, + prescription: ScannedPrescription, index: Int, onClick: () -> Unit ) { diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionServiceState.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionServiceState.kt index d4c37377..0f1355fe 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionServiceState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionServiceState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -20,9 +20,18 @@ package de.gematik.ti.erp.app.prescription.ui import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable +import de.gematik.ti.erp.app.Requirement interface PrescriptionServiceState +@Requirement( + "O.Source_3", + "O.Source_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Error messages are localized using the `PrescriptionServiceErrorState " + + "Search for `PrescriptionServiceErrorState`or State.Error to see all instances." + + "Most errors are localized with static text. Logging is only active on debug builds." +) interface PrescriptionServiceErrorState : PrescriptionServiceState @Stable diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionState.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionsController.kt similarity index 50% rename from android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionState.kt rename to android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionsController.kt index 669d7068..affe58a6 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/PrescriptionsController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,52 +23,42 @@ import androidx.compose.runtime.Stable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.saveable.rememberSaveable import de.gematik.ti.erp.app.core.complexAutoSaver -import de.gematik.ti.erp.app.prescription.ui.model.PrescriptionScreenData -import de.gematik.ti.erp.app.prescription.usecase.PrescriptionUseCase +import de.gematik.ti.erp.app.prescription.usecase.GetActivePrescriptionsUseCase +import de.gematik.ti.erp.app.prescription.usecase.GetArchivedPrescriptionsUseCase +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.ui.LocalProfileHandler -import de.gematik.ti.erp.app.profiles.usecase.activeProfile import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged import org.kodein.di.compose.rememberInstance @Stable -class PrescriptionState( - prescriptionUseCase: PrescriptionUseCase, - profileId: ProfileIdentifier +class PrescriptionsController( + private val activePrescriptionsUseCase: GetActivePrescriptionsUseCase, + private val archivedPrescriptionsUseCase: GetArchivedPrescriptionsUseCase, + private val profileId: ProfileIdentifier ) { - private val prescriptionFlow = combine( - prescriptionUseCase.scannedActiveRecipes(profileId), - prescriptionUseCase.syncedActiveRecipes(profileId) - ) { lowDetail, fullDetail -> - (lowDetail + fullDetail) - } - - private val stateFlow: Flow = - combine( - prescriptionFlow, - prescriptionUseCase.redeemedPrescriptions(profileId) - ) { prescriptions, redeemed -> - PrescriptionScreenData.State( - prescriptions = prescriptions, - redeemedPrescriptions = redeemed - ) - }.distinctUntilChanged() - - val state + private val activePrescriptions: Flow> + get() = activePrescriptionsUseCase(profileId) + private val archivedPrescriptions: Flow> + get() = archivedPrescriptionsUseCase(profileId) + val activePrescriptionsState + @Composable + get() = activePrescriptions.collectAsState(emptyList()) + val archivedPrescriptionsState @Composable - get() = stateFlow.collectAsState(PrescriptionScreenData.EmptyState) + get() = archivedPrescriptions.collectAsState(emptyList()) } @Composable -fun rememberPrescriptionState(): PrescriptionState { - val prescriptionUseCase by rememberInstance() +fun rememberPrescriptionsController(): PrescriptionsController { + val activePrescriptionsUseCase by rememberInstance() + val archivedPrescriptionsUseCase by rememberInstance() val activeProfile = LocalProfileHandler.current.activeProfile return rememberSaveable(activeProfile.id, saver = complexAutoSaver()) { - PrescriptionState( - prescriptionUseCase = prescriptionUseCase, + PrescriptionsController( + activePrescriptionsUseCase = activePrescriptionsUseCase, + archivedPrescriptionsUseCase = archivedPrescriptionsUseCase, profileId = activeProfile.id ) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/RefreshPrescriptionsController.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/RefreshPrescriptionsController.kt index d4207bd3..8a6f1e88 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/RefreshPrescriptionsController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/RefreshPrescriptionsController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanPrescriptionController.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanPrescriptionController.kt index 7ad76e49..9d0dc13b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanPrescriptionController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanPrescriptionController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanScreenComponent.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanScreenComponent.kt index 1e1999a7..da173ee2 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanScreenComponent.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/ScanScreenComponent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -45,7 +45,6 @@ import androidx.camera.core.TorchState import androidx.camera.lifecycle.ProcessCameraProvider import androidx.camera.view.PreviewView import androidx.compose.animation.AnimatedVisibility -import androidx.compose.animation.ExperimentalAnimationApi import androidx.compose.animation.core.LinearOutSlowInEasing import androidx.compose.animation.core.MutableTransitionState import androidx.compose.animation.core.RepeatMode @@ -144,7 +143,12 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.util.Locale import java.util.concurrent.Executors - +@Requirement( + "O.Purp_2#1", + "O.Data_6#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Scanning tasks contains purpose related data input." +) @OptIn(ExperimentalMaterialApi::class) @Composable fun ScanScreen( @@ -165,7 +169,11 @@ fun ScanScreen( rememberLauncherForActivityResult(ActivityResultContracts.RequestPermission()) { camPermissionGranted = it } - + @Requirement( + "O.Plat_3#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "platform dialog for CAMERA" + ) LaunchedEffect(Unit) { if (context.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { camPermissionLauncher.launch(Manifest.permission.CAMERA) @@ -567,7 +575,6 @@ private fun InfoError(text: String) { } } -@OptIn(ExperimentalAnimationApi::class) @SuppressLint("UnsafeOptInUsageError") @Composable private fun CameraView( diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/StatusChip.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/StatusChip.kt index 0669c4f4..c1a9deb3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/StatusChip.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/StatusChip.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeProcessor.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeProcessor.kt index 8642aa4f..1f99e554 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeProcessor.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeProcessor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -24,6 +24,7 @@ import android.graphics.Rect import android.util.Size import androidx.core.graphics.minus import com.google.mlkit.vision.barcode.common.Barcode +import de.gematik.ti.erp.app.Requirement import io.github.aakira.napier.Napier import kotlin.math.absoluteValue import kotlin.math.max @@ -105,6 +106,11 @@ class TwoDCodeProcessor { private var codeHist = listOf>() + @Requirement( + "O.Source_1#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Scanning data matrix codes" + ) fun process(batch: TwoDCodeScanner.Batch): Pair? { if (batch.cameraRotation != metrics.camRotation || batch.cameraSize != metrics.camImageSize) { val cs = batch.cameraSize diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeScanner.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeScanner.kt index 63338e2e..e343b609 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeScanner.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeScanner.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -31,12 +31,29 @@ import com.google.mlkit.vision.barcode.BarcodeScannerOptions import com.google.mlkit.vision.barcode.BarcodeScanning import com.google.mlkit.vision.barcode.common.Barcode import com.google.mlkit.vision.common.InputImage +import de.gematik.ti.erp.app.Requirement import kotlinx.coroutines.channels.BufferOverflow import kotlinx.coroutines.flow.MutableSharedFlow import io.github.aakira.napier.Napier private const val DEFAULT_SCAN_TIME = 250L +@Requirement( + "O.Source_1#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "analyse the camera input" +) +@Requirement( + "O.Data_8", + sourceSpecification = "BSI-eRp-ePA", + rationale = "This controller uses the camera as an input device. Frames are processed but never " + + "stored, metadata is never created here." +) +@Requirement( + "O.Data_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The device camera is exclusively used for scanning data matrix codes, no picture files are created." +) class TwoDCodeScanner( private val context: Context diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidator.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidator.kt index c5b2901d..129b1819 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidator.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidator.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.prescription.ui +import de.gematik.ti.erp.app.Requirement import kotlinx.serialization.Serializable import kotlinx.serialization.decodeFromString import kotlinx.serialization.json.Json @@ -43,6 +44,11 @@ data class Tasks( * The [TwoDCodeValidator] validates a [ScannedCode] and returns, if the containing json is valid, * a [ValidScannedCode] or otherwise null. */ +@Requirement( + "O.Source_1#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Validate the data matrix code structure" +) class TwoDCodeValidator { fun validate(code: ScannedCode): ValidScannedCode? { try { diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt index de4b1c1d..7f5f4c2d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/ScanData.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/ScanData.kt index edd0c9b1..27881e4c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/ScanData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/ScanData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompleted.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompleted.kt index 1e458e26..5da2e8e3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompleted.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompleted.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt new file mode 100644 index 00000000..71705f42 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetActivePrescriptionsUseCase.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.prescription.usecase + +import de.gematik.ti.erp.app.prescription.mapper.filterActiveTasks +import de.gematik.ti.erp.app.prescription.mapper.flatMapToPrescriptions +import de.gematik.ti.erp.app.prescription.mapper.groupByHospitalsOrDoctors +import de.gematik.ti.erp.app.prescription.mapper.sortByExpiredDateAndAuthoredDate +import de.gematik.ti.erp.app.prescription.mapper.toPrescription +import de.gematik.ti.erp.app.prescription.model.ScannedTaskData +import de.gematik.ti.erp.app.prescription.repository.PrescriptionRepository +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn + +class GetActivePrescriptionsUseCase( + private val repository: PrescriptionRepository, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + operator fun invoke( + id: ProfileIdentifier + ): Flow> = combine( + repository.scannedTasks(id), + repository.syncedTasks(id) + ) { scannedTasks, syncedTasks -> + val scannedPrescriptions = scannedTasks + .filterActiveTasks() + .map(ScannedTaskData.ScannedTask::toPrescription) + .sortedBy { it.startedOn } + + val syncedPrescriptions = syncedTasks + .filterActiveTasks() + .sortByExpiredDateAndAuthoredDate() + .groupByHospitalsOrDoctors() + .flatMapToPrescriptions() + + (scannedPrescriptions + syncedPrescriptions) + .sortedByDescending { it.redeemedOn ?: it.startedOn } + }.flowOn(dispatcher) +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt new file mode 100644 index 00000000..beb8002e --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/GetArchivedPrescriptionsUseCase.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.prescription.usecase + +import de.gematik.ti.erp.app.prescription.mapper.filterNonActiveTasks +import de.gematik.ti.erp.app.prescription.mapper.toPrescription +import de.gematik.ti.erp.app.prescription.model.ScannedTaskData.ScannedTask +import de.gematik.ti.erp.app.prescription.model.SyncedTaskData.SyncedTask +import de.gematik.ti.erp.app.prescription.repository.PrescriptionRepository +import de.gematik.ti.erp.app.prescription.usecase.model.Prescription +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import kotlinx.coroutines.CoroutineDispatcher +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine +import kotlinx.coroutines.flow.flowOn + +class GetArchivedPrescriptionsUseCase( + private val repository: PrescriptionRepository, + private val dispatcher: CoroutineDispatcher = Dispatchers.IO +) { + operator fun invoke( + id: ProfileIdentifier + ): Flow> = + combine( + repository.scannedTasks(id), + repository.syncedTasks(id) + ) { scannedTasks, syncedTasks -> + val scannedPrescriptions = scannedTasks + .filterNonActiveTasks() + .map(ScannedTask::toPrescription) + + val syncedPrescriptions = syncedTasks + .filterNonActiveTasks() + .map(SyncedTask::toPrescription) + + (syncedPrescriptions + scannedPrescriptions) + .sortedBy { it.taskId } + .sortedByDescending { it.redeemedOn ?: it.startedOn } + }.flowOn(dispatcher) +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt index 3c7771ca..b9b25aa4 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt index bb247b93..64518fcd 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/RefreshPrescriptionUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -22,7 +22,6 @@ import de.gematik.ti.erp.app.DispatchProvider import de.gematik.ti.erp.app.orders.repository.CommunicationRepository import de.gematik.ti.erp.app.prescription.repository.TaskRepository import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier -import de.gematik.ti.erp.app.protocol.repository.AuditEventsRepository import io.github.aakira.napier.Napier import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CoroutineScope @@ -38,7 +37,6 @@ import kotlinx.coroutines.withContext class RefreshPrescriptionUseCase( private val repository: TaskRepository, private val communicationRepository: CommunicationRepository, - private val auditRepository: AuditEventsRepository, dispatchers: DispatchProvider ) { private class Request( @@ -82,12 +80,6 @@ class RefreshPrescriptionUseCase( val resultChannel = Channel>() try { requestChannel.send(Request(resultChannel = resultChannel, forProfileId = profileId)) - scope.launch { - auditRepository.downloadAuditEvents(profileId).onFailure { - Napier.e(it) { "Failed to download audit events" } - } - } - return resultChannel.receive() } catch (cancellation: CancellationException) { Napier.d { "Cancelled waiting for result of refresh request" } diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt new file mode 100644 index 00000000..40df77b0 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/Prescription.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.prescription.usecase.model + +import androidx.compose.runtime.Immutable +import de.gematik.ti.erp.app.db.entities.v1.task.CommunicationEntityV1 +import de.gematik.ti.erp.app.prescription.model.SyncedTaskData +import kotlinx.datetime.Instant + +@Immutable +sealed interface Prescription { + val taskId: String + val redeemedOn: Instant? + val startedOn: Instant? + + /** + * Represents a single [Task] synchronized with the backend. + */ + @Immutable + data class SyncedPrescription( + override val taskId: String, + override val redeemedOn: Instant?, + val state: SyncedTaskData.SyncedTask.TaskState, + val name: String?, + val isIncomplete: Boolean, + val organization: String, + val authoredOn: Instant, + val expiresOn: Instant?, + val acceptUntil: Instant?, + val isDirectAssignment: Boolean, + val prescriptionChipInformation: PrescriptionChipInformation + ) : Prescription { + override val startedOn = authoredOn + } + + data class PrescriptionChipInformation( + val isPartOfMultiplePrescription: Boolean = false, + val numerator: String? = null, + val denominator: String? = null, + val start: Instant? = null + ) + + /** + * Represents a single [Task] scanned by the user. + */ + @Immutable + data class ScannedPrescription( + override val taskId: String, + override val redeemedOn: Instant?, + val scannedOn: Instant, + val communications: List + ) : Prescription { + override val startedOn = scannedOn + } + + fun redeemedOrExpiredOn(): Instant = + when (this) { + is ScannedPrescription -> requireNotNull(redeemedOn) { + "Scanned prescriptions require " + + "a redeemed timestamp" + } + + is SyncedPrescription -> redeemedOn ?: expiresOn ?: authoredOn + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt index d9e059b5..0b759571 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ProfilesModule.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ProfilesModule.kt index 3cc9c6ac..58dafe25 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ProfilesModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ProfilesModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -32,5 +32,5 @@ val profilesModule = DI.Module("profilesModule") { bindProvider { ProfilesWithPairedDevicesUseCase(instance(), instance()) } bindSingleton { ProfilesRepository(instance(), instance()) } - bindSingleton { ProfilesUseCase(instance(), instance(), instance()) } + bindSingleton { ProfilesUseCase(instance(), instance()) } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/Avatar.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/Avatar.kt index 742a92ae..1375d8a7 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/Avatar.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/Avatar.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt index 04472d79..d046e4fe 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileNavigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -38,10 +38,12 @@ import de.gematik.ti.erp.app.analytics.TrackNavigationChanges import de.gematik.ti.erp.app.mainscreen.ui.MainNavigationScreens import de.gematik.ti.erp.app.pkv.ui.InvoiceDetailsScreen import de.gematik.ti.erp.app.pkv.ui.InvoiceInformationScreen +import de.gematik.ti.erp.app.pkv.ui.InvoiceLocalCorrectionScreen import de.gematik.ti.erp.app.pkv.ui.InvoicesScreen import de.gematik.ti.erp.app.pkv.ui.ShareInformationScreen import de.gematik.ti.erp.app.pkv.ui.rememberInvoicesController import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData +import de.gematik.ti.erp.app.settings.rememberAuditEventsController import de.gematik.ti.erp.app.utils.compose.NavigationAnimation import de.gematik.ti.erp.app.utils.compose.NavigationMode import kotlinx.coroutines.launch @@ -71,6 +73,14 @@ object ProfileDestinations { fun path(taskId: String) = path("taskId" to taskId) } + object InvoiceLocalCorrection : + Route( + "chargeItem_correct_locally", + navArgument("taskId") { type = NavType.StringType } + ) { + fun path(taskId: String) = path("taskId" to taskId) + } + object ShareInformation : Route( "chargeItem_share", @@ -95,11 +105,14 @@ fun EditProfileNavGraph( TrackNavigationChanges(navController, previousNavEntry, onNavEntryChange = { previousNavEntry = it }) val scope = rememberCoroutineScope() val invoicesController = rememberInvoicesController(profileId = selectedProfile.id) + val auditEventsController = rememberAuditEventsController() NavHost(navController = navController, startDestination = ProfileDestinations.Profile.route) { composable(ProfileDestinations.Profile.route) { EditProfileScreenContent( onClickToken = { navController.navigate(ProfileDestinations.Token.path()) }, - onClickAuditEvents = { navController.navigate(ProfileDestinations.AuditEvents.path()) }, + onClickAuditEvents = { + navController.navigate(ProfileDestinations.AuditEvents.path()) + }, onClickLogIn = { scope.launch { profilesController.switchActiveProfile(selectedProfile) @@ -182,8 +195,15 @@ fun EditProfileNavGraph( NavigationAnimation(mode = NavigationMode.Closed) { AuditEventsScreen( profileId = selectedProfile.id, - profilesController = profilesController, - lastAuthenticated = selectedProfile.lastAuthenticated, + onShowCardWall = { + scope.launch { + profilesController.switchActiveProfile(selectedProfile) + } + mainNavController.navigate( + MainNavigationScreens.CardWall.path(selectedProfile.id) + ) + }, + auditEventsController = auditEventsController, tokenValid = selectedProfile.ssoTokenValid() ) { navController.popBackStack() } } @@ -209,11 +229,6 @@ fun EditProfileNavGraph( ProfileDestinations.InvoiceInformation.path(taskId) ) }, - onClickShare = { taskId -> - navController.navigate( - ProfileDestinations.ShareInformation.path(taskId) - ) - }, onShowCardWall = { mainNavController.navigate( MainNavigationScreens.CardWall.path(selectedProfile.id) @@ -238,9 +253,14 @@ fun EditProfileNavGraph( ProfileDestinations.InvoiceDetails.path(taskId) ) }, + onClickCorrectInvoiceLocally = { + navController.navigate( + ProfileDestinations.InvoiceLocalCorrection.path(it) + ) + }, onClickSubmit = { navController.navigate( - ProfileDestinations.ShareInformation.path(taskId) + ProfileDestinations.ShareInformation.path(it) ) }, onBack = { navController.popBackStack() } @@ -263,6 +283,21 @@ fun EditProfileNavGraph( } } + composable( + ProfileDestinations.InvoiceLocalCorrection.route, + ProfileDestinations.InvoiceLocalCorrection.arguments + ) { + val taskId = remember { requireNotNull(it.arguments?.getString("taskId")) } + + NavigationAnimation(mode = NavigationMode.Closed) { + InvoiceLocalCorrectionScreen( + invoicesController = invoicesController, + taskId = taskId, + onBack = { navController.popBackStack() } + ) + } + } + composable( ProfileDestinations.ShareInformation.route, ProfileDestinations.ShareInformation.arguments diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt index 30909480..d5f6da8c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/EditProfileScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -30,6 +30,9 @@ import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.imePadding +import androidx.compose.foundation.layout.navigationBars +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.lazy.LazyColumn @@ -45,6 +48,8 @@ import androidx.compose.material.DropdownMenu import androidx.compose.material.DropdownMenuItem import androidx.compose.material.Icon import androidx.compose.material.IconButton +import androidx.compose.material.LocalContentAlpha +import androidx.compose.material.LocalContentColor import androidx.compose.material.Surface import androidx.compose.material.Text import androidx.compose.material.TextButton @@ -53,7 +58,11 @@ import androidx.compose.material.icons.outlined.CloudQueue import androidx.compose.material.icons.outlined.Done import androidx.compose.material.icons.outlined.Edit import androidx.compose.material.icons.outlined.VpnKey +import androidx.compose.material.icons.rounded.AddAPhoto +import androidx.compose.material.icons.rounded.EuroSymbol import androidx.compose.material.icons.rounded.MoreVert +import androidx.compose.material.icons.rounded.Refresh +import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue @@ -65,10 +74,13 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.ExperimentalComposeUiApi import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clip import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.graphics.ImageBitmap +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.platform.LocalSoftwareKeyboardController import androidx.compose.ui.platform.testTag import androidx.compose.ui.res.painterResource @@ -88,18 +100,6 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.em import androidx.navigation.NavController import androidx.navigation.compose.rememberNavController -import androidx.compose.foundation.layout.imePadding -import androidx.compose.foundation.layout.navigationBars -import androidx.compose.foundation.layout.only -import androidx.compose.material.LocalContentAlpha -import androidx.compose.material.LocalContentColor -import androidx.compose.material.icons.rounded.AddAPhoto -import androidx.compose.material.icons.rounded.EuroSymbol -import androidx.compose.material.icons.rounded.Refresh -import androidx.compose.material.rememberScaffoldState -import androidx.compose.ui.draw.clip -import androidx.compose.ui.graphics.SolidColor -import androidx.compose.ui.graphics.vector.ImageVector import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag @@ -273,6 +273,11 @@ fun EditProfileScreenContent( ProfileEditPairedDeviceSection(onShowPairedDevices = onClickPairedDevices) } } + @Requirement( + "O.Tokn_5#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Section for Access and SSO Token display" + ) item { SecuritySection(onClickToken, onClickAuditEvents) } } @@ -343,6 +348,11 @@ fun ThreeDotMenu( onDismissRequest = { expanded = false }, offset = DpOffset(24.dp, 0.dp) ) { + @Requirement( + "O.Tokn_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "A logout button is available within each user profile." + ) DropdownMenuItem( modifier = Modifier.testTag( if (selectedProfile.ssoTokenScope != null) { @@ -409,6 +419,11 @@ fun SecuritySection( sourceSpecification = "gemSpec_eRp_FdV", rationale = "Button to display audit events for profile." ) +@Requirement( + "O.Auth_5#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Button to display audit events for profile." +) @Composable fun SecurityAuditEventsSubSection(onClickAuditEvents: () -> Unit) { Row( @@ -605,7 +620,7 @@ fun ProfileEditBasicTextField( BasicTextField( value = profileNameState, onValueChange = { - val name = sanitizeProfileName(it.text.trimStart()) + val name = it.text.trimStart().sanitizeProfileName() profileNameState = TextFieldValue( text = name, selection = it.selection, @@ -625,7 +640,7 @@ fun ProfileEditBasicTextField( cursorBrush = SolidColor(color), keyboardOptions = KeyboardOptions( autoCorrect = false, - capitalization = KeyboardCapitalization.None, + capitalization = KeyboardCapitalization.Sentences, imeAction = ImeAction.Done ), keyboardActions = KeyboardActions(onDone = { onDone() }) diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/PairedDevices.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/PairedDevices.kt index 7e9bde0b..807b9288 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/PairedDevices.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/PairedDevices.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt index c8ba7faa..88df4022 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColorAndImagePicker.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColors.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColors.kt index daf09bfa..0ba2e263 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColors.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileColors.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileController.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileController.kt index 6f33e2e1..98328398 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,14 +23,13 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember -import androidx.paging.PagingData +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.profiles.model.ProfilesData import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.usecase.ProfileAvatarUseCase import de.gematik.ti.erp.app.profiles.usecase.ProfilesUseCase import de.gematik.ti.erp.app.profiles.usecase.ProfilesWithPairedDevicesUseCase import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.protocol.model.AuditEventData import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import org.kodein.di.compose.rememberInstance @@ -57,6 +56,11 @@ class ProfilesController( fun decryptedAccessToken(profile: ProfilesUseCaseData.Profile) = profilesUseCase.decryptedAccessToken(profile.id) + @Requirement( + "O.Tokn_6#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "invalidate config and token " + ) suspend fun logout(profile: ProfilesUseCaseData.Profile) { profilesUseCase.logout(profile) } @@ -73,9 +77,6 @@ class ProfilesController( } } - fun loadAuditEventsForProfile(profileId: ProfileIdentifier): Flow> = - profilesUseCase.auditEvents(profileId) - override suspend fun switchActiveProfile(profile: ProfilesUseCaseData.Profile) { profilesUseCase.switchActiveProfile(profile) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt index bf068c7c..b5cd4a42 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileImageCropper.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileImageCropper.kt index eebf6dd0..dcdbff94 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileImageCropper.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileImageCropper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -54,6 +54,7 @@ import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.updateLayoutParams import com.canhub.cropper.CropImageView import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.NavigationTopAppBar @@ -79,7 +80,11 @@ fun ProfileImageCropper(onSaveCroppedImage: (Bitmap) -> Unit, onBack: () -> Unit val readStoragePermissionRequired = Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q - + @Requirement( + "O.Plat_3#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "platform dialog for READ_EXTERNAL_STORAGE" + ) LaunchedEffect(readStoragePermissionRequired, readStoragePermissionGranted) { if (readStoragePermissionRequired && !readStoragePermissionGranted) { readStoragePermissionLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE) diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileStringRessource.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileStringRessource.kt index b9f7a9c2..f4ec7802 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileStringRessource.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/ui/ProfileStringRessource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfileAvatarUsecase.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfileAvatarUsecase.kt index daadaf69..e4954b47 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfileAvatarUsecase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfileAvatarUsecase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCase.kt index cc245dd5..fd72eb50 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.profiles.usecase +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.db.entities.v1.InsuranceTypeV1 import de.gematik.ti.erp.app.idp.model.IdpData import de.gematik.ti.erp.app.idp.repository.IdpRepository @@ -25,7 +26,6 @@ import de.gematik.ti.erp.app.profiles.model.ProfilesData import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import de.gematik.ti.erp.app.profiles.repository.ProfilesRepository import de.gematik.ti.erp.app.profiles.usecase.model.ProfilesUseCaseData -import de.gematik.ti.erp.app.protocol.repository.AuditEventsRepository import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.flow.map @@ -37,8 +37,7 @@ fun List.activeProfile() = class ProfilesUseCase( private val profilesRepository: ProfilesRepository, - private val idpRepository: IdpRepository, - private val auditRepository: AuditEventsRepository + private val idpRepository: IdpRepository ) { val profiles: Flow> @@ -110,6 +109,11 @@ class ProfilesUseCase( profilesRepository.removeProfile(profile.id) } + @Requirement( + "O.Tokn_6#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "invalidate config and token" + ) suspend fun logout(profile: ProfilesUseCaseData.Profile) { idpRepository.invalidate(profile.id) } @@ -137,8 +141,6 @@ class ProfilesUseCase( profile.active } } - - fun auditEvents(profileId: ProfileIdentifier) = auditRepository.auditEvents(profileId) suspend fun switchProfileToPKV(profileId: ProfileIdentifier) { profilesRepository.switchProfileToPKV(profileId) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesWithPairedDevicesUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesWithPairedDevicesUseCase.kt index da46ba4e..c8845307 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesWithPairedDevicesUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesWithPairedDevicesUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/model/ProfilesUseCaseData.kt b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/model/ProfilesUseCaseData.kt index 47a3a0a1..6a00adaf 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/model/ProfilesUseCaseData.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/profiles/usecase/model/ProfilesUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/RedeemModule.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/RedeemModule.kt index c082e13d..e9bdb28f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/RedeemModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/RedeemModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/HowToRedeem.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/HowToRedeem.kt index d63fc459..04d14266 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/HowToRedeem.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/HowToRedeem.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemScreen.kt index 2cb86147..bd9b45a8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,16 +19,12 @@ package de.gematik.ti.erp.app.redeem.ui import android.annotation.SuppressLint -import android.graphics.Bitmap -import android.view.WindowManager import androidx.compose.foundation.background -import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer -import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBarsPadding @@ -37,15 +33,10 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material.Icon import androidx.compose.material.Scaffold import androidx.compose.material.Text import androidx.compose.material.TextButton -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.rounded.ZoomIn -import androidx.compose.material.icons.rounded.ZoomOut import androidx.compose.runtime.Composable -import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember @@ -54,35 +45,28 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip -import androidx.compose.ui.draw.drawWithCache -import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color -import androidx.compose.ui.graphics.asImageBitmap import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp import com.google.accompanist.pager.ExperimentalPagerApi import com.google.accompanist.pager.HorizontalPager import com.google.accompanist.pager.PagerState import com.google.accompanist.pager.rememberPagerState -import com.google.zxing.BarcodeFormat -import com.google.zxing.common.BitMatrix -import com.google.zxing.datamatrix.DataMatrixWriter import de.gematik.ti.erp.app.R import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.core.LocalActivity import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderState import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults +import de.gematik.ti.erp.app.utils.ForceBrightness import de.gematik.ti.erp.app.utils.compose.CommonAlertDialog +import de.gematik.ti.erp.app.utils.compose.DataMatrix import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.NavigationTopAppBar -import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.TertiaryButton +import de.gematik.ti.erp.app.utils.compose.createBitMatrix import kotlinx.coroutines.launch -import kotlin.math.max -import kotlin.math.roundToInt @Requirement( "A_20181", @@ -100,23 +84,12 @@ fun LocalRedeemScreen( val localRedeemState = rememberLocalRedeemState(orderState) val codes by localRedeemState.codes - var isZoomedOut by remember { mutableStateOf(true) } - if (codes.isEmpty()) { return } val activity = LocalActivity.current - DisposableEffect(Unit) { - activity.window?.attributes = activity.window?.attributes?.apply { - screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL - } - onDispose { - activity.window?.attributes = activity.window?.attributes?.apply { - screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE - } - } - } + activity.ForceBrightness() val redeemController = rememberRedeemController() var showRedeemScannedDialog by remember { mutableStateOf(false) } @@ -172,11 +145,7 @@ fun LocalRedeemScreen( modifier = Modifier .padding(PaddingDefaults.Medium) .fillMaxWidth(), - code = codes[page], - isZoomedOut = isZoomedOut, - onClickZoom = { - isZoomedOut = it - } + code = codes[page] ) } if (codes.size > 1 || (codes.size == 1 && codes.first().nrOfCodes > 1)) { @@ -209,65 +178,21 @@ fun LocalRedeemScreen( } } -@Requirement( - "A_19183#1", - sourceSpecification = "gemSpec_eRp_FdV", - rationale = "User displays a DMC to redeem a prescription in a pharmacy." -) @Composable -private fun DataMatrix( +fun DataMatrix( modifier: Modifier, - code: LocalRedeemState.DMCode, - isZoomedOut: Boolean, - onClickZoom: (Boolean) -> Unit + code: LocalRedeemState.DMCode ) { val matrix = remember(code) { createBitMatrix(code.payload) } - val shape = RoundedCornerShape(16.dp) - AppTheme(darkTheme = false) { - Column( - modifier = modifier - .background(AppTheme.colors.neutral000, shape) - .border(1.dp, AppTheme.colors.neutral300, shape) - .padding(PaddingDefaults.Medium) - ) { - @Suppress("MagicNumber") - Box( - modifier = Modifier - .scale(scale = if (isZoomedOut) 0.7f else 1f) - .drawDataMatrix(matrix) - .aspectRatio(1f) - .fillMaxWidth() - ) - SpacerMedium() - Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { - if (code.name != null) { - Text( - modifier = Modifier.weight(1f), - text = code.name, - style = AppTheme.typography.h6, - maxLines = 1, - overflow = TextOverflow.Ellipsis, - color = AppTheme.colors.neutral999 - ) - } else { - Spacer(Modifier.weight(1f)) - } - SpacerMedium() - TertiaryButton( - onClick = { onClickZoom(!isZoomedOut) } - ) { - if (isZoomedOut) { - Icon(Icons.Rounded.ZoomIn, null) - } else { - Icon(Icons.Rounded.ZoomOut, null) - } - } - } - } - } + DataMatrix(modifier, matrix, code.name) } +@Requirement( + "A_19183#1", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "User displays a DMC to redeem a prescription in a pharmacy." +) @OptIn(ExperimentalPagerApi::class) @Composable private fun PageIndicator( @@ -318,37 +243,3 @@ private fun RedeemScannedPrescriptionsDialog(onClickRedeem: () -> Unit, onCancel onCancel = onCancel, onClickAction = onClickRedeem ) - -private const val BitmapMinSize = 10 - -fun Modifier.drawDataMatrix(matrix: BitMatrix) = - drawWithCache { - val bmp = Bitmap.createScaledBitmap( - matrix.toBitmap(), - max(size.width.roundToInt(), BitmapMinSize), - max(size.height.roundToInt(), BitmapMinSize), - false - ) - - onDrawBehind { - drawImage(bmp.asImageBitmap()) - } - } - -fun createBitMatrix(data: String): BitMatrix = - // width & height is unused in the underlying implementation - DataMatrixWriter().encode(data, BarcodeFormat.DATA_MATRIX, 1, 1) - -fun BitMatrix.toBitmap(): Bitmap { - val bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) - for (x in 0 until width) { - for (y in 0 until height) { - bmp.setPixel( - x, - y, - if (get(x, y)) android.graphics.Color.BLACK else android.graphics.Color.WHITE - ) - } - } - return bmp -} diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemState.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemState.kt index dbf8901e..1b7a31a8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemState.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/LocalRedeemState.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -29,8 +29,7 @@ import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import de.gematik.ti.erp.app.pharmacy.ui.PharmacyOrderState import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData -import org.json.JSONArray -import org.json.JSONObject +import de.gematik.ti.erp.app.utils.createDMPayload @Stable class LocalRedeemState( @@ -79,7 +78,7 @@ class LocalRedeemState( .map { codes -> val prescriptions = codes.map { it.first } val urls = codes.map { it.second } - val json = createPayload(urls).toString().replace("\\", "") + val json = createDMPayload(urls) DMCode( payload = json, nrOfCodes = urls.size, @@ -88,16 +87,6 @@ class LocalRedeemState( ) } } - - private fun createPayload(data: List): JSONObject { - val rootObject = JSONObject() - val urls = JSONArray() - for (d in data) { - urls.put(d) - } - rootObject.put("urls", urls) - return rootObject - } } @Composable diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/Navigation.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/Navigation.kt index da00dac8..7935fa1f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/Navigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/OnlineRedeemScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/OnlineRedeemScreen.kt index 70f96b76..aa817db6 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/OnlineRedeemScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/OnlineRedeemScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/RedeemController.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/RedeemController.kt index 40b514d4..d0d68798 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/RedeemController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/RedeemController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt index 23d11c4d..1c26c9f3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/ui/model/RedeemNavigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/redeem/usecase/RedeemUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/redeem/usecase/RedeemUseCase.kt index 79947c17..e8ecab94 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/redeem/usecase/RedeemUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/redeem/usecase/RedeemUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/AuditEventsController.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/AuditEventsController.kt new file mode 100644 index 00000000..dca147f1 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/AuditEventsController.kt @@ -0,0 +1,153 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.settings + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.Stable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.setValue +import androidx.paging.PagingData +import de.gematik.ti.erp.app.cardwall.mini.ui.Authenticator +import de.gematik.ti.erp.app.core.LocalAuthenticator +import de.gematik.ti.erp.app.prescription.ui.GeneralErrorState +import de.gematik.ti.erp.app.prescription.ui.PrescriptionServiceState +import de.gematik.ti.erp.app.prescription.ui.catchAndTransformRemoteExceptions +import de.gematik.ti.erp.app.prescription.ui.retryWithAuthenticator +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import de.gematik.ti.erp.app.protocol.model.AuditEventData +import de.gematik.ti.erp.app.protocol.usecase.AuditEventsUseCase +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.cancellable +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.flow.flatMapLatest +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.shareIn +import org.kodein.di.compose.rememberInstance + +@Stable +class AuditEventsController( + private val auditEventsUseCase: AuditEventsUseCase, + private val authenticator: Authenticator, + coroutineScope: CoroutineScope +) { + + private val searchChannelFlow = MutableStateFlow("") + + var profileId by mutableStateOf("") + private set + + @Stable + sealed interface State : PrescriptionServiceState { + @Stable + object Loading : State + + @Stable + data class AuditEvents(val auditEvents: List) : State + } + + private var isLoading by mutableStateOf(false) + + suspend fun refresh( + profileId: ProfileIdentifier, + isUserAction: Boolean, + onUserNotAuthenticated: () -> Unit, + onShowCardWall: () -> Unit + ) { + val finalState = refreshFlow( + profileId = profileId, + isUserAction = isUserAction + ).cancellable().first() + + when (finalState) { + GeneralErrorState.NoneEnrolled -> { + onShowCardWall() + } + GeneralErrorState.UserNotAuthenticated -> { + onUserNotAuthenticated() + } + else -> { + } + } + } + + @OptIn(ExperimentalCoroutinesApi::class) + val auditEventPagingFlow: Flow> = + searchChannelFlow + .filterNotNull() + .onEach { + profileId = it + } + .flatMapLatest { searchData -> + isLoading = true + + auditEventsUseCase.loadAuditEventsPaged(searchData) + .onEach { + isLoading = false + } + .flowOn(Dispatchers.IO) + .shareIn( + coroutineScope, + SharingStarted.WhileSubscribed(), + 1 + ) + } + + private fun refreshFlow( + profileId: ProfileIdentifier, + isUserAction: Boolean + ): Flow = + flow { + searchChannelFlow.emit(profileId) + emit(State.Loading) + val auditEvents = auditEventsUseCase.loadAuditEvents(profileId) + emit(State.AuditEvents(auditEvents)) + } + .retryWithAuthenticator( + isUserAction = isUserAction, + authenticate = authenticator.authenticateForPrescriptions(profileId) + ) + .catchAndTransformRemoteExceptions() + .flowOn(Dispatchers.IO) +} + +@Composable +fun rememberAuditEventsController(): AuditEventsController { + val auditEventsUseCase by rememberInstance() + val authenticator = LocalAuthenticator.current + val scope = rememberCoroutineScope() + + return remember { + AuditEventsController( + auditEventsUseCase = auditEventsUseCase, + authenticator = authenticator, + coroutineScope = scope + ) + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/SettingsModule.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/SettingsModule.kt index 7ec38a5e..89b70057 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/SettingsModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/SettingsModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/repository/CardWallRepository.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/repository/CardWallRepository.kt index 1ac3db10..76b2c21a 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/repository/CardWallRepository.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/repository/CardWallRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt index 7535ef8d..51e00d76 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AccessibilitySettingsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowAnalyticsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowAnalyticsScreen.kt index f82a0cf6..ecf62dfa 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowAnalyticsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowAnalyticsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -40,11 +40,10 @@ import de.gematik.ti.erp.app.onboarding.ui.OnboardingBottomBar import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold - import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.annotatedStringBold import de.gematik.ti.erp.app.utils.compose.annotatedStringResource -import de.gematik.ti.erp.app.utils.compose.createToastShort +import de.gematik.ti.erp.app.utils.compose.shortToast @Requirement( "A_19087", @@ -72,7 +71,7 @@ fun AllowAnalyticsScreen(onAllowAnalytics: (Boolean) -> Unit, onBack: () -> Unit topBarTitle = stringResource(R.string.settings_tracking_allow_title), onBack = { onAllowAnalytics(false) - createToastShort(context, disAllowToast) + context.shortToast(disAllowToast) onBack() }, listState = lazyListState, @@ -86,7 +85,7 @@ fun AllowAnalyticsScreen(onAllowAnalytics: (Boolean) -> Unit, onBack: () -> Unit buttonText = stringResource(R.string.settings_tracking_allow_button), onButtonClick = { onAllowAnalytics(true) - createToastShort(context, allowText) + context.shortToast(allowText) onBack() }, buttonEnabled = true, diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt index 8571a5a3..76e34fb5 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AllowBiometryScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AuditEventsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AuditEventsScreen.kt index 82504e10..0c96447b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AuditEventsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/AuditEventsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -16,14 +16,12 @@ * */ -import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding @@ -31,7 +29,9 @@ import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.material.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.remember +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.testTag @@ -40,134 +40,136 @@ import androidx.compose.ui.text.style.TextAlign import androidx.paging.compose.collectAsLazyPagingItems import androidx.paging.compose.itemsIndexed import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag +import de.gematik.ti.erp.app.mainscreen.ui.RefreshScaffold +import de.gematik.ti.erp.app.mainscreen.ui.rememberMainScreenController +import de.gematik.ti.erp.app.prescription.ui.rememberRefreshPrescriptionsController import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier -import de.gematik.ti.erp.app.profiles.ui.ProfilesController +import de.gematik.ti.erp.app.settings.AuditEventsController import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold +import de.gematik.ti.erp.app.utils.compose.ConnectBottomBar import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.phrasedDateString -import kotlinx.datetime.Instant +import kotlinx.coroutines.launch import kotlinx.datetime.TimeZone import kotlinx.datetime.toJavaLocalDateTime import kotlinx.datetime.toLocalDateTime -import java.time.LocalDateTime -@OptIn(ExperimentalFoundationApi::class) +@Requirement( + "O.Auth_5#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Screen displaying the audit events." +) @Composable fun AuditEventsScreen( profileId: ProfileIdentifier, - profilesController: ProfilesController, - lastAuthenticated: Instant?, + onShowCardWall: () -> Unit, + auditEventsController: AuditEventsController, tokenValid: Boolean, onBack: () -> Unit ) { val header = stringResource(R.string.autitEvents_headline) - val auditEventPagingFlow = remember(profileId) { profilesController.loadAuditEventsForProfile(profileId) } - val pagingItems = auditEventPagingFlow.collectAsLazyPagingItems() + val pagingItems = auditEventsController.auditEventPagingFlow.collectAsLazyPagingItems() + val listState = rememberLazyListState() + val mainScreenController = rememberMainScreenController() + val refreshPrescriptionsController = rememberRefreshPrescriptionsController(mainScreenController) + + val scope = rememberCoroutineScope() + + LaunchedEffect(Unit) { + auditEventsController.refresh(profileId, false, {}, {}) + } AnimatedElevationScaffold( modifier = Modifier.testTag(TestTag.Profile.AuditEvents.AuditEventsScreen), listState = listState, topBarTitle = header, onBack = onBack, + bottomBar = { + if (!tokenValid) { + ConnectBottomBar( + infoText = stringResource(R.string.audit_events_connect_info) + ) { + scope.launch { + refreshPrescriptionsController.refresh( + profileId = profileId, + isUserAction = true, + onUserNotAuthenticated = {}, + onShowCardWall = onShowCardWall + ) + } + } + } + }, navigationMode = NavigationBarMode.Back ) { innerPadding -> - val infoText = if (lastAuthenticated == null) { - stringResource(R.string.no_audit_events_not_authenticated_info) - } else { - stringResource(R.string.no_audit_events_empty_protocol_list_info) - } - - if (pagingItems.itemCount == 0) { - LazyColumn( - modifier = Modifier - .padding(PaddingDefaults.Medium) - .fillMaxSize(), - state = listState, - verticalArrangement = Arrangement.Center, - horizontalAlignment = Alignment.CenterHorizontally - ) { - item { - Text( - stringResource(R.string.no_audit_events_header), - modifier = Modifier.testTag(TestTag.Profile.AuditEvents.NoAuditEventHeader), - style = AppTheme.typography.subtitle1 - ) - SpacerSmall() - Text( - infoText, - style = AppTheme.typography.body2l, - modifier = Modifier.testTag(TestTag.Profile.AuditEvents.NoAuditEventInfo), - textAlign = TextAlign.Center - ) - } - } - } else { - LazyColumn( - modifier = Modifier.padding(innerPadding), - state = listState, - contentPadding = WindowInsets.navigationBars.only(WindowInsetsSides.Bottom).asPaddingValues() - ) { - if (!tokenValid) { + RefreshScaffold( + profileId = profileId, + onUserNotAuthenticated = {}, + mainScreenController = mainScreenController, + onShowCardWall = onShowCardWall + ) { + if (pagingItems.itemCount == 0) { + LazyColumn( + modifier = Modifier + .padding(innerPadding) + .fillMaxSize(), + verticalArrangement = Arrangement.Center, + state = listState + ) { item { Column( - modifier = Modifier - .padding( - top = PaddingDefaults.Medium, - bottom = PaddingDefaults.Small, - start = PaddingDefaults.Medium, - end = PaddingDefaults.Medium - ) - .fillMaxWidth(), + modifier = Modifier.padding(PaddingDefaults.Medium).fillMaxSize(), horizontalAlignment = Alignment.CenterHorizontally ) { - val lastAuthenticatedDate = remember { - lastAuthenticated?.toLocalDateTime(TimeZone.currentSystemDefault()) - ?.toJavaLocalDateTime() ?: LocalDateTime.MIN - } - Text( - stringResource( - id = R.string.audit_events_updated_at, - phrasedDateString(date = lastAuthenticatedDate) - ), - style = AppTheme.typography.caption1l, - textAlign = TextAlign.Center + stringResource(R.string.no_audit_events_header), + modifier = Modifier.testTag(TestTag.Profile.AuditEvents.NoAuditEventHeader), + style = AppTheme.typography.subtitle1 ) + if (tokenValid) { + SpacerSmall() + Text( + stringResource(R.string.no_audit_events_empty_protocol_list_info), + style = AppTheme.typography.body2l, + modifier = Modifier.testTag(TestTag.Profile.AuditEvents.NoAuditEventInfo), + textAlign = TextAlign.Center + ) + } } } } + } else { + LazyColumn( + modifier = Modifier.padding(innerPadding), + state = listState, + contentPadding = WindowInsets.navigationBars.only(WindowInsetsSides.Bottom).asPaddingValues() + ) { + itemsIndexed(pagingItems) { _, auditEvent -> + auditEvent?.let { + Column( + modifier = Modifier.padding(PaddingDefaults.Medium) + .testTag(TestTag.Profile.AuditEvents.AuditEvent) + ) { + Text(auditEvent.description, style = AppTheme.typography.body2) + + val timestamp = remember { + auditEvent.timestamp + .toLocalDateTime(TimeZone.currentSystemDefault()) + .toJavaLocalDateTime() + } - itemsIndexed(pagingItems) { _, auditEvent -> - auditEvent?.let { - Column( - modifier = Modifier.padding(PaddingDefaults.Medium) - .testTag(TestTag.Profile.AuditEvents.AuditEvent) - ) { - auditEvent.medicationText?.let { Text( - it, - style = AppTheme.typography.subtitle1 + phrasedDateString(date = timestamp), + style = AppTheme.typography.body2l ) } - - Text(auditEvent.description, style = AppTheme.typography.body2) - - val timestamp = remember { - auditEvent.timestamp - .toLocalDateTime(TimeZone.currentSystemDefault()) - .toJavaLocalDateTime() - } - - Text( - phrasedDateString(date = timestamp), - style = AppTheme.typography.body2l - ) } } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt index df480305..c57bcb19 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/DeviceSecuritySettingsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -48,6 +48,7 @@ import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults @@ -112,6 +113,11 @@ fun DeviceSecuritySettingsScreen( } } item { + @Requirement( + "O.Pass_3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The user may change the app passwords within the settings." + ) AuthenticationModeCard( Icons.Outlined.Security, checked = authenticationModeState.authenticationMode is SettingsData.AuthenticationMode.Password, diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt index 42733537..a6b3070c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PasswordScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -79,6 +79,7 @@ import androidx.compose.ui.unit.dp import androidx.navigation.NavController import com.nulabinc.zxcvbn.Zxcvbn import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold @@ -190,6 +191,13 @@ fun SecureAppWithPassword(navController: NavController, settingsController: Sett } } +@Requirement( + "O.Data_10#1", + "O.Data_11#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Password field using the keyboard type password. Copying the content is not possible " + + "with this type. Autocorrect is disallowed. It`s not possible to disable third party keyboards." +) @OptIn(ExperimentalComposeUiApi::class) @Composable fun PasswordTextField( @@ -244,7 +252,7 @@ fun PasswordTextField( } }, singleLine = true, - keyboardOptions = KeyboardOptions(autoCorrect = true, keyboardType = KeyboardType.Password), + keyboardOptions = KeyboardOptions(autoCorrect = false, keyboardType = KeyboardType.Password), keyboardActions = KeyboardActions { onSubmit() }, @@ -337,7 +345,14 @@ fun ConfirmationPasswordTextField( } // tag::PasswordStrength[] - +@Requirement( + "O.Pass_1", + "O.Pass_2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "To determine the strength of the password, we use Zxcvbn. " + + "The strength of the password is shown with bars and colors. " + + "The minimum acceptable value of the score must be > 2." +) @Composable fun PasswordStrength( modifier: Modifier, diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PharmacyLicenseScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PharmacyLicenseScreen.kt index 74c73ec2..c5f901b8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PharmacyLicenseScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/PharmacyLicenseScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt index 658089b1..72f56290 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/ProductImprovementSettingsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -130,6 +130,17 @@ private fun SurveySection() { sourceSpecification = "gemSpec_eRp_FdV", rationale = "User can opt-in and opt-out of analytics" ) +@Requirement( + "O.Purp_5#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Toggle within Settings to enable and disable usage analytics." +) +@Requirement( + "O.Purp_6#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Current Analytics state is inspectable by the user, as most of the user deciscions are client side " + + "no history is available. Only the current state can be inspected." +) @Composable private fun AnalyticsSection( analyticsAllowed: Boolean, diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsController.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsController.kt index 69516296..27adbb96 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -24,6 +24,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.Immutable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.remember +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.analytics.Analytics import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase @@ -95,10 +96,20 @@ class SettingsController( settingsUseCase.saveZoomPreference(false) } + @Requirement( + "O.Purp_5#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Enable usage analytics." + ) fun onTrackingAllowed() { analytics.allowAnalytics() } + @Requirement( + "O.Purp_5#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Disable usage analytics." + ) fun onTrackingDisallowed() { analytics.disallowAnalytics() } diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt index 8a5ac475..df065ed8 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsNavigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -28,12 +28,13 @@ import androidx.navigation.NavHostController import androidx.navigation.compose.NavHost import androidx.navigation.compose.composable import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.Route import de.gematik.ti.erp.app.mainscreen.ui.MainNavigationScreens import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.utils.compose.NavigationAnimation import de.gematik.ti.erp.app.utils.compose.NavigationMode -import de.gematik.ti.erp.app.utils.compose.createToastShort +import de.gematik.ti.erp.app.utils.compose.shortToast import kotlinx.coroutines.launch object SettingsNavigationScreens { @@ -76,9 +77,21 @@ fun SettingsNavGraph( ProductImprovementSettingsScreen( settingsController = settingsController, onAllowAnalytics = { + @Requirement( + "O.Purp_5#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The agreement to the use of the analytics framework could be revoked. " + + "But other agreements cannot be revoked, since the app could not operate properly." + ) + @Requirement( + "A_19982", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "The agreement to the use of the analytics framework could be revoked. " + + "But other agreements cannot be revoked, since the app could not operate properly." + ) if (!it) { settingsController.onTrackingDisallowed() - createToastShort(context, disAllowAnalyticsToast) + context.shortToast(disAllowAnalyticsToast) } else { mainNavController.navigate(MainNavigationScreens.AllowAnalytics.path()) } diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt index 24e19a6b..7d64624d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/SettingsScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -87,6 +87,7 @@ import androidx.navigation.compose.rememberNavController import de.gematik.ti.erp.app.BuildConfig import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.analytics.TrackNavigationChanges import de.gematik.ti.erp.app.card.model.command.UnlockMethod @@ -101,10 +102,10 @@ import de.gematik.ti.erp.app.theme.AppTheme import de.gematik.ti.erp.app.theme.PaddingDefaults import de.gematik.ti.erp.app.utils.compose.AlertDialog import de.gematik.ti.erp.app.utils.compose.OutlinedDebugButton -import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.SpacerLarge import de.gematik.ti.erp.app.utils.compose.SpacerMedium import de.gematik.ti.erp.app.utils.compose.SpacerSmall +import de.gematik.ti.erp.app.utils.compose.SpacerTiny import de.gematik.ti.erp.app.utils.compose.handleIntent import de.gematik.ti.erp.app.utils.compose.navigationModeState import de.gematik.ti.erp.app.utils.compose.provideEmailIntent @@ -151,6 +152,14 @@ fun SettingsScreenWithScaffold( contentPadding = contentPadding, state = listState ) { + @Requirement( + "O.Source_8", + "O.Source_9", + "O.Source_11", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Debug options are not accessible in the production version." + + "All other debug mechanisms, including loogging, are disabled in the build pipeline." + ) if (BuildKonfig.INTERNAL) { item { DebugMenuSection(mainNavController) @@ -363,11 +372,10 @@ fun ProfileNameDialog( value = textValue, singleLine = true, onValueChange = { - val name = sanitizeProfileName(it.trimStart()) - textValue = name - duplicated = textValue.trim() != initialProfileName && - profilesState.containsProfileWithName(textValue) && - !wantRemoveLastProfile + val isExistingProfileName = profilesState.containsProfileWithName(textValue) + val isNotInitialProfileName = textValue.trim() != initialProfileName + textValue = it.trimStart().sanitizeProfileName() + duplicated = isNotInitialProfileName && isExistingProfileName && !wantRemoveLastProfile }, keyboardOptions = KeyboardOptions( autoCorrect = true, @@ -502,6 +510,11 @@ private fun LegalSection(navController: NavController) { ) { navController.navigate(MainNavigationScreens.Imprint.route) } + @Requirement( + "O.Arch_9", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Display data protection within settings" + ) LabelButton( Icons.Outlined.PrivacyTip, stringResource(R.string.settings_legal_dataprotection), diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/TokenScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/TokenScreen.kt index 5c5c7d0c..0278b892 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/ui/TokenScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/ui/TokenScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -47,6 +47,7 @@ import androidx.compose.ui.semantics.semantics import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.TestTag import de.gematik.ti.erp.app.TestTag.Profile.TokenList.AccessToken import de.gematik.ti.erp.app.TestTag.Profile.TokenList.NoTokenHeader @@ -58,7 +59,16 @@ import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.NavigationBarMode import de.gematik.ti.erp.app.utils.compose.SpacerSmall import de.gematik.ti.erp.app.utils.compose.visualTestTag - +@Requirement( + "O.Purp_9#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Access and SSO Token display relates to O.Tokn_5" +) +@Requirement( + "O.Tokn_5#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Access and SSO Token display" +) @Composable fun TokenScreen(onBack: () -> Unit, ssoToken: String?, accessToken: String?) { val header = stringResource(id = R.string.token_headline) diff --git a/android/src/main/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt index d0e9eae3..add03031 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -21,6 +21,7 @@ package de.gematik.ti.erp.app.settings.usecase import android.app.KeyguardManager import android.content.Context import de.gematik.ti.erp.app.BuildKonfig +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.profiles.usecase.sanitizedProfileName import de.gematik.ti.erp.app.settings.GeneralSettings import de.gematik.ti.erp.app.settings.PharmacySettings @@ -45,6 +46,11 @@ class SettingsUseCase( PharmacySettings by settingsRepository { // tag::ShowInsecureDevicePrompt[] + @Requirement( + "O.Plat_1#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Check for insecure Devices." + ) val showInsecureDevicePrompt = settingsRepository.general.map { val deviceSecured = diff --git a/android/src/main/java/de/gematik/ti/erp/app/theme/Color.kt b/android/src/main/java/de/gematik/ti/erp/app/theme/Color.kt index 1e4db71f..d45ede86 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/theme/Color.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/theme/Color.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/theme/Shape.kt b/android/src/main/java/de/gematik/ti/erp/app/theme/Shape.kt index a62bb189..5dcccc8b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/theme/Shape.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/theme/Shape.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/theme/Theme.kt b/android/src/main/java/de/gematik/ti/erp/app/theme/Theme.kt index 5da565fb..0fce01c3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/theme/Theme.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/theme/Theme.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/theme/Type.kt b/android/src/main/java/de/gematik/ti/erp/app/theme/Type.kt index 37af313f..a0aebe4d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/theme/Type.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/theme/Type.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/troubleShooting/TroubleshootingContent.kt b/android/src/main/java/de/gematik/ti/erp/app/troubleShooting/TroubleshootingContent.kt index be1e0308..73aac863 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/troubleShooting/TroubleshootingContent.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/troubleShooting/TroubleshootingContent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt index 30e31238..ced98b06 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/AuthenticationUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -26,6 +26,7 @@ import androidx.lifecycle.Lifecycle.Event.ON_STOP import androidx.lifecycle.LifecycleEventObserver import androidx.lifecycle.LifecycleOwner import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.settings.model.SettingsData import de.gematik.ti.erp.app.settings.model.SettingsData.AuthenticationMode.Password import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase @@ -63,6 +64,11 @@ private val PauseTimeout = Duration.ofSeconds(30) private const val ResetTimeout = -1L // tag::AuthenticationUseCase[] +@Requirement( + "O.Auth_8", + sourceSpecification = "BSI-eRp-ePA", + rationale = "A Timer is used to measure the time a user is inactive. Every user interaction resets the timer." +) class AuthenticationUseCase( private val settingsUseCase: SettingsUseCase, dispatchers: DispatchProvider @@ -190,6 +196,14 @@ class AuthenticationUseCase( suspend fun resetNumberOfAuthenticationFailures() = settingsUseCase.resetNumberOfAuthenticationFailures() + @Requirement( + "O.Auth_7", + "O.Plat_12", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The LifeCicleState of the app is monitored. If the app stopped, the authentication " + + "process starts after a delay of 30 seconds. We opted for this delay for usability reasons, " + + "as selecting the profile picture and external authentication requires pausing the app." + ) override fun onStateChanged(source: LifecycleOwner, event: Event) { Napier.d { "Authentication lifecycle event state: $event" } when (event) { diff --git a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt index 4ce9b857..6a81e642 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/BiometricPrompt.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -28,7 +28,7 @@ import androidx.core.content.ContextCompat import androidx.fragment.app.FragmentActivity import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.core.LocalActivity -import de.gematik.ti.erp.app.utils.compose.createToastShort +import de.gematik.ti.erp.app.utils.compose.shortToast // tag::BiometricPromptAndBestSecureOption[] @@ -76,7 +76,7 @@ fun BiometricPrompt( ) { onCancel() } else { - createToastShort(context, errString.toString()) + context.shortToast(errString.toString()) onAuthenticationError() } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt index a8c824b6..d173e4fc 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationController.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt index b2b8047d..3cc86fe6 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/userauthentication/ui/UserAuthenticationScreenComponents.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/Brightness.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/Brightness.kt new file mode 100644 index 00000000..8c0eb931 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/Brightness.kt @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils + +import android.view.WindowManager +import androidx.activity.ComponentActivity +import androidx.compose.runtime.Composable +import androidx.compose.runtime.DisposableEffect + +@Composable +fun ComponentActivity.ForceBrightness() { + DisposableEffect(Unit) { + val attributes = window?.attributes + val originalBrightness = attributes?.screenBrightness + window?.attributes = window?.attributes?.apply { + screenBrightness = WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_FULL + } + onDispose { + window?.attributes = window?.attributes?.apply { + screenBrightness = originalBrightness ?: WindowManager.LayoutParams.BRIGHTNESS_OVERRIDE_NONE + } + } + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/DateTime.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/DateTime.kt index 0baaafec..7f290481 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/DateTime.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/DateTime.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,7 +19,6 @@ package de.gematik.ti.erp.app.utils import android.os.Build -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.toJavaYear import de.gematik.ti.erp.app.fhir.parser.toJavaYearMonth import kotlinx.datetime.Instant @@ -28,11 +27,6 @@ import kotlinx.datetime.toJavaLocalDate import kotlinx.datetime.toJavaLocalDateTime import kotlinx.datetime.toJavaLocalTime import kotlinx.datetime.toLocalDateTime -import java.time.LocalDate -import java.time.LocalDateTime -import java.time.LocalTime -import java.time.Year -import java.time.YearMonth import java.time.format.DateTimeFormatter import java.time.format.FormatStyle diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/TextUtil.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/TextUtil.kt index f2d5ee08..c4460c84 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/TextUtil.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/TextUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -25,8 +25,11 @@ private fun Int.isEmoticon() = this in 0x1F600..0xE007F private val r = """[\p{L}\p{M}\p{N}\u200d -]""".toRegex() -fun sanitizeProfileName(name: String): String = - name.codePoints() +/** + * Take the String and map the characters that are characters or emoticon and return the string back + */ +fun String.sanitizeProfileName() = + codePoints() .asSequence() .mapNotNull { letter -> val s = Character.toChars(letter).concatToString() @@ -37,4 +40,3 @@ fun sanitizeProfileName(name: String): String = } } .joinToString("") - .replaceFirstChar { it.uppercase() } diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/AnimatedElevationScaffold.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/AnimatedElevationScaffold.kt index 77e8f6b7..4279eb4b 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/AnimatedElevationScaffold.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/AnimatedElevationScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Animations.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Animations.kt index 54d8e925..14761d96 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Animations.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Animations.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomBars.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomBars.kt new file mode 100644 index 00000000..e41fe8d0 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomBars.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material.Button +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import de.gematik.ti.erp.app.R +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults + +@Composable +fun ConnectBottomBar(infoText: String, onClickConnect: () -> Unit) { + Column( + modifier = Modifier + .fillMaxWidth() + .background( + color = AppTheme.colors.primary100 + ) + ) { + Row( + modifier = Modifier + .fillMaxWidth() + .padding( + start = PaddingDefaults.Medium, + end = PaddingDefaults.Medium, + top = PaddingDefaults.Medium, + bottom = PaddingDefaults.Large + ), + horizontalArrangement = Arrangement.SpaceBetween, + verticalAlignment = Alignment.CenterVertically + ) { + Text( + text = infoText, + modifier = Modifier + .weight(1f).padding(end = PaddingDefaults.Large), + style = AppTheme.typography.body2 + ) + Button( + onClick = onClickConnect + ) { + Text(text = stringResource(R.string.invoices_connect_btn)) + } + } + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheet.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheet.kt index 43b38cef..019217ce 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheet.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheet.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheetAction.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheetAction.kt index 81494e82..7f9c4dca 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheetAction.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/BottomSheetAction.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Buttons.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Buttons.kt index 4fee5945..3e5dd3eb 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Buttons.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Buttons.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Chip.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Chip.kt index 8dde4160..cc4d5dbf 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Chip.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Chip.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Common.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Common.kt index bdcfd9a5..01bf3102 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Common.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Common.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -554,17 +554,22 @@ fun AcceptDialog( @Composable fun AcceptDialog( + modifier: Modifier = Modifier.testTag(TestTag.AlertDialog.Modal), header: String, info: String, acceptText: String, onClickAccept: () -> Unit ) = AlertDialog( + modifier = modifier, title = { Text(header) }, onDismissRequest = {}, text = { Text(info) }, buttons = { - TextButton(onClick = onClickAccept) { + TextButton( + modifier = Modifier.testTag(TestTag.AlertDialog.ConfirmButton), + onClick = onClickAccept + ) { Text(acceptText) } }, diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposableEvent.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposableEvent.kt new file mode 100644 index 00000000..ba62c481 --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposableEvent.kt @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import android.annotation.SuppressLint +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import kotlinx.coroutines.CoroutineScope + +class ComposableEvent { + + private var trigger by mutableStateOf(false) + + var payload: T? by mutableStateOf(null) + + fun trigger(payload: T) { + this.payload = payload + trigger = true + } + + @Composable + @SuppressLint("ComposableNaming") + fun listen( + block: suspend CoroutineScope.(payload: T) -> Unit + ) { + LaunchedEffect(trigger) { + if (trigger) { + trigger = false + + // Has to be set via trigger as `T` + @Suppress("UNCHECKED_CAST") + block(payload as T) + } + } + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposeToastShort.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposeToastShort.kt new file mode 100644 index 00000000..e4775b8b --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/ComposeToastShort.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import android.annotation.SuppressLint +import android.content.Context +import android.widget.Toast +import androidx.compose.foundation.layout.Box +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext +import androidx.compose.ui.platform.testTag +import de.gematik.ti.erp.app.TestTag.PharmacySearch.OrderOptions.ComposeToast + +@SuppressLint("ComposableNaming") +@Composable +fun shortToast(text: String) { + val context = LocalContext.current + Box(Modifier.testTag(ComposeToast)) { + context.shortToast(text) + } +} + +fun Context.shortToast(text: String) = + Toast.makeText(this, text, Toast.LENGTH_SHORT).show() diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/DMCode.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/DMCode.kt new file mode 100644 index 00000000..f0a2e92e --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/DMCode.kt @@ -0,0 +1,145 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import android.graphics.Bitmap +import androidx.compose.foundation.background +import androidx.compose.foundation.border +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.aspectRatio +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon +import androidx.compose.material.Text +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.rounded.ZoomIn +import androidx.compose.material.icons.rounded.ZoomOut +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.setValue +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.drawWithCache +import androidx.compose.ui.draw.scale +import androidx.compose.ui.graphics.asImageBitmap +import androidx.compose.ui.text.style.TextOverflow +import androidx.compose.ui.unit.dp +import com.google.zxing.BarcodeFormat +import com.google.zxing.common.BitMatrix +import com.google.zxing.datamatrix.DataMatrixWriter +import de.gematik.ti.erp.app.theme.AppTheme +import de.gematik.ti.erp.app.theme.PaddingDefaults +import kotlin.math.max +import kotlin.math.roundToInt + +private const val BitmapMinSize = 10 +private const val ScaleOutValue = 0.7f +private const val ScaleInValue = 1f + +@Composable +fun DataMatrix( + modifier: Modifier, + matrix: BitMatrix, + codeName: String? = null +) { + var isZoomedOut by remember { mutableStateOf(false) } + + AppTheme(darkTheme = false) { + val shape = RoundedCornerShape(16.dp) + + Column( + modifier = modifier + .background(AppTheme.colors.neutral000, shape) + .border(1.dp, AppTheme.colors.neutral300, shape) + .padding(PaddingDefaults.Medium) + ) { + ( + Box( + modifier = Modifier + .scale(scale = if (isZoomedOut) ScaleOutValue else ScaleInValue) + .drawDataMatrix(matrix) + .aspectRatio(1f) + .fillMaxWidth() + ) + ) + SpacerMedium() + Row(Modifier.fillMaxWidth(), verticalAlignment = Alignment.CenterVertically) { + if (codeName != null) { + Text( + modifier = Modifier.weight(1f), + text = codeName, + style = AppTheme.typography.h6, + maxLines = 1, + overflow = TextOverflow.Ellipsis, + color = AppTheme.colors.neutral999 + ) + } else { + Spacer(Modifier.weight(1f)) + } + SpacerMedium() + TertiaryButton( + onClick = { isZoomedOut = !isZoomedOut } + ) { + when { + isZoomedOut -> Icon(Icons.Rounded.ZoomIn, null) + else -> Icon(Icons.Rounded.ZoomOut, null) + } + } + } + } + } +} + +fun Modifier.drawDataMatrix(matrix: BitMatrix) = + drawWithCache { + val bitmap = Bitmap.createScaledBitmap( + matrix.toBitmap(), + max(size.width.roundToInt(), BitmapMinSize), + max(size.height.roundToInt(), BitmapMinSize), + false + ) + + onDrawBehind { + drawImage(bitmap.asImageBitmap()) + } + } + +fun createBitMatrix(data: String): BitMatrix = + // width & height is unused in the underlying implementation + DataMatrixWriter().encode(data, BarcodeFormat.DATA_MATRIX, 1, 1) + +fun BitMatrix.toBitmap(): Bitmap { + val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565) + for (x in 0 until width) { + for (y in 0 until height) { + bitmap.setPixel( + x, + y, + if (get(x, y)) android.graphics.Color.BLACK else android.graphics.Color.WHITE + ) + } + } + return bitmap +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Dialog.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Dialog.kt index dda60e6d..bfbe63a1 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Dialog.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Dialog.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Hints.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Hints.kt index dc7993d6..64356973 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Hints.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Hints.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -454,7 +454,7 @@ fun HintCardWithActionButton() { } } -@Preview +@LightDarkPreview @Composable fun HintCardWithTextActionButton() { AppTheme { @@ -469,7 +469,7 @@ fun HintCardWithTextActionButton() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithActionButtonAndLargeImage() { AppTheme { @@ -485,7 +485,7 @@ fun ClosableHintCardWithActionButtonAndLargeImage() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithTextActionButtonAndLargeImage() { AppTheme { @@ -501,7 +501,7 @@ fun ClosableHintCardWithTextActionButtonAndLargeImage() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithActionButton() { AppTheme { @@ -517,7 +517,7 @@ fun ClosableHintCardWithActionButton() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithTextActionButton() { AppTheme { @@ -533,7 +533,7 @@ fun ClosableHintCardWithTextActionButton() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithActionButtonAndColors() { AppTheme { @@ -560,7 +560,7 @@ fun ClosableHintCardWithActionButtonAndColors() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithActionButtonAndColorsAndShortTitle() { AppTheme { @@ -587,7 +587,7 @@ fun ClosableHintCardWithActionButtonAndColorsAndShortTitle() { } } -@Preview +@LightDarkPreview @Composable fun HintCardWithNoTitle() { AppTheme { @@ -611,7 +611,7 @@ fun HintCardWithNoTitle() { } } -@Preview +@LightDarkPreview @Composable fun ClosableHintCardWithNoTitle() { AppTheme { @@ -641,8 +641,7 @@ fun ClosableHintCardWithNoTitle() { } } -@OptIn(ExperimentalAnimationApi::class) -@Preview +@LightDarkPreview @Composable fun AnimatedHintCardPreview() { AppTheme { diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/InsetAwareBars.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/InsetAwareBars.kt index 3c9ad874..c26bc658 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/InsetAwareBars.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/InsetAwareBars.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/AuditEvent.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/LightDarkPreview.kt similarity index 61% rename from common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/AuditEvent.kt rename to android/src/main/java/de/gematik/ti/erp/app/utils/compose/LightDarkPreview.kt index e011381d..5a0cbe61 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/AuditEvent.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/LightDarkPreview.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -16,16 +16,17 @@ * */ -package de.gematik.ti.erp.app.db.entities.v1 +package de.gematik.ti.erp.app.utils.compose -import io.realm.kotlin.types.RealmInstant -import io.realm.kotlin.types.RealmObject +import android.content.res.Configuration +import androidx.compose.ui.tooling.preview.Preview -class AuditEventEntityV1 : RealmObject { - var id: String = "" - var taskId: String? = null - var text: String = "" - var timestamp: RealmInstant = RealmInstant.MIN +@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +internal annotation class LightPreview - var profile: ProfileEntityV1? = null -} +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) +internal annotation class DarkPreview + +@LightPreview +@DarkPreview +internal annotation class LightDarkPreview diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Spacer.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Spacer.kt index a775f03e..85e4fb13 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Spacer.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Spacer.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/TimeDescription.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/TimeDescription.kt index 4009df23..e748dba4 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/TimeDescription.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/TimeDescription.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Title.kt b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Title.kt new file mode 100644 index 00000000..ac69503d --- /dev/null +++ b/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Title.kt @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils.compose + +import androidx.compose.material.Text +import androidx.compose.runtime.Composable +import de.gematik.ti.erp.app.theme.AppTheme + +@Composable +internal fun Title( + text: String +) { + Text( + text = text, + style = AppTheme.typography.h6 + ) +} + +@LightDarkPreview +@Composable +internal fun TitlePreview() { + AppTheme { + Title(text = "Title text") + } +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/vau/VauModule.kt b/android/src/main/java/de/gematik/ti/erp/app/vau/VauModule.kt index e35659ac..38bea7b3 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/vau/VauModule.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/vau/VauModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt b/android/src/main/java/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt index 30e3cc03..be23fe39 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/webview/WebViewScreen.kt b/android/src/main/java/de/gematik/ti/erp/app/webview/WebViewScreen.kt index 7c1a7642..5f1898cf 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/webview/WebViewScreen.kt +++ b/android/src/main/java/de/gematik/ti/erp/app/webview/WebViewScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -46,12 +46,20 @@ import androidx.compose.ui.unit.TextUnitType import androidx.compose.ui.viewinterop.AndroidView import androidx.core.view.updateLayoutParams import androidx.webkit.WebViewAssetLoader +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.utils.compose.AnimatedElevationScaffold import de.gematik.ti.erp.app.utils.compose.NavigationBarMode const val URI_TERMS_OF_USE = "file:///android_asset/terms_of_use.html" const val URI_DATA_TERMS = "file:///android_asset/data_terms.html" +@Requirement( + "O.Arch_8#1", + "O.Plat_11#1", + "O.Plat_14", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Webview containing local html without javascript. No cookies are created." +) @Composable fun WebViewScreen( modifier: Modifier = Modifier, @@ -192,6 +200,11 @@ fun createWebViewClient(colors: Colors, typo: Typography) = object : WebViewClie return cssLoader.shouldInterceptRequest(request.url) } + @Requirement( + "O.Plat_13", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Disables unused schemes" + ) override fun shouldOverrideUrlLoading(view: WebView, request: WebResourceRequest): Boolean { val isAllowedScheme = request.url.scheme == "https" || request.url.scheme == "mailto" return if (isAllowedScheme && request.url.host != "localhost") { diff --git a/android/src/main/res/values-ar/strings.xml b/android/src/main/res/values-ar/strings.xml index 06c92e02..bf0163a7 100644 --- a/android/src/main/res/values-ar/strings.xml +++ b/android/src/main/res/values-ar/strings.xml @@ -1,6 +1,5 @@ - الوصفة الإلكترونية موافق إلغاء تراجع @@ -181,22 +180,6 @@ لا يوجد مقر متاح مفهوم كلمة المرور المكرر مطابقة - - - يتبقى عدد %s يومًا للصرف كدافع ذاتي - - - - يتبقى عدد %sمن الأيام للصرف كدافع ذاتي - - - - سار لمدة %s يومًا - - - - سارٍ لمدة %s أيام - خطأ 20 10 76631 شهادة بطاقتك الصحية غير صالحة. هل ربما انتهت صلاحية بطاقتك؟ يُرجى الاتصال بشركة التأمين الصحي الخاصة بك. محاولات تسجيل دخول غير ناجحة @@ -296,9 +279,7 @@ المقصود به هو مفتاح دخول لخدمة الوصفات الطبية بروتوكول الدخول لا يوجد بروتوكول للدخول - تتلقى بروتوكل الدخول بعد التسجيل في خدمة الوصفات الطبية. لا يوجد بروتوكول للدخول بعد. - آخر تحديث في %s جاري معالجة الوصفة الطبية في الوقت الحالي ولا يمكن صرفها. الموافقة يبدو أن المحاولة فشلت @@ -366,7 +347,7 @@ تم استلام رمز PIN رمز PIN تحقق من الاتصال بالإنترنت وإعدادات الوقت / التاريخ لجهازك. - للمصادقة اضغط على \"إلغاء الحظر\". + لتسجيل الدخول، اضغط على \"فتح\". هل تم الإغلاق؟ يرجى التحقق من بيانات الدخول البيومترية الخاصة بك على هذا الجهاز. نسيت كلمة المرور؟ يرجى حذف التطبيق ثم إعادة تثبيته. يمكنك معرفة السبب في %s نطاق المساعدة @@ -380,7 +361,7 @@ الموافقة تراجع ملاحظة - هل تساعدنا في تحسين هذا التطبيق؟ + ساعدنا في جعل هذا التطبيق أفضل اختر كلمة مرور خاصة يجب أن تحتوي كلمة المرور على ثمانية حروف على الأقل قوة كلمة المرور غير كافية @@ -458,10 +439,7 @@ البطاقة الصحية اطلب رقم التعريف الشخصي أو البطاقة التسجيل - كيف ترغب في تسجيل نفسك؟ - APP من التأمين الصحي - بطاقة صحية - مطلوب رقم التعريف الشخصي المرتبط + كيف تريد تسجيل الدخول؟ بطاقة صحية مزودة بتقنية الإتصال اللاسلكية رقم التعريف الشخصي للبطاقة الصحية ليس لديك حتى الآن بطاقة صحية مزودة بتقنية الإتصال اللاسلكية ورقم تعريف شخصي؟ @@ -667,8 +645,7 @@ يجب على أولئك الذين لديهم تأمين صحي قانوني دفع مبلغ مشترك يصل إلى عشرة يورو للأدوية الموصوفة. \n\n يعتمد مبلغ الدفع المشترك على سعر الدواء الخاص بك. عليك أن تدفع ثمن الأدوية التي تقل تكلفتها عن 5 يورو بنفسك.\n بالنسبة للأدوية الأكثر تكلفة ، عليك أن تدفع عشرة بالمائة من السعر ، ولكن على الأقل 5 يورو و 10 يورو كحد أقصى. \n\n يُعفى الأطفال والشباب الذين تقل أعمارهم عن 18 عامًا بشكل عام من المشاركة في الدفع. \n\n إذا تجاوزت تكاليف الأدوية السنوية الخاصة بك الحد المالي الخاص بك ، فيمكن إعفائك من الدفع المشترك. تحدث إلى شركة التأمين الصحي الخاصة بك حول هذا الموضوع. أنت معفى من الدفع المشترك لهذا الدواء. سيغطي تأمينك الصحي تكلفة الدواء. ما هي مدة صلاحية هذه الوصفة؟ - خلال هذه الفترة ، يمكنك استبدال الوصفة الطبية الخاصة بك في أي صيدلية بدفع مبلغ إضافي. - خلال هذه الفترة ، لا يزال بإمكانك استرداد الوصفة الطبية في الصيدلية ، ولكن عليك دفع ثمن الشراء بنفسك. بدلاً من ذلك ، يمكنك أن تطلب من عيادتك إصدار الوصفة مرة أخرى. + خلال هذه الفترة، يمكنك استرداد الوصفة الطبية الخاصة بك في أي صيدلية بحد أقصى للدفع الإضافي قدره 10 يورو. يمكن تلقي مستحضرًا طبيًا بديلًا نظرًا للمتطلبات القانونية لشركة التأمين الصحي الخاصة بك ، يمكن أن تحصل على بديل يحتوي على نفس العنصر النشط. \n\n يمكن أن تبدو الأدوية وتسمى بشكل مختلف ، ولها أسعار ومصنعون مختلفون ، لكنها لا تزال تحتوي على نفس العنصر النشط. العنصر النشط نفسه والجرعة مهمان بشكل خاص لتأثير الأدوية في الجسم. غالبًا ما يحصل المرضى في الصيدلية على دواء مختلف عن الدواء الموصوف من قبل الطبيب في الوصفة الطبية - بشرط أن تكون الأدوية متشابهة. يمكن أن تكون هناك أسباب علاجية واقتصادية للتغيير. الوصفة الطبية التي تم مسحها @@ -739,11 +716,11 @@ لا توجد وصفات طبية أضف الوصفات الطبية باستخدام زر + في الزاوية اليمنى العليا. تسجيل الدخول - الوصفات الطبية المردودة + أرشيف الوصفات الطبية ربما لاحقا تسجيل الدخول تعديل الصورة الشخصية - الوصفات الطبية المردودة + أرشيف الوصفات الطبية أدخل الاسم حفظ طلبي @@ -765,7 +742,7 @@ بدون وصفة طبية ليس لديك حاليا أي وصفات طبية قابلة للاسترداد يلتقط - فتى التوصيل + ساعي إرسال اختر الوصفات الطبية انقر هنا لمسح الوصفات الطبية @@ -893,22 +870,15 @@ سيتم استبدالها لك تم استبدالها من أجلك يجب عليك تسجيل الدخول لاستخدام هذه الخدمة. - تم تحويل الوصفة (الوصفات) بنجاح. - لا يمكن معالجة الوصفة الطبية. حاول مرة اخرى. قد تضطر إلى اختيار صيدلية مختلفة. - لا يمكن معالجة الوصفة الطبية. أبلغت الصيدلية عن خطأ غير معروف. إذا لزم الأمر ، جرب صيدلية أخرى. - تم رفض الوصفة الطبية من قبل الصيدلية. ، أو قد يكون عنوان التسليم أو تفاصي ل الاتصال الخاصة بك غير صالحة. - غير قادر على الاسترداد ، يرجى التحقق من اتصالك بالإنترنت. - تم تحويل الوصفة بنجاح. ومع ذلك ، أبلغت الصيدلية عن خطأ في المعالجة. الرجاء الاتصال بالصيدلية. - تم رفض الوصفة الطبية من قبل الصيدلية. تم بالفعل استرداد الوصفة الطبية. - تم رفض الوصفة الطبية من قبل الصيدلية. تم حذف الوصفة. - لا يمكن نقل الوصفة. يرجى التحقق من اتصالك بالإنترنت وحاول مرة أخرى. - لا يمكن نقل وصفة واحدة أو أكثر. - أرسل بنجاح! - خطأ في الصيدلة - خطأ في الصيدلة - اتصل بالصيدلية - الوصفة الطبية استردت بالفعل - الوصفة محذوفة - لا انترنت - خطأ في الإرسال + APP من التأمين الصحي + بطاقة صحية + مطلوب رقم التعريف الشخصي المرتبط + لتلقي سجلات الوصول، يجب أن تكون متصلاً بالخادم. + لا يزال بإمكانك صرف الوصفة الطبية من الصيدلية خلال هذه الفترة، ولكن سيتعين عليك دفع سعر شراء الدواء بالكامل بنفسك. وبدلاً من ذلك، يمكنك أن تطلب من عيادتك إعادة إصدار الوصفة الطبية. + تم + طلب التصحيح + في الصيدلية + في التطبيق + قم بمسح هذا الرمز ضوئيًا في الصيدلية الخاصة بك. + طلب تصحيح الفواتير diff --git a/android/src/main/res/values-bg/strings.xml b/android/src/main/res/values-bg/strings.xml new file mode 100644 index 00000000..78c1b2e2 --- /dev/null +++ b/android/src/main/res/values-bg/strings.xml @@ -0,0 +1,852 @@ + + + Добре + Прекъсване + Връщане + наоколо + Дигитален. Бърз. Сигурно. + ID на задачата + код за достъп + Условия за ползване + Защита на данни + рецепти + Достъпът до камерата е отказан + За да използвате скенера, трябва да разрешите на приложението достъп до вашата камера в системните настройки. + Фокусирайте камерата върху код на рецепта + Това не е валиден код на рецепта + Този код на рецепта вече е сканиран + + %s рецепта е разпозната + %s разпознати рецепти + + Прекъсване + светлина на камерата + Да се отмени сканирането? + Добре + Не отменяй + Ето ни + От какво имаш нужда: + Въведете номера за достъп до картата + въведете ПИН кода + опитай пак + Неуспешно свързване със сървъра. + + Имате още %s опита, преди картата ви да бъде блокирана. + Имате още %s опита, преди картата ви да бъде блокирана. + + Ще намерите номера за достъп горе вдясно на вашата здравна карта. + Прекъсване + Търсене на карта... + Дръжте здравната карта на гърба на вашето устройство. + Все още се търси... + Бавно преместете картата в задната част на устройството. + Бакшиш + Калъфите на устройства може да затруднят свързването чрез NFC. + разпозната карта + Опитайте се да не местите здравната карта. + Намерена е здравна книжка. Моля те не мърдай. + връзката е изгубена + Задръжте отново здравната си карта на гърба на устройството + Версия: %s + Хеш компилация: %s + меню за отстраняване на грешки + Отворено до %s + Отворен през целия ден + отпечатък + редактор + gematik GmbH\n Фридрихщрасе 136\n 10117 Берлин + Управляващ директор: Dr. медицински Маркус Лейк-Дийкен\n Регистрационен съд: окръжен съд Берлин-Шарлотенбург\n Номер в търговския регистър: HRB 96351\n Идентификационен номер за данък върху продажбите: DE241843684 + Отговаря за съдържанието + д-р медицински Маркус Лейк-Дикен + Контакт + Забележете + Стремим се да използваме полово неутрален език. Ако забележите някакви грешки, очакваме с нетърпение да ни изпратите имейл. + Модерната германска платформа за цифрова медицина + пишете поща + отворен уебсайт + Добре дошли + Започнете регистрация + отключване + Регистрирам + Прекъсване + Сигурност + Законни + отпечатък + защита на данни + Условия за ползване + подробности + Маркирайте като изкупени + Маркирайте като неизкупени + доза от + размер на опаковката + Осигурено лице + Фамилия + адрес + рождена дата + Здравни осигуровки / Платци + състояние + осигурителен номер + Предписващо лице + Фамилия + Медицински специалист + Номер на лекар (LANR) + институция + Фамилия + адрес + Номер на бизнес помещение + телефонен номер + пощенски адрес + трудова злополука + ден на инцидента + Номер на компания или работодател при злополука + Искате ли да изтриете завинаги тази рецепта? + Гасете + Прекъсване + работно време + уебсайт + Може да се използва само днес като самоплащащ се + Регистрирам + Активирайте NFC + Моля, активирайте NFC функцията на вашето устройство, за да влезете със здравната си карта. + Активирате + Правилно + Изкупени рецепти? + Искате ли да маркирате рецептите като изкупени? + Не е изкупено + Изкупен + Отваря в %s + +49 800 277 377 7 + Техническа гореща линия + Отворете скенера за рецепти + Идеи + Потискане на екранни снимки + Предотвратява показването на миниатюра при превключване на приложения + Позволявате ли на електронната рецепта да анализира поведението ви при използване анонимно? + Техническа информация + Сигурност на вашите данни за рецепта + Моля, уверете се, че лицата, с които можете да споделяте това устройство и чиито биометрични характеристики може да се съхраняват на това устройство, също имат достъп до вашите рецепти. + изпращането е неуспешно + Няма настроена програма за електронна поща + Няма резултати + Не можахме да намерим резултати за тази дума за търсене. + Лицензи с отворен код + Контакт + Обадете се на гореща техническа линия + Участвайте в анкета + +49 800 277 377 7 + Искам да помогна да направим това приложение по-добро + Това включва информация за хардуера и софтуера на вашия телефон, настройки за приложението за електронна рецепта и количеството употреба, но никога никакви данни за вас или вашето здраве. + Данните се предоставят на gematik GmbH само от обработващия данни и се изтриват най-късно след 180 дни. Можете да деактивирате анализа отново по всяко време в менюто на приложението. + Тези данни ни позволяват да разберем кои функции се използват често и да ги подобрим. Освен това можем да преценим колко дълго трябва да се поддържа по-стара технология и кога можем например да направим по-нова версия на операционната система задължителна, без да засягаме (твърде много) потребители. + подобряване на приложението + Анонимният анализ остава деактивиран + %s Благодарим ви за подкрепата! + Регистрирам + Моля, идентифицирайте се, за да изтеглите рецепти. + Бележка за аптеките: Получаваме данните за контакт и информацията за аптеките от mein-apothekenportal.de на Германската фармацевтична асоциация. Открили ли сте грешка или искате да коригирате данните? + Научете повече + аптеки + За съжаление това не проработи \uD83D\uDE15 + Моля, опитайте отново. + Въведете паролата + По-нататък + Достъпност + увеличение + Позволява ви да увеличите приложението чрез прищипване или разтваряне на пръстите си (pinch-to-zoom). + парола + Защитете данните си с парола по ваш избор. + парола + Запазете на компютър + Покажи парола + Повтори паролата + Препоръки: %s + пишете поща + Когато изпратите вашето съобщение, ще бъде предадена следната информация за използвания хардуер и операционна система: + Осребряване само на място + Все още не можете да изпращате електронни рецепти до тази аптека. + В момента отворен + куриерска услуга + Пратка + филтър + Филтър + Няма налично местоположение + Разбрах + Повтарящи се пароли + Грешка 20 10 76631 + Вашата здравна карта е невалидна. Вашата карта изтекла ли е? Моля, свържете се с вашата здравна каса. + Неуспешни опити за влизане + + Открити са %s неуспешни опита за влизане. + Открити са %s неуспешни опита за влизане. + + Изберете най-доброто архивиране на устройството + Това може да бъде пръстов отпечатък, модел на плъзгане или подобен + токени + жетон за достъп + SSO токени + Няма наличен маркер за достъп + няма наличен SSO токен + копиран в клипборда + Щракнете, за да копирате токена в клипборда + Важи само днес + Позволява + няма връзка със сървъра + Моля опитайте отново след няколко минути + Заредете отново + покажи токени + Как искате да защитите приложението? + Забележете + За това устройство не е настроено резервно копие + Препоръчваме ви допълнително да защитите медицинските си данни със сигурност на устройството, като парола или биометрия. + Не показвайте това известие отново в бъдеще. + Свързването е неуспешно. Не може да се установи мрежова връзка. + Комуникацията със сървъра е неуспешна: код на състоянието %s . + Неуспешна комуникация със сървъра: Моля, проверете интернет връзката и настройките за час/дата. + внимание + Вашето устройство може да има намалена защита + Това може да бъде причинено например от манипулирани устройства или активиран режим за разработчици. От съображения за сигурност не препоръчваме да използвате приложението на джейлбрейкнати устройства. + Признавам повишения риск и все пак искам да продължа. + Защо устройствата с root достъп представляват потенциален риск за сигурността? + Научете повече + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Профилно име + Моля, въведете име за новия профил. + профилно име + профили + Как да разпознаете здравна карта с активиран NFC + Не е възможен контакт чрез това приложение + Моля, използвайте обичайните канали, за да се свържете с вашата застрахователна компания. + Здравна карта и ЕГН + само ПИН + Регистрация в приложението за електронна рецепта + Полето за име не може да бъде празно. + Вече съществува профил с въведеното име. + профил + %s избрано + Цвят на фона + пролетно сиво + съсънка + То! Е! Розово! + Дърво + Синя луна септември + Не сте влезли в системата + Завързани заедно + Последна връзка на %s + Изтриване на профил? + Това ще изтрие всички данни от профила на това устройство. Вашите рецепти в здравната мрежа ще останат непокътнати. + Гасете + Прекъсване + изтриване на профил + Искате да изтриете последния профил. + Приложението изисква поне един профил. Моля, въведете име за новия профил. + Грешка 20 10 76831 + Указателят със здравни карти не можа да бъде достигнат. Моля, опитайте отново. + В Националния здравен портал можете да намерите експертно проверена информация за заболявания, кодове по МКБ и по проблемите на профилактиката и грижите. + Отворете Gesund.bund.de + Променихме политиката за поверителност + Приложението за електронна рецепта се разви. Това наложи актуализирането на нашата политика за поверителност. + Отворена политика за поверителност + Това се промени след %s : + Какво се случва, когато отворите приложението? + Какво се случва, ако използвам функцията на камерата/чета рецепти с камерата? + Няма налични нови рецепти + + %s нова рецепта + %s нови рецепти + + Може да се изкупи + В изкупление + Изкупен + неизвестен + Преглед на регистрационните файлове за достъп + Кой и кога получи достъп до вашите рецепти? + Ключ за достъп до услугата по рецепта + регистрационни файлове за достъп + Няма регистрационни файлове за достъп + Все още няма регистрационни файлове за достъп. + Рецептата в момента се изпълнява и не може да бъде изтрита + Приеми + Явно това не проработи + Наясно сме, че връзката със здравната карта има своите подводни камъни. Следователно в бъдеще регистрацията трябва да е възможна и чрез вече удостоверено приложение за здравно осигуряване. \n\n Също така работим върху възможността за изкупуване на рецепти дигитално без регистрация. \n\n Забелязахте ли нещо по време на този процес, което бихте искали да споделите с нас? Моля, пишете ни, ние също се радваме да получим много критични отзиви. + Съвети за свързване + Подобрете силата на връзката + Ако е необходимо, отстранете защитния капак. + Ако устройството вибрира и след това прекъсне връзката, потърсете оптималната позиция в малък радиус. + Преместете устройството по картата много бавно. + Поставете устройството директно върху картата. + За да направите това, поставете здравната карта върху равна повърхност (напр. маса). + Подобрете силата на връзката + Обърнете внимание на разположението на NFC сензора + Разберете къде се намира NFC сензорът във вашето устройство (тук, например, общ преглед за устройства от %s ). + В някои случаи позицията на NFC сензора може да се различава в рамките на моделна серия (тук, например, информацията за %s ). + Следващ съвет + По-нататък + Близо + Опитай + пишете ни + Лиценз за търсене в аптека + изкупувам + Сканирана рецепта + Сканирано на %s + Маркирано като осребрено на %s + Как искате да продължите? + Поръчка + Наличен скоро + Резервирайте сега за вземане или го доставете с куриерска служба или доставка + Запазете за по-късна поръчка + Запазете рецепти на устройството + + Продължете с %s рецепта + Продължете с %s рецепти + + Неуспешно свързване на здравна карта + Текущият профил вече е свързан с друга здравна карта (здравноосигурителен номер %s ). + Вашата здравна карта вече е свързана с друг профил. Превключване към профил %s . + Запазете на компютър + данни за контакт и адрес + Контакт + телефонен номер + Моля, дайте телефон за връзка. + Пощенски адрес (по избор) + адрес за доставка + име и фамилия + Моля, въведете име и фамилия за контакт. + Улица и номер на къща + Моля, въведете улица и номер на къща, за да можем да се свържем с нас. + Допълнителен адрес (по избор) + Инструкция за доставка (по избор) + Необходима е допълнителна информация за контакт + Отхвърлите промените? + изхвърлям + За търсене аптечният указател използва геокоординати, определени с помощта на OpenStreetMap. Благодарим на проекта за тази помощ. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Поверителност и използване + По-нататък + Получихте своя ПИН в писмо от вашата здравноосигурителна компания. + Не е получен PIN + ПИН код + Проверете връзката с интернет и настройката за час/дата на вашето устройство. + За да влезете, натиснете „Отключи“. + заключен? Моля, проверете биометричните си данни на това устройство. + Забравена парола? Моля, изтрийте приложението и го инсталирайте отново. Можете да разберете защо в нашия %s . + зона за помощ + размер на опаковката и единица + активна съставка + Количество на активната съставка + обозначение на партидата + Exp + категория + Ваксина + Приеми + Отменено + Забележете + Помогнете ни да направим това приложение по-добро + Въведете паролата + Паролата трябва да е с дължина поне осем знака + Силата на паролата не е достатъчна + Достатъчна сила на паролата + Паролата се вижда + Паролата не се вижда + биометрия + парола + в очакване на отговор + Без рецепти + Понастоящем нямате рецепти за обратно изкупуване. + Да се актуализира + Автоматично излизане + От съображения за сигурност връзката със сървъра за рецепти се прекъсва след 12 часа. Свържете се отново, за да получите текущи рецепти. + Свържете се + Получихте ли хартиено копие? + Добавете рецепти към вашия списък, като докоснете бутона за сканиране в горния десен ъгъл. + Сканиране на разпечатка на хартия + Трябва да сте влезли, за да получавате рецепти автоматично. + Регистрирам + Няма изкупени рецепти + Вашите изкупени рецепти се показват тук. От съображения за защита на данните вашите рецепти ще бъдат изтрити от сървъра за рецепти след 100 дни. + Няма изкупени рецепти + Вашите изкупени рецепти се показват тук. Добавете рецепти чрез сканиране, за да започнете изкупуването. + управление на устройството + Свързани устройства + Регистриран от %s (това устройство) + Регистриран от %s + От съображения за сигурност връзката със сървъра за рецепти се прекъсва след 12 часа. За да се свържете отново, имате нужда от вашата здравна карта и ПИН за всеки процес на свързване. + ПИН код + Въведете своя ПИН (здравна карта). + По-нататък + Регистрирам + Свързани устройства + премахнете устройството? + Прекъсване + Премахнато + Премахване на това устройство? + Искате ли да премахнете %s ? + Ако премахнете %s , връзката със сървъра за рецепти ще бъде окончателно прекъсната най-късно след 12 часа. + Устройствата се зареждат... + Няма устройства + Няма устройства, свързани с тази здравна карта. + Опитай пак + Ох :-( + Списъкът с устройства не можа да бъде зареден. + wwweg… + Няма интернет връзка. + Лекарства и превързочни материали + наркотици + Доставка на лекарства с рецепта съгласно § 4 АМВВ + Имаш ли нужда от помощ? + Събрахме няколко съвета за решаване на най-често срещаните проблеми. + Стартирайте съвети за свързване + отключване + картата е блокирана + ПИН кодът е въведен неправилно три пъти. Следователно вашата карта е блокирана от съображения за сигурност. + отключи картата + Въведете PUK + С вашия ПИН вие сте получили 8-цифрен PUK от вашата застрахователна компания. + Изберете нов ПИН + Можете сами да изберете своя нов персонален идентификационен номер (ПИН) (6 до 8 цифри). + PIN запомнен? + Моля, запишете своя ПИН и го съхранявайте на сигурно място. + Прекъсване + Добре + Отключването не е възможно + Достигнали сте максималния брой отключвания на карти с този PUK или сте го въвели многократно неправилно. Моля, свържете се с вашата застрахователна компания. + Можете да използвате един PUK за до 10 отключвания. + картата е отключена + От какво имаш нужда: + вашата здравна карта + PUK на вашата здравна карта + По-нататък + здравна карта + Поръчайте ПИН или карта + Регистрирам + Как искате да влезете? + Здравна карта с активиран NFC + ЕГН за здравна карта + Все още нямате здравна карта и ПИН с активиран NFC? + Запиши се сега + Или: Влезте с %s . + Вашето приложение за здравно осигуряване + „Вашият номер за достъп може да бъде намерен в горния десен ъгъл на вашата здравна карта.“ + Картата ми няма номер за достъп + + Имате още %s опита, преди картата ви да бъде блокирана. + Имате още %s опита, преди картата ви да бъде блокирана. + + Поставете здравната карта на гърба на телефона + Следващият процес може да отнеме до 30 секунди. + Поставете карта %s на гърба на телефона. + в горния десен ъгъл + в горната среда + в горния ляв ъгъл + в средната зона вдясно + средата + в центъра вляво + в долната дясна област + в долния център + в долния ляв ъгъл + Помогне + Изпратено преди %s минути + Изпратено на %s + Изпратено току що + Изпратено в %s часа + Вече не е валиден + Влезте с приложението + изберете застраховка + Не намерихте това, което търсихте? Този списък непрекъснато се разширява. Регистрацията със здравна карта вече се поддържа от всяка здравноосигурителна компания. + Обратна връзка от приложението за електронна рецепта + Очакваме вашите отзиви. Моля, използвайте мястото по-долу и бъдете възможно най-точни: + PUK + Близо + Колко жалко… + За съжаление вашето устройство не отговаря на минималните изисквания за влизане в приложението за електронна рецепта. Необходими са поне Android 7 и NFC чип за сигурно удостоверяване със здравната ви карта. + Научете повече + Запазване на данните за вход? + Запазете на компютър + Не спестявайте + Забележете + От съображения за сигурност връзката със сървъра за рецепти се прекъсва след 12 часа. За да се свържете отново, имате нужда от здравна карта и ПИН за всеки процес на свързване. + Настройте биометрична защита + Запазването на данните за достъп не е възможно. Настройте биометрична защита (напр. пръстов отпечатък) на вашето устройство предварително. + Прекъсване + Идеи + Забележете + Приеми + Сигурност на вашите данни за рецепта + \"Това приложение използва най-сигурния биометричен сензор, осигурен от вашето устройство, за да съхранява вашите идентификационни данни в защитена зона на паметта на устройството.\" + Биометричната сигурност на вашите данни за достъп ви позволява да отваряте това приложение в бъдеще, без да въвеждате своя ПИН и здравна карта, както и да преглеждате, извиквате, осребрявате или изтривате рецепти. + Моля, уверете се, че лицата, с които можете да споделяте това устройство и чиито биометрични характеристики може да се съхраняват на това устройство, също имат достъп до вашите рецепти. + това за съжаление не проработи + Удостоверяването с приложението за здравно осигуряване беше неуспешно. + Изтекъл на %s + Рецептата вече е изтрита от сървъра + Моля, коригирайте въведеното или отхвърлете промените + Правилно + данни за застрахования + Фамилия + Застраховка + осигурителен номер + номер за достъп до картата + Регистрирам + Дерегистрирайте се + Запазете на компютър + промяна + Редактиране на профилна снимка + По-нататък + сървърът не отговаря + Моля, опитайте отново по-късно. + Опитай пак + Потърсете застраховка + Свързване към сървъра за рецепти сега? + Влязохте успешно + връзката е изгубена + Свързване към сървъра за рецепти сега? + Без жетони + Ще получите токен, когато влезете в услугата за рецепти.\n + поръчки + Изберете желания PIN + отключи картата + Изберете PIN + Повторете PIN + Записите се различават един от друг. + Без поръчки + Все още нямате поръчки. + Точно сега + В %s часа + Количката за пазаруване е готова + Рецептата е добавена към вашата пазарска количка. Моля, посетете уебсайта на аптеката, за да завършите поръчката. + Отворете количката за пазаруване + Покажете този код за получаване в аптеката. + Получаване на код за получаване + Съобщението не може да се покаже + Моля, свържете се с вашата аптека ( %s ). + Показване на връзката към количката + Показване на кода за получаване + Покажете съобщението + %s в %s часа + Рецептата е изпратена до %s . + Преглед на поръчката + Нов + курс + Поръчка + Безплатно за обаждащия се. Работно време: понеделник - петък 8:00 - 20:00 с изключение на национални празници + Аптека + Изберете желания PIN + Желаният ПИН е запазен + В момента отворен и близо до мен + Филтриране по... + започнете търсене + директно възлагане + аптеки + телефонен номер (по избор) + Търсене по име или адрес + Няма валидна информация за аптеката + Няма открита актуална информация за тази аптека. Записът за тази аптека ще бъде изтрит. + Добре + Указателят на аптеката не е наличен + В момента не може да бъде извлечена актуална информация за тази аптека. Моля, проверете вашата интернет връзка. + Прекъсване + Опитай пак + Запазване на околната среда + Влизането не е възможно + Изглежда, че вашите биометрични данни за вход са се променили. Моля, регистрирайте се отново със здравната си карта. + Прекъсване + Регистрирам + профил 1 + Близо до мен + Може да се изкупи по-късно + Може да се използва от %s + подобрения на продукта + Анонимен анализ + Помогнете ни да направим това приложение по-добро. Всички данни за използването се събират анонимно и се използват само за подобряване на потребителското изживяване. + сигурност на устройството + лични настройки + Достъпност + подобрения на продукта + Добавена рецепта + Рецептата вече е налична + Възникна грешка при импортирането + Гасете + Сканирана рецепта + Възможен заместител + Забравен ПИН + + %s рецепта + %s рецепти + + Прочетох и приемам политиката за поверителност и условията за ползване. + Защита на данни + Условия за ползване + Бихме желали: + Подобрете използваемостта. + Откриване на грешки и сривове. + Разбира се, всички данни се събират анонимно. + Можете да промените това решение в системните настройки по всяко време. + продължи + Приеми + Това приложение използва най-сигурния метод, предоставен от вашето устройство. + Запазете на компютър + Избирам + лекарство + търговско наименование + да + Не + дозировка + дата на издаване + Тази рецепта ще бъде осребрена за вас като част от лечението. + Неопределено + допълнително заплащане + лекарство + Бележки за доставка + Допустимо според BVG + алтернативна подготовка + име на рецепта + Опаковка + инструкция за изработка + Описание + дадена от + издадена на: + активна съставка + предписано + Получете + Какво е директно възлагане? + В случай на директни препоръки, рецепта от практика или болница се изкупува директно в аптека. Застрахованите лица не трябва да предприемат никакви действия и не могат да се намесват в процеса на обратно изкупуване. \n\n Директните препоръки са изброени в приложението за електронна рецепта, за да направи лечението ви по-прозрачно за вас. + такса за аварийно обслужване + Понякога се изисква бързане. Някои рецепти могат да бъдат изкупени без допълнително заплащане на такса за спешно обслужване, като например през нощта или на официални празници. + Лекарства с доплащане + Освободени от доплащане + Задължително здравноосигурените трябва да плащат доплащане до десет евро за лекарства с рецепта. \n\n Размерът на доплащането зависи от цената на вашето лекарство. Вие сами трябва да плащате за лекарства, които струват по-малко от 5 евро.\n За лекарства, които са по-скъпи, трябва да платите десет процента от цената, но най-малко 5 евро и максимум 10 евро. \n\n Децата и младежите под 18-годишна възраст обикновено са освободени от доплащане. \n\n Ако годишните ви разходи за лекарства надхвърлят вашия финансов лимит, можете да бъдете освободени от доплащане. Говорете с вашия здравен застраховател за това. + Вие сте освободени от доплащането на това лекарство. Вашата здравна застраховка ще покрие цената на лекарството. + Колко дълго е валидна тази рецепта? + През този период можете да осребрите своята рецепта във всяка аптека с максимално допълнително плащане от 10 евро. + Възможен заместител + Поради законовите изисквания на вашата здравноосигурителна компания, можете да получите алтернатива със същата активна съставка. \n\n Лекарствата могат да изглеждат и да се наричат по различен начин, да имат различни цени и производители, но да съдържат една и съща активна съставка. Самата активна съставка и дозировката са особено важни за действието на лекарствата в организма. Пациентите в аптеката често получават различно лекарство от предписаното от лекаря по рецепта - при условие че лекарствата са сравними. Може да има терапевтични и икономически причини за промяната. + Сканирана рецепта + От съображения за сигурност рецептите, импортирани от хартиена разпечатка, не трябва да показват лични или медицински данни. \n\n Влезте в това приложение със здравна карта или застрахователно приложение, за да видите цялата информация, съдържаща се в рецептата. + Рецептата е неправилна + Тази рецепта е издадена неправилно. + Сканирана рецепта + такса за аварийно обслужване + Дозировка според писмените инструкции + телефон + сайт + поща + Сортирането по разстояние не е възможно. + Добре + Въведете текущия ПИН + Въведен е неправилен ПИН + Текущият ПИН на вашата здравна карта + картата е блокирана + Разблокирайте картата си в Настройки > Деблокиране на карта. + От съображения за сигурност, моля, въведете текущия си PIN. + Забравен ПИН + Неправилна рецепта + лекарство + Изглежда нещо се е объркало при създаването на вашата рецепта. Съобщаване за грешка? + Докладвай + Не сте влезли в системата + Регистриран с + здравна карта + биометрия + Не сте влезли в системата + Интересуваме се от вашето мнение. Моля, отделете пет минути, за да отговорите на нашата анкета. Благодаря ви предварително. + предупредително съобщение + Аптеката е добавена към любими + Аптеката е премахната от любимите + Моите аптеки + Силата на паролата е много добра + Операцията за запис е неуспешна + ПИН не можа да бъде запазен + Докладвай + Задайте ПИН + Правилото за достъп е нарушено + Нямате разрешение за достъп до директорията на картата. + Задайте свой собствен щифт + Картата е защитена с ПИН от вашата здравноосигурителна компания (транспортен ПИН), моля, задайте свой собствен ПИН. + Паролата не е намерена + На вашата карта няма запазена парола. + Вие сте излезли + Влезте отново, за да актуализирате вашите рецепти. + номер на активната съставка + сила и единство + Осребрено преди %s минути + Осребрено на %s + Изкупено току-що + Осребрено в %s часа + поръчки + Тази рецепта е изкупена за вас като част от лечение. + такса за аварийно обслужване + Тази рецепта не може да бъде изпълнена през нощта в аптека без допълнително заплащане на такса за спешна помощ. + Търси тук + Идеи + Споделете местоположението в настройките. + Близо до мен + Задръжте, за да редактирате името. + Въведете новото име за профила. + Трябва да сте влезли, за да получавате цифрови рецепти от вашата практика. + Получаване на рецепти дигитално? + Плъзнете екрана надолу, за да опресните. + Без рецепти + Добавете рецепти, като използвате бутона + в горния десен ъгъл. + Регистрирам + архив с рецепти + Може би по-късно + Регистрирам + Редактиране на профилна снимка + архив с рецепти + Въведи име + Запазете на компютър + Моята поръчка + Получател: в + рецепти + Аптека + Изпратете + промяна + Вземете от аптеката + Доставка с куриер + Доставка по пощата + %s рецепти + Осребряването не е възможно + Една или повече рецепти не можаха да бъдат осребрени. + Няма избрана рецепта + За да осребрите рецепти, трябва да бъде избрана поне една рецепта. + Добавете информация за контакт + промяна + Без рецепта + Понастоящем нямате рецепти за обратно изкупуване + колекция + куриер + Пратка + изберете рецепти + Докоснете тук, за да сканирате рецепти + Натиснете продължително, за да редактирате имена + Добавете още профили, например за вашите деца или родители + Кликнете върху дисплея, за да пропуснете показаната подсказка. + Как да откупите? + Как бихте искали да получите вашето лекарство? + Осребрете директно + Купете лекарства на място + Поръчка + Резервирайте или го доставете + Готов + колективен код + единични кодове + + Имате %s рецепта. + Имате %s рецепти. + + направете избор + Всички рецепти + Кои рецепти? + По-нататък + По-нататък + Научете повече + Забележете + Това приложение използва софтуер от Google за разпознаване на кодове. + Научете повече + Относно скенера за кодове на рецепти + Какви данни съдържа кодът на рецептата? + Кодът на рецептата съдържа само идентификатор на рецептата. Това позволява рецептата да бъде намерена в услугата за рецепти в цифровата здравна мрежа. Кодът на рецептата не съдържа никакви данни за Вас или Вашето лекарство. + Значи никой не може да направи нищо само с кода на рецептата? + Правилно. Данните за рецептата трябва да бъдат изтеглени от службата за рецепти. Това изисква защитено влизане. + Кой може да се регистрира за услугата по рецепта? + Регистрирането в услугата за рецепти в цифровата здравна мрежа е възможно за осигурени лица, аптеки, медицински практики и болници. + Защо приложението за електронна рецепта използва функциите на Google? + Google предлага функции, които могат лесно да бъдат вградени в приложения и които непрекъснато се разработват и актуализират от Google. Това гарантира, че функциите работят на много различни крайни устройства и могат да се управляват сигурно. Приложението използва функция за подобряване на функцията на камерата и сканирането за устройства с Android (Google ML Kit). + Как работи подобрението на сканирането на Google ML Kit? + Google ML Kit помага за оптимизиране на изображението, заснето от камера, така че кодовете на рецептите да могат да се четат дори при условия на лошо осветление или с по-стари модели камери. + Данните за рецептата или моето лекарство ще бъдат ли предадени на Google? + Не. Прочетеният код на рецептата се записва директно в приложението. Няма да бъде предадено на Google. Данните за рецептата не се съхраняват в кода, а само в цифровата здравна мрежа. Оттам те се изпращат до приложението. Google няма достъп до цифровата здравна мрежа. + Какви данни обработва Google, когато използва ML Kit? + Google има достъп само до техническа информация за използваното крайно устройство и общото използване на допълнителната функция (напр. процент грешки, настройки на камерата), за да запише това статистически и по този начин да подобри допълнителната функция. Когато осъществявате достъп, Google временно записва IP адреса на вашето крайно устройство. Информацията за вас и съдържанието на рецептата няма да бъдат записани от Google. + Доброволно ли е използването на Google ML Kit? + да Въпреки това, ML Kit е вграден в скенера за код на рецепта във версията за Android на приложението за електронна рецепта. Ако използвате скенера за код на рецепта на устройство с Android, винаги се използва и функцията ML Kit. Можете обаче да го направите без да използвате скенера за код на рецепта. Вашите рецепти също могат да бъдат заредени в приложението, ако се регистрирате в дигиталната здравна мрежа с електронната здравна карта или чрез вашето приложение за здравно осигуряване. + Мога ли да видя кой е гледал моите рецепти? + да Целият достъп до вашите данни е изцяло регистриран в цифровата здравна мрежа. В приложението за електронна рецепта можете да видите кой има достъп до вашите данни. + С кого мога да се свържа, ако имам въпроси относно приложението или електронната рецепта? + Можете да намерите подробна информация в декларацията за защита на данните. + Предписан брой опаковки + Без рецепти + За това се нуждаете от рецепти, които могат да бъдат изкупени. + изберете застраховка + Потърсете застраховка + Прекъсване + За какво бихте искали да кандидатствате? + За това приложение се нуждаете от карта и свързания ПИН код. + Как бихте искали да се свържете с вашата застрахователна компания? + Вашата застрахователна компания предлага следните опции за контакт + Вашата застрахователна компания предлага следните опции за контакт + Близо + ПИН кодът е въведен неправилно. + Номерът за достъп е въведен неправилно + PUK въведен неправилно. + разходни бележки + Показване на квитанции за разходи + разходни бележки + За да получавате разписки за разходи, трябва да сте свързани със сървъра. + Свържете се + Няма квитанции за разходи + Деактивирайте + Прекъсване + деактивирайте функцията + Това ще изтрие всички разписки от това устройство и от сървъра. + Получавайте разписки за разходи + Вашите разписки за разходи също се записват на сървъра за рецепти. + Получете + Общо: %s %s + Избирам + Сплит + Гасете + Гасете + Изпращане + %s € + обща цена + Съвет: Изпратете разписки за разходи чрез застрахователното приложение + Изпращайте разписки за разходи лесно чрез приложението на вашата застрахователна компания. В следващата стъпка изберете това приложение и натиснете Споделяне. + Практикувайте + Аптека + Дата + Покажи повече + ID на лекарството + Издадена за + KVNR: %s + Дата на раждане: %s + Добре + Как изпращате разписки? + Прехвърлете директно в приложението на вашата застрахователна компания/офис за помощ. За да направите това, изберете приложението на следващата страница. + или + Запазете файла и по-късно го импортирайте в портала за застраховка/помощ. + Статия: %s + Номер: %s + ДДС: %s %% + Брутна цена в EUR: %s + Допълнителни такси + такса за аварийно обслужване + BTM такса + T такса за рецепта + разходи за доставка + куриерска услуга + Общо в евро: %s + такса + Наистина ли изтривам? + Файлът ще бъде изтрит от вашето устройство и от сървъра. + Гасете + Публикувано + Пощенски код + Местоположение + Моля, въведете вашия пощенски код, за да се свържете с нас. + Моля, въведете мястото си на пребиваване, когато се свързвате с нас. + Ще бъде изкупено за вас + Беше осребрено за вас + Трябва да сте влезли, за да използвате тази услуга. + застрахователно приложение + здравна карта + Изисква се свързан ПИН код + За да получавате регистрационни файлове за достъп, трябва да сте свързани към сървъра. + Все още можете да изпълните рецептата в аптека в рамките на този период, но ще трябва да заплатите цялата покупна цена за лекарството сами. Като алтернатива можете да поискате от вашата практика рецептата да бъде преиздадена. + Готов + Поискайте корекция + В аптеката + В ап + Сканирайте този код във вашата аптека. + Искане за корекция на таксуването + diff --git a/android/src/main/res/values-cs/strings.xml b/android/src/main/res/values-cs/strings.xml new file mode 100644 index 00000000..6aaddff3 --- /dev/null +++ b/android/src/main/res/values-cs/strings.xml @@ -0,0 +1,868 @@ + + + OK + Přerušit + Vrátit se + kolem + Digitální. Rychle. Zajistit. + ID úkolu + přístupový kód + Podmínky použití + Ochrana dat + recepty + Přístup ke kameře odepřen + Chcete-li skener používat, musíte aplikaci povolit přístup k fotoaparátu v nastavení systému. + Zaměřte fotoaparát na kód receptu + Toto není platný kód předpisu + Tento kód předpisu již byl naskenován + + %s recept rozpoznán + + + %s receptů rozpoznáno + + Přerušit + světlo fotoaparátu + Zrušit skenování? + OK + Nerušit + Tady jsme + Co potřebuješ: + Zadejte přístupové číslo karty + zadejte PIN kód + Zkus to znovu + Připojení k serveru se nezdařilo. + + Máte ještě %s pokusů, než bude vaše karta zablokována. + + + Máte ještě %s pokusů, než bude vaše karta zablokována. + + Přístupové číslo najdete na své zdravotní kartě vpravo nahoře. + Přerušit + Hledat mapu... + Přiložte zdravotní kartu k zadní straně zařízení. + Stále se hledá… + Pomalu posuňte kartu na zadní straně zařízení. + Spropitné + Pouzdra na zařízení mohou ztížit připojení přes NFC. + karta rozpoznána + Snažte se nehýbat zdravotní kartou. + Zdravotní průkaz nalezen. Prosím, nehýbej se. + spojení ztraceno + Znovu přiložte svou zdravotní kartu k zadní straně zařízení + Verze: %s + Sestavení hash: %s + menu ladění + Otevřeno do %s + Otevřeno celý den + otisk + editor + gematik GmbH\n Friedrichstrasse 136\n 10117 Berlín + Jednatel: Dr. lékařský Markus Leyck-Dieken\n Rejstříkový soud: okresní soud Berlin-Charlottenburg\n Číslo obchodního rejstříku: HRB 96351\n Daňové identifikační číslo: DE241843684 + Zodpovědnost za obsah + Dr lékařský Markus Leyck-Dieken + Kontakt + Oznámení + Snažíme se používat genderově neutrální jazyk. Pokud zaznamenáte nějaké chyby, těšíme se na vaši zprávu prostřednictvím e-mailu. + Německá moderní platforma pro digitální medicínu + napsat mail + otevřít webovou stránku + Vítejte + Spusťte registraci + odemknout + Registrovat + Přerušit + Bezpečnostní + Právní + otisk + ochrana dat + Podmínky použití + podrobnosti + Označit jako vyplacené + Označit jako neuplatněno + léková forma + velikost balení + Pojištěná osoba + Příjmení + adresa + datum narození + Zdravotní pojištění / Plátci + postavení + cislo pojistence + Předepisující osoba + Příjmení + Lékařský specialista + Číslo lékaře (LANR) + instituce + Příjmení + adresa + Číslo provozovny + telefonní číslo + emailová adresa + pracovní úraz + den nehody + Číslo havarijní společnosti nebo zaměstnavatele + Chcete tento recept trvale smazat? + Uhasit + Přerušit + Otevírací doba + webová stránka + Dnes splatný pouze jako samoplátce + Registrovat + Aktivujte NFC + Pro přihlášení pomocí zdravotní karty aktivujte na svém zařízení funkci NFC. + aktivovat + Opravit + Uplatněné recepty? + Chcete recepty označit jako uplatněné? + Není vykoupeno + Vykoupeno + Otevírá v %s + +49 800 277 377 7 + Technická horká linka + Otevřete skener pro recepty + Nápady + Potlačit snímky obrazovky + Zabrání zobrazení miniatury při přepínání aplikací + Umožňujete e-receptu anonymně analyzovat vaše chování při používání? + Technické informace + Zabezpečení vašich údajů o předpisech + Zajistěte prosím, aby osoby, se kterými můžete toto zařízení sdílet a jejichž biometrické charakteristiky mohou být v tomto zařízení uloženy, měly také přístup k vašim předpisům. + odeslání se nezdařilo + Není nastaven žádný e-mailový program + Žádné výsledky + Pro tento hledaný výraz jsme nenašli žádné výsledky. + Open Source licence + Kontakt + Zavolejte na technickou horkou linku + Zúčastněte se průzkumu + +49 800 277 377 7 + Chci pomoci vylepšit tuto aplikaci + To zahrnuje informace o hardwaru a softwaru ve vašem telefonu, nastavení aplikace pro elektronický předpis a množství používání, ale nikdy žádná data o vás nebo vašem zdraví. + Údaje jsou společnosti gematik GmbH zpřístupněny pouze zpracovatelem údajů a jsou vymazány nejpozději po 180 dnech. Analýzu můžete kdykoli znovu deaktivovat v nabídce aplikace. + Tato data nám umožňují pochopit, které funkce jsou často používány, a zlepšit je. Dále můžeme odhadnout, jak dlouho musí být podporována starší technologie a kdy můžeme například zavést povinně novější verzi operačního systému, aniž by to ovlivnilo (příliš mnoho) uživatelů. + zlepšit aplikaci + Anonymní analýza zůstává zakázána + %s Děkujeme za vaši podporu! + Registrovat + Pro stažení receptů se prosím identifikujte. + Poznámka pro lékárny: Kontaktní údaje a informace o lékárnách získáváme z mein-apothekenportal.de německého svazu lékáren Zjistili jste chybu nebo byste chtěli údaje opravit? + Zjistěte více + lékárny + Bohužel to nefungovalo \uD83D\uDE15 + Zkuste to znovu. + Zadejte heslo + Dále + Přístupnost + Zvětšení + Umožňuje zvětšit aplikaci sevřením nebo roztažením prstů (přiblížení sevřením). + Heslo + Zabezpečte svá data heslem dle vašeho výběru. + Heslo + Uložit do počítače + zobrazit heslo + Zopakovat heslo + Doporučení: %s + napsat mail + Když odešlete svou zprávu, budou odeslány následující informace o použitém hardwaru a operačním systému: + Uplatnit pouze na místě + Do této lékárny zatím nelze zasílat elektronické recepty. + Momentálně otevřeno + Kurýrní služba + náklad + filtr + Filtr + Není k dispozici žádná poloha + Rozuměl + Opakovaná hesla se shodují + Chyba 20 10 76631 + Váš certifikát zdravotní karty je neplatný. Vypršela platnost vaší karty? Kontaktujte prosím svou zdravotní pojišťovnu. + Neúspěšné pokusy o přihlášení + + Bylo zjištěno %s neúspěšných pokusů o přihlášení. + + + Bylo zjištěno %s neúspěšných pokusů o přihlášení. + + Vyberte nejlepší zálohu zařízení + Může to být otisk prstu, vzor přejetí nebo podobně + žetony + přístupový token + SSO tokeny + Není k dispozici žádný přístupový token + není k dispozici žádný token jednotného přihlášení + zkopírován do schránky + Kliknutím zkopírujete token do schránky + Platí pouze dnes + Dovolit + žádné připojení k serveru + Zkuste to znovu za několik minut + Znovu načíst + ukázat žetony + Jak chcete aplikaci zabezpečit? + Oznámení + Pro toto zařízení nebylo nastaveno žádné zálohování zařízení + Doporučujeme, abyste svá zdravotní data navíc chránili zabezpečením zařízení, jako je přístupový kód nebo biometrie. + Toto upozornění v budoucnu již nezobrazujte. + Připojení se nezdařilo. Síťové připojení se nepodařilo navázat. + Komunikace se serverem selhala: stavový kód %s . + Selhala komunikace se serverem: Zkontrolujte připojení k internetu a nastavení času a data. + Varování + Vaše zařízení může mít snížené zabezpečení + To může být způsobeno například manipulovanými zařízeními nebo aktivovaným vývojářským režimem. Z bezpečnostních důvodů nedoporučujeme používat aplikaci na jailbreaknutých zařízeních. + Uznávám zvýšené riziko a přesto chci pokračovat. + Proč jsou zařízení s přístupem root potenciálním bezpečnostním rizikem? + Zjistěte více + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Jméno profilu + Zadejte prosím název nového profilu. + jméno profilu + profily + Jak rozpoznat zdravotní kartu s podporou NFC + Prostřednictvím této aplikace není možný žádný kontakt + Ke kontaktování vaší pojišťovny použijte obvyklé kanály. + Zdravotní karta a PIN + Pouze PIN + Registrace v aplikaci e-recept + Pole názvu nesmí být prázdné. + Profil se zadaným názvem již existuje. + profil + %s vybráno + barva pozadí + jarní šedá + rosnatka + To! Je! Růžový! + Strom + Modrý měsíc září + Nepřihlášen + Svázané dohromady + Naposledy připojeno %s + Smazat profil? + Tím se vymažou všechna data profilu na tomto zařízení. Vaše recepty ve zdravotnické síti zůstanou nedotčeny. + Uhasit + Přerušit + smazat profil + Chcete smazat poslední profil. + Aplikace vyžaduje alespoň jeden profil. Zadejte prosím název nového profilu. + Chyba 20 10 76831 + Adresář zdravotních karet nebyl dostupný. Prosím zkuste to znovu. + Odborně ověřené informace o nemocech, ICD kódech ao problematice prevence a péče naleznete na Národním portálu zdraví. + Otevřete Gesund.bund.de + Změnili jsme zásady ochrany osobních údajů + Aplikace elektronických receptů se vyvíjela. Kvůli tomu bylo nutné aktualizovat naše zásady ochrany osobních údajů. + Otevřete zásady ochrany osobních údajů + To se od %s s změnilo: + Co se stane, když aplikaci otevřete? + Co se stane, když použiji funkci fotoaparátu / čtu recepty s fotoaparátem? + Nejsou k dispozici žádné nové recepty + + %s nový recept + + + %s nových receptů + + Splatný + Ve vykoupení + Vykoupeno + Neznámý + Zobrazit protokoly přístupu + Kdo a kdy měl přístup k vašim receptům? + Přístupový klíč ke službě předpisu + přístupové protokoly + Žádné protokoly přístupu + Zatím nejsou žádné přístupové protokoly. + Recept se právě zpracovává a nelze jej smazat + Akceptovat + Zřejmě to nefungovalo + Jsme si vědomi, že spojení se zdravotní kartou má svá úskalí. V budoucnu by proto měla být registrace možná i prostřednictvím již ověřené aplikace zdravotního pojištění. \n\n Pracujeme také na tom, aby bylo možné recepty uplatňovat digitálně bez registrace. \n\n Všimli jste si během tohoto procesu něčeho, o co byste se s námi chtěli podělit? Napište nám, rádi obdržíme i velmi kritickou zpětnou vazbu. + Tipy pro připojení + Zlepšete pevnost spojení + V případě potřeby sejměte ochranný kryt. + Pokud zařízení vibruje a následně přeruší spojení, hledejte optimální polohu v malém okruhu. + Pohybujte zařízením po mapě velmi pomalu. + Umístěte zařízení přímo na kartu. + Chcete-li to provést, položte zdravotní kartu na rovný povrch (např. + Zlepšete pevnost spojení + Všimněte si umístění snímače NFC + Zjistěte, kde se ve vašem zařízení nachází NFC senzor (zde např. přehled pro zařízení od %s ). + V některých případech se může poloha NFC senzoru v rámci modelové řady lišit (zde například informace pro %s ). + Další tip + Dále + Zavřít + Vyzkoušet + napište nám + Licence na vyhledávání lékáren + vykoupit + Naskenovaný předpis + Naskenováno %s + Označeno jako uplatněné %s + Jak chcete pokračovat? + Objednat + Brzy dostupný + Rezervujte si ji hned k vyzvednutí nebo si ji nechte doručit kurýrní službou nebo poštou + Uschovejte pro pozdější objednávku + Uložte recepty do zařízení + + Pokračujte %s receptem + + + Pokračujte s %s recepty + + Nepodařilo se připojit zdravotní kartu + Aktuální profil je již připojen k jiné zdravotní kartě (číslo zdravotního pojištění %s ). + Vaše zdravotní karta je již připojena k jinému profilu. Přepnout na profil %s . + Uložit do počítače + kontaktní údaje a adresu + Kontakt + telefonní číslo + Uveďte prosím telefonní číslo pro kontakt. + E-mailová adresa (volitelné) + doručovací adresa + jméno a příjmení + Pro kontaktní účely prosím zadejte jméno a příjmení. + Ulice a číslo domu + Zadejte prosím ulici a číslo domu, abychom vás mohli kontaktovat. + Další adresa (volitelné) + Pokyny k doručení (volitelné) + Jsou vyžadovány další kontaktní údaje + Zrušit změny? + vyřadit + Pro vyhledávání používá adresář lékáren zeměpisné souřadnice, které byly určeny pomocí OpenStreetMap. Děkujeme projektu za tuto pomoc. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Ochrana osobních údajů a použití + Dále + PIN jste obdrželi v dopise od vaší zdravotní pojišťovny. + Nebyl přijat žádný PIN + PIN kód + Zkontrolujte připojení k internetu a nastavení času a data na vašem zařízení. + Pro přihlášení stiskněte „Odemknout“. + uzamčen? Ověřte prosím své biometrické údaje na tomto zařízení. + Zapomenuté heslo? Smažte aplikaci a poté ji znovu nainstalujte. Proč tomu tak je, můžete zjistit v našem %s . + oblast pomoci + velikost balení a jednotka + aktivní složka + Množství účinné látky + označení šarže + Exp + kategorie + Vakcína + Akceptovat + Nehotový + Oznámení + Pomozte nám tuto aplikaci vylepšit + Zadejte heslo + Heslo musí mít alespoň osm znaků + Síla hesla není dostatečná + Dostatečná síla hesla + Heslo je viditelné + Heslo není viditelné + biometrie + Heslo + čekání na odpověď + Žádné recepty + Momentálně nemáte žádné recepty s možností uplatnění. + Aktualizovat + Automatické odhlášení + Z bezpečnostních důvodů je spojení se serverem receptů ukončeno po 12 hodinách. Znovu se připojte, abyste získali aktuální recepty. + Připojit + Obdrželi jste papírovou kopii? + Přidejte recepty do svého seznamu klepnutím na tlačítko skenování v pravém horním rohu. + Naskenujte papírový výtisk + Pro automatický příjem receptů musíte být přihlášeni. + Registrovat + Žádné vyplacené recepty + Zde jsou zobrazeny vaše uplatněné recepty. Z důvodu ochrany dat budou vaše recepty po 100 dnech smazány ze serveru receptů. + Žádné vyplacené recepty + Zde jsou zobrazeny vaše uplatněné recepty. Přidejte recepty pomocí skenování a začněte uplatňovat. + správa zařízení + Připojená zařízení + Registrováno od %s (toto zařízení) + Registrováno od %s + Z bezpečnostních důvodů je spojení se serverem receptů ukončeno po 12 hodinách. K opětovnému připojení potřebujete zdravotní kartu a PIN pro každý proces připojení. + PIN kód + Zadejte svůj PIN (zdravotní kartu). + Dále + Registrovat + Připojená zařízení + odebrat zařízení? + Přerušit + Odebráno + Odebrat toto zařízení? + Chcete odebrat %s ? + Pokud odeberete %s , bude připojení k receptovému serveru trvale přerušeno nejpozději do 12 hodin. + Zařízení se načítají... + Žádná zařízení + K této zdravotní kartě nejsou připojena žádná zařízení. + Zkus to znovu + A jé :-( + Seznam zařízení nelze načíst. + www např.… + Žádné internetové připojení. + Léky a obvazy + narkotika + Výdej léků na předpis dle § 4 AMVV + Potřebuješ pomoc? + Dali jsme pro vás dohromady několik tipů, jak vyřešit nejčastější problémy. + Spusťte tipy pro připojení + odemknout + karta zablokována + Kód PIN byl třikrát zadán nesprávně. Vaše karta byla proto z bezpečnostních důvodů zablokována. + odemknout kartu + Zadejte PUK + Spolu s PINem jste od své pojišťovny obdrželi 8místný PUK. + Vyberte nový PIN + Své nové osobní identifikační číslo (PIN) si můžete zvolit sami (6 až 8 číslic). + Pamatujete si PIN? + Poznamenejte si svůj PIN a uschovejte jej na bezpečném místě. + Přerušit + OK + Odemknutí není možné + Dosáhli jste maximálního počtu odemknutí karty pomocí tohoto PUK nebo jej opakovaně zadali nesprávně. Kontaktujte prosím svou pojišťovnu. + Jeden PUK můžete použít až pro 10 odemknutí. + karta odblokována + Co potřebuješ: + svou zdravotní kartu + PUK vašeho zdravotního průkazu + Dále + zdravotní průkaz + Objednejte si PIN nebo kartu + Registrovat + Jak se chcete přihlásit? + Zdravotní karta s podporou NFC + PIN ke zdravotní kartě + Ještě nemáte zdravotní kartu a PIN s podporou NFC? + Požádejte nyní + Nebo: Přihlaste se pomocí %s . + Vaše aplikace zdravotního pojištění + "Vaše přístupové číslo najdete v pravém horním rohu své zdravotní karty." + Moje karta nemá přístupové číslo + + Máte ještě %s pokusů, než bude vaše karta zablokována. + + + Máte ještě %s pokusů, než bude vaše karta zablokována. + + Vložte zdravotní kartu na zadní stranu telefonu + Následující proces může trvat až 30 sekund. + Umístěte kartu %s na zadní stranu telefonu. + v pravém horním rohu + v horním středu + vlevo nahoře + ve střední oblasti vpravo + střední + uprostřed vlevo + v pravé dolní oblasti + v dolním středu + vlevo dole + Pomoc + Odesláno před %s minutami + Odesláno %s + Právě odesláno + Odesláno v %s hodin + Nadále není platné + Přihlaste se pomocí aplikace + vybrat pojištění + Nenašli jste, co jste hledali? Tento seznam se neustále rozšiřuje. Registraci se zdravotním průkazem podporuje již každá zdravotní pojišťovna. + Zpětná vazba z aplikace e-recept + Těšíme se na vaši zpětnou vazbu. Použijte prosím níže uvedený prostor a buďte co nejpřesnější: + PUK + Zavřít + Jaká škoda… + Vaše zařízení bohužel nesplňuje minimální požadavky pro přihlášení do aplikace e-recept. Pro bezpečné ověření pomocí zdravotní karty je vyžadován alespoň Android 7 a čip NFC. + Zjistěte více + Uložit přihlašovací údaje? + Uložit do počítače + Nešetřete + Oznámení + Z bezpečnostních důvodů je spojení se serverem receptů ukončeno po 12 hodinách. Pro opětovné připojení potřebujete zdravotní kartu a PIN pro každý proces připojení. + Nastavte si biometrické zabezpečení + Uložení přístupových údajů není možné. Předem si na svém zařízení nastavte biometrické zabezpečení (např. otisk prstu). + Přerušit + Nápady + Oznámení + Akceptovat + Zabezpečení vašich údajů o předpisech + \\"Tato aplikace používá nejbezpečnější biometrický senzor poskytovaný vaším zařízením k ukládání vašich přihlašovacích údajů v zabezpečené oblasti paměti zařízení.\" + Biometrické zabezpečení vašich přístupových údajů vám umožňuje v budoucnu otevřít tuto aplikaci bez zadání PIN a zdravotní karty a prohlížet, vyvolávat, uplatňovat nebo mazat recepty. + Zajistěte prosím, aby osoby, se kterými můžete toto zařízení sdílet a jejichž biometrické charakteristiky mohou být v tomto zařízení uloženy, měly také přístup k vašim předpisům. + což se bohužel nepovedlo + Ověření pomocí aplikace zdravotního pojištění se nezdařilo. + Platnost vypršela %s + Recept byl již smazán ze serveru + Opravte svůj vstup nebo zrušte změny + Opravit + pojištěné údaje + Příjmení + Pojištění + cislo pojistence + přístupové číslo karty + Registrovat + Zrušit registraci + Uložit do počítače + Změna + Upravit profilový obrázek + Dále + server neodpovídá + Prosím zkuste to znovu později. + Zkus to znovu + Hledejte pojištění + Chcete se nyní připojit k serveru receptů? + Úspěšně jste se přihlásili + spojení ztraceno + Chcete se nyní připojit k serveru receptů? + Žádné žetony + Token obdržíte, když se přihlásíte do služby předpisu.\n + objednávky + Vyberte požadovaný PIN + odemknout kartu + Vyberte PIN + Opakujte PIN + Záznamy se od sebe liší. + Žádné rozkazy + Zatím nemáte žádné objednávky. + Právě teď + V %s hodin + Nákupní košík je připraven + Recept byl přidán do vašeho nákupního košíku. Pro dokončení objednávky prosím přejděte na web lékárny. + Otevřete nákupní košík + Ukažte tento kód pro vyzvednutí v lékárně. + Přijměte kód pro vyzvednutí + Zprávu nelze zobrazit + Kontaktujte prosím svou lékárnu ( %s ). + Zobrazit odkaz na košík + Zobrazit kód vyzvednutí + Ukažte zprávu + %s v %s hodin + Recept odeslán na %s . + Přehled objednávek + Nový + Chod + Objednat + Zdarma pro volajícího. Servisní časy: Po - Pá 8:00 - 20:00 kromě státních svátků + LÉKÁRNA + Vyberte požadovaný PIN + Požadovaný PIN byl uložen + Momentálně otevřené a blízko mě + Filtrovat podle … + spustit vyhledávání + přímé zadání + lékárny + telefonní číslo (nepovinné) + Hledejte podle jména nebo adresy + Žádné platné informace o lékárně + O této lékárně nebyly nalezeny žádné aktuální informace. Záznam pro tuto lékárnu bude smazán. + OK + Adresář lékáren není k dispozici + V současné době nelze získat žádné aktuální informace o této lékárně. Zkontrolujte prosím své internetové připojení. + Přerušit + Zkus to znovu + Zachraňte životní prostředí + Přihlášení není možné + Zdá se, že vaše biometrické přihlašovací údaje se změnily. Zaregistrujte se prosím znovu pomocí své zdravotní karty. + Přerušit + Registrovat + profil 1 + Blízko mě + Splatný později + Lze uplatnit od %s + vylepšení produktu + Anonymní analýza + Pomozte nám tuto aplikaci vylepšit. Všechny údaje o používání jsou shromažďovány anonymně a slouží pouze ke zlepšení uživatelské zkušenosti. + zabezpečení zařízení + osobní nastavení + Přístupnost + vylepšení produktu + Přidán recept + Recept je již k dispozici + Při importu došlo k chybě + Uhasit + Naskenovaný předpis + Náhrada možná + Zapomněli jste PIN + + %s recept + + + %s Recepty + + Přečetl jsem a přijímám zásady ochrany osobních údajů a podmínky použití. + Ochrana dat + Podmínky použití + Rádi bychom: + Zlepšete použitelnost. + Zjistit chyby a pády. + Všechna data jsou samozřejmě sbírána anonymně. + Toto rozhodnutí můžete kdykoli změnit v nastavení systému. + Pokračovat + Akceptovat + Tato aplikace používá nejbezpečnější metodu poskytovanou vaším zařízením. + Uložit do počítače + Vybrat + lék + jméno výrobku + Ano + Ne + dávkování + datum vydání + Tento předpis vám bude vyplacen jako součást léčby. + Nespecifikováno + doplatek + lék + Dodací listy + Způsobilé podle BVG + alternativní příprava + název receptu + Obal + crafting instrukce + Popis + dána + vydáno dne: + aktivní složka + předepsané + Dostávat + Co je to přímé zadání? + V případě přímého doporučení se recept z praxe nebo nemocnice vyplácí přímo v lékárně. Pojištěnci nemusejí činit žádnou akci a nemohou zasahovat do procesu odkupu. \n\n Přímá doporučení jsou uvedena v aplikaci e-recept, aby pro vás byla vaše léčba transparentnější. + poplatek za pohotovostní službu + Někdy je potřeba spěchat. Některé recepty lze uplatnit bez dodatečného placení poplatku za pohotovostní službu, například v noci nebo o státních svátcích. + Léky podléhající spoluúčasti + Osvobozeno od spoluúčasti + Osoby se zákonným zdravotním pojištěním musí za léky na předpis zaplatit spoluúčast až deset eur. \n\n Výše doplatku závisí na ceně vašeho léku. Léky, které stojí méně než 5 EUR, si musíte zaplatit sami.\n Za léky, které jsou dražší, musíte zaplatit deset procent z ceny, minimálně však 5 € a maximálně 10 €. \n\n Děti a mládež do 18 let jsou obecně od spoluúčasti osvobozeni. \n\n Pokud vaše roční náklady na léky překročí váš finanční limit, můžete být od spoluúčasti osvobozeni. Promluvte si o tom se svou zdravotní pojišťovnou. + Jste osvobozeni od spoluúčasti tohoto léku. Náklady na léky uhradí vaše zdravotní pojišťovna. + Jak dlouho je tento předpis platný? + Během tohoto období můžete svůj recept uplatnit v jakékoli lékárně s maximálním doplatkem 10 EUR. + Náhrada možná + Vzhledem k zákonným požadavkům vaší zdravotní pojišťovny vám může být poskytnuta alternativa se stejnou účinnou látkou. \n\n Léky mohou vypadat a jmenovat se různě, mít různé ceny i výrobce, ale stále obsahují stejnou účinnou látku. Pro účinek léků v organismu je důležitá především samotná účinná látka a dávkování. Pacienti v lékárně často dostanou jiný lék, než jaký jim lékař předepsal na receptu – pokud jsou léky srovnatelné. Pro změnu mohou existovat terapeutické a ekonomické důvody. + Naskenovaný předpis + Z bezpečnostních důvodů nesmí receptury importované z papírového výtisku zobrazovat žádné osobní nebo lékařské údaje. \n\n Přihlaste se do této aplikace pomocí zdravotní karty nebo pojišťovací aplikace a zobrazte všechny informace obsažené v předpisu. + Recept nesprávný + Tento předpis byl vystaven chybně. + Naskenovaný předpis + poplatek za pohotovostní službu + Dávkování dle písemného návodu + telefon + místo + Pošta + Třídění podle vzdálenosti není možné. + OK + Zadejte aktuální PIN + Zadán nesprávný PIN + Aktuální PIN vaší zdravotní karty + karta zablokována + Odblokujte kartu v Nastavení > Odblokovat kartu. + Z bezpečnostních důvodů zadejte svůj aktuální PIN. + Zapomněli jste PIN + Nesprávný recept + lék + Zdá se, že se při vytváření vašeho receptu něco pokazilo. Nahlásit chybu? + Zpráva + Nepřihlášen + Registrován u + zdravotní průkaz + biometrie + Nepřihlášen + Váš názor nás zajímá. Věnujte prosím pět minut odpovědi na náš průzkum. Děkuji předem. + varovné upozornění + Lékárna přidána do oblíbených + Lékárna byla odebrána z oblíbených + Moje lékárny + Síla hesla velmi dobrá + Operace zápisu se nezdařila + PIN se nepodařilo uložit + Zpráva + Přiřadit PIN + Porušeno pravidlo přístupu + Nemáte oprávnění pro přístup k adresáři map. + Přiřaďte svůj vlastní pin + Karta je zabezpečena PIN od vaší zdravotní pojišťovny (PIN pro přepravu), přidělte si prosím vlastní PIN. + Heslo nenalezeno + Na vaší kartě není uloženo žádné heslo. + Byli jste odhlášeni + Chcete-li aktualizovat své recepty, znovu se přihlaste. + číslo účinné látky + síla a jednota + Uplatněno před %s minutami + Uplatněno %s + Vykoupeno právě teď + Uplatněno v %s hodin + objednávky + Tento předpis byl pro vás vykoupen jako součást léčby. + poplatek za pohotovostní službu + Tento recept nelze vyplnit v noci v lékárně bez doplatku poplatku za pohotovostní službu. + Hledej tady + Nápady + Sdílejte polohu v nastavení. + Blízko mě + Podržením upravíte název. + Zadejte nový název profilu. + Abyste mohli dostávat digitální recepty z vaší praxe, musíte být přihlášeni. + Přijímat recepty digitálně? + Pro obnovení přetáhněte obrazovku dolů. + Žádné recepty + Přidejte recepty pomocí tlačítka + v pravém horním rohu. + Registrovat + archiv receptů + Možná později + Registrovat + Upravit profilový obrázek + archiv receptů + Napište jméno + Uložit do počítače + Moje objednávka + Příjemce: in + recepty + LÉKÁRNA + Poslat + Změna + Vyzvedněte v lékárně + Doručení kurýrem + Doručení poštou + %s Recepty + Uplatnění není možné + Jeden nebo více receptů nebylo možné uplatnit. + Není vybrán žádný recept + Pro uplatnění receptů je nutné vybrat alespoň jeden recept. + Přidejte kontaktní informace + Změna + Žádný předpis + Momentálně nemáte žádné recepty s možností uplatnění + sbírka + poslíček + náklad + vybrat recepty + Klepnutím sem naskenujete recepty + Dlouhým stisknutím upravíte jména + Přidejte další profily, např. pro vaše děti nebo rodiče + Klepnutím na displej přeskočíte zobrazený tip nástroje. + Jak vykoupit? + Jak byste chtěli dostávat své léky? + Uplatnit přímo + Uplatněte léky na místě + Objednat + Rezervujte nebo nechte dovézt + Připraveno + kolektivní kód + jednotlivé kódy + + Máte %s předpis. + + + Máte %s receptů. + + provést výběr + Všechny recepty + Jaké recepty? + Dále + Dále + Zjistěte více + Oznámení + Tato aplikace používá k rozpoznání kódů software od Googlu. + Zjistěte více + O skeneru kódů receptů + Jaká data obsahuje kód receptury? + Kód receptury obsahuje pouze identifikátor receptury. To umožňuje, aby byl recept nalezen na předpisové službě v digitální zdravotnické síti. Kód předpisu neobsahuje žádné údaje o vás nebo vašich lécích. + Takže jen s kódem receptu nemůže nikdo nic dělat? + Opravit. Údaje o receptu je nutné stáhnout ze služby předpisu. To vyžaduje bezpečné přihlášení. + Kdo se může zaregistrovat ke službě receptů? + Registraci k preskripční službě v síti digitálního zdraví mohou mít pojištěnci, lékárny, lékařské ordinace a nemocnice. + Proč aplikace pro elektronický předpis používá funkce Google? + Google nabízí funkce, které lze snadno zabudovat do aplikací a které společnost Google neustále vyvíjí a aktualizuje. To zajišťuje, že funkce fungují na mnoha různých koncových zařízeních a mohou být bezpečně provozovány. Aplikace využívá funkci ke zlepšení funkcí fotoaparátu a skenování pro zařízení Android (Google ML Kit). + Jak funguje vylepšení skenování sady Google ML Kit? + Google ML Kit pomáhá optimalizovat obraz snímaný kamerou tak, aby bylo možné číst kódy receptů i za zhoršených světelných podmínek nebo se staršími modely fotoaparátů. + Budou údaje o předpisu nebo mém léku předány společnosti Google? + Ne. Načtený kód receptu se uloží přímo v aplikaci. Nebudou předány společnosti Google. Údaje o předpisech nejsou uloženy v kódu, pouze v digitální zdravotnické síti. Odtud jsou odeslány do aplikace. Google nemá přístup k digitální zdravotnické síti. + Jaká data zpracovává Google při používání ML Kit? + Google má přístup pouze k technickým informacím o použitém koncovém zařízení a obecném použití doplňkové funkce (např. chybovost, nastavení fotoaparátu), aby to mohl statisticky zaznamenat a tím doplňkovou funkci vylepšit. Když přistupujete, Google dočasně zaznamená IP adresu vašeho koncového zařízení. Informace o vás a obsah receptu nebudou společností Google zaznamenány. + Je používání Google ML Kit dobrovolné? + Ano. Sada ML Kit je však zabudována do skeneru kódu receptu ve verzi aplikace pro elektronický předpis pro Android. Pokud používáte čtečku receptových kódů na zařízení Android, vždy se také použije funkce ML Kit. Můžete se však obejít bez použití skeneru kódů receptů. Vaše recepty lze také načíst do aplikace, pokud se zaregistrujete v digitální zdravotní síti pomocí elektronické zdravotní karty nebo prostřednictvím aplikace zdravotního pojištění. + Mohu vidět, kdo si prohlížel mé recepty? + Ano. Veškerý přístup k vašim datům je plně přihlášen do digitální zdravotnické sítě. V aplikaci elektronického receptu můžete vidět, kdo měl přístup k vašim datům. + Na koho se mohu obrátit, pokud mám dotazy k aplikaci nebo elektronickému receptu? + Podrobné informace naleznete v prohlášení o ochraně údajů. + Předepsaný počet balení + Žádné recepty + K tomu potřebujete splatné recepty. + vybrat pojištění + Hledejte pojištění + Přerušit + O co byste se chtěli ucházet? + Pro tuto aplikaci potřebujete kartu a související PIN. + Jak byste chtěli kontaktovat svou pojišťovnu? + Vaše pojišťovna nabízí následující možnosti kontaktu + Vaše pojišťovna nabízí následující možnosti kontaktu + Zavřít + PIN zadaný nesprávně. + Nesprávně zadané přístupové číslo + PUK zadaný nesprávně. + výdajové doklady + Zobrazit účtenky na výdaje + výdajové doklady + Chcete-li přijímat potvrzení o výdajích, musíte být připojeni k serveru. + Připojit + Žádné výdajové doklady + Deaktivovat + Přerušit + zakázat funkci + Tímto smažete všechny účtenky z tohoto zařízení a ze serveru. + Přijímejte stvrzenky o výdajích + Vaše účtenky jsou také uloženy na receptovém serveru. + Dostávat + Celkem: %s %s + Vybrat + Rozdělit + Uhasit + Uhasit + Předložit + %s € + Celková cena + Tip: Odešlete účtenky o výdajích prostřednictvím aplikace pojištění + Odešlete účtenky snadno prostřednictvím aplikace vaší pojišťovny. V dalším kroku vyberte tuto aplikaci a stiskněte Sdílet. + Praxe + LÉKÁRNA + datum + zobrazit více + ID léku + Vydáno pro + KVNR: %s + Datum narození: %s + OK + Jak předáváte účtenky? + Přeneste se přímo do aplikace vaší pojišťovny / asistenční kanceláře. Chcete-li to provést, vyberte aplikaci na další stránce. + nebo + Uložte soubor a později jej importujte do portálu pojištění/pomoci. + Článek: %s + Číslo: %s + DPH: %s %% + Hrubá cena v EUR: %s + Další poplatky + poplatek za pohotovostní službu + Poplatek za BTM + T poplatek za předpis + pořizovací náklady + Kurýrní služba + Celkem v EUR: %s + odvod + Opravdu smazat? + Soubor bude odstraněn z vašeho zařízení a ze serveru. + Uhasit + Vyslán + PSČ + Umístění + Chcete-li nás kontaktovat, zadejte své PSČ. + Při kontaktu s námi prosím uveďte své bydliště. + Bude pro vás vykoupeno + Bylo pro vás vykoupeno + Pro použití této služby musíte být přihlášeni. + aplikace pojištění + zdravotní průkaz + Je vyžadován přidružený PIN + Chcete-li přijímat protokoly o přístupu, musíte být připojeni k serveru. + V této lhůtě ještě můžete recept vyplnit v lékárně, ale celou kupní cenu za léky si budete muset zaplatit sami. Případně můžete požádat svou praxi o opětovné vystavení receptu. + Připraveno + Požádejte o opravu + V lékárně + V aplikaci + Nechte si tento kód naskenovat ve své lékárně. + Žádost o opravu vyúčtování + diff --git a/android/src/main/res/values-da/strings.xml b/android/src/main/res/values-da/strings.xml new file mode 100644 index 00000000..2a6966b2 --- /dev/null +++ b/android/src/main/res/values-da/strings.xml @@ -0,0 +1,852 @@ + + + Okay + Afbryde + Vend tilbage + rundt om + Digital. Hurtig. Sikker. + Opgave-id + adgangskode + Vilkår for brug + Data beskyttelse + opskrifter + Kameraadgang nægtet + For at bruge scanneren skal du give appen adgang til dit kamera i systemindstillingerne. + Fokuser kameraet på en opskriftskode + Dette er ikke en gyldig receptkode + Denne receptkode er allerede blevet scannet + + %s opskrift genkendt + %s opskrifter genkendt + + Afbryde + kamera lys + Vil du annullere scanningen? + Okay + Fortryd ikke + Nu sker det + Hvad du har brug for: + Indtast kortadgangsnummer + indtaste PIN-koden + Prøv igen + Kunne ikke oprette forbindelse til serveren. + + Du har %s forsøg mere, før dit kort blokeres. + Du har %s forsøg mere, før dit kort blokeres. + + Du finder adgangsnummeret øverst til højre på dit sundhedskort. + Afbryde + Søg efter kort... + Hold sundhedskortet på bagsiden af din enhed. + Søger stadig … + Flyt langsomt kortet bag på enheden. + Tip + Enhedsetuier kan gøre det vanskeligt at oprette forbindelse via NFC. + kort genkendt + Prøv ikke at flytte sundhedskortet. + Sundhedskort fundet. Bevæg dig ikke. + forbindelse afbrudt + Hold dit sundhedskort på bagsiden af enheden igen + Version: %s + Byg Hash: %s + fejlretningsmenu + Åben indtil %s + Åbent hele dagen + aftryk + redaktør + gematik GmbH\n Friedrichstrasse 136\n 10117 Berlin + Administrerende direktør: Dr. medicinsk Markus Leyck-Dieken\n Tinglysningsret: byretten Berlin-Charlottenburg\n Handelsregisternummer: HRB 96351\n Moms-identifikationsnummer: DE241843684 + Ansvarlig for indholdet + dr medicinsk Markus Leyck-Dieken + Kontakt + Varsel + Vi bestræber os på at bruge et kønsneutralt sprog. Hvis du bemærker fejl, ser vi frem til at høre fra dig via e-mail. + Tysklands moderne platform for digital medicin + skrive mail + åben hjemmeside + Velkommen + Start registreringen + låse op + Tilmeld + Afbryde + Sikkerhed + gyldige + aftryk + data beskyttelse + Vilkår for brug + detaljer + Markér som indløst + Markér som ikke indløst + doseringsform + pakkestørrelse + Forsikret person + Efternavn + adresse + fødselsdato + Sygesikring / betalere + status + forsikringsnummer + Foreskrivende person + Efternavn + Medicinsk specialist + Lægenummer (LANR) + institution + Efternavn + adresse + Erhvervslokalets nummer + telefonnummer + mail addresse + arbejdsulykke + ulykkesdag + Ulykkesvirksomheds- eller arbejdsgivernummer + Vil du slette denne opskrift permanent? + Sluk + Afbryde + åbningstider + internet side + Kan kun indløses i dag som selvbetaler + Tilmeld + Aktiver NFC + Aktiver venligst NFC-funktionen på din enhed for at logge på med dit sundhedskort. + Aktiver + Korrekt + Indløste recepter? + Vil du markere recepterne som indløste? + Ikke indløst + Forløst + Åbner kl. %s + +49 800 277 377 7 + Teknisk hotline + Åbn scanner for opskrifter + Ideer + Undertryk skærmbilleder + Forhindrer visning af et miniaturebillede, når der skiftes app + Tillader du e-opskrifter at analysere din brugsadfærd anonymt? + Teknisk information + Sikkerhed for dine receptdata + Sørg for, at personer, som du må dele denne enhed med, og hvis biometriske karakteristika kan være gemt på denne enhed, også har adgang til dine recepter. + afsendelse mislykkedes + Intet e-mail-program opsat + Ingen resultater + Vi kunne ikke finde nogen resultater for denne søgeterm. + Open Source-licenser + Kontakt + Ring til teknisk hotline + Deltag i undersøgelsen + +49 800 277 377 7 + Jeg vil gerne hjælpe med at gøre denne app bedre + Dette inkluderer hardware- og softwareoplysninger på din telefon, indstillinger for e-recept-appen og omfanget af brug, men aldrig data om dig personligt eller dit helbred. + Dataene stilles kun til rådighed for gematik GmbH af databehandleren og slettes senest efter 180 dage. Du kan til enhver tid deaktivere analysen igen i appmenuen. + Disse data gør det muligt for os at forstå, hvilke funktioner der bruges hyppigt, og at forbedre dem. Ydermere kan vi vurdere, hvor længe ældre teknologi skal understøttes, og hvornår vi for eksempel kan gøre en nyere version af operativsystemet obligatorisk uden at påvirke (for mange) brugere. + forbedre app + Anonym analyse forbliver deaktiveret + %s Tak for din støtte! + Tilmeld + Identificer dig selv for at downloade opskrifter. + Bemærkning til apoteker: Vi indhenter kontaktoplysninger og oplysninger om apoteker fra mein-apothekenportal.de fra den tyske apotekerforening Har du opdaget en fejl eller vil du rette data? + Lær mere + apoteker + Desværre virkede det ikke \uD83D\uDE15 + Prøv det igen. + Indtast adgangskode + Yderligere + Tilgængelighed + zoom + Giver dig mulighed for at forstørre appen ved at knibe eller sprede fingrene (knib for at zoome). + adgangskode + Sikre dine data med en adgangskode efter eget valg. + adgangskode + Gem på computer + Vis adgangskode + Gentag adgangskode + Anbefalinger: %s + skrive mail + Når du sender din besked, vil følgende oplysninger om den anvendte hardware og det anvendte operativsystem blive transmitteret: + Indløs kun på stedet + Du kan endnu ikke sende e-recepter til dette apotek. + I øjeblikket åben + Kurertjeneste + Forsendelse + filter + Filter + Ingen tilgængelig placering + Forstået + Gentagne password-matches + Fejl 20 10 76631 + Dit sundhedskortbevis er ugyldigt. Er dit kort udløbet? Kontakt venligst din sygesikring. + Mislykkede loginforsøg + + %s mislykkede loginforsøg blev fundet. + %s mislykkede loginforsøg blev fundet. + + Vælg den bedste sikkerhedskopiering af enheden + Dette kan være et fingeraftryk, swipe-mønster eller lignende + tokens + adgangstoken + SSO-tokens + Ingen adgangstoken tilgængelig + intet tilgængeligt SSO-token + kopieret til udklipsholderen + Klik for at kopiere tokenet til udklipsholderen + Gælder kun i dag + Give lov til + ingen forbindelse til serveren + Prøv venligst igen om et par minutter + Indlæs igen + vise poletter + Hvordan vil du gerne sikre appen? + Varsel + Der er ikke konfigureret sikkerhedskopiering af enheden for denne enhed + Vi anbefaler, at du yderligere beskytter dine medicinske data med enhedssikkerhed såsom en adgangskode eller biometri. + Vis ikke denne meddelelse igen i fremtiden. + Forbindelsen mislykkedes. En netværksforbindelse kunne ikke etableres. + Kommunikation med serveren mislykkedes: statuskode %s . + Kunne ikke kommunikere med serveren: Tjek venligst internetforbindelsen og indstillingerne for tid/dato. + advarsel + Din enhed kan have nedsat sikkerhed + Dette kan for eksempel være forårsaget af manipulerede enheder eller en aktiveret udviklertilstand. Af sikkerhedsmæssige årsager anbefaler vi ikke at bruge appen på jailbroken enheder. + Jeg anerkender den øgede risiko og ønsker stadig at fortsætte. + Hvorfor er enheder med root-adgang en potentiel sikkerhedsrisiko? + Lær mere + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Profil navn + Indtast venligst et navn til den nye profil. + profil navn + profiler + Sådan genkender du et NFC-aktiveret sundhedskort + Ingen kontakt mulig via denne app + Brug venligst de sædvanlige kanaler til at kontakte dit forsikringsselskab. + Sundhedskort og pinkode + Kun pinkode + Tilmelding i e-recept-appen + Navnefeltet må ikke være tomt. + Der findes allerede en profil med det indtastede navn. + profil + %s valgt + baggrundsfarve + forårsgrå + soldug + Det! Er! Lyserød! + Træ + Blå måne september + Ikke logget ind + Bundet sammen + Sidst tilsluttet den %s + Vil du slette profilen? + Dette vil slette alle profildata på denne enhed. Dine recepter i sundhedsnetværket forbliver intakte. + Sluk + Afbryde + slette profil + Du vil slette den sidste profil. + Appen kræver mindst én profil. Indtast venligst et navn til den nye profil. + Fejl 20 10 76831 + Biblioteket med sundhedskort kunne ikke nås. Prøv igen. + Du kan finde ekspertverificerede oplysninger om sygdomme, ICD-koder og om forebyggelses- og plejespørgsmål på den nationale sundhedsportal. + Åbn Gesund.bund.de + Vi har ændret privatlivspolitikken + E-recept-appen har udviklet sig. Dette har gjort det nødvendigt at opdatere vores privatlivspolitik. + Åbn privatlivspolitik + Dette har ændret sig siden %s : + Hvad sker der, når du åbner appen? + Hvad sker der, hvis jeg bruger kamerafunktionen/læser opskrifter med kameraet? + Ingen nye opskrifter tilgængelige + + %s ny opskrift + %s nye opskrifter + + Indløses + I forløsning + Forløst + Ukendt + Se adgangslogfiler + Hvem fik adgang til dine opskrifter og hvornår? + Adgangsnøgle til receptservicen + adgangslogfiler + Ingen adgangslogs + Der er endnu ingen adgangslogfiler. + Opskriften er i gang og kan ikke slettes + Acceptere + Det virkede åbenbart ikke + Vi er klar over, at sammenhængen med sundhedskortet har sine faldgruber. Fremover bør registrering derfor også være mulig via en allerede godkendt sygesikringsapp. \n\n Vi arbejder også på at gøre det muligt at indløse recepter digitalt uden registrering. \n\n Har du bemærket noget under denne proces, som du gerne vil dele med os? Skriv venligst til os, vi er også glade for at modtage meget kritisk feedback. + Tilslutningstips + Forbedre styrken af forbindelsen + Fjern om nødvendigt beskyttelsesdækslet. + Hvis enheden vibrerer og derefter afbryder forbindelsen, skal du søge efter den optimale position inden for en lille radius. + Flyt enheden meget langsomt hen over kortet. + Placer enheden direkte på kortet. + For at gøre dette skal du placere sundhedskortet på en flad overflade (f.eks. et bord). + Forbedre styrken af forbindelsen + Bemærk placeringen af NFC-sensoren + Find ud af, hvor NFC-sensoren er placeret i din enhed (her f.eks. en oversigt for enheder fra %s ). + I nogle tilfælde kan positionen af NFC-sensoren variere inden for en modelserie (her f.eks. oplysningerne for %s ). + Næste tip + Yderligere + Tæt + Prøv + skriv til os + Apotek søgelicens + Indløs + Scannet recept + Scannet den %s + Markeret som indløst den %s + Hvordan vil du fortsætte? + Bestille + Tilgængelig snart + Reserver nu til afhentning eller få det leveret med kurerservice eller forsendelse + Gem til senere bestilling + Gem opskrifter på enheden + + Fortsæt med %s opskrift + Fortsæt med %s opskrifter + + Sundhedskortet kunne ikke tilsluttes + Den aktuelle profil er allerede forbundet med et andet sundhedskort (sygesikringsnummer %s ). + Dit sundhedskort er allerede forbundet med en anden profil. Skift til profil %s . + Gem på computer + kontaktoplysninger og adresse + Kontakt + telefonnummer + Angiv venligst et telefonnummer for kontakt. + Mailadresse (valgfrit) + Leveringsadresse + fornavn og efternavn + Indtast et for- og efternavn til kontaktformål. + Gade og husnummer + Indtast venligst gade og husnummer, så vi kan kontaktes. + Yderligere adresse (valgfrit) + Leveringsinstruktion (valgfrit) + Yderligere kontaktoplysninger påkrævet + Vil du kassere ændringer? + kassere + Til søgningen bruger apotekskataloget geo-koordinater, der blev bestemt ved hjælp af OpenStreetMap. Vi takker projektet for denne hjælp. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Privatliv og brug + Yderligere + Du har modtaget din pinkode i et brev fra dit sygesikringsselskab. + Ingen pinkode modtaget + pinkode + Tjek forbindelsen til internettet og klokkeslættet/datoindstillingen på din enhed. + For at logge på, tryk på \"Lås op\". + låst ude? Bekræft venligst dine biometriske legitimationsoplysninger på denne enhed. + Glemt kodeord? Slet venligst appen og geninstaller den. Du kan finde ud af hvorfor i vores %s . + hjælpeområde + pakkestørrelse og enhed + aktiv ingrediens + Mængden af aktiv ingrediens + batchbetegnelse + Exp + kategori + Vaccine + Acceptere + Fortryd + Varsel + Hjælp os med at gøre denne app bedre + Indtast adgangskode + Adgangskoden skal være mindst otte tegn lang + Adgangskodestyrken er ikke tilstrækkelig + Adgangskodestyrke tilstrækkelig + Adgangskoden er synlig + Adgangskoden er ikke synlig + biometri + adgangskode + venter på svar + Ingen recepter + Du har i øjeblikket ingen indløselige recepter. + At opdatere + Automatisk logout + Af sikkerhedsmæssige årsager afbrydes forbindelsen til receptserveren efter 12 timer. Tilslut igen for at få aktuelle opskrifter. + Forbinde + Har du modtaget en papirkopi? + Tilføj opskrifter til din liste ved at trykke på scanningsknappen i øverste højre hjørne. + Scan papirudskrift + Du skal være logget ind for at modtage opskrifter automatisk. + Tilmeld + Ingen indløste recepter + Dine indløste recepter vises her. Af databeskyttelsesmæssige årsager vil dine opskrifter blive slettet fra opskriftsserveren efter 100 dage. + Ingen indløste recepter + Dine indløste recepter vises her. Tilføj recepter via scanning for at begynde at indløse. + enhedshåndtering + Tilsluttede enheder + Registreret siden %s (denne enhed) + Registreret siden %s + Af sikkerhedsmæssige årsager afbrydes forbindelsen til receptserveren efter 12 timer. For at oprette forbindelse igen skal du bruge dit sundhedskort og din pinkode for hver forbindelsesproces. + pinkode + Indtast din PIN-kode (sundhedskort). + Yderligere + Tilmeld + Tilsluttede enheder + fjerne enheden? + Afbryde + Fjernet + Vil du fjerne denne enhed? + Vil du fjerne %s ? + Hvis du fjerner %s , vil forbindelsen til opskriftsserveren blive afbrudt permanent om senest 12 timer. + Enheder indlæses... + Ingen enheder + Der er ingen enheder forbundet til dette sundhedskort. + Prøv igen + Åh åh :-( + Enhedslisten kunne ikke indlæses. + wwweg… + Ingen internetforbindelse. + Medicin og forbindinger + narkotika + Udlevering af receptpligtig medicin efter § 4 AMVV + Har du brug for hjælp? + Vi har samlet nogle tips til dig for at løse de mest almindelige problemer. + Startforbindelsestips + låse op + kortet er spærret + PIN-koden blev indtastet forkert tre gange. Dit kort er derfor blevet spærret af sikkerhedsmæssige årsager. + låse op kortet + Indtast PUK + Med din PIN-kode har du modtaget en 8-cifret PUK fra dit forsikringsselskab. + Vælg ny pinkode + Du kan selv vælge dit nye personlige identifikationsnummer (PIN) (6 til 8 cifre). + PIN-kode husket? + Noter venligst din PIN-kode og opbevar den et sikkert sted. + Afbryde + Okay + Det er ikke muligt at låse op + Du har nået det maksimale antal kortoplåsninger med denne PUK eller indtastet den forkert gentagne gange. Kontakt venligst dit forsikringsselskab. + Du kan bruge én PUK til op til 10 oplåsninger. + kort låst op + Hvad du har brug for: + dit sundhedskort + PUK på dit sundhedskort + Yderligere + sundhedskort + Bestil pinkode eller kort + Tilmeld + Hvordan vil du logge ind? + NFC-aktiveret sundhedskort + PIN-kode til sundhedskortet + Har du ikke et NFC-aktiveret sundhedskort og pinkode endnu? + Ansøg nu + Eller: Log på med %s . + Din sygesikring app + "Dit adgangsnummer kan findes i øverste højre hjørne af dit sundhedskort." + Mit kort har ikke et adgangsnummer + + Du har %s forsøg mere, før dit kort blokeres. + Du har %s forsøg mere, før dit kort blokeres. + + Sæt sundhedskortet på bagsiden af telefonen + Den følgende proces kan tage op til 30 sekunder. + Placer kortet %s på bagsiden af telefonen. + i øverste højre hjørne + i den øverste midte + øverst til venstre + i det midterste område til højre + midten + i midten til venstre + i det nederste højre område + i den nederste midte + nederst til venstre + Hjælp + Sendt for %s minutter siden + Sendt den %s + Sendt lige nu + Sendt klokken %s + Ikke længere gyldig + Log ind med appen + vælge forsikring + Fandt du ikke det, du ledte efter? Denne liste bliver konstant udvidet. Registrering med et sundhedskort understøttes allerede af alle sygeforsikringsselskaber. + Feedback fra e-recept-appen + Vi ser frem til din feedback. Brug venligst pladsen nedenfor og vær så præcis som muligt: + PUK + Tæt + Hvor er det synd… + Din enhed opfylder desværre ikke minimumskravene for at logge ind på e-recept-appen. Mindst Android 7 og en NFC-chip er påkrævet for sikker autentificering med dit sundhedskort. + Lær mere + Vil du gemme login-data? + Gem på computer + Gem ikke + Varsel + Af sikkerhedsmæssige årsager afbrydes forbindelsen til receptserveren efter 12 timer. For at oprette forbindelse igen skal du bruge et sundhedskort og en pinkode for hver forbindelsesproces. + Opsæt biometrisk sikkerhed + Det er ikke muligt at gemme adgangsdata. Konfigurer biometrisk sikkerhed (f.eks. fingeraftryk) på din enhed på forhånd. + Afbryde + Ideer + Varsel + Acceptere + Sikkerhed for dine receptdata + \"Denne app bruger den mest sikre biometriske sensor fra din enhed til at gemme dine legitimationsoplysninger i et sikkert område af enhedens hukommelse.\" + Den biometriske sikkerhed af dine adgangsdata giver dig mulighed for at åbne denne app i fremtiden uden at skulle indtaste din pinkode eller et sundhedskort, og for at se, ringe op, indløse eller slette recepter. + Sørg for, at personer, som du må dele denne enhed med, og hvis biometriske karakteristika kan være gemt på denne enhed, også har adgang til dine recepter. + det virkede desværre ikke + Godkendelse med sygesikringsappen mislykkedes. + Udløb %s + Opskriften er allerede blevet slettet fra serveren + Ret venligst dit input eller kasser ændringer + Korrekt + forsikrede data + Efternavn + Forsikring + forsikringsnummer + kortadgangsnummer + Tilmeld + Afmeld + Gem på computer + Lave om + Rediger profilbillede + Yderligere + serveren svarer ikke + Prøv igen senere. + Prøv igen + Se efter forsikring + Vil du oprette forbindelse til opskriftsserveren nu? + Logget ind + forbindelse afbrudt + Vil du oprette forbindelse til opskriftsserveren nu? + Ingen tokens + Du modtager et token, når du er logget ind på receptservicen.\n + Ordre:% s + Vælg den ønskede PIN-kode + låse op kortet + Vælg PIN + Gentag PIN-koden + Indtastningerne adskiller sig fra hinanden. + Ingen ordrer + Du har ingen ordrer endnu. + Lige nu + Klokken %s + Indkøbskurven er klar + Opskriften er tilføjet til din indkøbskurv. Gå til apotekets hjemmeside for at gennemføre bestillingen. + Åben indkøbskurv + Vis denne afhentningskode på apoteket. + Modtag afhentningskode + Meddelelsen kan ikke vises + Kontakt venligst dit apotek ( %s ). + Vis kurvlink + Vis afhentningskode + Vis beskeden + %s klokken %s + Opskrift sendt til %s . + Ordreoversigt + Ny + Rute + Bestille + Gratis for den, der ringer. Servicetider: Man-fre 8:00 - 20:00 undtagen på nationale helligdage + Apotek + Vælg den ønskede PIN-kode + Ønsket pinkode gemt + I øjeblikket åben og i nærheden af mig + Sorter efter … + start søgning + direkte opgave + apoteker + Telefonnummer (valgfrit) + Søg på navn eller adresse + Ingen gyldige apoteksoplysninger + Der blev ikke fundet nogen aktuelle oplysninger om dette apotek. Indgangen til dette apotek vil blive slettet. + Okay + Apotekets bibliotek er ikke tilgængeligt + I øjeblikket kan der ikke hentes aktuelle oplysninger om dette apotek. Tjek venligst din internetforbindelse. + Afbryde + Prøv igen + Gem miljø + Login er ikke muligt + Det ser ud til, at dine biometriske loginoplysninger er ændret. Tilmeld dig igen med dit sundhedskort. + Afbryde + Tilmeld + profil 1 + Tæt på mig + Indløses senere + Kan indløses fra %s + produktforbedringer + Anonym Analyse + Hjælp os med at gøre denne app bedre. Alle brugsdata indsamles anonymt og bruges kun til at forbedre brugeroplevelsen. + enhedssikkerhed + personlige indstillinger + Tilgængelighed + produktforbedringer + Tilføjet opskrift + Opskriften er allerede tilgængelig + Der opstod en fejl under import + Sluk + Scannet recept + Erstatning mulig + Glemt pinkode + + %s opskrift + %s Opskrifter + + Jeg har læst og accepterer privatlivspolitikken og brugsbetingelserne. + Data beskyttelse + Vilkår for brug + Vi vil gerne have: + Forbedre brugervenligheden. + Opdag fejl og nedbrud. + Alle data indsamles naturligvis anonymt. + Du kan til enhver tid ændre denne beslutning i systemindstillingerne. + Blive ved + Acceptere + Denne app bruger den mest sikre metode fra din enhed. + Gem på computer + Vælge + medicin + handelsnavn + Ja + Ingen + dosering + udstedelsesdato + Denne recept vil blive indløst for dig som en del af en behandling. + Ikke specificeret + ekstra betaling + medicin + Følgesedler + Berettiget ifølge BVG + alternativ forberedelse + opskriftens navn + Emballage + håndarbejde instruktion + Beskrivelse + givet af + udstedt den: + aktiv ingrediens + ordineret + Modtage + Hvad er en direkte opgave? + Ved direkte henvisninger indløses en recept fra praksis eller hospital direkte på apoteket. Forsikrede behøver ikke at foretage sig noget og kan ikke gribe ind i indløsningsprocessen. \n\n Direkte henvisninger er angivet i e-recept-appen for at gøre din behandling mere gennemsigtig for dig. + nødhjælpsgebyr + Nogle gange er det nødvendigt at skynde sig. Nogle recepter kan indløses uden yderligere betaling af et nødhjælpsgebyr, såsom om natten eller på helligdage. + Narkotika er omfattet af egenbetaling + Fritaget for egenbetaling + Dem med lovpligtig sygesikring skal betale en egenbetaling på op til ti euro for receptpligtig medicin. \n\n Størrelsen på egenbetalingen afhænger af prisen på din medicin. Du skal selv betale for medicin, der koster mindre end 5 €.\n For medicin, der er dyrere, skal du betale ti procent af prisen, dog mindst 5 € og ikke mere end 10 €. \n\n Børn og unge under 18 år er generelt fritaget for egenbetaling. \n\n Hvis dine årlige udgifter til medicin overstiger din økonomiske grænse, kan du blive fritaget for egenbetalingen. Tal med dit sygeforsikringsselskab om dette. + Du er fritaget for egenbetaling af dette lægemiddel. Din sundhedsforsikring dækker udgifterne til lægemidlet. + Hvor længe er denne recept gyldig? + I denne periode kan du indløse din recept på ethvert apotek med en maksimal ekstra betaling på €10. + Erstatning mulig + På grund af dit sygeforsikringsselskabs lovkrav kan du få et alternativ med det samme aktive stof. \n\n Medicin kan se ud og hedde forskelligt, have forskellige priser og producenter, men stadig indeholde det samme aktive stof. Det aktive stof i sig selv og doseringen er særligt vigtige for lægemidlers virkning i kroppen. Patienter på apoteket får ofte et andet lægemiddel end det, lægen har ordineret på recepten – forudsat at lægemidlerne er sammenlignelige. Der kan være terapeutiske og økonomiske årsager til ændringen. + Scannet recept + Af sikkerhedsmæssige årsager må recepter importeret fra en papirudskrift ikke vise personlige eller medicinske data. \n\n Log ind på denne app med sundhedskort eller forsikringsapp for at se alle oplysninger i recepten. + Opskriften er forkert + Denne recept blev udstedt forkert. + Scannet recept + nødhjælpsgebyr + Dosering i henhold til skriftlige instruktioner + telefon + websted + Post + Det er ikke muligt at sortere efter afstand. + Okay + Indtast den aktuelle PIN-kode + Forkert PIN-kode indtastet + Den aktuelle pinkode på dit sundhedskort + kortet er spærret + Fjern blokeringen af dit kort i Indstillinger > Fjern blokering af kort. + Af sikkerhedsmæssige årsager skal du indtaste din nuværende pinkode. + Glemt pinkode + Forkert opskrift + medicin + Noget ser ud til at være gået galt under oprettelsen af din opskrift. Rapportere en fejl? + Rapport + Ikke logget ind + Registreret med + sundhedskort + biometri + Ikke logget ind + Vi er interesserede i din mening. Brug venligst fem minutter på at besvare vores undersøgelse. Tak på forhånd. + advarselsmeddelelse + Apotek føjet til favoritter + Fjernet apotek fra favoritter + Mine apoteker + Adgangskodestyrke meget god + Skrivehandling mislykkedes + PIN-koden kunne ikke gemmes + Rapport + Tildel PIN-kode + Adgangsreglen er overtrådt + Du har ikke tilladelse til at få adgang til kortbiblioteket. + Tildel din egen pin + Kortet er sikret med pinkode fra dit sygesikringsselskab (transport pinkode), angiv venligst din egen pinkode. + Adgangskode ikke fundet + Der er ingen adgangskode gemt på dit kort. + Du er blevet logget ud + Log ind igen for at opdatere dine opskrifter. + aktiv ingrediens nummer + styrke og enhed + Indløst for %s minutter siden + Indløst den %s + Indløst lige nu + Indløst klokken %s + Ordre:% s + Denne recept blev indløst til dig som en del af en behandling. + nødhjælpsgebyr + Denne recept kan ikke udfyldes om natten på et apotek uden yderligere betaling af et akutgebyr. + Søg her + Ideer + Del placering i indstillinger. + Tæt på mig + Hold nede for at redigere navnet. + Indtast det nye navn til profilen. + Du skal være logget ind for at modtage digitale recepter fra din praksis. + Modtage opskrifter digitalt? + Træk skærmen ned for at opdatere. + Ingen recepter + Tilføj opskrifter ved hjælp af + knappen i øverste højre hjørne. + Tilmeld + receptarkiv + Måske senere + Tilmeld + Rediger profilbillede + receptarkiv + Indtast navn + Gem på computer + Min bestilling + Modtager: in + opskrifter + Apotek + Sende + Lave om + Afhentes på apoteket + Levering med kurer + Levering med post + %s Opskrifter + Indløsning ikke muligt + En eller flere recepter kunne ikke indløses. + Ingen opskrift valgt + For at indløse opskrifter skal der vælges mindst én opskrift. + Tilføj kontaktoplysninger + Lave om + Ingen recept + Du har i øjeblikket ingen indløselige recepter + kollektion + budbringer + Forsendelse + vælge opskrifter + Tryk her for at scanne opskrifter + Langt tryk for at redigere navne + Tilføj flere profiler, fx til dine børn eller forældre + Klik på displayet for at springe det viste værktøjstip over. + Hvordan indløser man? + Hvordan vil du gerne modtage din medicin? + Indløs direkte + Indløs medicin på stedet + Bestille + Reserver eller få det leveret + Parat + kollektiv kode + enkelte koder + + Du har %s recept. + Du har %s opskrifter. + + foretage et valg + Alle opskrifter + Hvilke opskrifter? + Yderligere + Yderligere + Lær mere + Varsel + Denne app bruger software fra Google til at genkende koder. + Lær mere + Om opskriftskodescanneren + Hvilke data indeholder opskriftskoden? + Opskriftskoden indeholder kun en identifikator for opskriften. Det gør, at recepten kan findes på recepttjenesten i det digitale sundhedsnetværk. Receptkoden indeholder ingen data om dig eller din medicin. + Så ingen kan gøre noget med opskriftskoden alene? + Korrekt. Receptdataene skal downloades fra receptservicen. Dette kræver et sikkert login. + Hvem kan tilmelde sig receptservicen? + Tilmelding til recepttjenesten i det digitale sundhedsnetværk er muligt for forsikrede, apoteker, lægepraksis og hospitaler. + Hvorfor bruger e-recept-appen Google-funktioner? + Google tilbyder funktioner, der nemt kan indbygges i apps, og som konstant udvikles og opdateres af Google. Dette sikrer, at funktionerne fungerer på mange forskellige slutenheder og kan betjenes sikkert. Appen bruger en funktion til at forbedre kamera- og scanningsfunktionaliteten til Android-enheder (Google ML Kit). + Hvordan virker Google ML Kit-scanningsforbedring? + Google ML Kit hjælper med at optimere billedet optaget af et kamera, så opskriftskoderne kan læses selv under dårlige lysforhold eller med ældre kameramodeller. + Vil data om recepten eller min medicin blive videregivet til Google? + Ingen. Den læste opskriftskode gemmes direkte i appen. Det vil ikke blive videregivet til Google. Receptdataene gemmes ikke i koden, kun i det digitale sundhedsnetværk. Derfra sendes de til appen. Google har ikke adgang til det digitale sundhedsnetværk. + Hvilke data behandler Google, når du bruger ML Kit? + Google har kun adgang til tekniske oplysninger om den anvendte slutenhed og den generelle brug af tillægsfunktionen (f.eks. fejlrate, kameraindstillinger) for at kunne registrere dette statistisk og dermed forbedre tillægsfunktionen. Når du tilgår, registrerer Google midlertidigt IP-adressen på din slutenhed. Oplysninger om dig og indholdet af opskriften vil ikke blive registreret af Google. + Er brugen af Google ML Kit frivillig? + Ja. ML Kit er dog indbygget i opskriftskodescanneren i Android-versionen af e-recept-appen. Hvis du bruger opskriftskodescanneren på en Android-enhed, bruges ML Kit-funktionen også altid. Du kan dog undvære at bruge opskriftskodescanneren. Dine recepter kan også indlæses i appen, hvis du tilmelder dig det digitale sundhedsnetværk med det elektroniske sundhedskort eller via din sygesikringsapp. + Kan jeg se, hvem der har set mine opskrifter? + Ja. Al adgang til dine data er fuldt logget i det digitale sundhedsnetværk. I e-recept-appen kan du se, hvem der har tilgået dine data. + Hvem kan jeg kontakte, hvis jeg har spørgsmål til appen eller e-recepten? + Du kan finde detaljerede oplysninger i databeskyttelseserklæringen. + Antal foreskrevne pakninger + Ingen recepter + Til dette har du brug for indløselige recepter. + vælge forsikring + Se efter forsikring + Afbryde + Hvad vil du gerne ansøge om? + Til denne app skal du bruge et kort og den tilhørende pinkode. + Hvordan vil du kontakte dit forsikringsselskab? + Dit forsikringsselskab tilbyder følgende kontaktmuligheder + Dit forsikringsselskab tilbyder følgende kontaktmuligheder + Tæt + PIN-koden er indtastet forkert. + Adgangsnummeret er indtastet forkert + PUK indtastet forkert. + udgiftskvitteringer + Vis udgiftskvitteringer + udgiftskvitteringer + For at modtage udgiftskvitteringer skal du være tilsluttet serveren. + Forbinde + Ingen kvitteringer + Deaktiver + Afbryde + deaktiver funktionen + Dette vil slette alle kvitteringer fra denne enhed og fra serveren. + Modtag udgiftskvitteringer + Dine omkostningskvitteringer gemmes også på opskriftsserveren. + Modtage + I alt: %s %s + Vælge + Dele + Sluk + Sluk + Indsend + %s € + total pris + Tip: Indsend udgiftskvitteringer via forsikringsappen + Indsend omkostningskvitteringer nemt via dit forsikringsselskabs app. I det næste trin skal du vælge denne app og trykke på Del. + Øve sig + Apotek + Dato + Vis mere + Lægemiddel-id + Udstedt for + KVNR: %s + Fødselsdato: %s + Okay + Hvordan indsender du kvitteringer? + Overfør direkte til dit forsikringsselskabs/bistandskontors app. For at gøre dette skal du vælge appen på næste side. + eller + Gem filen og importer den senere til forsikrings-/hjælpemiddelportalen. + Artikel: %s + Nummer: %s + moms: %s %% + Bruttopris i EUR: %s + Yderligere gebyrer + nødhjælpsgebyr + BTM gebyr + T receptgebyr + indkøbsomkostninger + Messenger service + I alt i EUR: %s + afgift + Virkelig slette? + Filen slettes fra din enhed og fra serveren. + Sluk + Udsendt + Postnummer + Beliggenhed + Indtast venligst dit postnummer for at kontakte os. + Indtast venligst din bopæl, når du kontakter os. + Vil blive indløst for dig + Er blevet indløst for dig + Du skal være logget ind for at bruge denne tjeneste. + forsikring app + sundhedskort + Tilknyttet pinkode påkrævet + For at modtage adgangslogfiler skal du være forbundet til serveren. + Du kan stadig udfylde recepten på et apotek inden for denne periode, men du skal selv betale hele købesummen for medicinen. Alternativt kan du bede din praksis om at få genudstedt recepten. + Parat + Anmod om rettelse + På apoteket + I appen + Få denne kode scannet på dit apotek. + Anmodning om faktureringskorrektion + diff --git a/android/src/main/res/values-en/strings.xml b/android/src/main/res/values-en/strings.xml index 91560276..3409a087 100644 --- a/android/src/main/res/values-en/strings.xml +++ b/android/src/main/res/values-en/strings.xml @@ -1,6 +1,5 @@ - - E-prescription + OK Cancel Back @@ -9,7 +8,7 @@ Task ID Access code Terms of Use - Privacy Policy + Privacy policy Prescriptions Access to camera denied To use the scanner, you must allow the app to access your camera in the system settings. @@ -25,7 +24,7 @@ Cancel scanning of prescription codes? Cancel scanning Continue - Let\'s get started + Let\'s go What you need: Enter card access number Enter PIN @@ -73,7 +72,7 @@ Security Legal information Imprint - Privacy Policy + Privacy policy Terms of Use Details Mark as redeemed @@ -173,14 +172,6 @@ No location available Agreed Repeated password matches - - Can still be redeemed for %s day as a self-paying customer - Can still be redeemed for %s days as a self-paying customer - - - Still valid for %s day - Still valid for %s days - Error 20 10 76631 Your medical card\'s certificate is invalid. Your card may have expired. Please contact your health insurance company. Unsuccessful login attempts @@ -205,7 +196,7 @@ Show tokens How would you like to secure this app? Note - No device security has been set up for this device + No device backup has been set up for this device We recommend that you add additional protection for your medical data by securing your device for instance with a code or biometrics. Do not show this message in future. Connection failed. A network connection could not be created. @@ -252,9 +243,9 @@ The register of medical cards could not be reached. Please try again. You can find professionally verified information on illnesses, ICD codes and issues around prevention and healthcare in the National Health Portal. Open gesund.bund.de - We have amended the Privacy Policy - The e-prescription app has evolved, so we have had to update our Privacy Policy. - Open Privacy Policy + We have amended the Privacy policy + The e-prescription app has evolved, so we have had to update our Privacy policy. + Open Privacy policy This has changed since %s: What happens when you open the app? What happens if I use the camera function/read prescriptions using the camera? @@ -272,9 +263,7 @@ This relates to access keys for the prescription service Access logs No access logs - Log into the prescription service to receive access logs. No access logs are available yet. - Last updated on %s The prescription is currently being processed and cannot be deleted Accept That didn\'t seem to work @@ -338,7 +327,7 @@ PIN not received PIN Check your connection to the Internet and your device\'s time/date setting. - Press \"Unlock\" to authenticate yourself. + To log in, press “Unlock”. Locked out? Please review your biometric access data on this device. Forgotten password? Please delete and reinstall the app. Find out why in our %s. Help zone @@ -352,7 +341,7 @@ Accept Undo Note - Would you like to help us improve the app? + Help us make this app better Select own password The password needs to be at least eight characters long Password strength not sufficient @@ -430,10 +419,7 @@ Medical card Order PIN or card Log in - How would you like to authenticate? - Insurance app - Insurance card - Associated PIN required + How do you want to sign in? NFC-enabled medical card Medical card PIN Don\'t have an NFC-enabled medical card and PIN yet? @@ -572,7 +558,7 @@ product improvements Anonymous Analysis Help us make this app better. All user data is collected anonymously and is only used to improve the user experience. - device security + Device security personal settings Accessibility aids product improvements @@ -588,7 +574,7 @@ %s Prescriptions I have read and accept the privacy policy and terms of use. - Privacy Policy + Privacy policy Terms of Use We would like: Improve usability. @@ -631,8 +617,7 @@ Those with statutory health insurance must pay a co-payment of up to ten euros for prescription drugs. \n\n The amount of the co-payment depends on the price of your medication. You have to pay for medicines that cost less than €5 yourself.\n For medicines that are more expensive, you have to pay ten percent of the price, but at least €5 and a maximum of €10. \n\n Children and young people under the age of 18 are generally exempt from co-payment. \n\n If your annual costs for medication exceed your financial limit, you can be exempted from the co-payment. Talk to your health insurer about this. You are exempt from the co-payment of this drug. Your health insurance will cover the cost of the medication. How long is this prescription valid? - During this period, you can redeem your prescription in any pharmacy with an additional payment. - During this period, you can still redeem the prescription in a pharmacy, but you have to pay the purchase price yourself. Alternatively, you can ask your practice to issue the prescription again. + During this period, you can redeem your prescription in any pharmacy with a maximum additional payment of €10. Substitute medication possible Due to the legal requirements of your health insurance company, you can be given an alternative with the same active ingredient. \n\n Medicines can look and be called differently, have different prices and manufacturers, but still contain the same active ingredient. The active ingredient itself and the dosage are particularly important for the effect of drugs in the body. Patients in the pharmacy often get a different drug than the one prescribed by the doctor on the prescription - provided the drugs are comparable. There can be therapeutic and economic reasons for the change. Scanned prescription @@ -703,11 +688,11 @@ No prescriptions Add prescriptions using the + button in the top right corner. log in - Redeemed prescriptions + prescription archive Vielleicht später log in Edit profile picture - Redeemed prescriptions + prescription archive Enter name Save My order @@ -729,7 +714,7 @@ No prescription You currently have no redeemable prescriptions pickup - delivery boy + courier Mail order choose prescriptions Tap here to scan prescriptions @@ -853,23 +838,15 @@ Will be redeemed for you Was redeemed for you You must be logged in to use this service. - The prescription(s) have been transferred successfully. - The prescription cannot be processed. Please try again. You may have to select a different pharmacy. - The prescription cannot be processed. The pharmacy reports an unknown error. If necessary, try another pharmacy. - The prescription was rejected by the pharmacy. The prescription may be invalid, or your delivery address or contact details may be invalid. - Unable to redeem, please check your internet connection. - The prescription was successfully transferred. However, the pharmacy reports a processing error. Please contact the pharmacy. - The prescription was rejected by the pharmacy. The prescription has already been redeemed. - The prescription was rejected by the pharmacy. The prescription has been deleted. - "The prescription could not be transferred. Please check your internet connection and try again. " - One or more recipes could not be transferred. - Send successfully! - Pharmacy mistake - Pharmacy mistake - Contact pharmacy - Prescription already redeemed - Prescription deleted - No Internet - Error sending - + Insurance app + Insurance card + Associated PIN required + To receive access logs, you must be connected to the server. + You can still fill the prescription at a pharmacy within this period, but you will have to pay the entire purchase price for the medication yourself. Alternatively, you can ask your practice to have the prescription reissued. + Done + Request correction + At the pharmacy + In the app + Have this code scanned at your pharmacy. + Billing correction request diff --git a/android/src/main/res/values-fr/strings.xml b/android/src/main/res/values-fr/strings.xml new file mode 100644 index 00000000..ec3c9f9a --- /dev/null +++ b/android/src/main/res/values-fr/strings.xml @@ -0,0 +1,852 @@ + + + D\'ACCORD + Interrompre + Retour + autour + Numérique. Rapide. Sécurisé. + ID de tâche + code d\'accès + Conditions d\'utilisation + Protection des données + recettes + Accès à la caméra refusé + Pour utiliser le scanner, vous devez autoriser l\'application à accéder à votre appareil photo dans les paramètres système. + Concentrez la caméra sur un code de recette + Ceci n\'est pas un code de prescription valide + Ce code de prescription a déjà été scanné + + %s recette reconnue + %s recettes reconnues + + Interrompre + lumière de la caméra + Annuler la numérisation ? + D\'ACCORD + N\'annulez pas + Nous y voilà + De quoi as-tu besoin: + Entrer le numéro d\'accès de la carte + entrez le code PIN + essayer à nouveau + Impossible de se connecter au serveur. + + Il vous reste %s tentatives avant que votre carte ne soit bloquée. + Il vous reste %s tentatives avant que votre carte ne soit bloquée. + + Vous trouverez le numéro d\'accès en haut à droite de votre carte santé. + Interrompre + Rechercher une carte... + Tenez la carte de santé à l\'arrière de votre appareil. + Toujours à la recherche … + Déplacez lentement la carte à l\'arrière de l\'appareil. + Conseil + Les boîtiers d\'appareils peuvent rendre difficile la connexion via NFC. + carte reconnue + Essayez de ne pas déplacer la carte Santé. + Carnet de santé retrouvé. Veuillez ne pas bouger. + connexion perdue + Tenez à nouveau votre carte de santé à l\'arrière de l\'appareil + Version : %s + Construire le hachage : %s + menu de débogage + Ouvert jusqu\'au %s + Ouvert toute la journée + imprimer + éditeur + gematik GmbH\n Friedrichstraße 136\n 10117Berlin + Directeur général : Dr. médical Markus Leyck-Dieken\n Tribunal d\'enregistrement : tribunal de district de Berlin-Charlottenburg\n Numéro de registre du commerce : HRB 96351\n Numéro d\'identification de la taxe de vente : DE241843684 + Responsable du contenu + docteur médical Markus Leyck-Dieken + Contact + Avis + Nous nous efforçons d\'utiliser un langage non sexiste. Si vous remarquez des erreurs, nous attendons avec impatience de vous entendre par e-mail. + La plate-forme allemande moderne pour la médecine numérique + écrire un courrier + site Web ouvert + Accueillir + Commencer l\'inscription + ouvrir + Enregistrer + Interrompre + Sécurité + Juridique + imprimer + protection des données + Conditions d\'utilisation + détails + Marquer comme utilisé + Marquer comme non utilisé + forme posologique + taille du paquet + Personne assurée + Nom de famille + adresse + date de naissance + Assurance maladie / Payeurs + statut + numéro d\'assurance + Prescripteur + Nom de famille + Spécialiste médical + Numéro de médecin (LANR) + institution + Nom de famille + adresse + Numéro de local commercial + numéro de téléphone + adresse mail + accident du travail + jour de l\'accident + Numéro d\'entreprise ou d\'employeur de l\'accident + Voulez-vous supprimer définitivement cette recette ? + Éteindre + Interrompre + Horaires d\'ouvertures + site Internet + Remboursable uniquement aujourd\'hui en tant qu\'auto-payeur + Enregistrer + Activer NFC + Veuillez activer la fonction NFC de votre appareil pour vous connecter avec votre carte de santé. + Activer + Correct + Des ordonnances rachetées ? + Voulez-vous marquer les ordonnances comme remboursées ? + Non échangé + Racheté + Ouvre à %s + +49 800 277 377 7 + Hotline technique + Ouvrir le scanner pour les recettes + Idées + Supprimer les captures d\'écran + Empêche l\'affichage d\'une vignette lors du changement d\'application + Autorisez-vous e-recipe à analyser votre comportement d\'utilisation de manière anonyme ? + Informations techniques + Sécurité de vos données de prescription + Veuillez vous assurer que les personnes avec qui vous partagez cet appareil et dont les caractéristiques biométriques peuvent être stockées sur cet appareil ont également accès à vos ordonnances. + Envoi échoué + Aucun programme de messagerie configuré + Aucun résultat + Nous n\'avons trouvé aucun résultat pour ce terme de recherche. + Licences Open Source + Contact + Appeler la hotline technique + Participer au sondage + +49 800 277 377 7 + Je veux aider à améliorer cette application + Cela inclut les informations matérielles et logicielles sur votre téléphone, les paramètres de l\'application d\'e-prescription et la quantité d\'utilisation, mais jamais de données sur vous ou votre santé. + Les données ne sont mises à la disposition de gematik GmbH que par le responsable du traitement et sont supprimées au plus tard au bout de 180 jours. Vous pouvez désactiver à nouveau l\'analyse à tout moment dans le menu de l\'application. + Ces données nous permettent de comprendre quelles fonctions sont fréquemment utilisées et de les améliorer. De plus, nous pouvons estimer combien de temps une technologie plus ancienne doit être prise en charge et quand nous pouvons, par exemple, rendre obligatoire une version plus récente du système d\'exploitation sans affecter (trop) d\'utilisateurs. + améliorer l\'application + L\'analyse anonyme reste désactivée + %s Merci pour votre soutien ! + Enregistrer + Merci de vous identifier pour télécharger les recettes. + Remarque pour les pharmacies : nous obtenons les coordonnées et les informations sur les pharmacies sur mein-apothekenportal.de de l\'Association allemande des pharmacies. Avez-vous découvert une erreur ou souhaitez-vous corriger des données ? + Apprendre encore plus + pharmacies + Malheureusement, cela n\'a pas fonctionné \uD83D\uDE15 + Veuillez réessayer. + Entrer le mot de passe + Plus loin + Accessibilité + Zoom + Permet d\'agrandir l\'application en pinçant ou en écartant les doigts (pincer pour zoomer). + mot de passe + Sécurisez vos données avec un mot de passe de votre choix. + mot de passe + Enregistrer sur ordinateur + montrer le mot de passe + Répéter le mot de passe + Recommandations : %s + écrire un courrier + Lorsque vous envoyez votre message, les informations suivantes sur le matériel et le système d\'exploitation utilisés seront transmises : + Échange sur place uniquement + Vous ne pouvez pas encore envoyer d\'ordonnances électroniques à cette pharmacie. + Actuellement ouvert + service de messagerie + Expédition + filtre + Filtre + Aucun emplacement disponible + Compris + Mots de passe répétés + Erreur 20 10 76631 + Votre certificat de carte de santé est invalide. Votre carte a-t-elle expiré ? Veuillez contacter votre assurance maladie. + Tentatives de connexion infructueuses + + %s tentatives de connexion infructueuses ont été détectées. + %s tentatives de connexion infructueuses ont été détectées. + + Choisissez la meilleure sauvegarde de périphérique + Il peut s\'agir d\'une empreinte digitale, d\'un motif de balayage ou similaire + jetons + jeton d\'accès + Jetons SSO + Aucun jeton d\'accès disponible + aucun jeton SSO disponible + copié dans le presse-papiers + Cliquez pour copier le jeton dans le presse-papiers + Valable aujourd\'hui seulement + Permettre + pas de connexion au serveur + S\'il vous plait, réessayez dans quelques minutes + Charger à nouveau + afficher les jetons + Comment souhaitez-vous sécuriser l\'application ? + Avis + Aucune sauvegarde d\'appareil n\'a été configurée pour cet appareil + Nous vous recommandons de protéger en outre vos données médicales avec la sécurité de l\'appareil, comme un code d\'accès ou la biométrie. + Ne plus afficher cet avis à l\'avenir. + La connexion a échoué. Une connexion réseau n\'a pas pu être établie. + Échec de la communication avec le serveur : code d\'état %s . + Impossible de communiquer avec le serveur : veuillez vérifier la connexion Internet et les paramètres d\'heure/date. + avertissement + Votre appareil peut avoir une sécurité réduite + Cela peut être causé, par exemple, par des appareils manipulés ou un mode développeur activé. Pour des raisons de sécurité, nous vous déconseillons d\'utiliser l\'application sur des appareils jailbreakés. + Je reconnais le risque accru et je veux continuer. + Pourquoi les appareils avec accès root représentent-ils un risque potentiel pour la sécurité ? + Apprendre encore plus + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Nom de profil + Veuillez entrer un nom pour le nouveau profil. + nom de profil + profils + Comment reconnaître une carte de santé compatible NFC + Aucun contact possible via cette application + Veuillez utiliser les canaux habituels pour contacter votre compagnie d\'assurance. + Carte Santé et NIP + NIP uniquement + Inscription dans l\'application e-prescription + Le champ du nom ne peut pas être vide. + Un profil avec le nom saisi existe déjà. + profil + %s sélectionné + Couleur de l\'arrière plan + gris printemps + droséra + Il! Est! Rose! + Arbre + Lune bleue de septembre + Pas connecté + Liés ensemble + Dernière connexion le %s + Supprimer le profil? + Cela effacera toutes les données de profil sur cet appareil. Vos ordonnances dans le réseau de la santé resteront intactes. + Éteindre + Interrompre + Supprimer le profil + Vous souhaitez supprimer le dernier profil. + L\'application nécessite au moins un profil. Veuillez entrer un nom pour le nouveau profil. + Erreur 20 10 76831 + Le répertoire des cartes de santé n\'a pas pu être atteint. Veuillez réessayer. + Vous pouvez trouver des informations vérifiées par des experts sur les maladies, les codes CIM et sur les questions de prévention et de soins sur le portail national de la santé. + Ouvrez Gesund.bund.de + Nous avons modifié la politique de confidentialité + L\'application e-prescription a évolué. Cela a rendu nécessaire la mise à jour de notre politique de confidentialité. + Ouvrir la politique de confidentialité + Cela a changé depuis le %s : + Que se passe-t-il lorsque vous ouvrez l\'application ? + Que se passe-t-il si j\'utilise la fonction appareil photo / lis des recettes avec l\'appareil photo ? + Aucune nouvelle recette disponible + + %s nouvelle recette + %s nouvelles recettes + + Rachetable + En rachat + Racheté + Inconnu + Afficher les journaux d\'accès + Qui a accédé à vos recettes et quand ? + Clé d\'accès au service de prescription + journaux d\'accès + Aucun journal d\'accès + Il n\'y a pas encore de journaux d\'accès. + La recette est actuellement en cours et ne peut pas être supprimée + Accepter + Apparemment ça n\'a pas marché + Nous sommes conscients que le lien avec la carte de santé a ses pièges. À l\'avenir, l\'inscription devrait donc également être possible via une application d\'assurance maladie déjà authentifiée. \n\n Nous nous efforçons également de permettre aux ordonnances d\'être échangées numériquement sans enregistrement. \n\n Avez-vous remarqué quelque chose au cours de ce processus que vous aimeriez partager avec nous ? Veuillez nous écrire, nous sommes également heureux de recevoir des commentaires très critiques. + Conseils de connexion + Améliorer la force de la connexion + Si nécessaire, retirez le capot de protection. + Si l\'appareil vibre puis rompt la connexion, recherchez la position optimale dans un petit rayon. + Déplacez l\'appareil sur la carte très lentement. + Placez l\'appareil directement sur la carte. + Pour ce faire, placez la carte de santé sur une surface plane (par exemple une table). + Améliorer la force de la connexion + Notez l\'emplacement du capteur NFC + Découvrez où se trouve le capteur NFC dans votre appareil (ici, par exemple, un aperçu des appareils de %s ). + Dans certains cas, la position du capteur NFC peut différer au sein d\'une série de modèles (ici, par exemple, les informations pour le %s ). + Prochain conseil + Plus loin + Fermer + Expérimenter + Écrivez-nous + Permis de recherche en pharmacie + racheter + Ordonnance scannée + Scanné le %s + Marqué comme échangé le %s + Comment voulez-vous continuer ? + Commande + Bientôt disponible + Réservez maintenant pour la collecte ou faites-vous livrer par service de messagerie ou par expédition + Enregistrer pour une commande ultérieure + Enregistrer les recettes sur l\'appareil + + Continuer avec la recette %s + Continuer avec %s recettes + + Impossible de connecter la carte de santé + Le profil actuel est déjà connecté à une autre carte santé (numéro d\'assurance maladie %s ). + Votre carte santé est déjà reliée à un autre profil. Passez au profil %s . + Enregistrer sur ordinateur + coordonnées et adresse + Contact + numéro de téléphone + Veuillez fournir un numéro de téléphone pour le contact. + Adresse e-mail (facultatif) + adresse de livraison + prénom et nom + Veuillez saisir un nom et un prénom à des fins de contact. + Rue et numéro de maison + Veuillez entrer une rue et un numéro de maison afin que nous puissions être contactés. + Adresse supplémentaire (facultatif) + Instructions de livraison (facultatif) + Coordonnées supplémentaires requises + Annuler les modifications? + jeter + Pour la recherche, l\'annuaire des pharmacies utilise des coordonnées géographiques qui ont été déterminées à l\'aide d\'OpenStreetMap. Nous remercions le projet pour cette aide. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Confidentialité et utilisation + Plus loin + Vous avez reçu votre NIP dans une lettre de votre compagnie d\'assurance maladie. + Aucun code PIN reçu + code PIN + Vérifiez la connexion à Internet et le réglage de l\'heure et de la date de votre appareil. + Pour vous connecter, appuyez sur « Déverrouiller ». + enfermé dehors? Veuillez vérifier vos identifiants biométriques sur cet appareil. + Mot de passe oublié? Veuillez supprimer l\'application, puis la réinstaller. Vous pouvez découvrir pourquoi dans notre %s . + zone d\'aide + taille de l\'emballage et unité + ingrédient actif + Quantité d\'ingrédient actif + désignation du lot + Exp + catégorie + Vaccin + Accepter + Défait + Avis + Aidez-nous à améliorer cette application + Entrer le mot de passe + Le mot de passe doit comporter au moins huit caractères + La force du mot de passe n\'est pas suffisante + Force du mot de passe suffisante + Le mot de passe est visible + Le mot de passe n\'est pas visible + biométrie + mot de passe + attendre une réponse + Aucune ordonnance + Vous n\'avez actuellement aucune ordonnance remboursable. + Mettre à jour + Déconnexion automatique + Pour des raisons de sécurité, la connexion au serveur de recettes est interrompue au bout de 12 heures. Reconnectez-vous pour obtenir les recettes actuelles. + Connecter + Avez-vous reçu une copie papier? + Ajoutez des recettes à votre liste en appuyant sur le bouton de numérisation dans le coin supérieur droit. + Numériser l\'impression papier + Vous devez être connecté pour recevoir les recettes automatiquement. + Enregistrer + Aucune ordonnance remboursée + Vos ordonnances échangées sont affichées ici. Pour des raisons de protection des données, vos recettes seront supprimées du serveur de recettes après 100 jours. + Aucune ordonnance remboursée + Vos ordonnances échangées sont affichées ici. Ajoutez des ordonnances via scan pour commencer à racheter. + gestion d\'appareils + Des appareils connectés + Inscrit depuis %s (ce périphérique) + Inscrit depuis %s + Pour des raisons de sécurité, la connexion au serveur de recettes est interrompue au bout de 12 heures. Pour vous reconnecter, vous avez besoin de votre carte Santé et de votre NIP pour chaque processus de connexion. + code PIN + Entrez votre NIP (carte Santé). + Plus loin + Enregistrer + Des appareils connectés + enlevez l\'appareil? + Interrompre + Supprimé + Supprimer cet appareil ? + Voulez-vous supprimer %s ? + Si vous supprimez %s , la connexion au serveur de recettes sera définitivement déconnectée dans 12 heures au plus tard. + Les appareils sont en cours de chargement... + Aucun appareil + Aucun appareil n\'est connecté à cette carte Santé. + Essayer à nouveau + Ah ah :-( + La liste des appareils n\'a pas pu être chargée. + wwweg… + Pas de connexion Internet. + Médicaments et pansements + stupéfiants + Livraison de médicaments sur ordonnance selon § 4 AMVV + As-tu besoin d\'aide? + Nous avons rassemblé pour vous quelques conseils pour résoudre les problèmes les plus courants. + Commencer les conseils de connexion + ouvrir + carte bloquée + Le code PIN a été saisi incorrectement trois fois. Votre carte a donc été bloquée pour des raisons de sécurité. + déverrouiller la carte + Entrez le code PUK + Avec votre code PIN, vous avez reçu un code PUK à 8 chiffres de votre compagnie d\'assurance. + Choisir un nouveau NIP + Vous pouvez choisir vous-même votre nouveau numéro d\'identification personnel (NIP) (6 à 8 chiffres). + NIP mémorisé ? + Veuillez noter votre code PIN et le conserver en lieu sûr. + Interrompre + D\'ACCORD + Déverrouillage impossible + Vous avez atteint le nombre maximum de cartes déverrouillées avec ce code PUK ou vous l\'avez saisi de manière incorrecte à plusieurs reprises. Veuillez contacter votre compagnie d\'assurance. + Vous pouvez utiliser un PUK pour un maximum de 10 déverrouillages. + carte déverrouillée + De quoi as-tu besoin: + votre carte de santé + PUK de votre carte santé + Plus loin + carte de santé + Commander un NIP ou une carte + Enregistrer + Comment voulez-vous vous connecter ? + Carte de santé compatible NFC + NIP pour la carte santé + Vous n\'avez pas encore de carte de santé et de code PIN compatibles NFC ? + Appliquer maintenant + Ou : Connectez-vous avec le %s . + Votre application d\'assurance maladie + "Votre numéro d\'accès se trouve dans le coin supérieur droit de votre carte Santé." + Ma carte n\'a pas de numéro d\'accès + + Il vous reste %s tentatives avant que votre carte ne soit bloquée. + Il vous reste %s tentatives avant que votre carte ne soit bloquée. + + Mettez la carte de santé au dos du téléphone + Le processus suivant peut prendre jusqu\'à 30 secondes. + Placez la carte %s au dos du téléphone. + dans le coin supérieur droit + au milieu supérieur + en haut à gauche + au milieu à droite + milieu + au centre gauche + dans la zone inférieure droite + en bas au centre + en bas à gauche + Aider + Envoyé il y a %s minutes + Envoyé le %s + Envoyé à l\'instant + Envoyé à %s heures + N\'est plus valide + Connectez-vous avec l\'application + choisir une assurance + Vous n\'avez pas trouvé ce que vous cherchiez ? Cette liste est constamment élargie. L\'inscription avec une carte de santé est déjà prise en charge par toutes les caisses d\'assurance maladie. + Retour d\'expérience de l\'application e-prescription + Nous attendons vos commentaires avec impatience. Veuillez utiliser l\'espace ci-dessous et être aussi précis que possible : + PUK + Fermer + Quel dommage… + Malheureusement, votre appareil ne répond pas aux exigences minimales pour vous connecter à l\'application e-prescription. Au moins Android 7 et une puce NFC sont nécessaires pour une authentification sécurisée avec votre carte de santé. + Apprendre encore plus + Enregistrer les données de connexion ? + Enregistrer sur ordinateur + Ne sauvegardez pas + Avis + Pour des raisons de sécurité, la connexion au serveur de recettes est interrompue au bout de 12 heures. Pour vous reconnecter, vous avez besoin de votre carte Santé et de votre NIP pour chaque processus de connexion. + Configurer la sécurité biométrique + Enregistrement des données d\'accès impossible. Configurez au préalable la sécurité biométrique (par exemple, empreinte digitale) sur votre appareil. + Interrompre + Idées + Avis + Accepter + Sécurité de vos données de prescription + \"Cette application utilise le capteur biométrique le plus sécurisé fourni par votre appareil pour stocker vos informations d\'identification dans une zone sécurisée de la mémoire de l\'appareil.\" + La sécurité biométrique de vos données d\'accès vous permet d\'ouvrir cette application à l\'avenir sans entrer votre code PIN et votre carte de santé, et de consulter, appeler, échanger ou supprimer des ordonnances. + Veuillez vous assurer que les personnes avec qui vous partagez cet appareil et dont les caractéristiques biométriques peuvent être stockées sur cet appareil ont également accès à vos ordonnances. + ça n\'a malheureusement pas fonctionné + L\'authentification avec l\'application d\'assurance maladie a échoué. + Expiré le %s + La recette a déjà été supprimée du serveur + Veuillez corriger votre saisie ou annuler les modifications + Correct + données assurées + Nom de famille + Assurance + numéro d\'assurance + numéro d\'accès à la carte + Enregistrer + Se désinscrire + Enregistrer sur ordinateur + Changement + Éditer la photo de profil + Plus loin + le serveur ne répond pas + Veuillez réessayer plus tard. + Essayer à nouveau + Rechercher une assurance + Se connecter au serveur de recettes maintenant ? + Connecté avec succès + connexion perdue + Se connecter au serveur de recettes maintenant ? + Pas de jetons + Vous recevrez un jeton lorsque vous serez connecté au service de prescription.\n + ordres + Sélectionnez le code PIN souhaité + déverrouiller la carte + Choisissez NIP + Répéter le NIP + Les entrées diffèrent les unes des autres. + Aucune commande + Vous n\'avez pas encore de commandes. + Juste maintenant + A %s heures + Le panier est prêt + La recette a été ajoutée à votre panier. Veuillez vous rendre sur le site Web de la pharmacie pour terminer la commande. + Ouvrir le panier + Présentez ce code de retrait à la pharmacie. + Recevoir le code de prise en charge + Le message ne peut pas s\'afficher + Veuillez contacter votre pharmacie ( %s ). + Afficher le lien du panier + Afficher le code de retrait + Afficher le message + %s à %s heures + Recette envoyée à %s . + Aperçu de la commande + Nouveau + Cours + Commande + Gratuit pour l\'appelant. Horaires de service : du lundi au vendredi de 8h00 à 20h00 sauf jours fériés + Pharmacie + Sélectionnez le code PIN souhaité + PIN souhaité enregistré + Actuellement ouvert et près de chez moi + Filtrer par … + lancer la recherche + affectation directe + pharmacies + Numéro de téléphone (facultatif) + Recherche par nom ou adresse + Aucune information pharmaceutique valide + Aucune information actuelle n\'a été trouvée sur cette pharmacie. L\'entrée pour cette pharmacie sera supprimée. + D\'ACCORD + Répertoire des pharmacies non disponible + Actuellement, aucune information actuelle sur cette pharmacie ne peut être récupérée. S\'il vous plait, vérifiez votre connexion internet. + Interrompre + Essayer à nouveau + Enregistrer l\'environnement + La connexion n\'est pas possible + Il semble que vos identifiants de connexion biométriques aient changé. Veuillez vous réinscrire avec votre carte santé. + Interrompre + Enregistrer + profil 1 + Près de moi + Remboursable plus tard + Rachetable à partir de %s + améliorations du produit + Analyse anonyme + Aidez-nous à améliorer cette application. Toutes les données d\'utilisation sont collectées de manière anonyme et ne sont utilisées que pour améliorer l\'expérience utilisateur. + sécurité de l\'appareil + paramètres personnels + Accessibilité + améliorations du produit + Recette ajoutée + Recette déjà disponible + Une erreur s\'est produite lors de l\'importation + Éteindre + Ordonnance scannée + Remplacement possible + NIP oublié + + %s Recette + %s Recettes + + J\'ai lu et j\'accepte la politique de confidentialité et les conditions d\'utilisation. + Protection des données + Conditions d\'utilisation + Nous voudrions: + Améliorer la convivialité. + Détecter les erreurs et les plantages. + Toutes les données sont bien sûr collectées de manière anonyme. + Vous pouvez modifier cette décision dans les paramètres système à tout moment. + Continuer + Accepter + Cette application utilise la méthode la plus sécurisée fournie par votre appareil. + Enregistrer sur ordinateur + Choisir + médicament + nom commercial + Oui + Non + dosage + date d\'émission + Cette ordonnance vous sera rachetée dans le cadre d\'un traitement. + Non spécifié + paiement supplémentaire + médicament + Bons de livraison + Admissible selon LPP + préparation alternative + nom de la recette + Emballage + instruction d\'artisanat + Description + donné par + publié le: + ingrédient actif + prescrit + Recevoir + Qu\'est-ce qu\'une mission directe ? + Dans le cas des références directes, une ordonnance d\'un cabinet ou d\'un hôpital est échangée directement en pharmacie. Les assurés n\'ont aucune démarche à entreprendre et ne peuvent intervenir dans le processus de rachat. \n\n Les références directes sont répertoriées dans l\'application e-prescription pour rendre votre traitement plus transparent pour vous. + frais de service d\'urgence + Il faut parfois se dépêcher. Certaines ordonnances peuvent être échangées sans le paiement supplémentaire de frais de service d\'urgence, comme la nuit ou les jours fériés. + Médicaments soumis à co-paiement + Exonéré de co-paiement + Les titulaires d\'une assurance maladie légale doivent payer une participation pouvant aller jusqu\'à dix euros pour les médicaments sur ordonnance. \n\n Le montant de la quote-part dépend du prix de vos médicaments. Vous devez payer vous-même les médicaments qui coûtent moins de 5 €.\n Pour les médicaments plus chers, vous devez payer 10 % du prix, mais au moins 5 € et au maximum 10 €. \n\n Les enfants et les jeunes de moins de 18 ans sont généralement exemptés du ticket modérateur. \n\n Si vos frais annuels de médicaments dépassent votre limite financière, vous pouvez être exempté du ticket modérateur. Parlez-en à votre mutuelle. + Vous êtes exonéré du co-paiement de ce médicament. Votre assurance maladie prendra en charge le coût des médicaments. + Combien de temps cette ordonnance est-elle valable ? + Pendant cette période, vous pouvez faire racheter votre ordonnance dans n\'importe quelle pharmacie moyennant un supplément de 10 € maximum. + Remplacement possible + En raison des exigences légales de votre caisse maladie, une alternative avec le même principe actif peut vous être proposée. \n\n Les médicaments peuvent avoir une apparence et un nom différents, avoir des prix et des fabricants différents, mais contenir toujours le même ingrédient actif. L\'ingrédient actif lui-même et le dosage sont particulièrement importants pour l\'effet des médicaments dans le corps. Les patients en pharmacie obtiennent souvent un médicament différent de celui prescrit par le médecin sur l\'ordonnance – à condition que les médicaments soient comparables. Il peut y avoir des raisons thérapeutiques et économiques au changement. + Ordonnance scannée + Pour des raisons de sécurité, les ordonnances importées à partir d\'un imprimé papier ne doivent comporter aucune donnée personnelle ou médicale. \n\n Connectez-vous à cette application avec une carte de santé ou une application d\'assurance pour afficher toutes les informations contenues dans l\'ordonnance. + Recette incorrecte + Cette ordonnance a été émise de manière incorrecte. + Ordonnance scannée + frais de service d\'urgence + Dosage selon les instructions écrites + téléphone + placer + Poster + Tri par distance impossible. + D\'ACCORD + Entrez le code PIN actuel + Code PIN saisi incorrect + Le NIP actuel de votre carte Santé + carte bloquée + Débloquez votre carte dans Paramètres > Débloquer la carte. + Pour des raisons de sécurité, veuillez saisir votre code PIN actuel. + NIP oublié + Recette incorrecte + médicament + Quelque chose semble s\'être mal passé lors de la création de votre recette. Signaler une erreur ? + Rapport + Pas connecté + Enregistrer par + carte de santé + biométrie + Pas connecté + Votre avis nous intéresse. Merci de prendre cinq minutes pour répondre à notre enquête. Merci d\'avance. + avis d\'avertissement + Pharmacie ajoutée aux favoris + Pharmacie supprimée des favoris + Mes pharmacies + Force du mot de passe très bonne + Échec de l\'opération d\'écriture + Le code PIN n\'a pas pu être enregistré + Rapport + Attribuer un code PIN + Règle d\'accès violée + Vous n\'êtes pas autorisé à accéder au répertoire de la carte. + Attribuez votre propre code PIN + La carte est sécurisée par un code PIN de votre caisse maladie (PIN transport), veuillez attribuer votre propre code PIN. + Mot de passe introuvable + Il n\'y a pas de mot de passe stocké sur votre carte. + vous avez été déconnecté + Connectez-vous à nouveau pour mettre à jour vos recettes. + numéro d\'ingrédient actif + puissance et unité + Utilisé il y a %s minutes + Réclamé le %s + Racheté à l\'instant + Racheté à %s heures + Ordres + Cette prescription a été rachetée pour vous dans le cadre d\'un traitement. + frais de service d\'urgence + Cette ordonnance ne peut être exécutée de nuit dans une pharmacie sans le paiement supplémentaire d\'un forfait de service d\'urgence. + Cherche ici + Idées + Partager l\'emplacement dans les paramètres. + Près de moi + Maintenez enfoncé pour modifier le nom. + Saisissez le nouveau nom du profil. + Vous devez être connecté pour recevoir des ordonnances numériques de votre cabinet. + Recevoir des recettes numériquement ? + Faites glisser l\'écran vers le bas pour l\'actualiser. + Aucune ordonnance + Ajoutez des recettes à l\'aide du bouton + dans le coin supérieur droit. + Enregistrer + archives d\'ordonnances + Peut-être plus tard + Enregistrer + Éditer la photo de profil + archives d\'ordonnances + Entrez le nom + Enregistrer sur ordinateur + Ma commande + Destinataire : en + recettes + Pharmacie + Envoyer + Changement + A retirer à la pharmacie + Livraison par coursier + Livraison par courrier + %s Recettes + Échange impossible + Une ou plusieurs ordonnances n\'ont pas pu être échangées. + Aucune recette sélectionnée + Pour échanger des recettes, au moins une recette doit être sélectionnée. + Ajouter des informations de contact + Changement + Sans ordonnance + Vous n\'avez actuellement aucune ordonnance remboursable + collection + courrier + Expédition + choisir des recettes + Appuyez ici pour scanner les recettes + Appuyez longuement pour modifier les noms + Ajoutez plus de profils, par exemple pour vos enfants ou vos parents + Cliquez sur l\'affichage pour ignorer l\'info-bulle affichée. + Comment racheter ? + Comment souhaitez-vous recevoir vos médicaments ? + Échangez directement + Échange de médicaments sur place + Commande + Réservez ou faites-vous livrer + Prêt + code collectif + codes uniques + + Vous avez %s ordonnance. + Vous avez %s recettes. + + choisissez + Toutes les recettes + Quelles recettes ? + Plus loin + Plus loin + Apprendre encore plus + Avis + Cette application utilise un logiciel de Google pour reconnaître les codes. + Apprendre encore plus + À propos du scanner de code de recette + Quelles données le code de recette contient-il ? + Le code recette contient uniquement un identifiant de la recette. Cela permet de retrouver la prescription sur le service de prescription du réseau numérique de santé. Le code de prescription ne contient aucune donnée sur vous ou vos médicaments. + Donc personne ne peut rien faire avec le code de recette seul ? + Correct. Les données de prescription doivent être téléchargées depuis le service de prescription. Cela nécessite une connexion sécurisée. + Qui peut s\'inscrire au service de prescription? + L\'inscription au service de prescription du réseau numérique de santé est possible pour les assurés, les pharmacies, les cabinets médicaux et les hôpitaux. + Pourquoi l\'application e-prescription utilise-t-elle les fonctionnalités de Google ? + Google propose des fonctions qui peuvent être facilement intégrées dans des applications et qui sont constamment développées et mises à jour par Google. Cela garantit que les fonctions fonctionnent sur de nombreux terminaux différents et peuvent être utilisées en toute sécurité. L\'application utilise une fonctionnalité pour améliorer la fonctionnalité de caméra et de numérisation pour les appareils Android (Google ML Kit). + Comment fonctionne l\'amélioration de l\'analyse de Google ML Kit ? + Google ML Kit aide à optimiser l\'image capturée par une caméra afin que les codes de recette puissent être lus même dans de mauvaises conditions d\'éclairage ou avec des modèles de caméra plus anciens. + Les données relatives à la prescription ou à mes médicaments seront-elles transmises à Google ? + Non. Le code de recette lu est enregistré directement dans l\'application. Il ne sera pas transmis à Google. Les données de prescription ne sont pas stockées dans le code, uniquement dans le réseau de santé numérique. De là, ils sont envoyés à l\'application. Google n\'a pas accès au réseau numérique de santé. + Quelles données Google traite-t-il lors de l\'utilisation de ML Kit ? + Google n\'a accès qu\'aux informations techniques sur l\'appareil final utilisé et l\'utilisation générale de la fonction supplémentaire (par exemple, le taux d\'erreur, les paramètres de l\'appareil photo) afin de les enregistrer statistiquement et d\'améliorer ainsi la fonction supplémentaire. Lors de votre accès, Google enregistre temporairement l\'adresse IP de votre terminal. Les informations vous concernant et le contenu de la recette ne seront pas enregistrées par Google. + L\'utilisation de Google ML Kit est-elle volontaire ? + Oui. Cependant, ML Kit est intégré au scanner de code de recette dans la version Android de l\'application e-prescription. Si vous utilisez le scanner de code de recette sur un appareil Android, la fonction ML Kit est également toujours utilisée. Cependant, vous pouvez vous passer du scanner de code de recette. Vos ordonnances peuvent également être chargées dans l\'application si vous vous inscrivez au réseau de santé numérique avec la carte de santé électronique ou via votre application d\'assurance maladie. + Puis-je voir qui a vu mes recettes ? + Oui. Tous les accès à vos données sont entièrement enregistrés dans le réseau de santé numérique. Dans l\'application e-prescription, vous pouvez voir qui a accédé à vos données. + Qui puis-je contacter si j\'ai des questions sur l\'application ou l\'e-prescription ? + Vous trouverez des informations détaillées dans la déclaration de protection des données. + Nombre de boîtes prescrites + Aucune ordonnance + Pour cela, vous avez besoin d\'ordonnances remboursables. + choisir une assurance + Rechercher une assurance + Interrompre + Pour quoi souhaitez-vous postuler ? + Pour cette application, vous avez besoin d\'une carte et du code PIN associé. + Comment souhaitez-vous contacter votre compagnie d\'assurance ? + Votre compagnie d\'assurance vous propose les possibilités de contact suivantes + Votre compagnie d\'assurance vous propose les possibilités de contact suivantes + Fermer + PIN mal saisi. + Numéro d\'accès mal saisi + PUK entré incorrectement. + notes de frais + Afficher les reçus de dépenses + notes de frais + Pour recevoir les notes de frais, vous devez être connecté au serveur. + Connecter + Pas de reçus de dépenses + Désactiver + Interrompre + désactiver la fonction + Cela supprimera tous les reçus de cet appareil et du serveur. + Recevoir les notes de frais + Vos justificatifs de coûts sont également enregistrés sur le serveur de recettes. + Recevoir + Total : %s %s + Choisir + Diviser + Éteindre + Éteindre + Soumettre + %s € + prix total + Conseil : Soumettez les justificatifs de dépenses via l\'application d\'assurance + Soumettez facilement des reçus de frais via l\'application de votre compagnie d\'assurance. À l\'étape suivante, sélectionnez cette application et appuyez sur Partager. + Pratique + Pharmacie + Date + montre plus + Identification du médicament + Émis pour + KVNR : %s + Date de naissance : %s + D\'ACCORD + Comment soumettez-vous les reçus? + Transférez directement sur l\'application de votre compagnie d\'assurance/bureau d\'aide. Pour ce faire, sélectionnez l\'application sur la page suivante. + ou + Enregistrez le fichier et importez-le ultérieurement dans le portail assurance/aide. + Article : %s + Numéro : %s + TVA : %s %% + Prix brut en EUR : %s + Frais supplémentaires + frais de service d\'urgence + Frais BTM + Frais d\'ordonnance T + les frais d\'approvisionnement + Service de messagerie + Total en EUR : %s + prélèvement + Vraiment supprimer ? + Le fichier sera supprimé de votre appareil et du serveur. + Éteindre + Posté + Code postal + Emplacement + Veuillez entrer votre code postal pour nous contacter. + Veuillez indiquer votre lieu de résidence lorsque vous nous contactez. + Sera racheté pour vous + A été racheté pour vous + Vous devez être connecté pour utiliser ce service. + application d\'assurance + carte de santé + Code PIN associé requis + Pour recevoir les journaux d\'accès, vous devez être connecté au serveur. + Vous pouvez toujours exécuter l’ordonnance en pharmacie pendant cette période, mais vous devrez payer vous-même la totalité du prix d’achat du médicament. Vous pouvez également demander à votre cabinet de faire rééditer l’ordonnance. + Prêt + Demander une correction + A la pharmacie + Dans l\'application + Faites scanner ce code dans votre pharmacie. + Demande de correction de facturation + diff --git a/android/src/main/res/values-it/strings.xml b/android/src/main/res/values-it/strings.xml new file mode 100644 index 00000000..f7bf5808 --- /dev/null +++ b/android/src/main/res/values-it/strings.xml @@ -0,0 +1,852 @@ + + + OK + Interrompere + Ritorno + in giro + Digitale. Veloce. Sicuro. + ID attività + codice d\'accesso + Termini di utilizzo + Protezione dati + ricette + Accesso alla telecamera negato + Per utilizzare lo scanner, devi consentire all\'app di accedere alla tua fotocamera nelle impostazioni di sistema. + Metti a fuoco la fotocamera su un codice ricetta + Questo non è un codice di prescrizione valido + Questo codice di prescrizione è già stato scansionato + + %s ricetta riconosciuta + %s ricette riconosciute + + Interrompere + luce della fotocamera + Annullare la scansione? + OK + Non annullare + Eccoci qui + Quello che ti serve: + Inserisci il numero di accesso alla carta + inserire il codice PIN + riprova + Impossibile connettersi al server. + + Hai altri %s tentativi prima che la tua carta venga bloccata. + Hai altri %s tentativi prima che la tua carta venga bloccata. + + Troverai il numero di accesso in alto a destra della tua tessera sanitaria. + Interrompere + Cerca mappa... + Tieni la tessera sanitaria sul retro del tuo dispositivo. + Ancora cercando … + Sposta lentamente la scheda sul retro del dispositivo. + Mancia + Le custodie dei dispositivi possono rendere difficile la connessione tramite NFC. + carta riconosciuta + Cerca di non spostare la tessera sanitaria. + Tessera sanitaria ritrovata. Per favore, non muoverti. + Collegamento perso + Avvicina nuovamente la tua tessera sanitaria al retro del dispositivo + Versione: %s + Costruisci hash: %s + menu di debug + Aperto fino %s + Aperto tutto il giorno + impronta + editore + Gematik GmbH\n Friedrichstraße 136\n 10117 Berlino + Amministratore delegato: Dott. medico Markus Leyck-Dieken\n Tribunale di registrazione: tribunale distrettuale di Berlino-Charlottenburg\n Numero di registro delle imprese: HRB 96351\n Numero di identificazione IVA: DE241843684 + Responsabile del contenuto + dott medico Markus Leyck-Dieken + Contatto + Avviso + Ci sforziamo di utilizzare un linguaggio neutro rispetto al genere. Se noti errori, non vediamo l\'ora di sentirti via e-mail. + La moderna piattaforma tedesca per la medicina digitale + scrivere posta + sito web aperto + Benvenuto + Inizia la registrazione + sbloccare + Registrati + Interrompere + Sicurezza + Legale + impronta + protezione dati + Termini di utilizzo + dettagli + Segna come riscattato + Segna come non riscattato + forma di dosaggio + dimensione della confezione + Persona assicurata + Cognome + indirizzo + Data di nascita + Assicurazione sanitaria / Pagatori + stato + numero di polizza + Persona che prescrive + Cognome + Specialista medico + Numero del medico (LANR) + istituzione + Cognome + indirizzo + Numero locali commerciali + numero di telefono + indirizzo di posta + incidente sul lavoro + giorno dell\'incidente + Numero dell\'azienda o del datore di lavoro dell\'incidente + Vuoi eliminare definitivamente questa ricetta? + Spegnere + Interrompere + orari di apertura + sito web + Riscattabile solo oggi come autopagante + Registrati + Attiva l\'NFC + Attiva la funzione NFC del tuo dispositivo per accedere con la tua tessera sanitaria. + Attivare + Corretto + Prescrizioni riscattate? + Vuoi contrassegnare le prescrizioni come riscattate? + Non riscattato + Redento + Apre alle %s + +49 800 277 377 7 + Hotline tecnica + Apri lo scanner per le ricette + Idee + Elimina gli screenshot + Impedisce la visualizzazione di una miniatura quando si passa da un\'app all\'altra + Consenti a e-recipe di analizzare il tuo comportamento di utilizzo in modo anonimo? + Informazioni tecniche + Sicurezza dei tuoi dati di prescrizione + Assicurati che anche le persone con cui potresti condividere questo dispositivo e le cui caratteristiche biometriche potrebbero essere memorizzate su questo dispositivo abbiano accesso alle tue prescrizioni. + invio fallito + Nessun programma di posta elettronica installato + Nessun risultato + Non siamo riusciti a trovare alcun risultato per questo termine di ricerca. + Licenze Open Source + Contatto + Chiama la hotline tecnica + Partecipa al sondaggio + +49 800 277 377 7 + Voglio contribuire a migliorare questa app + Ciò include informazioni su hardware e software sul tuo telefono, impostazioni dell\'app di prescrizione elettronica e portata di utilizzo, ma mai dati su di te o sulla tua salute. + I dati vengono messi a disposizione di gematik GmbH solo dal responsabile del trattamento e vengono cancellati al più tardi dopo 180 giorni. È possibile disattivare nuovamente l\'analisi in qualsiasi momento nel menu dell\'app. + Questi dati ci permettono di capire quali funzioni vengono utilizzate frequentemente e di migliorarle. Inoltre, possiamo stimare per quanto tempo la tecnologia precedente deve essere supportata e quando possiamo, ad esempio, rendere obbligatoria una versione del sistema operativo più recente senza influire su (troppi) utenti. + migliorare l\'app + L\'analisi anonima rimane disabilitata + %s Grazie per il tuo supporto! + Registrati + Identificati per scaricare le ricette. + Nota per le farmacie: otteniamo i dettagli di contatto e le informazioni sulle farmacie da mein-apothekenportal.de dell\'Associazione tedesca delle farmacie Hai scoperto un errore o desideri correggere i dati? + Saperne di più + farmacie + Sfortunatamente, non ha funzionato \uD83D\uDE15 + Si prega di riprovare. + Inserire la password + Ulteriore + Accessibilità + Ingrandisci + Consente di ingrandire l\'app pizzicando o allargando le dita (pinch-to-zoom). + parola d\'ordine + Proteggi i tuoi dati con una password a tua scelta. + parola d\'ordine + Salva sul computer + mostra password + Ripeti la password + Raccomandazioni: %s + scrivere posta + Quando invii il tuo messaggio, verranno trasmesse le seguenti informazioni sull\'hardware e sul sistema operativo utilizzato: + Riscatta solo in loco + Non puoi ancora inviare ricette elettroniche a questa farmacia. + Attualmente aperto + servizio di messaggeria + Spedizione + filtro + Filtro + Nessuna posizione disponibile + Inteso + Corrispondenze password ripetute + Errore 20 10 76631 + Il tuo certificato di tessera sanitaria non è valido. La tua carta è scaduta? Si prega di contattare la propria assicurazione sanitaria. + Tentativi di accesso non riusciti + + Sono stati rilevati %s tentativi di accesso non riusciti. + Sono stati rilevati %s tentativi di accesso non riusciti. + + Scegli il miglior backup del dispositivo + Può trattarsi di un\'impronta digitale, di una sequenza di scorrimento o simili + gettoni + token di accesso + Token SSO + Nessun token di accesso disponibile + nessun token SSO disponibile + copiato negli appunti + Fare clic per copiare il token negli appunti + Valido solo oggi + Permettere + nessuna connessione al server + Riprova tra qualche minuto + Carica di nuovo + mostra gettoni + Come vuoi proteggere l\'app? + Avviso + Nessun backup del dispositivo è stato impostato per questo dispositivo + Ti consigliamo di proteggere ulteriormente i tuoi dati medici con la sicurezza del dispositivo come un passcode o dati biometrici. + Non mostrare più questo avviso in futuro. + Connessione fallita. Non è stato possibile stabilire una connessione di rete. + Comunicazione con il server non riuscita: codice di stato %s . + Impossibile comunicare con il server: controllare la connessione Internet e le impostazioni di ora/data. + avvertimento + Il tuo dispositivo potrebbe avere una sicurezza ridotta + Ciò può essere causato, ad esempio, da dispositivi manipolati o da una modalità sviluppatore attivata. Per motivi di sicurezza, non consigliamo di utilizzare l\'app su dispositivi con jailbreak. + Riconosco l\'aumento del rischio e voglio ancora continuare. + Perché i dispositivi con accesso root rappresentano un potenziale rischio per la sicurezza? + Saperne di più + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Nome del profilo + Inserisci un nome per il nuovo profilo. + nome del profilo + profili + Come riconoscere una tessera sanitaria abilitata NFC + Nessun contatto possibile tramite questa app + Si prega di utilizzare i consueti canali per contattare la propria compagnia assicurativa. + Tessera Sanitaria e PIN + Solo PIN + Registrazione nell\'app di prescrizione elettronica + Il campo del nome non può essere vuoto. + Esiste già un profilo con il nome inserito. + profilo + %s selezionato + colore di sfondo + grigio primaverile + drosera + Esso! È! Rosa! + Albero + Luna Blu Settembre + Accesso non effettuato + Legati insieme + Ultima connessione il %s + Eliminare profilo? + Questa operazione cancellerà tutti i dati del profilo su questo dispositivo. Le tue prescrizioni nella rete sanitaria rimarranno intatte. + Spegnere + Interrompere + eliminare il profilo + Vuoi eliminare l\'ultimo profilo. + L\'app richiede almeno un profilo. Inserisci un nome per il nuovo profilo. + Errore 20 10 76831 + Non è stato possibile raggiungere l\'elenco delle tessere sanitarie. Per favore riprova. + Puoi trovare informazioni verificate da esperti su malattie, codici ICD e su temi di prevenzione e cura sul Portale Sanitario Nazionale. + Apri Gesund.bund.de + Abbiamo modificato l\'informativa sulla privacy + L\'app per la prescrizione elettronica si è evoluta. Ciò ha reso necessario aggiornare la nostra politica sulla privacy. + Apri l\'informativa sulla privacy + Questo è cambiato dal %s : + Cosa succede quando apri l\'app? + Cosa succede se utilizzo la funzione fotocamera / leggo le ricette con la fotocamera? + Nessuna nuova ricetta disponibile + + %s nuova ricetta + %s nuove ricette + + Riscattabile + Nel riscatto + Redento + Sconosciuto + Visualizza i log di accesso + Chi ha avuto accesso alle tue ricette e quando? + Chiave di accesso al servizio di prescrizione + log di accesso + Nessun registro di accesso + Non ci sono ancora registri di accesso. + La ricetta è attualmente in lavorazione e non può essere cancellata + Accettare + A quanto pare non ha funzionato + Siamo consapevoli che il collegamento con la tessera sanitaria ha le sue insidie. In futuro, quindi, la registrazione dovrebbe essere possibile anche tramite un\'app di assicurazione sanitaria già autenticata. \n\n Stiamo anche lavorando per consentire il riscatto digitale delle prescrizioni senza registrazione. \n\n Hai notato qualcosa durante questo processo che vorresti condividere con noi? Per favore scrivici, siamo anche felici di ricevere feedback molto critici. + Suggerimenti per la connessione + Migliora la forza della connessione + Se necessario, rimuovere la copertura protettiva. + Se il dispositivo vibra e quindi interrompe la connessione, cercare la posizione ottimale entro un raggio ridotto. + Muovi il dispositivo sulla mappa molto lentamente. + Posizionare il dispositivo direttamente sulla scheda. + Per fare ciò appoggiare la tessera sanitaria su una superficie piana (es. un tavolo). + Migliora la forza della connessione + Notare il posizionamento del sensore NFC + Scopri dove si trova il sensore NFC nel tuo dispositivo (qui, ad esempio, una panoramica dei dispositivi di %s ). + In alcuni casi, la posizione del sensore NFC può differire all\'interno di una serie di modelli (qui, ad esempio, le informazioni per %s ). + Prossimo Consiglio + Ulteriore + Vicino + Provare + scrivici + Licenza di ricerca farmacia + riscattare + Prescrizione scansionata + Scansionato su %s + Contrassegnato come riscattato su %s + Come vuoi continuare? + Ordine + Disponibile a breve + Prenota ora per il ritiro o fallo consegnare tramite corriere o spedizione + Salva per ordine successivo + Salva le ricette sul dispositivo + + Continua con la ricetta %s + Continua con %s ricette + + Impossibile collegare la tessera sanitaria + Il profilo attuale è già collegato ad un\'altra tessera sanitaria (numero di assicurazione sanitaria %s ). + La tua tessera sanitaria è già collegata ad un altro profilo. Passa al profilo %s . + Salva sul computer + recapiti e indirizzo + Contatto + numero di telefono + Si prega di fornire un numero di telefono per il contatto. + Indirizzo di posta (facoltativo) + indirizzo di consegna + nome e cognome + Si prega di inserire un nome e cognome per scopi di contatto. + Via e numero civico + Inserisci una via e un numero civico per essere ricontattato. + Indirizzo aggiuntivo (facoltativo) + Istruzioni di consegna (facoltativo) + Ulteriori informazioni di contatto richieste + Non salvare le modifiche? + scartare + Per la ricerca, la directory della farmacia utilizza le coordinate geografiche che sono state determinate con l\'aiuto di OpenStreetMap. Ringraziamo il progetto per questo aiuto. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Privacy e utilizzo + Ulteriore + Hai ricevuto il PIN in una lettera dalla tua compagnia di assicurazione sanitaria. + Nessun PIN ricevuto + Codice PIN + Controlla la connessione a Internet e l\'impostazione di ora/data del tuo dispositivo. + Per accedere, premere \"Sblocca\". + chiuso fuori? Verifica le tue credenziali biometriche su questo dispositivo. + Ha dimenticato la password? Elimina l\'app e reinstallala. Puoi scoprire perché nel nostro %s . + zona di aiuto + confezione e unità + principio attivo + Quantità di principio attivo + designazione del lotto + Esp + categoria + Vaccino + Accettare + Annullato + Avviso + Aiutaci a migliorare questa app + Inserire la password + La password deve essere lunga almeno otto caratteri + Sicurezza della password non sufficiente + Sicurezza della password sufficiente + La password è visibile + La password non è visibile + biometrica + parola d\'ordine + aspettando una risposta + Nessuna prescrizione + Al momento non hai prescrizioni rimborsabili. + Aggiornare + Disconnessione automatica + Per motivi di sicurezza, la connessione al server delle ricette viene interrotta dopo 12 ore. Riconnettiti per ottenere le ricette correnti. + Collegare + Hai ricevuto una copia cartacea? + Aggiungi ricette alla tua lista toccando il pulsante di scansione nell\'angolo in alto a destra. + Eseguire la scansione della stampa cartacea + Devi essere loggato per ricevere le ricette automaticamente. + Registrati + Nessuna prescrizione riscattata + Le tue prescrizioni riscattate vengono visualizzate qui. Per motivi di protezione dei dati, le tue ricette verranno cancellate dal server delle ricette dopo 100 giorni. + Nessuna prescrizione riscattata + Le tue prescrizioni riscattate vengono visualizzate qui. Aggiungi prescrizioni tramite scansione per iniziare a riscattare. + gestione dei dispositivi + Dispositivi connessi + Registrato da %s (questo dispositivo) + Registrato da %s + Per motivi di sicurezza, la connessione al server delle ricette viene interrotta dopo 12 ore. Per riconnettersi servono tessera sanitaria e PIN per ogni processo di connessione. + Codice PIN + Inserisci il tuo PIN (tessera sanitaria). + Ulteriore + Registrati + Dispositivi connessi + rimuovere il dispositivo? + Interrompere + RIMOSSO + Rimuovere questo dispositivo? + Vuoi rimuovere %s ? + Se rimuovi %s , la connessione al server della ricetta verrà disconnessa definitivamente entro 12 ore al massimo. + Caricamento dispositivi in corso... + Nessun dispositivo + Non ci sono dispositivi collegati a questa tessera sanitaria. + Riprova + Uh Oh :-( + Impossibile caricare l\'elenco dei dispositivi. + wwweg… + Nessuna connessione internet. + Medicinali e medicazioni + stupefacenti + Consegna di farmaci soggetti a prescrizione ai sensi del § 4 AMVV + Hai bisogno di aiuto? + Abbiamo raccolto alcuni consigli per risolvere i problemi più comuni. + Avvia suggerimenti per la connessione + sbloccare + carta bloccata + Il PIN è stato inserito in modo errato per tre volte. La tua carta è stata quindi bloccata per motivi di sicurezza. + carta di sblocco + Inserisci PUK + Con il tuo PIN hai ricevuto un PUK a 8 cifre dalla tua compagnia assicurativa. + Scegli nuovo PIN + Puoi scegliere tu stesso il tuo nuovo numero di identificazione personale (PIN) (da 6 a 8 cifre). + PIN ricordato? + Prendi nota del PIN e conservalo in un luogo sicuro. + Interrompere + OK + Sblocco non possibile + Hai raggiunto il numero massimo di carte sbloccate con questo PUK o lo hai inserito ripetutamente in modo errato. Si prega di contattare la propria compagnia assicurativa. + Puoi utilizzare un PUK per un massimo di 10 sblocchi. + carta sbloccata + Quello che ti serve: + la tua tessera sanitaria + PUK della tua tessera sanitaria + Ulteriore + tessera sanitaria + Ordine PIN o carta + Registrati + Come vuoi accedere? + Tessera sanitaria abilitata NFC + PIN per la tessera sanitaria + Non hai ancora tessera sanitaria e PIN abilitati NFC? + Applica ora + Oppure: Accedi con %s . + La tua app per l\'assicurazione sanitaria + "Il tuo numero di accesso si trova nell\'angolo in alto a destra della tua tessera sanitaria." + La mia carta non ha un numero di accesso + + Hai altri %s tentativi prima che la tua carta venga bloccata. + Hai altri %s tentativi prima che la tua carta venga bloccata. + + Metti la tessera sanitaria sul retro del telefono + Il seguente processo può richiedere fino a 30 secondi. + Posiziona la carta %s sul retro del telefono. + nell\'angolo in alto a destra + nella parte centrale superiore + in alto a sinistra + nella zona centrale a destra + mezzo + nel centrosinistra + nella zona in basso a destra + in basso al centro + in basso a sinistra + Aiuto + Inviato %s minuti fa + Inviato il %s + Inviato proprio ora + Inviato alle %s in punto + Non più valido + Accedi con l\'app + scegli l\'assicurazione + Non hai trovato quello che stavi cercando? Questo elenco viene costantemente ampliato. La registrazione con tessera sanitaria è già supportata da tutte le compagnie di assicurazione sanitaria. + Feedback dall\'app di prescrizione elettronica + Non vediamo l\'ora di ricevere il tuo feedback. Si prega di utilizzare lo spazio sottostante e di essere il più precisi possibile: + PUK + Vicino + Che peccato… + Sfortunatamente, il tuo dispositivo non soddisfa i requisiti minimi per accedere all\'app di prescrizione elettronica. Per l\'autenticazione sicura con la tessera sanitaria sono necessari almeno Android 7 e un chip NFC. + Saperne di più + Salvare i dati di accesso? + Salva sul computer + Non salvare + Avviso + Per motivi di sicurezza, la connessione al server delle ricette viene interrotta dopo 12 ore. Per riconnettersi servono tessera sanitaria e PIN per ogni processo di connessione. + Imposta la sicurezza biometrica + Impossibile salvare i dati di accesso. Imposta in anticipo la sicurezza biometrica (ad es. impronta digitale) sul tuo dispositivo. + Interrompere + Idee + Avviso + Accettare + Sicurezza dei tuoi dati di prescrizione + \"Questa app utilizza il sensore biometrico più sicuro fornito dal tuo dispositivo per archiviare le tue credenziali in un\'area sicura della memoria del dispositivo.\" + La sicurezza biometrica dei tuoi dati di accesso ti consente di aprire in futuro questa app senza inserire PIN e tessera sanitaria e di visualizzare, richiamare, riscattare o cancellare le prescrizioni. + Assicurati che anche le persone con cui potresti condividere questo dispositivo e le cui caratteristiche biometriche potrebbero essere memorizzate su questo dispositivo abbiano accesso alle tue prescrizioni. + che purtroppo non ha funzionato + L\'autenticazione con l\'app della cassa malati non è riuscita. + Scaduto il %s + La ricetta è già stata cancellata dal server + Correggi l\'input o annulla le modifiche + Corretto + dati assicurati + Cognome + Assicurazione + numero di polizza + numero di accesso alla carta + Registrati + Annulla registrazione + Salva sul computer + Modifica + Modifica la foto profilo + Ulteriore + il server non risponde + Per favore riprova più tardi. + Riprova + Cerca un\'assicurazione + Connettersi ora al server delle ricette? + Accesso effettuato con successo + Collegamento perso + Connettersi ora al server delle ricette? + Nessun gettone + Riceverai un token quando avrai effettuato l\'accesso al servizio di prescrizione.\n + ordini + Seleziona il PIN desiderato + carta di sblocco + Scegli PIN + Ripetere PIN + Le voci differiscono l\'una dall\'altra. + Nessun ordine + Non hai ancora nessun ordine. + Proprio adesso + Alle %s in punto + Il carrello è pronto + La ricetta è stata aggiunta al tuo carrello. Vai al sito web della farmacia per completare l\'ordine. + Apri carrello + Mostra questo codice di ritiro in farmacia. + Ricevi il codice di ritiro + Il messaggio non può essere visualizzato + Contatta la tua farmacia ( %s ). + Mostra link al carrello + Mostra il codice di ritiro + Mostra il messaggio + %s alle %s in punto + Ricetta inviata a %s . + Panoramica dell\'ordine + Nuovo + Corso + Ordine + Gratuito per il chiamante. Orari di servizio: Lun - Ven 8:00 - 20:00 escluse le festività nazionali + Farmacia + Seleziona il PIN desiderato + PIN desiderato salvato + Attualmente aperto e vicino a me + Filtra per... + Inizia la ricerca + affidamento diretto + farmacie + numero di telefono (facoltativo) + Cerca per nome o indirizzo + Nessuna informazione valida sulla farmacia + Non sono state trovate informazioni aggiornate su questa farmacia. La voce per questa farmacia verrà cancellata. + OK + Elenco delle farmacie non disponibile + Al momento non è possibile recuperare informazioni aggiornate su questa farmacia. Per favore controlla la tua connessione Internet. + Interrompere + Riprova + Salva Ambiente + Non è possibile accedere + Sembra che le tue credenziali di accesso biometrico siano cambiate. Si prega di registrarsi nuovamente con la propria tessera sanitaria. + Interrompere + Registrati + profilo 1 + Vicino a me + Riscattabile in seguito + Riscattabile da %s + miglioramenti del prodotto + Analisi anonima + Aiutaci a migliorare questa app. Tutti i dati di utilizzo vengono raccolti in forma anonima e vengono utilizzati solo per migliorare l\'esperienza dell\'utente. + sicurezza del dispositivo + impostazioni personali + Accessibilità + miglioramenti del prodotto + Ricetta aggiunta + Ricetta già disponibile + Si è verificato un errore durante l\'importazione + Spegnere + Prescrizione scansionata + Sostituzione possibile + PIN dimenticato + + %s ricetta + %s Ricette + + Ho letto e accetto l\'informativa sulla privacy e i termini di utilizzo. + Protezione dati + Termini di utilizzo + Vorremmo: + Migliora l\'usabilità. + Rileva errori e arresti anomali. + Tutti i dati sono naturalmente raccolti in forma anonima. + Puoi modificare questa decisione nelle impostazioni di sistema in qualsiasi momento. + Continua + Accettare + Questa app utilizza il metodo più sicuro fornito dal tuo dispositivo. + Salva sul computer + Scegliere + farmaco + nome depositato + + NO + dosaggio + data di rilascio + Questa prescrizione verrà riscattata per te come parte di un trattamento. + Non specificato + pagamento aggiuntivo + farmaco + Bolle di consegna + Idoneo secondo LPP + preparazione alternativa + nome della ricetta + Confezione + istruzione di lavorazione + Descrizione + dato da + rilasciato il: + principio attivo + prescritta + Ricevere + Che cos\'è un incarico diretto? + In caso di invio diretto, una prescrizione di uno studio o di un ospedale viene riscattata direttamente in farmacia. Gli assicurati non devono intraprendere alcuna azione e non possono intervenire nel processo di riscatto. \n\n I referral diretti sono elencati nell\'app di prescrizione elettronica per rendere il trattamento più trasparente per te. + tariffa del servizio di emergenza + A volte è necessaria la fretta. Alcune prescrizioni possono essere riscattate senza il pagamento aggiuntivo di una tariffa per il servizio di emergenza, ad esempio di notte o nei giorni festivi. + Farmaci soggetti a ticket + Esente da partecipazione al pagamento + Coloro che hanno un\'assicurazione sanitaria obbligatoria devono pagare una partecipazione ai costi fino a dieci euro per i farmaci da prescrizione. \n\n L\'importo del ticket dipende dal prezzo dei medicinali. Devi pagare tu stesso i farmaci che costano meno di 5€.\n Per i medicinali più costosi, devi pagare il dieci per cento del prezzo, ma almeno 5€ e non più di 10€. \n\n I bambini ei giovani di età inferiore ai 18 anni sono generalmente esentati dal ticket. \n\n Se i tuoi costi annuali per i farmaci superano il tuo limite finanziario, puoi essere esentato dalla partecipazione ai costi. Parlane con la tua cassa malati. + Sei esente dal co-pagamento di questo farmaco. La tua assicurazione sanitaria coprirà il costo del farmaco. + Per quanto tempo è valida questa prescrizione? + Durante questo periodo puoi riscattare la tua ricetta in qualsiasi farmacia con un pagamento aggiuntivo massimo di 10€. + Sostituzione possibile + A causa dei requisiti legali della tua compagnia di assicurazione sanitaria, puoi ricevere un\'alternativa con lo stesso principio attivo. \n\n I medicinali possono avere un aspetto ed essere chiamati in modo diverso, hanno prezzi e produttori diversi, ma contengono sempre lo stesso principio attivo. Il principio attivo stesso e il dosaggio sono particolarmente importanti per l\'effetto dei farmaci nel corpo. I pazienti in farmacia spesso ricevono un farmaco diverso da quello prescritto dal medico sulla prescrizione, a condizione che i farmaci siano comparabili. Ci possono essere ragioni terapeutiche ed economiche per il cambiamento. + Prescrizione scansionata + Per motivi di sicurezza, le prescrizioni importate da una stampa cartacea non devono riportare alcun dato personale o medico. \n\n Accedi a questa app con tessera sanitaria o app assicurativa per visualizzare tutte le informazioni contenute nella ricetta. + Ricetta errata + Questa prescrizione è stata emessa in modo errato. + Prescrizione scansionata + tariffa del servizio di emergenza + Dosaggio secondo istruzioni scritte + telefono + luogo + Posta + Ordinamento per distanza non possibile. + OK + Inserisci il PIN attuale + PIN errato inserito + Il PIN attuale della tua tessera sanitaria + carta bloccata + Sblocca la tua carta in Impostazioni > Sblocca carta. + Per motivi di sicurezza, inserisci il tuo PIN attuale. + PIN dimenticato + Ricetta sbagliata + farmaco + Qualcosa sembra essere andato storto durante la creazione della tua ricetta. Segnalare un errore? + Rapporto + Accesso non effettuato + Registrato con + tessera sanitaria + biometrica + Accesso non effettuato + Siamo interessati alla tua opinione. Ti preghiamo di dedicare cinque minuti per rispondere al nostro sondaggio. Grazie in anticipo. + avviso di avvertimento + Farmacia aggiunta ai preferiti + Farmacia rimossa dai preferiti + Le mie farmacie + Sicurezza della password molto buona + Operazione di scrittura non riuscita + Impossibile salvare il PIN + Rapporto + Assegna PIN + Regola di accesso violata + Non sei autorizzato ad accedere alla directory della mappa. + Assegna il tuo pin + La carta è protetta da un PIN della tua compagnia di assicurazione sanitaria (PIN di trasporto), si prega di assegnare il proprio PIN. + Password non trovata + Non c\'è nessuna password memorizzata sulla tua carta. + Sei stato disconnesso + Accedi di nuovo per aggiornare le tue ricette. + numero di principio attivo + potenza e unità + Riscattato %s minuti fa + Riscattato il %s + Riscattato proprio ora + Riscattato alle %s in punto + Ordini + Questa prescrizione è stata riscattata per te come parte di un trattamento. + tariffa del servizio di emergenza + Questa prescrizione non può essere compilata di notte in una farmacia senza il pagamento aggiuntivo di una tassa per il servizio di emergenza. + Cerca qui + Idee + Condividi la posizione nelle impostazioni. + Vicino a me + Tenere premuto per modificare il nome. + Immettere il nuovo nome per il profilo. + Devi essere loggato per ricevere le prescrizioni digitali dal tuo studio. + Ricevi le ricette in digitale? + Trascina lo schermo verso il basso per aggiornare. + Nessuna prescrizione + Aggiungi ricette utilizzando il pulsante + nell\'angolo in alto a destra. + Registrati + archivio prescrizioni + Forse più tardi + Registrati + Modifica la foto profilo + archivio prescrizioni + Inserisci il nome + Salva sul computer + Il mio ordine + Destinatario: dentro + ricette + Farmacia + Inviare + Modifica + Ritiro in farmacia + Consegna tramite corriere + Consegna per posta + %s Ricette + Riscatto non possibile + Non è stato possibile riscattare una o più prescrizioni. + Nessuna ricetta selezionata + Per riscattare le ricette, è necessario selezionare almeno una ricetta. + Aggiungi informazioni di contatto + Modifica + Nessuna prescrizione + Al momento non hai prescrizioni rimborsabili + collezione + ragazzo delle consegne + Spedizione + scegli le ricette + Tocca qui per scansionare le ricette + Premere a lungo per modificare i nomi + Aggiungi più profili, ad esempio per i tuoi figli o genitori + Fare clic sul display per saltare il suggerimento visualizzato. + Come riscattare? + Come vorresti ricevere i tuoi farmaci? + Riscatta direttamente + Riscatta i farmaci in loco + Ordine + Prenota o fatti consegnare + Pronto + codice collettivo + codici singoli + + Hai %s ricetta. + Hai %s ricette. + + fare una selezione + Tutte le ricette + Quali ricette? + Ulteriore + Ulteriore + Saperne di più + Avviso + Questa app utilizza il software di Google per riconoscere i codici. + Saperne di più + Informazioni sullo scanner del codice della ricetta + Quali dati contiene il codice della ricetta? + Il codice della ricetta contiene solo un identificatore della ricetta. Ciò consente di reperire la prescrizione sul servizio di prescrizione della rete sanitaria digitale. Il codice di prescrizione non contiene dati su di te o sui tuoi farmaci. + Quindi nessuno può fare nulla solo con il codice della ricetta? + Corretto. I dati della prescrizione devono essere scaricati dal servizio di prescrizione. Ciò richiede un accesso sicuro. + Chi può registrarsi al servizio di prescrizione? + L\'iscrizione al servizio di prescrizione nella rete sanitaria digitale è possibile per assicurati, farmacie, studi medici e ospedali. + Perché l\'app per la prescrizione elettronica utilizza le funzionalità di Google? + Google offre funzioni che possono essere facilmente integrate nelle app e che vengono costantemente sviluppate e aggiornate da Google. Ciò garantisce che le funzioni funzionino su molti dispositivi terminali diversi e possano essere utilizzate in modo sicuro. L\'app utilizza una funzione per migliorare la fotocamera e la funzionalità di scansione per i dispositivi Android (Google ML Kit). + Come funziona il miglioramento della scansione di Google ML Kit? + Google ML Kit aiuta a ottimizzare l\'immagine catturata da una fotocamera in modo che i codici delle ricette possano essere letti anche in condizioni di scarsa illuminazione o con modelli di fotocamere meno recenti. + I dati sulla prescrizione o sul mio farmaco verranno trasmessi a Google? + NO. Il codice della ricetta letto viene salvato direttamente nell\'app. Non verrà trasmesso a Google. I dati di prescrizione non sono memorizzati nel codice, solo nella rete sanitaria digitale. Da lì vengono inviati all\'app. Google non ha accesso alla rete sanitaria digitale. + Quali dati elabora Google quando utilizza ML Kit? + Google ha accesso solo alle informazioni tecniche sul dispositivo finale utilizzato e sull\'uso generale della funzione aggiuntiva (ad es. Tasso di errore, impostazioni della fotocamera) per registrarle statisticamente e quindi migliorare la funzione aggiuntiva. Quando accedi, Google registra temporaneamente l\'indirizzo IP del tuo terminale. Le informazioni su di te e il contenuto della ricetta non verranno registrati da Google. + L\'uso di Google ML Kit è volontario? + SÌ. Tuttavia, ML Kit è integrato nello scanner del codice della ricetta nella versione Android dell\'app di prescrizione elettronica. Se si utilizza lo scanner del codice ricetta su un dispositivo Android, viene sempre utilizzata anche la funzione ML Kit. Tuttavia, puoi fare a meno di utilizzare lo scanner del codice della ricetta. Le tue prescrizioni possono essere caricate in app anche se ti registri alla rete sanitaria digitale con la tessera sanitaria elettronica o tramite la tua app della cassa malati. + Posso vedere chi ha visualizzato le mie ricette? + SÌ. Tutti gli accessi ai tuoi dati sono completamente registrati nella rete sanitaria digitale. Nell\'app di prescrizione elettronica puoi vedere chi ha avuto accesso ai tuoi dati. + Chi posso contattare se ho domande sull\'app o sulla ricetta elettronica? + Puoi trovare informazioni dettagliate nella dichiarazione sulla protezione dei dati. + Numero di confezioni prescritte + Nessuna prescrizione + Per questo hai bisogno di prescrizioni rimborsabili. + scegli l\'assicurazione + Cerca un\'assicurazione + Interrompere + Per cosa vorresti candidarti? + Per questa app è necessaria una carta e il PIN associato. + Come vorresti contattare la tua compagnia assicurativa? + La tua compagnia assicurativa offre le seguenti opzioni di contatto + La tua compagnia assicurativa offre le seguenti opzioni di contatto + Vicino + PIN inserito in modo errato. + Numero di accesso inserito in modo errato + PUK inserito in modo errato. + ricevute di spesa + Mostra le ricevute di spesa + ricevute di spesa + Per ricevere le ricevute di spesa è necessario essere connessi al server. + Collegare + Nessuna ricevuta di spesa + Disattivare + Interrompere + disabilitare la funzione + Questo eliminerà tutte le ricevute da questo dispositivo e dal server. + Ricevi le ricevute delle spese + Anche le tue ricevute di spesa vengono salvate sul server delle ricette. + Ricevere + Totale: %s %s + Scegliere + Diviso + Spegnere + Spegnere + Invia + %s € + prezzo totale + Suggerimento: invia le ricevute delle spese tramite l\'app dell\'assicurazione + Invia facilmente le ricevute dei costi tramite l\'app della tua compagnia assicurativa. Nel passaggio successivo, seleziona questa app e premi Condividi. + Pratica + Farmacia + Data + mostra di più + ID farmaco + Rilasciato per + KVNR: %s + Data di nascita: %s + OK + Come si inviano le ricevute? + Trasferimento direttamente all\'app della tua compagnia assicurativa/ufficio di assistenza. Per fare ciò, seleziona l\'app nella pagina successiva. + O + Salva il file e successivamente importalo nel portale assicurazioni/aiuti. + Articolo: %s + Numero: %s + IVA: %s %% + Prezzo lordo in EUR: %s + Tariffe aggiuntive + tariffa del servizio di emergenza + Commissione BTM + Tassa di prescrizione T + costi di approvvigionamento + Servizio di corriere + Totale in EUR: %s + prelievo + Eliminare davvero? + Il file verrà eliminato dal tuo dispositivo e dal server. + Spegnere + Inserito + Codice postale + Posizione + Inserisci il tuo codice postale per contattarci. + Inserisci il tuo luogo di residenza quando ci contatti. + sarà riscattato per te + è stato riscattato per te + Devi essere loggato per utilizzare questo servizio. + app assicurativa + tessera sanitaria + PIN associato richiesto + Per ricevere i log di accesso, è necessario essere connessi al server. + Entro questo termine potete comunque compilare la ricetta in farmacia, ma dovrete pagare voi stessi l\'intero prezzo d\'acquisto del medicinale. In alternativa potete chiedere al vostro studio di farvi riemettere la prescrizione. + Pronto + Richiedi la correzione + In farmacia + Nell\'app + Fai scansionare questo codice in farmacia. + Richiesta di correzione della fatturazione + diff --git a/android/src/main/res/values-nl/strings.xml b/android/src/main/res/values-nl/strings.xml new file mode 100644 index 00000000..f6ef428c --- /dev/null +++ b/android/src/main/res/values-nl/strings.xml @@ -0,0 +1,852 @@ + + + OK + Onderbreken + Opbrengst + rondom + Digitaal. Snel. Zeker. + Taak-ID + toegangscode + Gebruiksvoorwaarden + Gegevensbescherming + recepten + Cameratoegang geweigerd + Om de scanner te gebruiken, moet je de app toegang geven tot je camera in de systeeminstellingen. + Richt de camera op een receptcode + Dit is geen geldige receptcode + Deze receptcode is al gescand + + %s recept herkend + %s recepten herkend + + Onderbreken + camera licht + Scannen annuleren? + OK + Annuleer niet + Daar gaan we + Wat je nodig hebt: + Voer het toegangsnummer van de kaart in + voer de pincode in + probeer het nog eens + Kan geen verbinding maken met de server. + + Je hebt nog %s pogingen voordat je kaart wordt geblokkeerd. + Je hebt nog %s pogingen voordat je kaart wordt geblokkeerd. + + Het toegangsnummer vindt u rechtsboven op uw gezondheidskaart. + Onderbreken + Zoek naar kaart... + Houd de gezondheidskaart tegen de achterkant van uw apparaat. + Nog steeds aan het zoeken … + Verplaats de kaart langzaam aan de achterkant van het apparaat. + Tip + Apparaatbehuizingen kunnen het moeilijk maken om verbinding te maken via NFC. + kaart herkend + Probeer de gezondheidskaart niet te verplaatsen. + Gezondheidskaart gevonden. Gelieve niet te bewegen. + verbinding verbroken + Houd uw gezondheidskaart opnieuw tegen de achterkant van het apparaat + Versie: %s + Build-hash: %s + debug-menu + Open tot %s + De hele dag geopend + afdruk + editor + gematik GmbH\n Friedrichstraße 136\n 10117 Berlijn + Directeur: dr. medisch Markus Leyck-Dieken\n Registratierechtbank: arrondissementsrechtbank Berlijn-Charlottenburg\n Handelsregisternummer: HRB 96351\n Btw-identificatienummer: DE241843684 + Verantwoordelijk voor de inhoud + Dr medisch Markus Leyck-Dieken + Contact + Kennisgeving + We streven ernaar om genderneutraal taalgebruik te gebruiken. Als u fouten opmerkt, horen we graag van u via e-mail. + Duitslands moderne platform voor digitale geneeskunde + mail schrijven + website openen + Welkom + Start registratie + ontgrendelen + Register + Onderbreken + Beveiliging + Juridisch + afdruk + gegevensbescherming + Gebruiksvoorwaarden + details + Markeer als ingewisseld + Markeer als niet ingewisseld + doseringsvorm + pakket grootte + Verzekerd persoon + Achternaam + adres + geboortedatum + Ziektekostenverzekering / betalers + toestand + verzekerings nummer + Voorschrijvende persoon + Achternaam + Medische specialist + Artsennummer (LANR) + instelling + Achternaam + adres + Bedrijfspand nummer + telefoonnummer + Mail adres + ongeval op het werk + ongeval dag + Ongeval bedrijfs- of werkgeversnummer + Wil je dit recept permanent verwijderen? + Blussen + Onderbreken + openingstijden + website + Alleen vandaag inwisselbaar als zelfbetaler + Register + Activeer NFC + Activeer de NFC-functie van uw toestel om in te loggen met uw gezondheidskaart. + Activeren + Juist + Recepten ingewisseld? + Wilt u de recepten markeren als ingewisseld? + Niet ingewisseld + Ingewisseld + Opent om %s + +49 800 277 377 7 + Technische hotline + Open scanner voor recepten + Ideeën + Onderdruk schermafbeeldingen + Voorkomt de weergave van een miniatuur bij het schakelen tussen apps + Staat u toe dat e-recipe uw gebruiksgedrag anoniem analyseert? + Technische informatie + Beveiliging van uw receptgegevens + Zorg ervoor dat personen met wie u dit apparaat mogelijk deelt en van wie de biometrische kenmerken op dit apparaat kunnen worden opgeslagen, ook toegang hebben tot uw recepten. + verzenden is mislukt + Geen e-mailprogramma ingesteld + Geen resultaten + We konden geen resultaten vinden voor deze zoekterm. + Open Source-licenties + Contact + Bel de technische hotline + Doe mee aan enquête + +49 800 277 377 7 + Ik wil helpen deze app beter te maken + Dit omvat hardware- en software-informatie op uw telefoon, instellingen voor de e-prescription-app en de hoeveelheid gebruik, maar nooit gegevens over u of uw gezondheid. + De gegevens worden alleen door de gegevensverwerker aan gematik GmbH ter beschikking gesteld en uiterlijk na 180 dagen verwijderd. U kunt de analyse op elk moment weer deactiveren in het app-menu. + Deze gegevens stellen ons in staat om te begrijpen welke functies vaak worden gebruikt en om deze te verbeteren. Verder kunnen we inschatten hoe lang oudere technologie ondersteund moet worden en wanneer we bijvoorbeeld een nieuwere versie van het besturingssysteem verplicht kunnen stellen zonder dat dit gevolgen heeft voor (te veel) gebruikers. + app verbeteren + Anonieme analyse blijft uitgeschakeld + %s Bedankt voor uw steun! + Register + Identificeer uzelf om recepten te downloaden. + Opmerking voor apotheken: De contactgegevens en informatie over apotheken verkrijgen wij van mein-apothekenportal.de van de Duitse Apothekersvereniging Heeft u een fout ontdekt of wilt u gegevens corrigeren? + Kom meer te weten + apotheken + Dat werkte helaas niet \uD83D\uDE15 + Probeer het opnieuw. + Voer wachtwoord in + Verder + Toegankelijkheid + zoom + Hiermee kunt u de app vergroten door uw vingers samen te knijpen of te spreiden (pinch-to-zoom). + wachtwoord + Beveilig uw gegevens met een wachtwoord naar keuze. + wachtwoord + Opslaan op computer + laat wachtwoord zien + herhaal wachtwoord + Aanbevelingen: %s + mail schrijven + Wanneer u uw bericht verzendt, wordt de volgende informatie over de gebruikte hardware en het besturingssysteem verzonden: + Alleen ter plaatse inwisselen + U kunt nog geen e-recepten naar deze apotheek sturen. + Momenteel geopend + Koeriersdienst + Verzending + filter + Filter + Geen locatie beschikbaar + Begrepen + Herhaalde wachtwoordovereenkomsten + Fout 20 10 76631 + Uw gezondheidskaartcertificaat is ongeldig. Is uw kaart verlopen? Neem dan contact op met uw zorgverzekering. + Mislukte inlogpogingen + + Er zijn %s mislukte inlogpogingen gedetecteerd. + Er zijn %s mislukte inlogpogingen gedetecteerd. + + Kies de beste apparaatback-up + Dit kan een vingerafdruk, veegpatroon of iets dergelijks zijn + Munten + toegangstoken + SSO-tokens + Geen toegangstoken beschikbaar + geen SSO-token beschikbaar + gekopieerd naar het klembord + Klik om het token naar het klembord te kopiëren + Alleen vandaag geldig + Toestaan + geen verbinding met de server + Probeer het over een paar minuten opnieuw + Laad opnieuw + fiches tonen + Hoe wil je de app beveiligen? + Kennisgeving + Er is geen apparaatback-up ingesteld voor dit apparaat + We raden u aan om uw medische gegevens extra te beschermen met apparaatbeveiliging zoals een toegangscode of biometrie. + Laat deze melding in de toekomst niet meer zien. + Verbinding mislukt. Er kon geen netwerkverbinding tot stand worden gebracht. + Communicatie met de server mislukt: statuscode %s . + Kan niet communiceren met de server: controleer de internetverbinding en de tijd-/datuminstellingen. + waarschuwing + Uw apparaat is mogelijk minder beveiligd + Dit kan bijvoorbeeld worden veroorzaakt door gemanipuleerde apparaten of een geactiveerde ontwikkelaarsmodus. Om veiligheidsredenen raden we het gebruik van de app op gejailbreakte apparaten af. + Ik erken het verhoogde risico en wil toch doorgaan. + Waarom vormen apparaten met root-toegang een potentieel beveiligingsrisico? + Kom meer te weten + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Profielnaam + Voer een naam in voor het nieuwe profiel. + profielnaam + profielen + Hoe een NFC-enabled gezondheidskaart te herkennen + Geen contact mogelijk via deze app + Gebruik de gebruikelijke kanalen om contact op te nemen met uw verzekeringsmaatschappij. + Gezondheidskaart & pincode + Alleen pincode + Registratie in de e-recepten app + Het naamveld mag niet leeg zijn. + Er bestaat al een profiel met de ingevoerde naam. + profiel + %s geselecteerd + Achtergrond kleur + lente grijs + zonnedauw + Het! Is! Roze! + Boom + Blauwe maan september + Niet ingelogd + Samengebonden + Laatst verbonden op %s + Verwijder profiel? + Hiermee worden alle profielgegevens op dit apparaat gewist. Uw voorschriften in het gezondheidsnetwerk blijven intact. + Blussen + Onderbreken + Verwijder profiel + U wilt het laatste profiel verwijderen. + De app vereist ten minste één profiel. Voer een naam in voor het nieuwe profiel. + Fout 20 10 76831 + De directory met gezondheidskaarten kon niet worden bereikt. Probeer het opnieuw. + Op het Nationaal Gezondheidsportaal vindt u deskundig geverifieerde informatie over ziekten, ICD-codes en over preventie- en zorgkwesties. + Open Gesund.bund.de + We hebben het privacybeleid gewijzigd + De app voor e-recepten is geëvolueerd. Dit heeft het noodzakelijk gemaakt om ons privacybeleid te actualiseren. + Privacybeleid openen + Dit is veranderd sinds de %s : + Wat gebeurt er als je de app opent? + Wat gebeurt er als ik de camerafunctie gebruik / recepten lees met de camera? + Geen nieuwe recepten beschikbaar + + %s nieuw recept + %s nieuwe recepten + + Inwisselbaar + In verlossing + Ingewisseld + Onbekend + Toegangslogboeken bekijken + Wie heeft toegang gekregen tot uw recepten en wanneer? + Toegangssleutel tot de receptenservice + toegangslogboeken + Geen toegangslogboeken + Er zijn nog geen toegangslogboeken. + Het recept wordt momenteel verwerkt en kan niet worden verwijderd + Aanvaarden + Dat werkte blijkbaar niet + We zijn ons ervan bewust dat de koppeling met de zorgpas valkuilen kent. In de toekomst moet registratie dus ook mogelijk zijn via een reeds geauthenticeerde zorgverzekeringsapp. \n\n We werken er ook aan om recepten digitaal in te wisselen zonder te registreren. \n\n Is u tijdens dit proces iets opgevallen dat u met ons wilt delen? Schrijf ons alstublieft, ook zeer kritische feedback ontvangen wij graag. + Verbindingstips + Verbeter de sterkte van de verbinding + Verwijder indien nodig de beschermkap. + Als het apparaat trilt en vervolgens de verbinding verbreekt, zoek dan naar de optimale positie binnen een kleine straal. + Beweeg het apparaat heel langzaam over de kaart. + Plaats het apparaat direct op de kaart. + Leg hiervoor de gezondheidskaart op een vlakke ondergrond (bijvoorbeeld een tafel). + Verbeter de sterkte van de verbinding + Let op de plaatsing van de NFC-sensor + Zoek uit waar de NFC-sensor zich in uw apparaat bevindt (hier bijvoorbeeld een overzicht voor apparaten van %s ). + In sommige gevallen kan de positie van de NFC-sensor binnen een modelserie verschillen (hier bijvoorbeeld de informatie voor de %s ). + Volgende tip + Verder + Dichtbij + Probeer + Schrijf ons + Zoeklicentie voor apotheek + inwisselen + Gescand voorschrift + Gescand op %s + Gemarkeerd als ingewisseld op %s + Hoe wil je verder? + Volgorde + Binnenkort beschikbaar + Reserveer nu om af te halen of te laten bezorgen per koerier of verzending + Bewaar voor latere bestelling + Bewaar recepten op het apparaat + + Ga verder met %s recept + Ga verder met %s recepten + + Verbinding met gezondheidskaart is mislukt + Het huidige profiel is al gekoppeld aan een andere zorgkaart (ziekteverzekeringsnummer %s ). + Je gezondheidskaart is al gekoppeld aan een ander profiel. Schakel over naar profiel %s . + Opslaan op computer + contactgegevens en adres + Contact + telefoonnummer + Geef een telefoonnummer op voor contact. + E-mailadres (optioneel) + bezorgadres + voornaam en achternaam + Vul a.u.b. een voor- en achternaam in voor contactdoeleinden. + straat en huisnummer + Vul a.u.b. een straatnaam en huisnummer in zodat wij gecontacteerd kunnen worden. + Extra adres (optioneel) + Bezorginstructie (optioneel) + Aanvullende contactgegevens vereist + Veranderingen ongedaan maken? + weggooien + Voor het zoeken gebruikt de apotheekdirectory geografische coördinaten die zijn bepaald met behulp van OpenStreetMap. Wij danken het project voor deze hulp. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Privacy & Gebruik + Verder + U heeft uw pincode ontvangen in een brief van uw zorgverzekeraar. + Geen pincode ontvangen + pincode + Controleer de internetverbinding en de tijd-/datuminstelling van uw apparaat. + Om in te loggen, drukt u op “Ontgrendelen”. + buitengesloten? Verifieer uw biometrische referenties op dit apparaat. + Wachtwoord vergeten? Verwijder de app en installeer deze opnieuw. U kunt ontdekken waarom in onze %s . + hulp gebied + verpakkingsgrootte en eenheid + actief ingrediënt + Hoeveelheid actief ingrediënt + batch aanduiding + Exp + categorie + Vaccin + Aanvaarden + Ongedaan gemaakt + Kennisgeving + Help ons deze app beter te maken + Voer wachtwoord in + Het wachtwoord moet minimaal acht tekens lang zijn + Wachtwoordsterkte niet voldoende + Wachtwoordsterkte voldoende + Wachtwoord is zichtbaar + Wachtwoord is niet zichtbaar + biometrie + wachtwoord + wachten op antwoord + Geen recepten + U heeft momenteel geen inwisselbare recepten. + Updaten + Automatisch uitloggen + Om veiligheidsredenen wordt de verbinding met de receptenserver na 12 uur verbroken. Maak opnieuw verbinding om actuele recepten te krijgen. + Aansluiten + Heeft u een papieren exemplaar ontvangen? + Voeg recepten toe aan uw lijst door op de scanknop in de rechterbovenhoek te tikken. + Scan de papieren afdruk + Je moet ingelogd zijn om recepten automatisch te ontvangen. + Register + Geen ingewisselde recepten + Uw ingewisselde recepten worden hier weergegeven. Om redenen van gegevensbescherming worden uw recepten na 100 dagen van de receptenserver verwijderd. + Geen ingewisselde recepten + Uw ingewisselde recepten worden hier weergegeven. Voeg recepten toe via scan om te beginnen met inwisselen. + apparaatbeheer + Verbonden apparaten + Geregistreerd sinds %s (dit apparaat) + Geregistreerd sinds %s + Om veiligheidsredenen wordt de verbinding met de receptenserver na 12 uur verbroken. Om opnieuw verbinding te maken, hebt u voor elk verbindingsproces een gezondheidskaart en een pincode nodig. + pincode + Voer uw pincode (gezondheidskaart) in. + Verder + Register + Verbonden apparaten + Verwijder apparaat? + Onderbreken + VERWIJDERD + Dit apparaat verwijderen? + Wilt u %s verwijderen? + Als u %s verwijdert, wordt de verbinding met de receptenserver uiterlijk binnen 12 uur definitief verbroken. + Apparaten worden geladen... + Geen apparaten + Er zijn geen toestellen aangesloten op deze gezondheidskaart. + Probeer het nog eens + Oh Oh :-( + Apparatenlijst kon niet worden geladen. + wwweg… + Geen internet verbinding. + Medicijnen en verbandmiddelen + narcotica + Levering van geneesmiddelen op recept volgens § 4 AMVV + Heb je hulp nodig? + We hebben enkele tips voor je op een rij gezet om de meest voorkomende problemen op te lossen. + Begin met verbindingstips + ontgrendelen + kaart geblokkeerd + De pincode is drie keer verkeerd ingevoerd. Uw kaart is daarom om veiligheidsredenen geblokkeerd. + kaart ontgrendelen + Voer PUK in + Met uw pincode heeft u van uw verzekeringsmaatschappij een 8-cijferige PUK ontvangen. + Kies een nieuwe pincode + U kunt zelf uw nieuwe persoonlijk identificatienummer (PIN) kiezen (6 tot 8 cijfers). + Pincode onthouden? + Noteer uw pincode en bewaar deze op een veilige plaats. + Onderbreken + OK + Ontgrendelen niet mogelijk + U heeft het maximale aantal kaartontgrendelingen met deze puk bereikt of heeft deze herhaaldelijk verkeerd ingevoerd. Neem dan contact op met uw verzekeringsmaatschappij. + U kunt één PUK gebruiken voor maximaal 10 ontgrendelingen. + kaart ontgrendeld + Wat je nodig hebt: + uw gezondheidskaart + PUK van uw zorgpas + Verder + gezondheidskaart + Pincode of kaart bestellen + Register + Hoe wil je inloggen? + NFC-enabled gezondheidskaart + Pincode voor de zorgpas + Heb je nog geen NFC-compatibele gezondheidskaart en pincode? + Nu toepassen + Of: Log in met de %s . + Uw zorgverzekering app + "Uw toegangsnummer vindt u rechtsboven op uw gezondheidskaart." + Mijn kaart heeft geen toegangsnummer + + Je hebt nog %s pogingen voordat je kaart wordt geblokkeerd. + Je hebt nog %s pogingen voordat je kaart wordt geblokkeerd. + + Plaats de gezondheidskaart op de achterkant van de telefoon + Het volgende proces kan tot 30 seconden duren. + Plaats kaart %s op de achterkant van de telefoon. + in de rechterbovenhoek + in het bovenste midden + linksboven + in het middengebied aan de rechterkant + midden + in het centrum links + in het gebied rechtsonder + in het onderste midden + linksonder + Hulp + %s minuten geleden verzonden + Verzonden op %s + Zojuist verzonden + Verzonden om %s uur + Niet meer geldig + Log in met de app + verzekering kiezen + Niet gevonden wat u zocht? Deze lijst wordt voortdurend uitgebreid. Registratie met een zorgpas wordt al door elke zorgverzekeraar ondersteund. + Feedback van de e-recepten-app + We kijken uit naar uw feedback. Gebruik de ruimte hieronder en wees zo nauwkeurig mogelijk: + PUK + Dichtbij + Wat jammer… + Helaas voldoet uw apparaat niet aan de minimale vereisten om in te loggen op de e-recepten-app. Voor veilige authenticatie met je zorgpas zijn minimaal Android 7 en een NFC-chip nodig. + Kom meer te weten + Inloggegevens bewaren? + Opslaan op computer + Sla niet op + Kennisgeving + Om veiligheidsredenen wordt de verbinding met de receptenserver na 12 uur verbroken. Om opnieuw verbinding te maken, hebt u voor elk verbindingsproces uw gezondheidskaart en pincode nodig. + Stel biometrische beveiliging in + Het opslaan van toegangsgegevens is niet mogelijk. Stel vooraf biometrische beveiliging (bijv. vingerafdruk) op uw apparaat in. + Onderbreken + Ideeën + Kennisgeving + Aanvaarden + Beveiliging van uw receptgegevens + \"Deze app gebruikt de veiligste biometrische sensor van uw apparaat om uw inloggegevens op te slaan in een beveiligd gedeelte van het apparaatgeheugen.\" + Door de biometrische beveiliging van uw toegangsgegevens kunt u deze app in de toekomst zonder invoer van uw pincode en gezondheidskaart openen en recepten inzien, opvragen, inwisselen of verwijderen. + Zorg ervoor dat personen met wie u dit apparaat mogelijk deelt en van wie de biometrische kenmerken op dit apparaat kunnen worden opgeslagen, ook toegang hebben tot uw recepten. + dat is helaas niet gelukt + Verificatie met de zorgverzekeringsapp is niet gelukt. + Verlopen op %s + Het recept is al verwijderd van de server + Corrigeer uw invoer of gooi wijzigingen weg + Juist + verzekerde gegevens + Achternaam + Verzekering + verzekerings nummer + kaart toegangsnummer + Register + Afmelden + Opslaan op computer + Wijziging + Profielfoto wijzigen + Verder + server reageert niet + Probeer het later opnieuw. + Probeer het nog eens + Zoek naar verzekeringen + Nu verbinding maken met de receptenserver? + succesvol ingelogd + verbinding verbroken + Nu verbinding maken met de receptenserver? + Geen penningen + U ontvangt een token wanneer u bent ingelogd op de receptenservice.\n + bestellingen + Selecteer de gewenste pincode + kaart ontgrendelen + Kies pincode + Herhaal pincode + De inzendingen verschillen van elkaar. + Geen bestellingen + U heeft nog geen bestellingen. + Net nu + Om %s uur + Winkelwagen is klaar + Het recept is toegevoegd aan je winkelmandje. Ga naar de website van de apotheek om de bestelling af te ronden. + Winkelwagen openen + Toon deze afhaalcode bij de apotheek. + Ophaalcode ontvangen + Bericht kan niet worden getoond + Neem contact op met uw apotheek ( %s ). + Winkelwagenlink tonen + Toon afhaalcode + Laat het bericht zien + %s om %s uur + Recept verzonden naar %s . + Bestel overzicht + Nieuw + Cursus + Volgorde + Gratis voor de beller. Servicetijden: ma - vr 08:00 - 20:00 behalve op nationale feestdagen + Apotheek + Selecteer de gewenste pincode + Gewenste pincode opgeslagen + Momenteel open en bij mij in de buurt + Filteren op … + start met zoeken + directe opdracht + apotheken + telefoon nummer (optioneel) + Zoek op naam of adres + Geen geldige apotheekinformatie + Er is geen actuele informatie gevonden over deze apotheek. De invoer voor deze apotheek wordt verwijderd. + OK + Apotheeklijst niet beschikbaar + Momenteel kan er geen actuele informatie over deze apotheek worden opgevraagd. Controleer uw internetverbinding. + Onderbreken + Probeer het nog eens + Milieu redden + Inloggen is niet mogelijk + Het lijkt erop dat uw biometrische inloggegevens zijn gewijzigd. Gelieve opnieuw te registreren met uw gezondheidskaart. + Onderbreken + Register + profiel 1 + Dicht bij mij + Later inwisselbaar + Inwisselbaar vanaf %s + productverbeteringen + Anonieme analyse + Help ons deze app beter te maken. Alle gebruiksgegevens worden anoniem verzameld en worden alleen gebruikt om de gebruikerservaring te verbeteren. + apparaat beveiliging + persoonlijke instellingen + Toegankelijkheid + productverbeteringen + Recept toegevoegd + Recept al beschikbaar + Er is een fout opgetreden tijdens het importeren + Blussen + Gescand voorschrift + Vervanging mogelijk + Pincode vergeten + + %s recept + %s Recepten + + Ik heb het privacybeleid en de gebruiksvoorwaarden gelezen en geaccepteerd. + Gegevensbescherming + Gebruiksvoorwaarden + We zouden graag: + Verbeter de bruikbaarheid. + Detecteer fouten en crashes. + Alle gegevens worden uiteraard anoniem verzameld. + U kunt deze beslissing op elk moment wijzigen in de systeeminstellingen. + Doorgaan + Aanvaarden + Deze app gebruikt de veiligste methode van uw apparaat. + Opslaan op computer + Kiezen + medicijn + handelsnaam + Ja + Nee + dosering + Uitgavedatum + Dit recept wordt voor u ingewisseld als onderdeel van een behandeling. + Niet gespecificeerd + extra betaling + medicijn + Pakbonnen + Komt in aanmerking volgens BVG + alternatieve bereiding + recept naam + Verpakking + knutselinstructie + Beschrijving + gegeven door + uitgegeven op: + actief ingrediënt + voorgeschreven + Ontvangen + Wat is een directe opdracht? + Bij directe verwijzingen wordt een recept uit een praktijk of ziekenhuis direct bij een apotheek ingewisseld. Verzekerden hoeven niets te doen en kunnen niet tussenkomen in het afkoopproces. \n\n Directe verwijzingen worden vermeld in de e-prescription-app om uw behandeling voor u transparanter te maken. + toeslag voor noodhulp + Soms is haast geboden. Sommige recepten kunnen worden ingewisseld zonder extra betaling van een spoedservice, zoals \'s nachts of op feestdagen. + Geneesmiddelen met eigen bijdrage + Vrijgesteld van eigen bijdrage + Degenen met een wettelijke ziektekostenverzekering moeten een eigen bijdrage betalen van maximaal tien euro voor geneesmiddelen op recept. \n\n De hoogte van het eigen risico is afhankelijk van de prijs van uw medicatie. Geneesmiddelen die minder dan € 5 kosten, moet u zelf betalen.\n Voor medicijnen die duurder zijn, moet u tien procent van de prijs betalen, maar minimaal € 5 en maximaal € 10. \n\n Kinderen en jongeren onder de 18 jaar zijn over het algemeen vrijgesteld van eigen bijdrage. \n\n Als uw jaarlijkse kosten voor geneesmiddelen uw financiële grens overschrijden, kunt u worden vrijgesteld van de eigen bijdrage. Overleg hierover met uw zorgverzekeraar. + U bent vrijgesteld van de eigen bijdrage van dit geneesmiddel. Uw zorgverzekering vergoedt de medicatie. + Hoe lang is dit recept geldig? + Tijdens deze periode kunt u uw recept in elke apotheek inwisselen tegen een maximale bijbetaling van € 10,-. + Vervanging mogelijk + Vanwege de wettelijke vereisten van uw zorgverzekeraar kunt u een alternatief krijgen met dezelfde werkzame stof. \n\n Geneesmiddelen kunnen er anders uitzien en anders worden genoemd, hebben verschillende prijzen en fabrikanten, maar bevatten toch dezelfde werkzame stof. Vooral de werkzame stof zelf en de dosering zijn belangrijk voor de werking van medicijnen in het lichaam. Patiënten in de apotheek krijgen vaak een ander middel dan de arts op het recept heeft voorgeschreven - mits de middelen vergelijkbaar zijn. Er kunnen therapeutische en economische redenen zijn voor de verandering. + Gescand voorschrift + Om veiligheidsredenen mogen recepten die zijn geïmporteerd uit een papieren afdruk geen persoonlijke of medische gegevens bevatten. \n\n Log in op deze app met de zorgkaart of verzekeringsapp om alle informatie op het recept te bekijken. + Recept klopt niet + Dit voorschrift is ten onrechte afgegeven. + Gescand voorschrift + toeslag voor spoedeisende hulp + Dosering volgens schriftelijke instructies + telefoon + plaats + Mail + Sorteren op afstand is niet mogelijk. + OK + Voer de huidige pincode in + Onjuiste pincode ingevoerd + De huidige pincode van uw zorgpas + kaart geblokkeerd + Deblokkeer je kaart in Instellingen > Kaart deblokkeren. + Voer om veiligheidsredenen uw huidige pincode in. + Pincode vergeten + Onjuist recept + medicijn + Er lijkt iets mis te zijn gegaan tijdens het maken van je recept. Fout melden? + Rapport + Niet ingelogd + Aangemeld met + gezondheidskaart + biometrie + Niet ingelogd + Wij zijn geïnteresseerd in uw mening. Neem vijf minuten de tijd om onze enquête in te vullen. Alvast bedankt. + waarschuwingsbericht + Apotheek toegevoegd aan favorieten + Apotheek verwijderd uit favorieten + Mijn apotheken + Wachtwoordsterkte zeer goed + Schrijfbewerking mislukt + Pincode kan niet worden opgeslagen + Rapport + Pincode toewijzen + Toegangsregel geschonden + U heeft geen toestemming om toegang te krijgen tot de kaartmap. + Wijs uw eigen pincode toe + De kaart is beveiligd met een pincode van uw zorgverzekeraar (transportpincode), wijs uw eigen pincode toe. + Wachtwoord niet gevonden + Er is geen wachtwoord op uw kaart opgeslagen. + je bent uitgelogd + Log opnieuw in om uw recepten bij te werken. + actief ingrediënt nummer + kracht en eenheid + %s minuten geleden ingewisseld + ingewisseld op %s + Zojuist verzilverd + Ingewisseld om %s uur + Bestellingen + Dit recept is voor u ingewisseld als onderdeel van een behandeling. + toeslag voor noodhulp + Dit recept kan niet \'s nachts in een apotheek worden ingevuld zonder extra betaling van een spoedservicetarief. + Zoek hier + Ideeën + Locatie delen in instellingen. + Dicht bij mij + Houd ingedrukt om de naam te bewerken. + Voer de nieuwe naam voor het profiel in. + U moet ingelogd zijn om digitale recepten van uw praktijk te ontvangen. + Recepten digitaal ontvangen? + Sleep het scherm omlaag om te vernieuwen. + Geen recepten + Voeg recepten toe met de + knop in de rechterbovenhoek. + Register + receptenarchief + Misschien later + Register + Profielfoto wijzigen + receptenarchief + Voer naam in + Opslaan op computer + Mijn bestelling + Ontvanger: in + recepten + Apotheek + Versturen + Wijziging + Afhalen bij de apotheek + Levering per koerier + Levering per post + %s Recepten + Inwisselen niet mogelijk + Een of meer recepten konden niet worden ingewisseld. + Geen recept geselecteerd + Om recepten in te wisselen, moet er ten minste één recept zijn geselecteerd. + Contactgegevens toevoegen + Wijziging + Geen recept + U heeft momenteel geen inwisselbare recepten + verzameling + koerier + Verzending + kies recepten + Tik hier om recepten te scannen + Lang indrukken om namen te bewerken + Voeg meer profielen toe, bijvoorbeeld voor uw kinderen of ouders + Klik op het scherm om de weergegeven tooltip over te slaan. + Hoe inwisselen? + Hoe wilt u uw medicatie ontvangen? + Direct inwisselen + Medicijnen ter plekke inwisselen + Volgorde + Reserveer of laat het bezorgen + Klaar + collectieve code + enkele codes + + U heeft een recept van %s . + Je hebt %s recepten. + + Maak een selectie + Alle recepten + Welke recepten? + Verder + Verder + Kom meer te weten + Kennisgeving + Deze app gebruikt software van Google om codes te herkennen. + Kom meer te weten + Over de receptcodescanner + Welke gegevens bevat de receptcode? + De receptcode bevat alleen een identificatie van het recept. Hierdoor is het recept terug te vinden op de receptenservice in het digitale gezondheidsnetwerk. De receptcode bevat geen gegevens over u of uw medicatie. + Dus niemand kan iets met de receptcode alleen? + Juist. De receptgegevens moeten worden gedownload van de receptenservice. Hiervoor is een beveiligde login vereist. + Wie kan zich inschrijven voor de receptenservice? + Inschrijven bij de receptenservice in het digitale gezondheidsnetwerk is mogelijk voor verzekerden, apotheken, artsenpraktijken en ziekenhuizen. + Waarom gebruikt de e-prescription-app Google-functies? + Google biedt functies die eenvoudig in apps kunnen worden ingebouwd en die voortdurend door Google worden ontwikkeld en bijgewerkt. Dit zorgt ervoor dat de functies op veel verschillende eindapparaten werken en veilig kunnen worden bediend. De app gebruikt een functie om de camera- en scanfunctionaliteit voor Android-apparaten te verbeteren (Google ML Kit). + Hoe werkt Google ML Kit-scanverbetering? + Google ML Kit helpt het door een camera vastgelegde beeld te optimaliseren, zodat de receptcodes zelfs bij slechte lichtomstandigheden of met oudere cameramodellen kunnen worden gelezen. + Worden gegevens over het voorschrift of mijn medicatie doorgegeven aan Google? + Nee. De gelezen receptcode wordt direct in de app opgeslagen. Het wordt niet doorgegeven aan Google. De receptgegevens worden niet in de code opgeslagen, alleen in het digitale gezondheidsnetwerk. Van daaruit worden ze naar de app gestuurd. Google heeft geen toegang tot het digitale gezondheidsnetwerk. + Welke gegevens verwerkt Google bij het gebruik van ML Kit? + Google heeft alleen toegang tot technische informatie over het gebruikte eindapparaat en het algemene gebruik van de extra functie (bijv. foutpercentage, camera-instellingen) om dit statistisch vast te leggen en zo de extra functie te verbeteren. Bij uw toegang registreert Google tijdelijk het IP-adres van uw eindapparaat. Informatie over u en de inhoud van het recept wordt niet door Google vastgelegd. + Is het gebruik van Google ML Kit vrijwillig? + Ja. ML Kit is echter ingebouwd in de receptcodescanner in de Android-versie van de e-prescription-app. Als u de receptcodescanner op een Android-apparaat gebruikt, wordt ook altijd de ML Kit-functie gebruikt. U kunt het echter zonder de receptcodescanner doen. Uw recepten kunnen ook in de app worden geladen als u zich met de elektronische gezondheidskaart of via de app van uw zorgverzekering aanmeldt bij het digitale zorgnetwerk. + Kan ik zien wie mijn recepten heeft bekeken? + Ja. Alle toegang tot uw gegevens wordt volledig ingelogd in het digitale gezondheidsnetwerk. In de e-recepten-app kunt u zien wie er toegang heeft tot uw gegevens. + Met wie kan ik contact opnemen als ik vragen heb over de app of het e-recept? + Gedetailleerde informatie vindt u in de gegevensbeschermingsverklaring. + Aantal voorgeschreven verpakkingen + Geen recepten + Hiervoor heeft u verzilverbare recepten nodig. + verzekering kiezen + Zoek naar verzekeringen + Onderbreken + Wat wilt u aanvragen? + Voor deze app heb je een pas en de bijbehorende pincode nodig. + Hoe wilt u contact opnemen met uw verzekeringsmaatschappij? + Uw verzekeringsmaatschappij biedt de volgende contactmogelijkheden + Uw verzekeringsmaatschappij biedt de volgende contactmogelijkheden + Dichtbij + Pincode onjuist ingevoerd. + Toegangsnummer verkeerd ingevoerd + PUK verkeerd ingevoerd. + onkostenbonnen + Onkostennota\'s tonen + onkostenbonnen + Om onkostennota\'s te ontvangen, moet u verbonden zijn met de server. + Aansluiten + Geen onkostennota\'s + Deactiveren + Onderbreken + functie uitschakelen + Hiermee worden alle betalingsbewijzen van dit apparaat en van de server verwijderd. + Onkostennota\'s ontvangen + Ook uw kostenbonnen worden op de receptenserver bewaard. + Ontvangen + Totaal: %s %s + Kiezen + Splitsen + Blussen + Blussen + Indienen + %s € + totale prijs + Tip: Dien declaraties in via de verzekeringsapp + Dien eenvoudig kostenbonnen in via de app van uw verzekeringsmaatschappij. Selecteer in de volgende stap deze app en druk op Delen. + Oefening + Apotheek + Datum + laat meer zien + Medicijn-ID + Afgegeven voor + KVNR: %s + Geboortedatum: %s + OK + Hoe dient u bonnetjes in? + Zet direct over naar de app van uw verzekeringsmaatschappij/hulpkantoor. Selecteer hiervoor de app op de volgende pagina. + of + Sla het bestand op en importeer het later in het verzekerings-/hulpportaal. + Artikel: %s + Getal: %s + BTW: %s %% + Brutoprijs in EUR: %s + Extra toeslagen + toeslag voor spoedeisende hulp + BTM-vergoeding + T recept vergoeding + inkoop kosten + Koeriersdienst + Totaal in EUR: %s + heffing + Echt verwijderen? + Het bestand wordt van uw apparaat en van de server verwijderd. + Blussen + Geplaatst + Postcode + Plaats + Vul uw postcode in om contact met ons op te nemen. + Vul uw woonplaats in als u contact met ons opneemt. + Wordt voor je verzilverd + Is voor u verzilverd + U moet ingelogd zijn om van deze dienst gebruik te kunnen maken. + verzekering app + gezondheidskaart + Bijbehorende pincode vereist + Om toegangslogboeken te ontvangen, moet u verbonden zijn met de server. + Binnen deze termijn kunt u het recept nog steeds bij een apotheek invullen, maar u moet dan wel de volledige aankoopprijs van het medicijn zelf betalen. U kunt ook uw praktijk vragen om het recept opnieuw te laten verstrekken. + Klaar + Correctie aanvragen + Bij de apotheek + In de app + Laat deze code scannen bij uw apotheek. + Factureringscorrectieverzoek + diff --git a/android/src/main/res/values-pl/strings.xml b/android/src/main/res/values-pl/strings.xml index 8a60cce6..d503c060 100644 --- a/android/src/main/res/values-pl/strings.xml +++ b/android/src/main/res/values-pl/strings.xml @@ -1,6 +1,5 @@ - E-recepta OK Anuluj Powrót @@ -177,18 +176,6 @@ Brak dostępnych lokalizacji Rozumiem Ponownie wprowadzone hasło zgadza się - - Możliwość zrealizowania jeszcze przez %s dzień jako płatnik indywidualny - Możliwość zrealizowania jeszcze przez %s dni jako płatnik indywidualny - - - - - Ważne jeszcze %s dzień - Ważne jeszcze %s dni - - - Błąd 20 10 76631 Certyfikat Twojej karty zdrowia jest nieważny. Być może termin ważności Twojej karty już upłynął. Skontaktuj się ze swoją kasą chorych. Bezskuteczne próby zalogowania się @@ -284,9 +271,7 @@ To jest kod dostępu do aplikacji E-recepta Protokoły dostępu Brak protokołów dostępu - Otrzymasz protokoły dostępu, jeśli jesteś zalogowany na serwerze z receptami. Brak jeszcze protokołów dostępu. - Ostatnia aktualizacja dnia %s Recepta jest teraz edytowana i nie można jej usunąć Zaakceptuj Wygląda na to, że operacja nie powiodła się @@ -352,7 +337,7 @@ Nie otrzymałem(am) kodu PIN PIN Sprawdź połączenie z internetem oraz ustawienie godziny/daty na swoim urządzeniu. - Aby przeprowadzić uwierzytelnienie, naciśnij \"Odblokuj\". + Aby się zalogować, naciśnij „Odblokuj”. Nie możesz uzyskać dostępu? Sprawdź swoje biometryczne dane dostępowe na tym urządzeniu. Nie pamiętasz hasła? Usuń aplikację i następnie zainstaluj ją ponownie. Z naszego %s dowiesz się, dlaczego tak się dzieje. Pomoc @@ -366,7 +351,7 @@ Zaakceptuj Cofnij Wskazówka - Pomożesz nam ulepszyć tę aplikację? + Pomóż nam ulepszyć tę aplikację Wybierz własne hasło Hasło musi zawierać co najmniej osiem znaków Niewystarczająca siła hasła @@ -444,10 +429,7 @@ Karta zdrowia Zamów PIN lub kartę Zaloguj się - Jak chcesz się uwierzytelnić? - Aplikacja ubezpieczeniowa - Karta ubezpieczeniowa - Wymagany powiązany kod PIN + Jak chcesz się zalogować? Karta zdrowia obsługująca funkcję NFC PIN do karty zdrowia Nie masz jeszcze karty zdrowia obsługującej funkcję NFC i kodu PIN? @@ -649,8 +631,7 @@ Osoby posiadające ustawowe ubezpieczenie zdrowotne muszą zapłacić do dziesięciu euro za leki na receptę. \n\n Wysokość dopłaty zależy od ceny leku. Sam musisz zapłacić za leki, które kosztują mniej niż 5 euro.\n W przypadku droższych leków trzeba zapłacić dziesięć procent ceny, ale co najmniej 5 euro, a maksymalnie 10 euro. \n\n Dzieci i młodzież poniżej 18 roku życia są z reguły zwolnione ze współpłacenia. \n\n Jeśli Twoje roczne koszty leków przekraczają Twój limit finansowy, możesz zostać zwolniony ze współpłacenia. Porozmawiaj o tym ze swoim ubezpieczycielem zdrowotnym. Jesteś zwolniony ze współpłacenia tego leku. Twoje ubezpieczenie zdrowotne pokryje koszty leków. Jak długo ta recepta jest ważna? - W tym okresie możesz zrealizować receptę w dowolnej aptece za dodatkową opłatą. - W tym okresie możesz jeszcze zrealizować receptę w aptece, ale musisz sam zapłacić cenę zakupu. Możesz też poprosić swoją praktykę o ponowne wystawienie recepty. + W tym okresie możesz zrealizować receptę w dowolnej aptece za maksymalną dopłatą w wysokości 10 €. Możliwość wyboru preparatu zastępczego Ze względu na wymagania prawne Twojej firmy ubezpieczeniowej, możesz otrzymać alternatywę z tą samą substancją czynną. \n\n Leki mogą wyglądać i nazywać się inaczej, mieć różne ceny i producentów, a mimo to zawierają ten sam składnik aktywny. Sam składnik aktywny i dawkowanie są szczególnie ważne dla działania leków na organizm. Pacjenci w aptece często otrzymują inny lek niż ten przepisany przez lekarza na receptę – pod warunkiem, że leki są porównywalne. Zmiana może mieć przyczyny terapeutyczne i ekonomiczne. Zeskanowana recepta @@ -721,11 +702,11 @@ Brak recept Dodaj recepty za pomocą przycisku + w prawym górnym rogu. Zaloguj sie - Realizowane recepty + archiwum recept Może później Zaloguj sie Edytuj zdjęcie profilowe - Realizowane recepty + archiwum recept Podaj nazwę Zapisz Moje zamówienie @@ -747,7 +728,7 @@ Bez recepty Obecnie nie masz żadnych recept do zrealizowania ulec poprawie - dostawca + kurier Wysyłka wybieraj recepty Kliknij tutaj, aby zeskanować recepty @@ -873,22 +854,15 @@ Zostanie dla ciebie odkupiony Został odkupiony dla ciebie Aby korzystać z tej usługi, musisz być zalogowany. - " Recepty zostały pomyślnie przeniesione." - Recepta never może zostać zrealizowana. Proszę sprobuj ponownie. Być może będziesz musiał wybrać inną aptekę. - Recepta never może zostać zrealizowana. Apteka zgłasza nieznany błąd. W razie potrzeby spróbuj w innej aptece. - Recepta została odrzucona przez aptekę. Recepta może być nieważna lub Twój address dostawy lub dane kontaktowe mogą być nieprawidłowe. - Never można wykorzystać, sprawdź swoje połączenie internetowe. - Recepta została pomyślnie przeniesiona. Jednak apteka zgłasza błąd przzweirzania. Prosimy o contact z apteką. - Recepta została odrzucona przez aptekę. Recepta została już zrealizowana. - Recepta została odrzucona przez aptekę. Przepis został usunięty. - Recepta never mogła zostać przeniesiona. Sprawdź połączenie internetowe i spróbuj ponownie. - Nie można przenieść jednego lub więcej przepisów. - Wyslano pomyślnie! - Błąd w aptece - Błąd w aptece - Skontaktuj się z apteką - Recepta już zrealizowana - Przepis usunięty - Brak internetu - Błąd wysyłania + Aplikacja ubezpieczeniowa + Karta ubezpieczeniowa + Wymagany powiązany kod PIN + Aby otrzymać logi dostępowe musisz być połączony z serwerem. + W tym okresie nadal możesz zrealizować receptę w aptece, ale całą cenę zakupu leku będziesz musiał sam zapłacić. Alternatywnie możesz poprosić swoją praktykę o ponowne wystawienie recepty. + Gotowe + Poproś o korektę + W aptece + W aplikacji + Zeskanuj ten kod w swojej aptece. + Żądanie korekty płatności diff --git a/android/src/main/res/values-ro/strings.xml b/android/src/main/res/values-ro/strings.xml new file mode 100644 index 00000000..382d8297 --- /dev/null +++ b/android/src/main/res/values-ro/strings.xml @@ -0,0 +1,860 @@ + + + Bine + Întrerupe + Întoarcere + în jurul + Digital. Rapid. Sigur. + ID-ul sarcinii + cod de acces + Termeni de utilizare + Protejarea datelor + Rețete + Accesul la cameră a fost interzis + Pentru a utiliza scanerul, trebuie să permiteți accesul aplicației la camera dvs. în setările de sistem. + Focalizează camera pe un cod de rețetă + Acesta nu este un cod de prescripție valid + Acest cod de rețetă a fost deja scanat + + Rețeta %s a fost recunoscută + + %s rețete recunoscute + + Întrerupe + lumina camerei + Anulați scanarea? + Bine + Nu anulați + Începem + De ce ai nevoie: + Introduceți numărul de acces al cardului + introduceți codul PIN + încearcă din nou + Eroare de conectare la server. + + Mai aveți %s încercări înainte ca cardul dvs. să fie blocat. + + Mai aveți %s încercări înainte ca cardul dvs. să fie blocat. + + Numărul de acces îl veți găsi în partea dreaptă sus a cardului dumneavoastră de sănătate. + Întrerupe + Caută harta... + Țineți cardul de sănătate în spatele dispozitivului. + Încă mai caut… + Mutați încet cardul din spatele dispozitivului. + Bacsis + Carcasele dispozitivului pot îngreuna conectarea prin NFC. + card recunoscut + Încercați să nu mutați cardul de sănătate. + Carte de sănătate găsită. Te rog nu te mișca. + conexiunea pierdută + Țineți cardul de sănătate pe spatele dispozitivului din nou + Versiune: %s + Build Hash: %s + meniul de depanare + Deschis până %s + Deschis toată ziua + imprima + editor + gematik GmbH\n Friedrichstrasse 136\n 10117 Berlin + Director general: Dr. medical Markus Leyck-Dieken\n Judecătoria de înregistrare: tribunalul districtual Berlin-Charlottenburg\n Număr registru comercial: HRB 96351\n Număr de identificare fiscală: DE241843684 + Responsabil pentru conținut + dr medical Markus Leyck-Dieken + a lua legatura + Înștiințare + Ne străduim să folosim un limbaj neutru din punct de vedere al genului. Dacă observați vreo eroare, așteptăm cu nerăbdare să primim răspunsuri prin e-mail. + Platforma modernă a Germaniei pentru medicina digitală + scrie mail + site web deschis + Bine ati venit + Începeți înregistrarea + debloca + Inregistreaza-te + Întrerupe + Securitate + Legal + imprima + protejarea datelor + Termeni de utilizare + Detalii + Marcați ca răscumpărat + Marcați ca nerăscumpărat + forma de dozare + dimensiunea pachetului + Persoana asigurata + Nume de familie + abordare + Data de naștere + Asigurări de sănătate / Plătitori + stare + numar de asigurare + Persoana care prescrie + Nume de familie + Medic specialist + Numărul medicului (LANR) + instituţie + Nume de familie + abordare + Numărul sediului comercial + număr de telefon + adresa postala + accident la locul de muncă + ziua accidentului + Firma accidentului sau numărul angajatorului + Doriți să ștergeți definitiv această rețetă? + A stinge + Întrerupe + ore de deschidere + site-ul web + Rambursabil doar astăzi ca plătitor propriu + Inregistreaza-te + Activați NFC + Vă rugăm să activați funcția NFC a dispozitivului dvs. pentru a vă conecta cu cardul de sănătate. + Activati + Corect + Rețete răscumpărate? + Doriți să marcați rețetele ca răscumpărate? + Nu este răscumpărat + Răscumpărat + Se deschide la %s + +49 800 277 377 7 + Linia de asistență tehnică + Deschideți scanerul pentru rețete + Idei + Suprimați capturile de ecran + Împiedică afișarea unei miniaturi atunci când comutați între aplicații + Permiteți e-rețetei să vă analizeze comportamentul de utilizare în mod anonim? + Informații tehnice + Securitatea datelor dumneavoastră de prescripție + Vă rugăm să vă asigurați că persoanele cu care puteți partaja acest dispozitiv și ale căror caracteristici biometrice pot fi stocate pe acest dispozitiv au și acces la rețetele dumneavoastră. + trimitere esuata + Nu a fost configurat niciun program de e-mail + Fara rezultate + Nu am găsit niciun rezultat pentru acest termen de căutare. + Licențe Open Source + a lua legatura + Apelați linia de asistență tehnică + Participa la sondaj + +49 800 277 377 7 + Vreau să ajut la îmbunătățirea acestei aplicații + Acestea includ informații despre hardware și software de pe telefon, setări pentru aplicația de prescriere electronică și cantitatea de utilizare, dar niciodată date despre tine sau despre sănătatea ta. + Datele sunt puse la dispoziția gematik GmbH numai de către procesorul de date și sunt șterse cel târziu după 180 de zile. Puteți dezactiva analiza din nou în orice moment în meniul aplicației. + Aceste date ne permit să înțelegem ce funcții sunt utilizate frecvent și să le îmbunătățim. Mai mult, putem estima cât timp trebuie suportată tehnologia mai veche și când putem, de exemplu, să facem obligatorie o versiune mai nouă a sistemului de operare fără a afecta (prea mulți) utilizatori. + îmbunătăți aplicația + Analiza anonimă rămâne dezactivată + %s Vă mulțumim pentru sprijin! + Inregistreaza-te + Vă rugăm să vă identificați pentru a descărca rețete. + Notă pentru farmacii: Obținem datele de contact și informațiile despre farmacii de la mein-apothekenportal.de al Asociației Germane de Farmacie Ați descoperit o eroare sau doriți să corectați datele? + Află mai multe + farmacii + Din păcate, nu a funcționat \uD83D\uDE15 + Vă rugăm să încercați din nou. + Introdu parola + Mai departe + Accesibilitate + zoom + Vă permite să măriți aplicația prin ciupirea sau desfășurarea degetelor (pentru a mări). + parola + Asigurați-vă datele cu o parolă la alegere. + parola + Salvați pe computer + arata parola + Repetați parola + Recomandări: %s + scrie mail + Când trimiteți mesajul dvs., vor fi transmise următoarele informații despre hardware-ul și sistemul de operare utilizat: + Valorificați numai pe site + Încă nu puteți trimite rețete electronice la această farmacie. + Momentan deschis + serviciu de mesagerie + Expediere + filtru + Filtru + Nicio locație disponibilă + Înțeles + Parola repetată se potrivește + Eroare 20 10 76631 + Certificatul cardului de sănătate este invalid. Ți-a expirat cardul? Vă rugăm să contactați asigurarea dumneavoastră de sănătate. + Încercări de conectare nereușite + + Au fost detectate %s încercări de conectare nereușite. + + Au fost detectate %s încercări de conectare nereușite. + + Alegeți cel mai bun backup pentru dispozitiv + Aceasta poate fi o amprentă, model de glisare sau similar + jetoane + jeton de acces + Jetoane SSO + Nu există un jeton de acces disponibil + nu este disponibil niciun simbol SSO + copiat în clipboard + Faceți clic pentru a copia jetonul în clipboard + Valabil doar azi + Permite + nicio conexiune la server + Vă rugăm să încercați din nou în câteva minute + Încărcați din nou + arată jetoane + Cum ați dori să securizați aplicația? + Înștiințare + Nu a fost configurată nicio copie de rezervă a dispozitivului pentru acest dispozitiv + Vă recomandăm să vă protejați suplimentar datele medicale cu securitatea dispozitivului, cum ar fi un cod de acces sau datele biometrice. + Nu mai afișa această notificare în viitor. + Conexiune esuata. O conexiune la rețea nu a putut fi stabilită. + Comunicarea cu serverul a eșuat: codul de stare %s . + Nu s-a putut comunica cu serverul: vă rugăm să verificați conexiunea la internet și setările de oră/data. + avertizare + Este posibil ca dispozitivul dvs. să aibă securitate redusă + Acest lucru poate fi cauzat, de exemplu, de dispozitive manipulate sau de un mod de dezvoltator activat. Din motive de securitate, nu vă recomandăm să utilizați aplicația pe dispozitive cu jailbreak. + Recunosc riscul crescut și tot vreau să continui. + De ce sunt dispozitivele cu acces root un potențial risc de securitate? + Află mai multe + https://www.bsi.bund.de/SharedDocs/Glossareintraege/DE/R/Rooten.html + Numele profilului + Introduceți un nume pentru noul profil. + Numele profilului + profiluri + Cum să recunoașteți un card de sănătate compatibil NFC + Nu este posibil niciun contact prin această aplicație + Vă rugăm să utilizați canalele obișnuite pentru a contacta compania de asigurări. + Card de sănătate și PIN + Numai PIN + Înregistrare în aplicația e-rețetă + Câmpul de nume nu poate fi gol. + Un profil cu numele introdus există deja. + profil + %s selectat + culoare de fundal + gri de primăvară + roa soarelui + Aceasta! Este! Roz! + Copac + Luna albastră septembrie + Neconectat + Legați împreună + Ultima conectare pe %s + Ștergeți profilul? + Aceasta va șterge toate datele de profil de pe acest dispozitiv. Rețetele dumneavoastră din rețeaua de sănătate vor rămâne intacte. + A stinge + Întrerupe + șterge profilul + Doriți să ștergeți ultimul profil. + Aplicația necesită cel puțin un profil. Vă rugăm să introduceți un nume pentru noul profil. + Eroare 20 10 76831 + Directorul cardurilor de sănătate nu a putut fi accesat. Vă rugăm să încercați din nou. + Puteți găsi informații verificate de experți despre boli, coduri ICD și despre probleme de prevenire și îngrijire pe Portalul Național de Sănătate. + Deschideți Gesund.bund.de + Am schimbat politica de confidențialitate + Aplicația e-rețetă a evoluat. Acest lucru a făcut necesară actualizarea politicii noastre de confidențialitate. + Deschideți politica de confidențialitate + Acest lucru s-a schimbat de la %s : + Ce se întâmplă când deschideți aplicația? + Ce se întâmplă dacă folosesc funcția de cameră / citesc rețete cu camera? + Nu există rețete noi disponibile + + %s rețetă nouă + + %s rețete noi + + Rambursabil + În răscumpărare + Răscumpărat + Necunoscut + Vizualizați jurnalele de acces + Cine a accesat rețetele tale și când? + Cheie de acces la serviciul de prescripție medicală + jurnalele de acces + Niciun jurnal de acces + Nu există încă jurnalele de acces. + Rețeta este în curs de desfășurare și nu poate fi ștearsă + Accept + Se pare că nu a funcționat + Suntem conștienți că legătura cu cardul de sănătate are capcanele ei. În viitor, înregistrarea ar trebui, prin urmare, să fie posibilă și prin intermediul unei aplicații de asigurări de sănătate deja autentificate. \n\n De asemenea, lucrăm pentru a permite valorificarea digitală a rețetelor fără înregistrare. \n\n Ați observat ceva în timpul acestui proces pe care ați dori să ne împărtășiți? Vă rugăm să ne scrieți, suntem bucuroși să primim feedback foarte critic. + Sfaturi de conectare + Îmbunătățiți puterea conexiunii + Dacă este necesar, îndepărtați capacul de protecție. + Dacă dispozitivul vibrează și apoi întrerupe conexiunea, căutați poziția optimă pe o rază mică. + Mutați dispozitivul pe hartă foarte încet. + Așezați dispozitivul direct pe card. + Pentru a face acest lucru, așezați cardul de sănătate pe o suprafață plană (de exemplu, o masă). + Îmbunătățiți puterea conexiunii + Observați amplasarea senzorului NFC + Aflați unde se află senzorul NFC pe dispozitivul dvs. (aici, de exemplu, o prezentare generală pentru dispozitivele de la %s ). + În unele cazuri, poziția senzorului NFC poate diferi în cadrul unei serii de model (aici, de exemplu, informațiile pentru %s ). + Urmatorul sfat + Mai departe + Închide + Încercați + scrie-ne + Licență de căutare în farmacii + răscumpăra + Rețetă scanată + Scanat pe %s + Marcat ca valorificat pe %s + Cum vrei să continui? + Ordin + Disponibil în curând + Rezervați acum pentru colectare sau primiți-l prin serviciu de curierat sau transport + Salvează pentru o comandă ulterioară + Salvați rețetele pe dispozitiv + + Continuați cu rețeta %s + + Continuați cu %s rețete + + Nu s-a putut conecta cardul de sănătate + Profilul actual este deja conectat la un alt card de sănătate (numărul de asigurări de sănătate %s ). + Cardul tău de sănătate este deja conectat la alt profil. Comutați la profilul %s . + Salvați pe computer + datele de contact si adresa + a lua legatura + număr de telefon + Vă rugăm să furnizați un număr de telefon pentru contact. + Adresă de e-mail (opțional) + adresă de livrare + Primul nume si ultimul nume + Vă rugăm să introduceți un nume și un prenume pentru contact. + Strada și numărul casei + Vă rugăm să introduceți o stradă și un număr de casă pentru a putea fi contactați. + Adresă suplimentară (opțional) + Instrucțiuni de livrare (opțional) + Sunt necesare informații de contact suplimentare + Renunțați la modificări? + arunca + Pentru căutare, directorul farmaciilor folosește coordonatele geografice care au fost determinate cu ajutorul OpenStreetMap. Mulțumim proiectului pentru acest ajutor. + © OpenStreetMap ( %s ) + https://www.openstreetmap.org/copyright + Confidențialitate și utilizare + Mai departe + Ați primit PIN-ul dvs. într-o scrisoare de la compania dumneavoastră de asigurări de sănătate. + Nu s-a primit niciun cod PIN + cod PIN + Verificați conexiunea la internet și setarea orei/datei dispozitivului dvs. + Pentru a vă autentifica, apăsați pe „Deblocare”. + închis pe dinafară? Vă rugăm să vă verificați acreditările biometrice pe acest dispozitiv. + Aţi uitat parola? Vă rugăm să ștergeți aplicația și apoi să o reinstalați. Puteți afla de ce în %s nostru. + zona de ajutor + dimensiunea pachetului și unitate + ingredient activ + Cantitatea de ingredient activ + desemnarea lotului + Exp + categorie + Vaccin + Accept + Anulat + Înștiințare + Ajutați-ne să îmbunătățim această aplicație + Introdu parola + Parola trebuie să aibă cel puțin opt caractere + Puterea parolei nu este suficientă + Puterea parolei este suficientă + Parola este vizibilă + Parola nu este vizibilă + biometrie + parola + așteptând un răspuns + Fara retete + În prezent, nu aveți rețete rambursabile. + A updata + Deconectare automată + Din motive de securitate, conexiunea la serverul de rețete se întrerupe după 12 ore. Reconectați-vă pentru a obține rețetele actuale. + Conectați + Ai primit o copie pe hârtie? + Adăugați rețete în lista dvs. atingând butonul de scanare din colțul din dreapta sus. + Scanați imprimarea pe hârtie + Trebuie să fii autentificat pentru a primi rețete automat. + Inregistreaza-te + Fără rețete răscumpărate + Rețetele dvs. răscumpărate sunt afișate aici. Din motive de protecție a datelor, rețetele dumneavoastră vor fi șterse de pe serverul de rețete după 100 de zile. + Fără rețete răscumpărate + Rețetele dvs. răscumpărate sunt afișate aici. Adăugați rețete prin scanare pentru a începe valorificarea. + managementul dispozitivelor + Dispozitive conectate + Înregistrat de la %s (acest dispozitiv) + Înregistrat din %s + Din motive de securitate, conexiunea la serverul de rețete se întrerupe după 12 ore. Pentru a vă reconecta, aveți nevoie de cardul de sănătate și PIN-ul pentru fiecare proces de conectare. + cod PIN + Introduceți codul PIN (cardul de sănătate). + Mai departe + Inregistreaza-te + Dispozitive conectate + indepartati dispozitivul? + Întrerupe + Îndepărtat + Eliminați acest dispozitiv? + Doriți să eliminați %s ? + Dacă eliminați %s , conexiunea la serverul de rețete va fi deconectată definitiv în cel mult 12 ore. + Dispozitivele se încarcă... + Fără dispozitive + Nu există dispozitive conectate la acest card de sănătate. + Încearcă din nou + Uh oh :-( + Lista de dispozitive nu a putut fi încărcată. + wwweg... + Fără conexiune internet. + Medicamente și pansamente + narcotice + Livrarea medicamentelor prescrise conform § 4 AMVV + Ai nevoie de ajutor? + Am adunat câteva sfaturi pentru a rezolva cele mai frecvente probleme. + Începeți sfaturi de conectare + debloca + card blocat + PIN-ul a fost introdus incorect de trei ori. Prin urmare, cardul dvs. a fost blocat din motive de securitate. + debloca cardul + Introduceți PUK + Cu PIN-ul dvs. ați primit un PUK de 8 cifre de la compania dvs. de asigurări. + Alegeți codul PIN nou + Puteți alege singur noul număr de identificare personală (PIN) (6 până la 8 cifre). + PIN reținut? + Vă rugăm să notați codul PIN și să-l păstrați într-un loc sigur. + Întrerupe + Bine + Deblocarea nu este posibilă + Ați atins numărul maxim de deblocări de card cu acest PUK sau l-ați introdus incorect în mod repetat. Vă rugăm să contactați compania dumneavoastră de asigurări. + Puteți folosi un singur PUK pentru până la 10 deblocări. + card deblocat + De ce ai nevoie: + cardul tau de sanatate + PUK-ul cardului dumneavoastră de sănătate + Mai departe + card de sanatate + Comandați PIN sau card + Inregistreaza-te + Cum doriți să vă conectați? + Card de sănătate compatibil NFC + PIN pentru cardul de sănătate + Nu aveți încă un card de sănătate și un cod PIN activat pentru NFC? + Aplica acum + Sau: Conectați-vă cu %s . + Aplicația dvs. de asigurări de sănătate + „Numărul dumneavoastră de acces se găsește în colțul din dreapta sus al cardului de sănătate.” + Cardul meu nu are un număr de acces + + Mai aveți %s încercări înainte ca cardul dvs. să fie blocat. + + Mai aveți %s încercări înainte ca cardul să fie blocat. + + Pune cardul de sănătate pe spatele telefonului + Următorul proces poate dura până la 30 de secunde. + Puneți cardul %s pe spatele telefonului. + în colțul din dreapta sus + în mijlocul de sus + în stânga sus + în zona de mijloc din dreapta + mijloc + în centrul stânga + în zona din dreapta jos + în centrul inferior + în stânga jos + Ajutor + Trimis acum %s minute + Trimis pe %s + Trimis chiar acum + Trimis la ora %s + Nu mai este valabil + Conectați-vă cu aplicația + alege asigurarea + Nu ați găsit ceea ce căutați? Această listă este în continuă extindere. Înregistrarea cu cardul de sănătate este deja acceptată de fiecare companie de asigurări de sănătate. + Feedback din aplicația e-rețetă + Așteptăm cu nerăbdare feedback-ul dvs. Vă rugăm să folosiți spațiul de mai jos și să fiți cât mai precis posibil: + PUK + Închide + Ce păcat… + Din păcate, dispozitivul dvs. nu îndeplinește cerințele minime pentru a vă conecta la aplicația e-prescription. Cel puțin Android 7 și un cip NFC sunt necesare pentru autentificarea sigură cu cardul de sănătate. + Află mai multe + Salvați datele de conectare? + Salvați pe computer + Nu salva + Înștiințare + Din motive de securitate, conexiunea la serverul de rețete se întrerupe după 12 ore. Pentru a vă reconecta, aveți nevoie de un card de sănătate și PIN pentru fiecare proces de conectare. + Configurați securitatea biometrică + Salvarea datelor de acces nu este posibilă. Configurați în prealabil securitatea biometrică (de exemplu, amprenta digitală) pe dispozitiv. + Întrerupe + Idei + Înștiințare + Accept + Securitatea datelor dumneavoastră de prescripție + „Această aplicație folosește cel mai sigur senzor biometric oferit de dispozitiv pentru a vă stoca acreditările într-o zonă securizată a memoriei dispozitivului.” + Securitatea biometrică a datelor de acces vă permite să deschideți această aplicație în viitor fără a fi nevoie să introduceți codul PIN sau un card de sănătate și să vizualizați, să apelați, să răscumpărați sau să ștergeți rețetele. + Vă rugăm să vă asigurați că persoanele cu care puteți partaja acest dispozitiv și ale căror caracteristici biometrice pot fi stocate pe acest dispozitiv au și acces la rețetele dumneavoastră. + care din pacate nu a functionat + Autentificarea cu aplicația de asigurări de sănătate nu a reușit. + A expirat pe %s + Rețeta a fost deja ștearsă de pe server + Vă rugăm să corectați introducerea sau să renunțați la modificări + Corect + date asigurate + Nume de familie + Asigurare + numar de asigurare + numărul de acces al cardului + Inregistreaza-te + De-înregistrați + Salvați pe computer + Schimbare + Editează poza de profil + Mai departe + serverul nu răspunde + Vă rugăm să încercați din nou mai târziu. + Încearcă din nou + Caută asigurare + Conectați-vă la serverul de rețete acum? + Conectat cu succes + conexiunea pierdută + Conectați-vă la serverul de rețete acum? + Fără jetoane + Veți primi un simbol atunci când sunteți conectat la serviciul de prescripție medicală.\n + Comenzi + Selectați codul PIN dorit + debloca cardul + Alegeți codul PIN + Repetați codul PIN + Intrările diferă unele de altele. + Fara comenzi + Încă nu aveți nicio comandă. + Chiar acum + La ora %s + Coșul de cumpărături este gata + Rețeta a fost adăugată în coșul de cumpărături. Vă rugăm să accesați site-ul farmaciei pentru a finaliza comanda. + Deschideți coșul de cumpărături + Arată acest cod de ridicare la farmacie. + Primește codul de ridicare + Mesajul nu poate fi afișat + Vă rugăm să contactați farmacia ( %s ). + Afișați linkul coșului + Afișați codul de ridicare + Arată mesajul + %s la ora %s + Rețeta trimisă către %s . + Prezentare generală a comenzii + Nou + Curs + Ordin + Gratuit pentru apelant. Orele de serviciu: Luni - Vineri 8:00 - 20:00, cu excepția sărbătorilor naționale + Farmacie + Selectați codul PIN dorit + PIN-ul dorit a fost salvat + Momentan deschis și lângă mine + Filtreaza dupa … + incepe cautarea + atribuire directă + farmacii + numarul de telefon (optional) + Căutați după nume sau adresă + Nu există informații valide despre farmacie + Nu au fost găsite informații actuale despre această farmacie. Înregistrarea pentru această farmacie va fi ștearsă. + Bine + Directorul farmaciilor nu este disponibil + În prezent, nicio informație actuală despre această farmacie nu poate fi preluată. Vă rugăm să vă verificați conexiunea la internet. + Întrerupe + Încearcă din nou + Salvați Mediul + Conectarea nu este posibilă + Se pare că datele dvs. de conectare biometrice s-au schimbat. Vă rugăm să vă înregistrați din nou cu cardul de sănătate. + Întrerupe + Inregistreaza-te + profilul 1 + Aproape de mine + Rambursabil mai târziu + Rambursabil de la %s + îmbunătățiri ale produsului + Analiza anonima + Ajutați-ne să îmbunătățim această aplicație. Toate datele de utilizare sunt colectate anonim și sunt folosite doar pentru a îmbunătăți experiența utilizatorului. + securitatea dispozitivului + setari personale + Accesibilitate + îmbunătățiri ale produsului + Rețetă adăugată + Reteta deja disponibila + A apărut o eroare la import + A stinge + Rețetă scanată + Posibil înlocuire + Am uitat PIN-ul + + %s Rețetă + + %s Rețete + + Am citit și accept politica de confidențialitate și termenii de utilizare. + Protejarea datelor + Termeni de utilizare + Am vrea: + Îmbunătățiți gradul de utilizare. + Detectează erori și blocări. + Toate datele sunt desigur colectate anonim. + Puteți modifica oricând această decizie în setările sistemului. + Continua + Accept + Această aplicație folosește cea mai sigură metodă oferită de dispozitivul dvs. + Salvați pe computer + Alege + medicament + nume comercial + da + Nu + dozare + data emiterii + Această rețetă va fi răscumpărată pentru dvs. ca parte a unui tratament. + Nu este specificat + plata aditionala + medicament + Note de livrare + Eligibil conform BVG + pregătire alternativă + numele retetei + Ambalare + instrucție de lucru + Descriere + dat de + emis la: + ingredient activ + prescris + A primi + Ce este o misiune directă? + În cazul trimiterilor directe, o rețetă de la un cabinet sau un spital este răscumpărată direct la o farmacie. Asigurații nu trebuie să întreprindă nicio măsură și nu pot interveni în procesul de răscumpărare. \n\n Recomandările directe sunt enumerate în aplicația e-rețetă pentru a face tratamentul mai transparent pentru dvs. + taxa de serviciu de urgenta + Uneori este nevoie de grabă. Unele rețete pot fi răscumpărate fără plata suplimentară a unei taxe de serviciu de urgență, cum ar fi noaptea sau de sărbătorile legale. + Medicamente supuse coplății + Scutit de coplata + Cei cu asigurare legală de sănătate trebuie să plătească o coplata de până la zece euro pentru medicamentele eliberate pe bază de rețetă. \n\n Valoarea coplății depinde de prețul medicamentului dumneavoastră. Trebuie să plătiți singur pentru medicamentele care costă mai puțin de 5 EUR.\n Pentru medicamentele care sunt mai scumpe, trebuie să plătiți zece la sută din preț, dar cel puțin 5 euro și maxim 10 euro. \n\n Copiii și tinerii cu vârsta sub 18 ani sunt, în general, scutiți de coplăți. \n\n Dacă costurile dumneavoastră anuale pentru medicamente depășesc limita dumneavoastră financiară, puteți fi scutit de coplată. Discutați cu asigurătorul dvs. de sănătate despre acest lucru. + Sunteți scutit de coplată pentru acest medicament. Asigurarea dumneavoastră de sănătate va acoperi costul medicamentelor. + Cât timp este valabilă această rețetă? + În această perioadă, vă puteți răscumpăra rețeta în orice farmacie cu o plată suplimentară maximă de 10 EUR. + Posibil înlocuire + Datorită cerințelor legale ale companiei dumneavoastră de asigurări de sănătate, vi se poate oferi o alternativă cu același ingredient activ. \n\n Medicamentele pot arăta și pot fi numite diferit, au prețuri și producători diferiți, dar conțin totuși același ingredient activ. Ingredientul activ în sine și doza sunt deosebit de importante pentru efectul medicamentelor în organism. Pacienții din farmacie primesc adesea un alt medicament decât cel prescris de medic pe rețetă - cu condiția ca medicamentele să fie comparabile. Pot exista motive terapeutice și economice pentru schimbare. + Rețetă scanată + Din motive de securitate, rețetele importate dintr-un tipărit pe hârtie nu trebuie să afișeze date personale sau medicale. \n\n Conectați-vă la această aplicație cu cardul de sănătate sau aplicația de asigurare pentru a vedea toate informațiile conținute în rețetă. + Reteta incorecta + Această rețetă a fost emisă incorect. + Rețetă scanată + taxa de serviciu de urgenta + Dozare conform instrucțiunilor scrise + telefon + site-ul + Poștă + Sortarea după distanță nu este posibilă. + Bine + Introduceți codul PIN actual + PIN introdus incorect + PIN-ul actual al cardului dumneavoastră de sănătate + card blocat + Deblocați-vă cardul în Setări > Deblocați cardul. + Din motive de securitate, introduceți codul PIN actual. + Am uitat PIN-ul + Rețetă incorectă + medicament + Ceva pare să fi mers prost în timpul creării rețetei. Raportați o eroare? + Raport + Neconectat + Înregistrat cu + card de sanatate + biometrie + Neconectat + Ne interesează opinia dumneavoastră. Vă rugăm să acordați cinci minute pentru a răspunde la sondajul nostru. Vă mulțumesc anticipat. + avertisment de avertizare + Farmacie adăugată la favorite + S-a eliminat Farmacia din Favorite + Farmaciile mele + Puterea parolei foarte bună + Operația de scriere nu a reușit + PIN-ul nu a putut fi salvat + Raport + Atribuiți codul PIN + Regula de acces a fost încălcată + Nu aveți permisiunea de a accesa directorul hărților. + Atribuiți-vă propriul PIN + Cardul este securizat cu un PIN de la compania dumneavoastră de asigurări de sănătate (PIN de transport), vă rugăm să vă atribuiți propriul PIN. + Parola nu a fost găsită + Nu există nicio parolă stocată pe cardul dvs. + ai fost deconectat + Conectați-vă din nou pentru a vă actualiza rețetele. + numărul ingredientului activ + potenta si unitate + Valorificată acum %s minute + Valorificat pe %s + Răscumpărat chiar acum + Valorificat la ora %s + Comenzi + Această rețetă a fost răscumpărată pentru dvs. ca parte a unui tratament. + taxa de serviciu de urgenta + Această rețetă nu poate fi obținută noaptea într-o farmacie fără plata suplimentară a unei taxe de serviciu de urgență. + Caută aici + Idei + Partajați locația în setări. + Aproape de mine + Țineți apăsat pentru a edita numele. + Introduceți noul nume pentru profil. + Trebuie să fiți autentificat pentru a primi rețete digitale de la cabinetul dumneavoastră. + Primiți rețete digital? + Trageți ecranul în jos pentru a reîmprospăta. + Fara retete + Adăugați rețete folosind butonul + din colțul din dreapta sus. + Inregistreaza-te + arhiva de rețete + Poate mai târziu + Inregistreaza-te + Editează poza de profil + arhiva de rețete + Introdu numele + Salvați pe computer + Comanda mea + Destinatar: in + Rețete + Farmacie + Trimite + Schimbare + Ridicați de la farmacie + Livrare prin curier + Livrare prin posta + %s Rețete + Valorificarea nu este posibilă + Una sau mai multe rețete nu au putut fi răscumpărate. + Nicio rețetă selectată + Pentru a valorifica rețetele, trebuie selectată cel puțin o rețetă. + Adăugați informații de contact + Schimbare + Fără prescripție medicală + În prezent, nu aveți rețete rambursabile + Colectie + curier + Expediere + alege rețete + Atingeți aici pentru a scana rețetele + Apăsați lung pentru a edita numele + Adăugați mai multe profiluri, de exemplu pentru copiii sau părinții dvs + Faceți clic pe afișaj pentru a sări peste indicația afișată. + Cum să răscumpărați? + Cum ați dori să primiți medicamentele? + Răscumpărați direct + Rambursați medicamentele la fața locului + Ordin + Rezervați sau primiți-l + Gata + cod colectiv + coduri unice + + Aveți %s rețetă. + + Aveți %s rețete. + + face o selecție + Toate retetele + Ce retete? + Mai departe + Mai departe + Află mai multe + Înștiințare + Această aplicație folosește software de la Google pentru a recunoaște codurile. + Află mai multe + Despre scanerul de coduri de rețetă + Ce date contine codul retetei? + Codul rețetei conține doar un identificator al rețetei. Acest lucru permite rețeta să fie găsită pe serviciul de prescripție în rețeaua digitală de sănătate. Codul de prescripție nu conține date despre dumneavoastră sau despre medicamentul dumneavoastră. + Deci nimeni nu poate face nimic singur cu codul rețetei? + Corect. Datele de prescripție trebuie descărcate de la serviciul de prescripție medicală. Acest lucru necesită o autentificare securizată. + Cine se poate înregistra pentru serviciul de prescripție medicală? + Înregistrarea la serviciul de prescripție medicală în rețeaua digitală de sănătate este posibilă pentru asigurați, farmacii, cabinete medicale și spitale. + De ce aplicația de prescriere electronică folosește funcțiile Google? + Google oferă funcții care pot fi integrate cu ușurință în aplicații și care sunt dezvoltate și actualizate în mod constant de Google. Acest lucru asigură că funcțiile funcționează pe multe dispozitive finale diferite și pot fi operate în siguranță. Aplicația folosește o funcție pentru a îmbunătăți camera și funcționalitatea de scanare pentru dispozitivele Android (Google ML Kit). + Cum funcționează îmbunătățirea scanării Google ML Kit? + Google ML Kit ajută la optimizarea imaginii surprinse de o cameră astfel încât codurile rețetei să poată fi citite chiar și în condiții de iluminare slabă sau cu modele de camere mai vechi. + Datele despre rețetă sau medicamentele mele vor fi transmise la Google? + Nu. Codul rețetei citit este salvat direct în aplicație. Nu va fi transmis la Google. Datele de prescripție nu sunt stocate în cod, ci doar în rețeaua digitală de sănătate. De acolo sunt trimise în aplicație. Google nu are acces la rețeaua digitală de sănătate. + Ce date prelucrează Google când folosește ML Kit? + Google are acces numai la informații tehnice despre dispozitivul final utilizat și despre utilizarea generală a funcției suplimentare (de exemplu, rata de eroare, setările camerei) pentru a înregistra acest lucru statistic și a îmbunătăți astfel funcția suplimentară. Când accesați, Google înregistrează temporar adresa IP a dispozitivului dvs. final. Informațiile despre dvs. și conținutul rețetei nu vor fi înregistrate de Google. + Utilizarea Google ML Kit este voluntară? + Da. Cu toate acestea, ML Kit este încorporat în scanerul de coduri de rețetă din versiunea Android a aplicației e-prescription. Dacă utilizați scanerul de coduri de rețetă pe un dispozitiv Android, funcția ML Kit este întotdeauna utilizată. Cu toate acestea, puteți face fără a utiliza scanerul de coduri de rețetă. Rețetele dumneavoastră pot fi încărcate în aplicație și dacă vă înregistrați în rețeaua digitală de sănătate cu cardul electronic de sănătate sau prin aplicația de asigurări de sănătate. + Pot să văd cine mi-a văzut rețetele? + Da. Toate accesul la datele dvs. este complet înregistrat în rețeaua digitală de sănătate. În aplicația de rețetă electronică puteți vedea cine v-a accesat datele. + Pe cine pot contacta dacă am întrebări despre aplicație sau rețetă electronică? + Puteți găsi informații detaliate în declarația de protecție a datelor. + Numărul de pachete prescris + Fara retete + Pentru aceasta aveți nevoie de rețete rambursabile. + alege asigurarea + Caută asigurare + Întrerupe + Pentru ce ați dori să aplicați? + Pentru această aplicație aveți nevoie de un card și PIN-ul asociat. + Cum ați dori să contactați compania dvs. de asigurări? + Compania dumneavoastră de asigurări vă oferă următoarele opțiuni de contact + Compania dumneavoastră de asigurări vă oferă următoarele opțiuni de contact + Închide + PIN introdus incorect. + Numărul de acces a fost introdus incorect + PUK a fost introdus incorect. + chitanțe de cheltuieli + Afișați chitanțele de cheltuieli + chitanțe de cheltuieli + Pentru a primi chitanțe de cheltuieli, trebuie să fiți conectat la server. + Conectați + Fără chitanțe de cheltuieli + Dezactivați + Întrerupe + dezactivați funcția + Aceasta va șterge toate chitanțele de pe acest dispozitiv și de pe server. + Primiți chitanțe de cheltuieli + Încasările dvs. de cost sunt salvate și pe serverul de rețete. + A primi + Total: %s %s + Alege + Despică + A stinge + A stinge + Trimite + %s € + pretul total + Sfat: trimiteți chitanțele de cheltuieli prin aplicația de asigurare + Trimiteți cu ușurință chitanțele de cost prin aplicația companiei dvs. de asigurări. În pasul următor, selectați această aplicație și apăsați Partajare. + Practică + Farmacie + Data + Afișați mai multe + ID de droguri + Eliberat pentru + KVNR: %s + Data nașterii: %s + Bine + Cum depuneți chitanțele? + Transferați direct în aplicația companiei dumneavoastră de asigurări/oficiului de ajutor. Pentru a face acest lucru, selectați aplicația de pe pagina următoare. + sau + Salvați fișierul și apoi importați-l în portalul de asigurări/ajutor. + Articol: %s + Număr: %s + TVA: %s %% + Preț brut în EUR: %s + Taxe suplimentare + taxa de serviciu de urgenta + Taxa BTM + T taxa de prescriptie medicala + costurile de achiziție + serviciu de mesagerie + Total în EUR: %s + taxă + Ștergeți cu adevărat? + Fișierul va fi șters de pe dispozitiv și de pe server. + A stinge + Postat + Cod poștal + Locație + Vă rugăm să introduceți codul poștal pentru a ne contacta. + Vă rugăm să introduceți locul de reședință când ne contactați. + Va fi răscumpărat pentru tine + A fost răscumpărat pentru tine + Trebuie să fiți autentificat pentru a utiliza acest serviciu. + aplicația de asigurare + card de sanatate + PIN asociat este necesar + Pentru a primi jurnalele de acces, trebuie să fiți conectat la server. + Puteți completa rețeta la o farmacie în această perioadă, dar va trebui să plătiți singur prețul de achiziție al medicamentului. Ca alternativă, puteți cere cabinetului dumneavoastră să fie reemisă rețeta. + Gata + Solicitați corectare + La farmacie + În aplicație + Scanează acest cod la farmacie. + Solicitare de corectare a facturării + diff --git a/android/src/main/res/values-ru/strings.xml b/android/src/main/res/values-ru/strings.xml index 7e373091..1176427c 100644 --- a/android/src/main/res/values-ru/strings.xml +++ b/android/src/main/res/values-ru/strings.xml @@ -1,6 +1,5 @@ - E-Rezept OK Отмена Назад @@ -177,18 +176,6 @@ Местоположение недоступно Понятно Пароли совпадают - - Можно выкупить в качестве самостоятельного плательщика еще в течение %s дня - Можно выкупить в качестве самостоятельного плательщика еще в течение %s дней - Можно выкупить в качестве самостоятельного плательщика еще в течение %s дней - Можно выкупить в качестве самостоятельного плательщика еще в течение %s дней - - - Действует еще %s день - Действует еще %s дня - Действует еще %s дней - Действует еще %s дней - Ошибка 20 10 76631 Сертификат вашей медицинской карточки недействителен. Может быть, срок действия вашей карточки истек? Обратитесь в свою организацию медицинского страхования. Безуспешные попытки входа @@ -284,9 +271,7 @@ Это ключ для доступа к службе рецептов Протоколы доступа Нет протоколов доступа - Вы получите протоколы доступа, когда войдете в службу рецептов. Протоколов доступа еще нет. - Дата последнего обновления %s Рецепт в настоящее время обрабатывается и не может быть удален Принять Видимо, что-то пошло не так @@ -352,7 +337,7 @@ PIN-код не получен PIN-код Проверьте соединение с Интернетом и настройки времени/даты на вашем устройстве. - Для аутентификации нажмите \"Разблокировать\". + Для входа нажмите «Разблокировать». Блокировка? Проверьте свои биометрические данные доступа на этом устройстве. Забыли пароль? Удалите приложение и затем установите его заново. Причины мы объясняем в %s. Раздел справки @@ -366,7 +351,7 @@ Принять Отменить Указание - Поможете нам сделать это приложение лучше? + Помогите нам сделать это приложение лучше Установить собственный пароль Пароль должен состоять как минимум из восьми символов Надежность пароля недостаточная @@ -444,10 +429,7 @@ Медицинская карточка Заказать PIN-код или карту Войти - Как вы хотите пройти аутентификацию? - страховое приложение - страховой полис - Требуется соответствующий PIN-код + Как вы хотите войти в систему? Медицинская карточка с поддержкой NFC PIN-код медицинской карточки У вас еще нет медицинской карточки с поддержкой NFC и PIN-кода? @@ -649,8 +631,7 @@ Те, у кого есть государственная медицинская страховка, должны внести доплату в размере до десяти евро за лекарства, отпускаемые по рецепту. \n\n Размер доплаты зависит от стоимости вашего лекарства. Вы должны платить за лекарства стоимостью менее 5 евро самостоятельно.\n За более дорогие лекарства вы должны заплатить десять процентов от цены, но не менее 5 евро и не более 10 евро. \n\n Дети и молодые люди в возрасте до 18 лет, как правило, освобождаются от доплаты. \n\n Если ваши ежегодные расходы на лекарства превышают ваш финансовый лимит, вы можете быть освобождены от доплаты. Поговорите об этом со своей страховой компанией. Вы освобождаетесь от доплаты за этот препарат. Ваша медицинская страховка покроет стоимость лекарства. Как долго действует этот рецепт? - В течение этого периода вы можете выкупить рецепт в любой аптеке за дополнительную плату. - В течение этого периода вы все еще можете выкупить рецепт в аптеке, но вам придется заплатить покупную цену самостоятельно. Кроме того, вы можете попросить свою практику выписать рецепт еще раз. + В течение этого периода вы можете выкупить рецепт в любой аптеке с максимальной доплатой в размере 10 евро. Возможна замена препарата В соответствии с юридическими требованиями вашей медицинской страховой компании вам может быть предоставлена альтернатива с тем же активным ингредиентом. \n\n Лекарства могут выглядеть и называться по-разному, иметь разную цену и производителя, но при этом содержать одно и то же действующее вещество. Сам активный ингредиент и дозировка особенно важны для действия лекарств в организме. Пациенты в аптеке часто получают другой препарат, чем тот, который выписал врач по рецепту, при условии, что препараты сопоставимы. Для изменения могут быть терапевтические и экономические причины. Отсканированный рецепт @@ -721,11 +702,11 @@ Нет рецептов Добавляйте рецепты с помощью кнопки + в правом верхнем углу. Авторизоваться - Погашенные рецепты + архив рецептов Может быть позже Авторизоваться Изменить изображение профиля - Погашенные рецепты + архив рецептов Ввести фамилию Сохранить Мой заказ @@ -747,7 +728,7 @@ Без рецепта В настоящее время у вас нет погашаемых рецептов поднимать - курьером + курьер Отправка выбирать рецепты Нажмите здесь, чтобы отсканировать рецепты @@ -873,22 +854,15 @@ Будет искуплен для вас Был искуплен за тебя Вы должны войти в систему, чтобы использовать эту услугу. - Рецепт(ы) успешно передан(ы). - Рецепт не может быть обработан. Пожалуйста, попробуйте еще раз. Возможно, вам придется выбрать другую аптеку. - Рецепт не может быть обработан. Аптека сообщает о неизвестной ошибке. При необходимости попробуйте другую аптеку. - Рецепт был отклонен аптекой. Рецепт может быть недействительным, или ваш адрес доставки или контактные данные могут быть недействительн ыми. - Don\'t worry, you should try to connect to the Internet. - Рецепт успешно передан. Однако аптека сообщает об ошибке обработки. Пожалуйста, свяжитесь с аптекой. - Рецепт был отклонен аптекой. Рецепт уже погашен. - Рецепт был отклонен аптекой. Рецепт удален. - Рецепт не может быть передан. Prove it to the Internet and open the Pope. - Не удалось передать один или несколько рецептов. - Успешно отправлено! - Ошибка аптеки - Ошибка аптеки - Связаться с аптекой - Рецепт уже погашен - Рецепт удален - Без интернета - Ошибка отправки + страховое приложение + страховой полис + Требуется соответствующий PIN-код + Для получения логов доступа необходимо подключение к серверу. + В течение этого периода вы по-прежнему можете получить рецепт в аптеке, но вам придется оплатить всю покупную стоимость лекарства самостоятельно. Кроме того, вы можете попросить свою практику переоформить рецепт. + Готово + Запросить исправление + В аптеке + В приложении + Отсканируйте этот код в своей аптеке. + Запрос на исправление платежа diff --git a/android/src/main/res/values-tr/strings.xml b/android/src/main/res/values-tr/strings.xml index d7c40dea..a6122432 100644 --- a/android/src/main/res/values-tr/strings.xml +++ b/android/src/main/res/values-tr/strings.xml @@ -1,6 +1,5 @@ - E-Rezept Tamam İptal et Geri @@ -173,14 +172,6 @@ Herhangi bir konum mevcut değil Anladım Tekrarlanan şifre eşleşiyor - - Kendiniz ödeyerek %s gün daha geçerli - Kendiniz ödeyerek %s gün daha geçerli - - - %s gün daha geçerli - %s gün daha geçerli - Hata 20 10 76631 Sağlık kartınızın sertifikası geçerli değil. Kartınızın süresi dolmuş olabilir mi? Lütfen sağlık sigortanız ile iletişime geçin. Başarısız oturum açma denemesi @@ -272,9 +263,7 @@ Burada reçete hizmetine olan erişim anahtarı söz konusudur Erişim protokolleri Herhangi bir erişim protokolü yok - Reçete hizmetlerine kaydolduysanız erişim protokolleri alırsınız. Halihazırda erişim protokolleri bulunmuyor. - Son güncelleme tarihi: %s Reçete şu an düzenlenmekte ve silinemez Kabul et Bu maalesef başarılı olmadı @@ -338,7 +327,7 @@ PIN alınmadı PIN Lütfen internet bağlantınızı ve cihazınızın saat ile tarih ayarlarını kontrol edin. - Kimliğinizi doğrulamak için \"Blokeyi kaldır\" üzerine basın. + Giriş yapmak için “Kilidi Aç”a basın. Engellendiniz mi? Lütfen bu cihazdaki biyometrik erişim verilerinizi tekrar kontrol edin. Şifreyi mi unuttunuz? Lütfen uygulamayı silin ve ardından yeniden yükleyin. Bunun neden böyle olduğunu şuradan öğrenebilirsiniz: %s. Yardım alanı @@ -352,7 +341,7 @@ Kabul et Geri al Not - Bu uygulamayı daha iyi hale getirmek için bize yardımcı olur musunuz? + Bu uygulamayı daha iyi hale getirmemize yardımcı olun Kendi parolanızı seçin Parola en az sekiz basamaklı olmalıdır Parola yeterince güçlü değil @@ -430,10 +419,7 @@ Sağlık kartı PIN veya kart sipariş edin Oturum aç - Kimlik doğrulamasını nasıl yapmak istersiniz? - sigorta uygulaması - Sigorta kartı - İlişkili PIN gerekli + Nasıl oturum açmak istiyorsunuz? NFC özellikli sağlık kartı Sağlık kartının PIN\'i NFC özellikli sağlık kartına ve PIN\'e henüz sahip değil misiniz? @@ -631,8 +617,7 @@ Yasal sağlık sigortası olanlar, reçeteli ilaçlar için on Euro\'ya kadar katkı payı ödemek zorundadır. \n\n Katkı payı miktarı, ilacınızın fiyatına bağlıdır. Maliyeti 5 €\'dan az olan ilaçlar için kendiniz ödeme yapmanız gerekir.\n Daha pahalı ilaçlar için fiyatın yüzde onunu, ancak en az 5 € ve maksimum 10 € ödemeniz gerekir. \n\n 18 yaşın altındaki çocuklar ve gençler genellikle katkı payından muaftır. \n\n Yıllık ilaç masraflarınız mali limitinizi aşarsa, katkı payından muaf olabilirsiniz. Bu konuda sağlık sigortanız ile konuşun. Bu ilacın katkı payından muafsınız. Sağlık sigortanız ilacın maliyetini karşılayacaktır. Bu reçete ne kadar süreyle geçerlidir? - Bu süre zarfında reçetenizi herhangi bir eczanede ek bir ödeme ile kullanabilirsiniz. - Bu süre zarfında reçeteyi eczaneden almaya devam edebilirsiniz, ancak satın alma fiyatını kendiniz ödemeniz gerekir. Alternatif olarak, muayenehanenizden reçeteyi yeniden vermesini isteyebilirsiniz. + Bu süre zarfında reçetenizi herhangi bir eczaneden maksimum 10 € ek ödemeyle alabilirsiniz. Muadil mümkün Sağlık sigortanızın yasal zorunlulukları nedeniyle, aynı etken maddeye sahip bir alternatif sunulabilir. \n\n İlaçlar farklı görünebilir ve farklı adlandırılabilir, farklı fiyatlara ve üreticilere sahip olabilir, ancak yine de aynı etken maddeyi içerir. Aktif bileşenin kendisi ve dozajı, ilaçların vücuttaki etkisi için özellikle önemlidir. Eczanedeki hastalar, ilaçların karşılaştırılabilir olması koşuluyla, genellikle doktorun reçetede yazdığından farklı bir ilaç alırlar. Değişimin terapötik ve ekonomik nedenleri olabilir. Taranmış reçete @@ -703,11 +688,11 @@ Reçete yok Sağ üst köşedeki + düğmesini kullanarak reçete ekleyin. Giriş yapmak - Kullanılan reçeteler + reçete arşivi Belki sonra Giriş yapmak Profil resmini düzenle - Kullanılmış reçeteler + reçete arşivi İsim giriniz Kaydet Siparişim @@ -853,22 +838,15 @@ senin için kurtarılacak Senin için kurtarıldı Bu hizmeti kullanmak için giriş yapmalısınız. - Reçete(ler) başarıyla aktarıldı. - Reçete işlenemez. Air tekrar deneyin. Farklı bir eczane seçmeniz gerekebilir. - Reçete işlenemez. Eczane bilinmeyen bir hata bildirir. Gerekirse başka bir eczane deneyin. - Reçete eczane tarafından reddedildi. Reçete geçersiz olabilir veya teslimat adresiniz veya iletişim bilgileriniz geçersiz olabilir. - Kullanılamıyor, air internet bağlantınızı kontrol edin. - Reçete başarıyla aktarıldı. Ancak eczane bir işleme hatası bildiriyor. Air eczane ile iletişime geçiniz. - Reçete eczane tarafından reddedildi. Reçete zaten kullanıldı. - Reçete eczane tarafından reddedildi. Tariff silindi. - Reçete aktarılamadı. Air internet bağlantınızı kontrol edin ve tekrar deneyin. - Bir veya daha fazla tarif aktarılamadı. - Başarıyla gönderildi! - eczane hatasi - eczane hatasi - Eczane ile iletişim kurun - Reçete zaten kullanıldı - tarif silindi - İnternet yok - Gönderme hatası + sigorta uygulaması + Sigorta kartı + İlişkili PIN gerekli + Erişim günlüklerini almak için sunucuya bağlı olmanız gerekir. + Bu süre içinde reçeteyi yine eczanede doldurabilirsiniz, ancak ilacın satın alma bedelinin tamamını kendiniz ödemek zorunda kalacaksınız. Alternatif olarak muayenehanenizden reçetenin yeniden düzenlenmesini isteyebilirsiniz. + Hazır + Düzeltme iste + Eczanede + Uygulamada + Bu kodu eczanenizde tarattırın. + Faturalandırma düzeltme talebi diff --git a/android/src/main/res/values-uk/strings.xml b/android/src/main/res/values-uk/strings.xml index bd070ce9..5f7c17b5 100644 --- a/android/src/main/res/values-uk/strings.xml +++ b/android/src/main/res/values-uk/strings.xml @@ -1,6 +1,5 @@ - E-Rezept Ok Скасувати Назад @@ -177,18 +176,6 @@ Жодна локація не доступна Зрозуміло Паролі не збігаються - - Залишається ще %s день, щоб погасити рецепт, якщо ви оплачуєте самостійно. - Залишається ще %s дні, щоб погасити рецепт, якщо ви оплачуєте самостійно. - Залишається ще %s днів, щоб погасити рецепт, якщо ви оплачуєте самостійно. - - - - Діє ще %s день - Діє ще %s дні - Діє ще %s днів - - Помилка 20 10 76631 Сертифікат вашої картка здоров\'я недійсний. Можливо, термін дії вашої картки закінчився? Зв’яжіться зі своєю медичною страховою компанією. Невдалі спроби входу @@ -284,9 +271,7 @@ Мова про ключ доступу до сервісу рецептів Протоколи доступу Протоколи доступу відсутні - Ви отримаєте протоколи доступу, якщо ви увійшли в службу рецептів. Протоколів доступу ще немає. - Останнє оновлення: %s Наразі рецепт обробляється, і його неможливо видалити. Прийняти Мабуть, спроба невдала. @@ -352,7 +337,7 @@ PIN-код не отримано PIN Перевірте підключення до Інтернету та налаштування часу/дати на вашому пристрої. - Для автентифікації натисніть \"Розблокувати\". + Для входу натисніть «Розблокувати». Заблоковано? Перевірте свої біометричні облікові дані на цьому пристрої. Забули пароль? Видаліть застосунок, а потім повторно встановіть його. Чому це так, ви можете дізнатися в %s Довідка @@ -366,7 +351,7 @@ Прийняти Скасувати Указівка - Допоможете нам покращити цей застосунок? + Допоможіть нам зробити цю програму кращою Вибрати власний пароль Пароль повинен містити не менше восьми символів Надійність пароля не достатня @@ -444,10 +429,7 @@ Картка здоров\'я Замовити ПІН або картку Вхід - Як би ви хотіли пройти автентифікацію? - страховий додаток - страхова картка - Потрібен пов\'язаний PIN-код + Як ви хочете ввійти? Картка здоров’я з підтримкою NFC PIN-код картки здоров’я У вас ще немає картки здоров’я з підтримкою NFC та PIN-коду до неї? @@ -649,8 +631,7 @@ Ті, хто має державне медичне страхування, повинні сплачувати доплату в розмірі до десяти євро за рецептурні ліки. \n\n Сума співоплати залежить від вартості ваших ліків. За ліки, які коштують менше 5 євро, ви повинні платити самі.\n За ліки, які коштують дорожче, потрібно заплатити десять відсотків від ціни, але не менше 5 євро, а максимум 10 євро. \n\n Діти та молодь віком до 18 років, як правило, звільнені від співоплати. \n\n Якщо ваші річні витрати на ліки перевищують ваш фінансовий ліміт, ви можете бути звільнені від співоплати. Поговоріть про це зі своїм медичним страхувальником. Ви звільнені від спільної оплати цього препарату. Ваше медичне страхування покриває вартість ліків. Скільки дійсний цей рецепт? - У цей період ви можете отримати рецепт в будь-якій аптеці з доплатою. - Протягом цього періоду ви все ще можете придбати рецепт в аптеці, але ви повинні заплатити вартість покупки самостійно. Крім того, ви можете попросити свою практику виписати рецепт повторно. + Протягом цього періоду ви можете отримати рецепт у будь-якій аптеці з максимальною додатковою оплатою 10 євро. Можливий замінник Відповідно до юридичних вимог вашої страхової компанії, вам можуть надати альтернативу з тим самим діючим інгредієнтом. \n\n Ліки можуть виглядати і називатися по-різному, мати різні ціни та виробників, але містити однакову діючу речовину. Сам активний інгредієнт і дозування особливо важливі для впливу ліків на організм. Пацієнти в аптеці часто отримують інший препарат, ніж той, який виписав лікар за рецептом – за умови, що препарати порівнювані. Для зміни можуть бути терапевтичні та економічні причини. Відсканований рецепт @@ -721,11 +702,11 @@ Кожних рецептів Додайте рецепти за допомогою кнопки + у верхньому правому куті. Увійти - Викуплені рецепти + архів рецептів Можливо пізніше Увійти Редагувати зображення профілю - Викуплені рецепти + архів рецептів Введіть ім\'я Зберегти Моє замовлення @@ -873,22 +854,15 @@ Буде викуплено для вас Був викуплений для вас Ви повинні увійти в систему, щоб скористатися цією послугою. - Рецепт(и) успішно передано. - Рецепт не підлягає обробці. Будь ласка спробуйте ще раз. Можливо, вам доведеться вибрати іншу аптеку. - Рецепт не підлягає обробці. Аптека повідомляє про невідому помилку. Якщо потрібно, спробуйте іншу аптеку. - Рецепт був відхилений аптекою. Рецепт може бути недійсним, або ваша адреса доставки чи контактні дані можуть бути недійсними. - No activation is required, then the next step is to enter the center. - Рецепт успішно передано. Однак аптека повідомляє про помилку обробки. Будь ласка, зверніться в аптеку. - Рецепт був відхилений аптекою. Рецепт вже погашений. - Рецепт був відхилений аптекою. Рецепт видалено. - Рецепт не можна було передати. Перевірте підключення до Інтернету та повторіть спробу. - Не вдалося передати один або кілька рецептів. - Успішно відправлено! - Помилка аптеки - Помилка аптеки - Зверніться в аптеку - Рецепт уже погашений - Рецепт видалено - Немає Інтернету - Помилка відправки + страховий додаток + страхова картка + Потрібен пов\'язаний PIN-код + Щоб отримати журнали доступу, ви повинні бути підключені до сервера. + Ви все ще можете виписати рецепт в аптеці протягом цього терміну, але вам доведеться заплатити всю вартість ліків самостійно. Крім того, ви можете попросити свою практику повторно виписати рецепт. + Готово + Запит на виправлення + В аптеці + У додатку + Відскануйте цей код у своїй аптеці. + Запит на виправлення рахунку diff --git a/android/src/main/res/values/strings.xml b/android/src/main/res/values/strings.xml index 984ad31a..d0b04e15 100644 --- a/android/src/main/res/values/strings.xml +++ b/android/src/main/res/values/strings.xml @@ -1,6 +1,6 @@ - - E-Rezept + + E-Rezept Okay Abbrechen Zurück @@ -184,14 +184,6 @@ Kein Standort verfügbar Verstanden Wiederholtes Passwort stimmt überein - - Noch %s Tag als Selbstzahlender einlösbar - Noch %s Tage als Selbstzahlender einlösbar - - - Noch %s Tag gültig - Noch %s Tage gültig - Fehler 20 10 76631 Das Zertifikat Ihrer Gesundheitskarte ist ungültig. Ist Ihre Karte möglicherweise abgelaufen? Bitte kontaktieren Sie Ihre Krankenversicherung. Erfolglose Anmeldeversuche @@ -288,9 +280,7 @@ Zugangsschlüssel zum Rezeptdienst Zugriffsprotokolle Keine Zugriffsprotokolle - Sie erhalten Zugriffsprotokolle, wenn Sie am Rezeptdienst angemeldet sind. Es liegen noch keine Zugriffsprotokolle vor. - Zuletzt aktualisiert am %s Das Rezept ist derzeit in Bearbeitung und kann nicht gelöscht werden Akzeptieren Das hat anscheinend nicht geklappt @@ -358,7 +348,7 @@ Keine PIN erhalten PIN Überprüfen Sie die Verbindung mit dem Internet und die Uhrzeit-/Datumseinstellung Ihres Geräts. - Um sich zu authentifizieren, drücken Sie auf “Entsperren”. + Um sich anzumelden, drücken Sie auf “Entsperren”. Ausgesperrt? Bitte überprüfen Sie Ihre biometrischen Zugangsdaten auf diesem Gerät. Passwort vergessen? Bitte löschen Sie die App und installieren sie anschließend erneut. Weshalb das so ist, erfahren Sie in unserem %s. https://www.das-e-rezept-fuer-deutschland.de/faq @@ -373,7 +363,7 @@ Akzeptieren Rückgängig Hinweis - Helfen Sie uns, diese App besser zu machen? + Helfen Sie uns, diese App besser zu machen Kennwort eingeben Das Kennwort muss mindestens acht Zeichen lang sein Kennwortstärke nicht ausreichend @@ -451,10 +441,7 @@ Gesundheitskarte PIN oder Karte bestellen Anmelden - Wie möchten Sie sich authentifizieren? - Versicherungs-App - Gesundheitskarte - Zugehörige PIN benötigt + Wie möchten Sie sich anmelden? NFC-fähige Gesundheitskarte PIN zur Gesundheitskarte Sie verfügen noch nicht über eine NFC-fähige Gesundheitskarte und PIN? @@ -658,8 +645,7 @@ Gesetzlich Versicherte müssen für verschreibungspflichtige Medikamente eine Zuzahlung von bis zu zehn Euro leisten.\n\nDie Höhe der Zuzahlung ist abhängig von dem Preis Ihres Medikaments. Medikamente, die weniger als 5€ kosten müssen Sie selbst zahlen.\nBei Medikamenten die teurer sind, müssen Sie zehn Prozent des Preises zuzahlen, mindestens aber 5€ und höchstens 10€.\n\nGrundsätzlich befreit von einer Zuzahlung sind Kinder und Jugendliche unter 18 Jahren. \n\nSollten Ihre jährlichen Kosten für Medikamente Ihre finanzielle Belastungsgrenzt überschreiten können Sie sich von der Zuzahlung befreien lassen. Sprechen Sie dazu mit Ihrer Krankenversicherung. Sie sind von der Zuzahlung von diesem Medikament befreit. Die Kosten für das Medikament übernimmt Ihre Krankenkasse. Wie lange ist dieses Rezept gültig? - Innerhalb dieses Zeitraums können Sie Ihr Rezept in einer beliebigen Apotheke mit einer Zuzahlung einlösen. - Innerhalb dieses Zeitraums können Sie das Rezept nach wie vor in einer Apotheke einlösen, müssen jedoch die Kaufsumme selbst übernehmen. Alternativ können Sie in Ihrer Praxis im eine erneute Ausstellung des Rezepts bitten. + Innerhalb dieses Zeitraums können Sie Ihr Rezept in einer beliebigen Apotheke mit einer Zuzahlung von maximal 10€ einlösen. Ersatzpräparat möglich Aufgrund gesetzlicher Vorgaben Ihrer Krankenkasse kann Ihnen eine Alternative mit dem selben Wirkstoff ausgehändigt werden.\n\nMedikamente können unterschiedlich aussehen und heißen, andere Preise und Hersteller haben, aber dennoch den gleichen Wirkstoff beinhalten. Für die Wirkung von Arzneimitteln im Körper sind vor allem der Wirkstoff selbst und die Dosierung ausschlaggebend. Oft bekommen Patienten und Patientinnen in der Apotheke ein anderes Medikament als das vom Arzt oder der Ärztin auf dem Rezept verordnete – vorausgesetzt, die Medikamente sind vergleichbar. Für den Wechsel kann es therapeutische und wirtschaftliche Gründe geben. Gescanntes Rezept @@ -730,11 +716,11 @@ Keine Rezepte Fügen Sie Rezepte über den + Button in der rechten oberen Ecke hinzu. Anmelden - Eingelöste Rezepte + Rezeptarchiv Vielleicht später Anmelden Profilbild bearbeiten - Eingelöste Rezepte + Rezeptarchiv Name eingeben Speichern Meine Bestellung @@ -885,6 +871,17 @@ Wird für Sie eingelöst Wurde für Sie eingelöst Sie müssen angemeldet sein, um diesen Service zu nutzen. + Versicherungs-App + Gesundheitskarte + Zugehörige PIN benötigt + Nur noch morgen als Selbstzahlender einlösbar + Nur noch %s Tage als Selbstzahlender einlösbar + \n Noch %s Tage als Selbstzahlender einlösbar\n + Nur noch %s Tage gültig + \n Noch %s Tage gültig\n + Nur noch morgen gültig + Gebührenpflichtig + Übernimmt Versicherung Das Rezept/die Rezepte wurden erfolgreich übertragen. Das Rezept kann nicht verarbeitet werden. Bitte versuchen Sie es erneut. Eventuell müssen Sie eine andere Apotheke auswählen. Das Rezept kann nicht verarbeitet werden. Die Apotheke meldet einen unbekannten Fehler. Probieren Sie ggf. eine andere Apotheke. @@ -903,4 +900,12 @@ Rezept bereits eingelöst Rezept gelöscht Kein Internet + Um Zugriffsprotokolle zu empfangen, müssen Sie mit dem Server verbunden sein. + Innerhalb dieses Zeitraums können Sie das Rezept nach wie vor in einer Apotheke einlösen, müssen jedoch die gesamte Kaufsumme des Medikaments selbst übernehmen. Alternativ können Sie in Ihrer Praxis um eine erneute Ausstellung des Rezepts bitten. + Fertig + Korrektur anfragen + In der Apotheke + In der App + Lassen Sie diesen Code in Ihrer Apotheke abscannen. + Korrekturanfrage der Abrechnung diff --git a/android/src/release/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt b/android/src/release/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt index 6d565947..2b76a8f4 100644 --- a/android/src/release/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt +++ b/android/src/release/java/de/gematik/ti/erp/app/debug/ui/DebugScreenWrapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/release/java/de/gematik/ti/erp/app/di/EndpointHelper.kt b/android/src/release/java/de/gematik/ti/erp/app/di/EndpointHelper.kt index 5d70873c..54f9c0de 100644 --- a/android/src/release/java/de/gematik/ti/erp/app/di/EndpointHelper.kt +++ b/android/src/release/java/de/gematik/ti/erp/app/di/EndpointHelper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/release/java/de/gematik/ti/erp/app/utils/compose/ReleaseCommon.kt b/android/src/release/java/de/gematik/ti/erp/app/utils/compose/ReleaseCommon.kt index d159a2a2..54121d5d 100644 --- a/android/src/release/java/de/gematik/ti/erp/app/utils/compose/ReleaseCommon.kt +++ b/android/src/release/java/de/gematik/ti/erp/app/utils/compose/ReleaseCommon.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/android/util/Base64.kt b/android/src/test/java/android/util/Base64.kt index c754b3ae..79f2d834 100644 --- a/android/src/test/java/android/util/Base64.kt +++ b/android/src/test/java/android/util/Base64.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/CoroutineTestRule.kt b/android/src/test/java/de/gematik/ti/erp/app/CoroutineTestRule.kt index c26eb160..6c1ac3e2 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/CoroutineTestRule.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/CoroutineTestRule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/consent/model/ConsentMapperTest.kt b/android/src/test/java/de/gematik/ti/erp/app/consent/model/ConsentMapperTest.kt index 84543c90..7a29c6d0 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/consent/model/ConsentMapperTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/consent/model/ConsentMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/consent/usecase/ConsentUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/consent/usecase/ConsentUseCaseTest.kt index 0f620ee4..b6e9c680 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/consent/usecase/ConsentUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/consent/usecase/ConsentUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/idp/JWTExtensionsTest.kt b/android/src/test/java/de/gematik/ti/erp/app/idp/JWTExtensionsTest.kt index fd98fe14..d934d68d 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/idp/JWTExtensionsTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/idp/JWTExtensionsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCaseTest.kt index 04f65d5a..3d1c5c35 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -81,4 +81,8 @@ class InvoiceUseCaseTest { invoices ) } + + @Test + fun `invoice create dmc payload`() = + assertEquals("{\"urls\":[\"ChargeItem/01234?ac=98765\"]}", pkvInvoice.dmcPayload) } diff --git a/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/TestInvoices.kt b/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/TestInvoices.kt index d905583a..9e50f8c3 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/TestInvoices.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/invoice/usecase/TestInvoices.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.invoice.usecase -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import de.gematik.ti.erp.app.invoice.model.InvoiceData import de.gematik.ti.erp.app.prescription.model.SyncedTaskData import kotlinx.datetime.Clock @@ -31,6 +31,7 @@ val later = now.plus(8760, DateTimeUnit.HOUR) val pkvInvoice = InvoiceData.PKVInvoice( profileId = "1234", taskId = "01234", + accessCode = "98765", timestamp = now, invoice = InvoiceData.Invoice( 2.30, @@ -72,6 +73,7 @@ val pkvInvoice = InvoiceData.PKVInvoice( val pkvInvoice2 = InvoiceData.PKVInvoice( profileId = "23456", taskId = "65432", + accessCode = "98765", timestamp = later, invoice = InvoiceData.Invoice( 2.30, diff --git a/android/src/test/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCaseTest.kt index 8dbf29d3..154e2ecc 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/orderhealthcard/usecase/HealthCardOrderUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCaseTest.kt index 88600e48..1a5182af 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/orders/usecase/OrderUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunicationTest.kt b/android/src/test/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunicationTest.kt index 80bcd28e..f8982198 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunicationTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunicationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyControllerTest.kt b/android/src/test/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyControllerTest.kt index 0cc8e585..9e3c5204 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyControllerTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/pharmacy/ui/PharmacyControllerTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/prescription/MapperTest.kt b/android/src/test/java/de/gematik/ti/erp/app/prescription/MapperTest.kt index 3a11a9a5..95d5a831 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/prescription/MapperTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/prescription/MapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidatorTest.kt b/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidatorTest.kt index f226a1a8..8353c610 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidatorTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/TwoDCodeValidatorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompletedTest.kt b/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompletedTest.kt index d46cb304..8542d1a1 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompletedTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/prescription/ui/model/SentOrCompletedTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCaseTest.kt index 32296208..ec440b8e 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCaseTest.kt index 94f2d44e..d2842e1e 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/profiles/usecase/ProfilesUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -68,8 +68,7 @@ class ProfilesUseCaseTest { profilesUseCase = ProfilesUseCase( profilesRepository = profilesRepository, - idpRepository = idpRepository, - auditRepository = auditEventsRepository + idpRepository = idpRepository ) } diff --git a/android/src/test/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCaseTest.kt b/android/src/test/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCaseTest.kt index a118cc0d..5d2af20d 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCaseTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/settings/usecase/SettingsUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/utils/DateTimeTest.kt b/android/src/test/java/de/gematik/ti/erp/app/utils/DateTimeTest.kt index fcc485cd..a50f0d24 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/utils/DateTimeTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/utils/DateTimeTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,6 @@ package de.gematik.ti.erp.app.utils -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal import org.junit.Test import java.util.Locale import kotlin.test.assertEquals diff --git a/android/src/test/java/de/gematik/ti/erp/app/utils/Proxy.kt b/android/src/test/java/de/gematik/ti/erp/app/utils/Proxy.kt index e6452db0..4ff42a72 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/utils/Proxy.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/utils/Proxy.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/utils/TestData.kt b/android/src/test/java/de/gematik/ti/erp/app/utils/TestData.kt index 82f28f31..260f4baa 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/utils/TestData.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/utils/TestData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,6 @@ package de.gematik.ti.erp.app.utils -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal import de.gematik.ti.erp.app.prescription.model.ScannedTaskData import de.gematik.ti.erp.app.prescription.model.SyncedTaskData import kotlinx.datetime.Clock diff --git a/android/src/test/java/de/gematik/ti/erp/app/utils/TestExtensions.kt b/android/src/test/java/de/gematik/ti/erp/app/utils/TestExtensions.kt index da10b448..bf1ad4c3 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/utils/TestExtensions.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/utils/TestExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/vau/TestData.kt b/android/src/test/java/de/gematik/ti/erp/app/vau/TestData.kt index d1bee3aa..03c09cd2 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/vau/TestData.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/vau/TestData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreIntegrationTest.kt b/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreIntegrationTest.kt index 63b8d997..246a53c9 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreIntegrationTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreIntegrationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreTest.kt b/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreTest.kt index 62b4cd14..4b82e807 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/vau/TruststoreTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/test/java/de/gematik/ti/erp/app/vau/repository/VauRepositoryTest.kt b/android/src/test/java/de/gematik/ti/erp/app/vau/repository/VauRepositoryTest.kt index 984c061f..aa16593c 100644 --- a/android/src/test/java/de/gematik/ti/erp/app/vau/repository/VauRepositoryTest.kt +++ b/android/src/test/java/de/gematik/ti/erp/app/vau/repository/VauRepositoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/build.gradle.kts b/build.gradle.kts index 8f300824..8bfc7d11 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,5 +1,10 @@ import com.github.benmanes.gradle.versions.updates.DependencyUpdatesTask +buildscript { + dependencies { + classpath("com.karumi:shot:6.0.0") + } +} // NOTE: Only pre-include plugins (apply false) required by the modules android, common // and desktop within this block to keep them excluded from the root module. // If the plugin can't be resolved add a custom resolution strategy to `settings.gradle.kts`. @@ -23,6 +28,8 @@ plugins { id("org.jetbrains.compose") version "1.4.0" apply false id("com.codingfeline.buildkonfig") version "0.13.3" apply false id("io.gitlab.arturbosch.detekt") version "1.22.0" + id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") + } val ktlintMain by configurations.creating diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 758680f3..4c7898b0 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -16,6 +16,7 @@ plugins { id("org.jetbrains.compose") id("com.codingfeline.buildkonfig") id("de.gematik.ti.erp.dependencies") + id("de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin") } fun getGitHash() = diff --git a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt index b5b11d7d..01e3ed6d 100644 --- a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt +++ b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -20,7 +20,15 @@ package de.gematik.ti.erp.app import android.os.Build import java.security.SecureRandom - +@Requirement( + "O.Rand_1", + "O.Rand_2", + "O.Rand_3", + "O.Rand_4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Generation of random values by secure random generator specified in FIPS 140-2, " + + "Security Requirements for Cryptographic Modules, section 4.9.1." +) actual fun secureRandomInstance(): SecureRandom = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { SecureRandom.getInstanceStrong() diff --git a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonthAndroid.kt b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonthAndroid.kt index d2bc2f34..948d4666 100644 --- a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonthAndroid.kt +++ b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonthAndroid.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt index 621f7f6c..af144cd7 100644 --- a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt +++ b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt index 5ef97608..2a9f85be 100644 --- a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt +++ b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt index 07ce8dea..6b6ed7ed 100644 --- a/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt +++ b/common/src/androidMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/BCProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/BCProvider.kt index f997ee75..8efd98af 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/BCProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/BCProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/CryptoUtils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/CryptoUtils.kt index 66b6c069..01a613a1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/CryptoUtils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/CryptoUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -24,12 +24,25 @@ import javax.crypto.SecretKey @Requirement( "A_19179", "A_21323", - "GS-A_4368", - "GS-A_4367", sourceSpecification = "gemSpec_eRp_FdV", rationale = "Entropy is ensured by using SecureRandom for generation." // TODO Update this req. when using the health card for random number generation is also implemented for Android. ) +@Requirement( + "GS-A_4368", + "GS-A_4367#1", + sourceSpecification = "gemSpec_Krypt", + rationale = "Entropy is ensured by using SecureRandom for generation. The only statement regarding the quality " + + "of random number generation from Android is, that the requirements of FIPS 140-2 are met." + + "However, there is no direct relation between FIPS 140-2 and DRG.2, because DRG.2 describes a concrete " + + "implementation of a PRNG, and FIPS 140-2 defines requirements on the quality of randomness." + // TODO Update this req. when using the health card for random number generation is also implemented for Android. +) +@Requirement( + "O.Cryp_3#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Key Generation AES256 - Entropy is ensured by using SecureRandom for generation." +) fun generateRandomAES256Key(): SecretKey = KeyGenerator.getInstance("AES").apply { init(256, secureRandomInstance()) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/DispatchProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/DispatchProvider.kt index aed77ef7..438f0631 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/DispatchProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/DispatchProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/Requirement.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/Requirement.kt index 5ca92175..13bd3c7f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/Requirement.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/Requirement.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt index 9181161f..2d52c34f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt index 2f4dc83e..be0fddb4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -61,8 +61,7 @@ interface ErpService { suspend fun getAuditEvents( @Tag profileId: ProfileIdentifier, @Header("Accept-Language") language: String, - @Query("date") lastKnownDate: String?, - @Query("_sort") sort: String = "+date", + @Query("_sort") sort: String = "-date", @Query("_count") count: Int? = null, @Query("__offset") offset: Int? = null ): Response diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/NetworkUtil.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/NetworkUtil.kt index 13279ba7..56fbad08 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/NetworkUtil.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/NetworkUtil.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacyRedeemService.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacyRedeemService.kt index 77e06364..96db1cce 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacyRedeemService.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacyRedeemService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacySearchService.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacySearchService.kt index 923493f9..58066bf6 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacySearchService.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/PharmacySearchService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ResourcePaging.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ResourcePaging.kt index e2a2685d..b8a9426a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ResourcePaging.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/api/ResourcePaging.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/apicheck/usecase/CheckVersionUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/apicheck/usecase/CheckVersionUseCase.kt index 5f2c8986..8ec8ea8e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/apicheck/usecase/CheckVersionUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/apicheck/usecase/CheckVersionUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,10 +23,16 @@ import okhttp3.Request import java.net.HttpURLConnection import de.gematik.ti.erp.app.BuildKonfig import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.Requirement import io.github.aakira.napier.Napier import kotlinx.coroutines.withContext import java.io.IOException - +@Requirement( + "O.Arch_10#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Currently only implemented via APIKey usage against the FD. " + + "All requests against the backends may respond with an 403 status code." +) class CheckVersionUseCase( private val okHttp: OkHttpClient, private val dispatchers: DispatchProvider diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/CardUtilities.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/CardUtilities.kt index 78c20efb..9351dca1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/CardUtilities.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/CardUtilities.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/CardKey.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/CardKey.kt index aa7c7e5f..15d821e4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/CardKey.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/CardKey.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/EncryptedPinFormat2.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/EncryptedPinFormat2.kt index 9c9e984f..87919aa8 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/EncryptedPinFormat2.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/EncryptedPinFormat2.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/HealthCardVersion2.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/HealthCardVersion2.kt index 998681ac..c7cbb156 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/HealthCardVersion2.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/HealthCardVersion2.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardChannel.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardChannel.kt index c0d56811..3a1b6329 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardChannel.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardKeyReference.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardKeyReference.kt index 020c06b5..d339be21 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardKeyReference.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/ICardKeyReference.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/IHealthCard.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/IHealthCard.kt index 8233c77e..e529b21e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/IHealthCard.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/IHealthCard.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PaceKey.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PaceKey.kt index 3b21176e..e3bea420 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PaceKey.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PaceKey.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PasswordReference.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PasswordReference.kt index 1254e442..b281b247 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PasswordReference.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PasswordReference.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PsoAlgorithm.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PsoAlgorithm.kt index 75b9dcbc..68a8912e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PsoAlgorithm.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/PsoAlgorithm.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/SecureMessaging.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/SecureMessaging.kt index 4fca4187..7284fcbd 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/SecureMessaging.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/card/SecureMessaging.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/cardobjects/FileSystem.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/cardobjects/FileSystem.kt index 4faa6beb..3399f66e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/cardobjects/FileSystem.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/cardobjects/FileSystem.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/Apdu.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/Apdu.kt index bd8fb614..f1104606 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/Apdu.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/Apdu.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ChangeReferenceDataCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ChangeReferenceDataCommand.kt index f536d0ae..3d2ba454 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ChangeReferenceDataCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ChangeReferenceDataCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GeneralAuthenticateCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GeneralAuthenticateCommand.kt index 817d2430..436b57b1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GeneralAuthenticateCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GeneralAuthenticateCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetPinStatusCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetPinStatusCommand.kt index ee70b377..d6dc0b07 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetPinStatusCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetPinStatusCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetRandomValues.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetRandomValues.kt index 4bbc14d4..5869d380 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetRandomValues.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/GetRandomValues.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -32,7 +32,7 @@ private const val NO_MEANING = 0x00 * Use case Get Random gemSpec_COS#14.9.5.1 */ @Requirement( - "GS-A_4367#5", + "GS-A_4367#6", "GS-A_4368#5", sourceSpecification = "gemSpec_Krypt", rationale = "Random numbers are generated using the RNG of the health card." + diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/HealthCardCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/HealthCardCommand.kt index 5a62d54f..8f67eb41 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/HealthCardCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/HealthCardCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ManageSecurityEnvironmentCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ManageSecurityEnvironmentCommand.kt index 9f39eebf..fbc017ea 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ManageSecurityEnvironmentCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ManageSecurityEnvironmentCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/PsoComputeDigitalSignatureCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/PsoComputeDigitalSignatureCommand.kt index b8eee0cf..9ceba18d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/PsoComputeDigitalSignatureCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/PsoComputeDigitalSignatureCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ReadCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ReadCommand.kt index 78fcffc7..2fa22244 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ReadCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ReadCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ResponseStatus.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ResponseStatus.kt index 5c537ad8..b0fb9277 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ResponseStatus.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/ResponseStatus.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/SelectCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/SelectCommand.kt index 97c9da4e..8f9bc5cc 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/SelectCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/SelectCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/UnlockEgkCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/UnlockEgkCommand.kt index 90397245..97e6f1ac 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/UnlockEgkCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/UnlockEgkCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/VerifyCommand.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/VerifyCommand.kt index f7d39a8a..f4526fe0 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/VerifyCommand.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/command/VerifyCommand.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/CertificateExchange.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/CertificateExchange.kt index 44e85069..15061a2a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/CertificateExchange.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/CertificateExchange.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/KeyDerivationFunction.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/KeyDerivationFunction.kt index a1b7e14f..c3ef98dd 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/KeyDerivationFunction.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/KeyDerivationFunction.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PaceInfo.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PaceInfo.kt index 3fe41381..78ceab96 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PaceInfo.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PaceInfo.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PinExchange.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PinExchange.kt index 371d7726..105d9dfa 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PinExchange.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/PinExchange.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/RandomExchange.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/RandomExchange.kt index 2baedbcb..809754ca 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/RandomExchange.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/RandomExchange.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -27,7 +27,7 @@ import de.gematik.ti.erp.app.card.model.command.getRandomValues import de.gematik.ti.erp.app.card.model.command.select @Requirement( - "GS-A_4367#4", + "GS-A_4367#5", "GS-A_4368#4", sourceSpecification = "gemSpec_Krypt", rationale = "Random numbers are generated using the RNG of the health card." + diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/SignChallengeExchange.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/SignChallengeExchange.kt index b15a3f95..db9ec115 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/SignChallengeExchange.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/SignChallengeExchange.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -41,6 +41,12 @@ import de.gematik.ti.erp.app.card.model.identifier.ApplicationIdentifier sourceSpecification = "gemF_Tokenverschlüsselung", rationale = "Sign challenge using the health card certificate." ) +@Requirement( + "O.Cryp_1#1", + "O.Cryp_4#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" +) fun ICardChannel.signChallenge(challenge: ByteArray): ByteArray { HealthCardCommand.select(ApplicationIdentifier(Df.Esign.AID)).executeSuccessfulOn(this) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/TrustedChannelPaceKeyExchange.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/TrustedChannelPaceKeyExchange.kt index 52d69743..e38ba0a3 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/TrustedChannelPaceKeyExchange.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/exchange/TrustedChannelPaceKeyExchange.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.cardwall.model.nfc.exchange +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.card.model.CardUtilities.byteArrayToECPoint import de.gematik.ti.erp.app.card.model.CardUtilities.extractKeyObjectEncoded import de.gematik.ti.erp.app.card.model.card.CardKey @@ -101,6 +102,13 @@ suspend fun ICardChannel.establishTrustedChannel(cardAccessNumber: String): Pace val nonceZBytes = HealthCardCommand.generalAuthenticate(true).executeSuccessfulOn(this).apdu.data val nonceZBytesEncoded = extractKeyObjectEncoded(nonceZBytes) val canBytes = cardAccessNumber.toByteArray() + + @Requirement( + "O.Cryp_3#2", + "O.Cryp_4#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "AES Key-Generation and one time usage" + ) val aes128Key = getAES128Key(canBytes, KeyDerivationFunction.Mode.PASSWORD) val encKey = KeyParameter(aes128Key) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ApplicationIdentifier.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ApplicationIdentifier.kt index 4823eb41..b05fc64a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ApplicationIdentifier.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ApplicationIdentifier.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/FileIdentifier.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/FileIdentifier.kt index 6c8074ee..c466de94 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/FileIdentifier.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/FileIdentifier.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ShortFileIdentifier.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ShortFileIdentifier.kt index aad15bc8..d2a9304e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ShortFileIdentifier.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/identifier/ShortFileIdentifier.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/DataObject.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/DataObject.kt index 506f90d5..ad7c00c2 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/DataObject.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/DataObject.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/LengthObject.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/LengthObject.kt index 5cd42727..d0fd446d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/LengthObject.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/LengthObject.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/MacObject.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/MacObject.kt index 0969887f..baee6381 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/MacObject.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/MacObject.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/StatusObject.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/StatusObject.kt index 50157a69..78c8bad5 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/StatusObject.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/card.model/tagobjects/StatusObject.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/model/ConsentMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/model/ConsentMapper.kt index f8001514..a547705c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/model/ConsentMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/model/ConsentMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,7 +19,7 @@ package de.gematik.ti.erp.app.consent.model import de.gematik.ti.erp.app.fhir.model.json -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedString import de.gematik.ti.erp.app.fhir.parser.findAll diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRemoteDataSource.kt index 9f578b8f..33549d87 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRepository.kt index 2ae901e9..fbff8a4e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/repository/ConsentRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/usecase/ConsentUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/usecase/ConsentUseCase.kt index 48d38c1d..212bb6db 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/usecase/ConsentUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/consent/usecase/ConsentUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt index c1a3ae78..194e2820 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Migrations.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,7 +19,6 @@ package de.gematik.ti.erp.app.db import de.gematik.ti.erp.app.db.entities.v1.AddressEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.AuditEventEntityV1 import de.gematik.ti.erp.app.db.entities.v1.AvatarFigureV1 import de.gematik.ti.erp.app.db.entities.v1.IdpAuthenticationDataEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpConfigurationEntityV1 @@ -56,7 +55,7 @@ import io.realm.kotlin.ext.query import io.realm.kotlin.ext.realmListOf import kotlinx.datetime.Instant -const val ACTUAL_SCHEMA_VERSION = 24L +const val ACTUAL_SCHEMA_VERSION = 26L val appSchemas = setOf( AppRealmSchema( @@ -77,7 +76,6 @@ val appSchemas = setOf( PractitionerEntityV1::class, ScannedTaskEntityV1::class, SyncedTaskEntityV1::class, - AuditEventEntityV1::class, IdpAuthenticationDataEntityV1::class, AddressEntityV1::class, InsuranceInformationEntityV1::class, diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/QueryUtils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/QueryUtils.kt index 5364f937..5e517d31 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/QueryUtils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/QueryUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverter.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverter.kt index 38583332..2dd99a16 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverter.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverter.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Schema.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Schema.kt index cb40a02f..7e66efa8 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Schema.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/Schema.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/Delegates.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/Delegates.kt index 3b88af1b..0e05142d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/Delegates.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/Delegates.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,8 +18,8 @@ package de.gematik.ti.erp.app.db.entities -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import java.lang.IllegalArgumentException import kotlin.properties.ReadWriteProperty import kotlin.reflect.KMutableProperty diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtils.kt index f247f6c4..2a697c5f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Address.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Address.kt index bb86f153..9a882c05 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Address.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Address.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpAuthenticationData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpAuthenticationData.kt index f55f6dcb..a3671a5c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpAuthenticationData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpAuthenticationData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpConfiguration.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpConfiguration.kt index b8405190..9baf1de1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpConfiguration.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/IdpConfiguration.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Profile.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Profile.kt index fd8b3b4b..40ca827e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Profile.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Profile.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -109,13 +109,11 @@ class ProfileEntityV1 : RealmObject, Cascading { var invoices: RealmList = realmListOf() var idpAuthenticationData: IdpAuthenticationDataEntityV1? = null - var auditEvents: RealmList = realmListOf() override fun objectsToFollow(): Iterator = iterator { yield(syncedTasks) yield(scannedTasks) - yield(auditEvents) yield(invoices) idpAuthenticationData?.let { yield(it) } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt index 6e219c54..56f7fb8a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Settings.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.db.entities.v1 +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.db.entities.Cascading import de.gematik.ti.erp.app.db.entities.byteArrayBase64 import de.gematik.ti.erp.app.db.entities.enumName @@ -62,6 +63,17 @@ class PharmacySearchEntityV1 : RealmObject { var filterOpenNow: Boolean = false } +@Requirement( + "O.Data_1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "The settings of the app offer maximum data protection and security on first app start." + + "User preferences are asked without discrimination within the onboarding process" +) +@Requirement( + "O.Data_13", + sourceSpecification = "BSI-eRp-ePA", + rationale = "default settings are not allow screenshots" +) class SettingsEntityV1 : RealmObject, Cascading { var _authenticationMethod: String = Unspecified.toString() @@ -90,7 +102,7 @@ class SettingsEntityV1 : RealmObject, Cascading { var mlKitAccepted: Boolean = false // `gemSpec_eRp_FdV A_20203` default settings are not allow screenshots - var screenshotsAllowed: Boolean = false // TODO this needs a if BuildKonfig.debug then true else false + var screenshotsAllowed: Boolean = false override fun objectsToFollow(): Iterator = iterator { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/ShippingContact.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/ShippingContact.kt index bb50765a..e14baa41 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/ShippingContact.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/ShippingContact.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Truststore.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Truststore.kt index 73b94d96..c6469899 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Truststore.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/Truststore.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/ChargeableItem.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/ChargeableItem.kt index 9edfd0d5..8918171c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/ChargeableItem.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/ChargeableItem.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/Invoice.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/Invoice.kt index 0ae43cbe..99ae8f6d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/Invoice.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/Invoice.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PKVInvoice.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PKVInvoice.kt index 67848d8a..062b65f1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PKVInvoice.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PKVInvoice.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -26,7 +26,7 @@ import de.gematik.ti.erp.app.db.entities.v1.task.MedicationRequestEntityV1 import de.gematik.ti.erp.app.db.entities.v1.task.OrganizationEntityV1 import de.gematik.ti.erp.app.db.entities.v1.task.PatientEntityV1 import de.gematik.ti.erp.app.db.entities.v1.task.PractitionerEntityV1 -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import io.realm.kotlin.Deleteable import io.realm.kotlin.types.RealmInstant import io.realm.kotlin.types.RealmObject @@ -35,6 +35,7 @@ import io.realm.kotlin.types.annotations.Ignore class PKVInvoiceEntityV1 : RealmObject, Cascading { var taskId: String = "" + var accessCode: String = "" var timestamp: RealmInstant = RealmInstant.MIN diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PriceComponent.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PriceComponent.kt index 26a9441c..350b3708 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PriceComponent.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/invoice/PriceComponent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/FavoritePharmacy.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/FavoritePharmacy.kt index ac5d0070..a6208c9b 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/FavoritePharmacy.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/FavoritePharmacy.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/OftenUsedPharmacy.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/OftenUsedPharmacy.kt index 1a5a9fdf..71f6d5a9 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/OftenUsedPharmacy.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/OftenUsedPharmacy.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/PharmacyCache.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/PharmacyCache.kt index 23753c82..fafc2ff4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/PharmacyCache.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/pharmacy/PharmacyCache.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Communication.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Communication.kt index a60360a4..5306f812 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Communication.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Communication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ingredient.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ingredient.kt index 83afff7e..f493404c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ingredient.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ingredient.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/InsuranceInformation.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/InsuranceInformation.kt index ea180a45..47f54b02 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/InsuranceInformation.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/InsuranceInformation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Medication.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Medication.kt index 7f27275e..3b16cabc 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Medication.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Medication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -21,7 +21,7 @@ package de.gematik.ti.erp.app.db.entities.v1.task import de.gematik.ti.erp.app.db.entities.Cascading import de.gematik.ti.erp.app.db.entities.enumName import de.gematik.ti.erp.app.db.entities.temporalAccessorNullable -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import io.realm.kotlin.Deleteable import io.realm.kotlin.types.RealmList import io.realm.kotlin.types.RealmObject diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationDispense.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationDispense.kt index 3ceb61b0..033e1a0a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationDispense.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationDispense.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -20,7 +20,7 @@ package de.gematik.ti.erp.app.db.entities.v1.task import de.gematik.ti.erp.app.db.entities.Cascading import de.gematik.ti.erp.app.db.entities.temporalAccessorNullable -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import io.realm.kotlin.Deleteable import io.realm.kotlin.types.RealmObject import io.realm.kotlin.types.annotations.Ignore diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationRequest.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationRequest.kt index 3896e7ef..c978a496 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationRequest.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MedicationRequest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -21,7 +21,7 @@ package de.gematik.ti.erp.app.db.entities.v1.task import de.gematik.ti.erp.app.db.entities.Cascading import de.gematik.ti.erp.app.db.entities.enumName import de.gematik.ti.erp.app.db.entities.temporalAccessorNullable -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import io.realm.kotlin.Deleteable import io.realm.kotlin.types.RealmInstant import io.realm.kotlin.types.RealmObject diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MultiplePrescription.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MultiplePrescription.kt index 28175de2..feafab65 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MultiplePrescription.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/MultiplePrescription.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Organization.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Organization.kt index 8defda21..7debecef 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Organization.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Organization.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Patient.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Patient.kt index f4204865..38a39ebf 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Patient.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Patient.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -21,7 +21,7 @@ package de.gematik.ti.erp.app.db.entities.v1.task import de.gematik.ti.erp.app.db.entities.Cascading import de.gematik.ti.erp.app.db.entities.temporalAccessorNullable import de.gematik.ti.erp.app.db.entities.v1.AddressEntityV1 -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import io.realm.kotlin.Deleteable import io.realm.kotlin.types.RealmObject import io.realm.kotlin.types.annotations.Ignore diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Practitioner.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Practitioner.kt index 4b389793..3ac6b0dd 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Practitioner.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Practitioner.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Quantity.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Quantity.kt index 775308ba..3f1a9101 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Quantity.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Quantity.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ratio.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ratio.kt index 68bcdff1..2de1f797 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ratio.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/Ratio.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/ScannedTask.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/ScannedTask.kt index 09d50870..d00211bb 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/ScannedTask.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/ScannedTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/SyncedTask.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/SyncedTask.kt index 8c492380..b78588d2 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/SyncedTask.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/db/entities/v1/task/SyncedTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/di/JWSConverterFactory.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/di/JWSConverterFactory.kt index 64a02763..f12697e3 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/di/JWSConverterFactory.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/di/JWSConverterFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapper.kt deleted file mode 100644 index f5b321ca..00000000 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapper.kt +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2023 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -package de.gematik.ti.erp.app.fhir.model - -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirInstant -import de.gematik.ti.erp.app.fhir.parser.contained -import de.gematik.ti.erp.app.fhir.parser.containedArrayOrNull -import de.gematik.ti.erp.app.fhir.parser.containedString -import de.gematik.ti.erp.app.fhir.parser.filterWith -import de.gematik.ti.erp.app.fhir.parser.findAll -import de.gematik.ti.erp.app.fhir.parser.isProfileValue -import de.gematik.ti.erp.app.fhir.parser.stringValue -import kotlinx.serialization.json.JsonElement -import kotlinx.serialization.json.jsonPrimitive - -fun extractAuditEvents( - bundle: JsonElement, - save: (id: String, taskId: String?, description: String, timestamp: FhirTemporal.Instant) -> Unit -): Int { - val bundleTotal = bundle.containedArrayOrNull("entry")?.size ?: 0 - - val resources = bundle - .findAll(listOf("entry", "resource")) - - resources.forEach { resource -> - - val profileString = resource.contained("meta").contained("profile").contained() - - if (profileString.isProfileValue( - "https://gematik.de/fhir/StructureDefinition/ErxAuditEvent", - "1.1.1" - ) || - profileString.isProfileValue( - "https://gematik.de/fhir/erp/StructureDefinition/GEM_ERP_PR_AuditEvent", - "1.2" - ) - ) { - extractAuditEvent(resource, save) - } - } - - return bundleTotal -} - -fun extractAuditEvent( - resource: JsonElement, - save: (id: String, taskId: String?, description: String, timestamp: FhirTemporal.Instant) -> Unit -) { - val id = resource.containedString("id") - val text = resource.contained("text").containedString("div") - val taskId = resource - .findAll(listOf("entity", "what", "identifier")) - .filterWith("system", stringValue("https://gematik.de/fhir/NamingSystem/PrescriptionID")) - .firstOrNull() - ?.containedString("value") - - val timestamp = requireNotNull(resource.contained("recorded").jsonPrimitive.asFhirInstant()) { - "Audit event field `recorded` missing" - } - - val description = text.removeSurrounding("
", "
") - - save(id, taskId, description, timestamp) -} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonPharmacyTimes.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonPharmacyTimes.kt index 6f29c94d..10e67032 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonPharmacyTimes.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonPharmacyTimes.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,8 +18,8 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirLocalTime +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.asFhirLocalTime import kotlinx.serialization.json.JsonPrimitive import kotlinx.datetime.LocalTime diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapper.kt index 542dc934..050b5696 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -28,7 +28,7 @@ import de.gematik.ti.erp.app.fhir.parser.containedStringOrNull import de.gematik.ti.erp.app.fhir.parser.filterWith import de.gematik.ti.erp.app.fhir.parser.findAll import de.gematik.ti.erp.app.fhir.parser.stringValue -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapper.kt index b5ac64f1..7fc059d3 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,8 +19,8 @@ package de.gematik.ti.erp.app.fhir.model import de.gematik.ti.erp.app.Requirement -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirInstant +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.asFhirInstant import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedArrayOrNull import de.gematik.ti.erp.app.fhir.parser.containedString @@ -35,7 +35,13 @@ import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.jsonPrimitive -private fun template( +/** + * Template version 1.2 + * Changes + * - profile + * - recipient.system + */ +private fun templateVersion12( orderId: String, reference: String, payload: String, @@ -45,7 +51,7 @@ private fun template( "resourceType": "Communication", "meta": { "profile": [ - "https://gematik.de/fhir/StructureDefinition/ErxCommunicationDispReq" + "https://gematik.de/fhir/erp/StructureDefinition/GEM_ERP_PR_Communication_DispReq|1.2" ] }, "identifier": [ @@ -63,7 +69,7 @@ private fun template( "recipient": [ { "identifier": { - "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "system": "https://gematik.de/fhir/sid/telematik-id", "value": $recipientTID } } @@ -76,47 +82,6 @@ private fun template( } """.trimIndent() -// private fun templateVersion1_2( -// orderId: String, -// reference: String, -// payload: String, -// recipientTID: String -// ) = """ -// { -// "resourceType": "Communication", -// "meta": { -// "profile": [ -// "https://gematik.de/fhir/erp/StructureDefinition/GEM_ERP_PR_Communication_DispReq|1.2" -// ] -// }, -// "identifier": [ -// { -// "system": "https://gematik.de/fhir/NamingSystem/OrderID", -// "value": $orderId -// } -// ], -// "status": "unknown", -// "basedOn": [ -// { -// "reference": $reference -// } -// ], -// "recipient": [ -// { -// "identifier": { -// "system": "https://gematik.de/fhir/NamingSystem/TelematikID", -// "value": $recipientTID -// } -// } -// ], -// "payload": [ -// { -// "contentString": $payload -// } -// ] -// } -// """.trimIndent() - val json = Json { encodeDefaults = true prettyPrint = false @@ -132,12 +97,11 @@ fun createCommunicationDispenseRequest( val payloadString = json.encodeToString(payload) val reference = "Task/$taskId/\$accept?ac=$accessCode" - // Todo: use template Version 1.2 if supported - val templateString = template( + val templateString = templateVersion12( orderId = JsonPrimitive(orderId).toString(), reference = JsonPrimitive(reference).toString(), - recipientTID = JsonPrimitive(recipientTID).toString(), - payload = JsonPrimitive(payloadString).toString() + payload = JsonPrimitive(payloadString).toString(), + recipientTID = JsonPrimitive(recipientTID).toString() ) return json.parseToJsonElement(templateString) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationModel.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationModel.kt index d2f2da24..e9b0c87c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationModel.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -22,7 +22,7 @@ import kotlinx.serialization.Serializable @Serializable data class CommunicationPayload( - val version: String = "1", + val version: Int = 1, val supplyOptionsType: String, val name: String, val address: List, @@ -32,7 +32,7 @@ data class CommunicationPayload( @Serializable data class DirectCommunicationMessage( - val version: String = "2", + val version: Int = 2, val supplyOptionsType: String, val name: String, val address: List, diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapper.kt index c118bafd..6f92df10 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedArrayOrNull import de.gematik.ti.erp.app.fhir.parser.containedDouble @@ -30,8 +30,8 @@ import de.gematik.ti.erp.app.fhir.parser.findAll import de.gematik.ti.erp.app.fhir.parser.isProfileValue import de.gematik.ti.erp.app.fhir.parser.or import de.gematik.ti.erp.app.fhir.parser.stringValue -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal -import de.gematik.ti.erp.app.fhir.parser.toFormattedDateTime +import de.gematik.ti.erp.app.utils.toFhirTemporal +import de.gematik.ti.erp.app.utils.toFormattedDateTime import de.gematik.ti.erp.app.invoice.model.InvoiceData import kotlinx.datetime.Instant import kotlinx.datetime.toInstant @@ -61,6 +61,7 @@ fun extractInvoiceKBVAndErpPrBundle( bundle: JsonElement, process: ( taskId: String, + accessCode: String, invoiceBundle: JsonElement, kbvBundle: JsonElement, erpPrBundle: JsonElement @@ -72,7 +73,9 @@ fun extractInvoiceKBVAndErpPrBundle( lateinit var invoiceBundle: JsonElement lateinit var kbvBundle: JsonElement lateinit var erpPrBundle: JsonElement + var taskId = "" + var accessCode = "" resources.forEach { resource -> val profileString = resource @@ -82,8 +85,8 @@ fun extractInvoiceKBVAndErpPrBundle( when { profileString.isProfileValue( - "http://fhir.abda.de/eRezeptAbgabedaten/StructureDefinition/DAV-PKV-PR-ERP-AbgabedatenBundle", - "1.2" + "https://gematik.de/fhir/erpchrg/StructureDefinition/GEM_ERPCHRG_PR_ChargeItem", + "1.0" ) -> { taskId = resource .findAll("identifier") @@ -94,6 +97,20 @@ fun extractInvoiceKBVAndErpPrBundle( .firstOrNull() ?.containedString("value") ?: "" + accessCode = resource + .findAll("identifier") + .filterWith( + "system", + stringValue("https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode") + ) + .firstOrNull() + ?.containedString("value") ?: "" + } + + profileString.isProfileValue( + "http://fhir.abda.de/eRezeptAbgabedaten/StructureDefinition/DAV-PKV-PR-ERP-AbgabedatenBundle", + "1.2" + ) -> { invoiceBundle = resource } @@ -112,7 +129,7 @@ fun extractInvoiceKBVAndErpPrBundle( } } } - process(taskId, invoiceBundle, kbvBundle, erpPrBundle) + process(taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle) } fun extractBinary(bundle: JsonElement): ByteArray? { return bundle.contained("signature").containedString("data").toByteArray() diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/KBVMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/KBVMapper.kt index c333f642..330412b4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/KBVMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/KBVMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.isProfileValue import kotlinx.serialization.json.JsonElement diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapper.kt index ddc74b07..a17b2205 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedArray import de.gematik.ti.erp.app.fhir.parser.containedBooleanOrNull @@ -26,7 +26,7 @@ import de.gematik.ti.erp.app.fhir.parser.containedOrNull import de.gematik.ti.erp.app.fhir.parser.containedString import de.gematik.ti.erp.app.fhir.parser.containedStringOrNull import de.gematik.ti.erp.app.fhir.parser.isProfileValue -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapper.kt index b5f09e16..628d9c1d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -112,21 +112,16 @@ fun extractPharmacyServices( .first() .containedString("value") - var isOutpatientPharmacy = false var isMobilePharmacy = false pharmacy.findAll(TypeCodingCode).forEach { when (it.containedString()) { - "OUTPHARM" -> isOutpatientPharmacy = true "MOBL" -> isMobilePharmacy = true } } - val pickUpPharmacyService = if (isOutpatientPharmacy) { - PickUpPharmacyService(name = locationName) - } else { - null - } + // All pharmacies offer pickup service + val pickUpPharmacyService = PickUpPharmacyService(name = locationName) val onlinePharmacyService = if (isMobilePharmacy) { OnlinePharmacyService(name = locationName) @@ -196,7 +191,7 @@ fun extractBinaryCertificatesAsBase64( return resourceStrings.toList() } -private fun Sequence.mapCatching( +fun Sequence.mapCatching( onError: (JsonElement, Exception) -> Unit, transform: (JsonElement) -> R? ): Sequence = diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacySearchModel.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacySearchModel.kt index 9d653a31..95b5f635 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacySearchModel.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacySearchModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_0_2.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_0_2.kt index 2269ab7e..7a115eb9 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_0_2.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_0_2.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.asFhirLocalDate +import de.gematik.ti.erp.app.utils.asFhirLocalDate import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedBoolean import de.gematik.ti.erp.app.fhir.parser.containedDouble @@ -29,7 +29,7 @@ import de.gematik.ti.erp.app.fhir.parser.filterWith import de.gematik.ti.erp.app.fhir.parser.findAll import de.gematik.ti.erp.app.fhir.parser.isProfileValue import de.gematik.ti.erp.app.fhir.parser.stringValue -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_1_0.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_1_0.kt index 3c38e675..d2fc691c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_1_0.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/ResourceMapperVersion_1_1_0.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.asFhirLocalDate +import de.gematik.ti.erp.app.utils.asFhirLocalDate import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedBoolean import de.gematik.ti.erp.app.fhir.parser.containedBooleanOrNull @@ -30,7 +30,7 @@ import de.gematik.ti.erp.app.fhir.parser.filterWith import de.gematik.ti.erp.app.fhir.parser.findAll import de.gematik.ti.erp.app.fhir.parser.isProfileValue import de.gematik.ti.erp.app.fhir.parser.stringValue -import de.gematik.ti.erp.app.fhir.parser.toFhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapper.kt index b053ca5f..2185684d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapper.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,9 +18,9 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirInstant -import de.gematik.ti.erp.app.fhir.parser.asFhirLocalDate +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.asFhirInstant +import de.gematik.ti.erp.app.utils.asFhirLocalDate import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedArrayOrNull import de.gematik.ti.erp.app.fhir.parser.containedString @@ -30,8 +30,6 @@ import de.gematik.ti.erp.app.fhir.parser.isProfileValue import de.gematik.ti.erp.app.fhir.parser.stringValue import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.jsonPrimitive -import kotlinx.datetime.Instant -import kotlinx.datetime.LocalDate enum class TaskStatus { Ready, @@ -61,18 +59,25 @@ fun extractTaskIds( .contained("profile") .contained() + val status = mapTaskStatus(resource.containedString("status")) when { - profileString.isProfileValue("https://gematik.de/fhir/StructureDefinition/ErxTask", "1.1.1") -> + profileString.isProfileValue( + "https://gematik.de/fhir/StructureDefinition/ErxTask", + "1.1.1" + ) && status != TaskStatus.Canceled -> resource .findAll("identifier") - .filterWith("system", stringValue("https://gematik.de/fhir/NamingSystem/PrescriptionID")) + .filterWith( + "system", + stringValue("https://gematik.de/fhir/NamingSystem/PrescriptionID") + ) .first() .containedString("value") profileString.isProfileValue( "https://gematik.de/fhir/erp/StructureDefinition/GEM_ERP_PR_Task", "1.2" - ) -> + ) && status != TaskStatus.Canceled -> resource .findAll("identifier") .filterWith( @@ -192,8 +197,7 @@ fun extractTaskVersion111( .firstOrNull() ?.containedString("value") - val status = mapTaskstatus(task.containedString("status")) - + val status = mapTaskStatus(task.containedString("status")) val authoredOn = requireNotNull(task.contained("authoredOn").jsonPrimitive.asFhirInstant()) { "Couldn't parse `authoredOn`" } @@ -250,7 +254,7 @@ fun extractTaskVersion12( .firstOrNull() ?.containedString("value") - val status = mapTaskstatus(task.containedString("status")) + val status = mapTaskStatus(task.containedString("status")) val authoredOn = requireNotNull(task.contained("authoredOn").jsonPrimitive.asFhirInstant()) { "Couldn't parse `authoredOn`" @@ -284,11 +288,11 @@ fun extractTaskVersion12( ) } -private fun mapTaskstatus(status: String): TaskStatus = when (status) { +private fun mapTaskStatus(status: String): TaskStatus = when (status) { "ready" -> TaskStatus.Ready "in-progress" -> TaskStatus.InProgress "completed" -> TaskStatus.Completed - "canceled" -> TaskStatus.Canceled + "cancelled" -> TaskStatus.Canceled "accepted" -> TaskStatus.Accepted "draft" -> TaskStatus.Draft "failed" -> TaskStatus.Failed diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Comperator.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Comperator.kt index 2933b5ae..4417a79e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Comperator.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Comperator.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Converter.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Converter.kt index bf9d13a3..e82b7a74 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Converter.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Converter.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Formatter.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Formatter.kt index 7e6b26c3..57e1a5ee 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Formatter.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Formatter.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Parser.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Parser.kt index 966c4d03..020c2375 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Parser.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/Parser.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonth.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonth.kt index eb52d74b..343cb471 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonth.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/YearMonth.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,9 @@ package de.gematik.ti.erp.app.fhir.parser +import de.gematik.ti.erp.app.utils.FhirYearMonthRegex +import de.gematik.ti.erp.app.utils.FhirYearRegex + // just support sane values private const val YearMin = 1000 private const val YearMax = 9999 diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/AlgorithmIdentifiersExtending.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/AlgorithmIdentifiersExtending.kt index 6a912338..c76846c6 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/AlgorithmIdentifiersExtending.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/AlgorithmIdentifiersExtending.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EcdsaUsingShaAlgorithmExtending.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EcdsaUsingShaAlgorithmExtending.kt index 2af23295..ebc0eff8 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EcdsaUsingShaAlgorithmExtending.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EcdsaUsingShaAlgorithmExtending.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EllipticCurvesExtending.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EllipticCurvesExtending.kt index a932cb4f..30656f35 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EllipticCurvesExtending.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/EllipticCurvesExtending.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -33,8 +33,9 @@ import java.security.spec.ECPoint import java.security.spec.EllipticCurve @Requirement( - "GS-A_4361", - sourceSpecification = "gemSpec_eRp_FdV", + "GS-A_4357-2#2", + "GS-A_4361-2#2", + sourceSpecification = "gemSpec_Krypt", rationale = "Support for required algorithms implemented using ECDSA." ) object EllipticCurvesExtending : EllipticCurves() { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/JWTExtensions.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/JWTExtensions.kt index 98fea6b6..3329454a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/JWTExtensions.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/JWTExtensions.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -81,6 +81,12 @@ suspend fun buildJsonWebSignatureWithHealthCard( return "$headerAndPayload.${Base64Url().base64UrlEncode(signed)}" } +@Requirement( + "O.Cryp_1#5", + "O.Cryp_4#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" +) fun buildJsonWebSignatureWithSecureElement( builder: JsonWebSignature.() -> Unit, privateKey: PrivateKey, diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt index 74362a3b..ccc4a3c8 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -54,6 +54,11 @@ const val CLIENT_ID = "eRezeptApp" const val REDIRECT_URI = "https://redirect.gematik.de/erezept" const val EXT_AUTH_REDIRECT_URI: String = "https://das-e-rezept-fuer-deutschland.de/extauth" +@Requirement( + "O.Purp_8#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Interface of external idp service" +) interface IdpService { @Headers( diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/AuthenticationData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/AuthenticationData.kt index c11322c5..2abb59ac 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/AuthenticationData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/AuthenticationData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt index 6752a4c9..bb9098ba 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt index 8fd5c24b..505e32ac 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/model/IdpData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/model/IdpData.kt index bc3201c8..d581044f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/model/IdpData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/model/IdpData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt index 22fc0ebd..641b0767 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -89,6 +89,11 @@ class IdpLocalDataSource constructor( sourceSpecification = "gemSpec_eRp_FdV", rationale = "Save the SSO token to database." ) + @Requirement( + "O.Tokn_1#1", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Save the SSO token to realm database." + ) suspend fun saveSingleSignOnToken( profileId: ProfileIdentifier, tokenScope: IdpData.SingleSignOnTokenScope @@ -145,6 +150,11 @@ class IdpLocalDataSource constructor( } } + @Requirement( + "O.Tokn_6#5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "invalidate authentication data from keystore " + ) suspend fun invalidateAuthenticationData(profileId: ProfileIdentifier) { writeToRealm(profileId) { profile -> getOrInsertAuthData(profile)?.apply { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpPairingRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpPairingRepository.kt index cecbeeb2..fc3a71ec 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpPairingRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpPairingRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.idp.repository +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.idp.model.IdpData import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier import kotlinx.coroutines.flow.MutableStateFlow @@ -37,12 +38,25 @@ class IdpPairingRepository constructor( fun decryptedAccessToken(profileId: ProfileIdentifier) = decryptedAccessTokenMap.map { it[profileId] }.distinctUntilChanged() + @Requirement( + "O.Tokn_1#2", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Save the access token token to mutable state." + ) fun saveDecryptedAccessToken(profileId: ProfileIdentifier, accessToken: String) { decryptedAccessTokenMap.update { it + (profileId to accessToken) } } + @Requirement( + "A_21326#1", + sourceSpecification = "gemSpec_IDP_Frontend", + rationale = "removing decrypted access token from map" + + "since we have automatic memory management, we can't delete the token. " + + "Due to the use of frameworks we have sensitive data as immutable objects and hence " + + "cannot override it" + ) fun invalidateDecryptedAccessToken(profileId: ProfileIdentifier) { decryptedAccessTokenMap.update { it - profileId diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt index 2bd6485d..a5da3777 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt index 3a1d12d1..5428a9e7 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -238,7 +238,15 @@ class IdpRepository constructor( "A_20499-01", "A_21603", sourceSpecification = "gemSpec_eRp_FdV", - rationale = "Invalidate/delete session data upon logout." + rationale = "Invalidate/delete session data upon logout. " + + "since we have automatic memory management, we can't delete the token. " + + "Due to the use of frameworks we have sensitive data as immutable objects and hence " + + "cannot override it" + ) + @Requirement( + "O.Tokn_6#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "invalidate config and token " ) suspend fun invalidate(profileId: ProfileIdentifier) { invalidateConfig() diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/ExternalAuthenticationPreferences.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/ExternalAuthenticationPreferences.kt index 368d21fb..e0190a34 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/ExternalAuthenticationPreferences.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/ExternalAuthenticationPreferences.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpAlternateAuthenticationUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpAlternateAuthenticationUseCase.kt index 63e734ed..498f6bf9 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpAlternateAuthenticationUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpAlternateAuthenticationUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -216,6 +216,13 @@ class IdpAlternateAuthenticationUseCase( deviceInformation, authenticationMethod ) + + @Requirement( + "O.Cryp_1#3", + "O.Cryp_4#3", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" + ) val signedAuthData = buildSignedAuthenticationData(authData, privateKeyOfSecureElementEntry, signatureObjectOfSecureElementEntry) val encryptedAuthData = @@ -384,6 +391,12 @@ class IdpAlternateAuthenticationUseCase( ) } + @Requirement( + "O.Cryp_1#4", + "O.Cryp_4#4", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" + ) fun buildSignedAuthenticationData( authenticationData: AuthenticationData, privateKey: PrivateKey, diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt index b2280711..de37a5b5 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -256,6 +256,14 @@ class IdpBasicUseCase( sourceSpecification = "gemSpec_IDP_Frontend", rationale = "Returns the AUTHORIZATION_CODE (accessToken) and the SSO token." ) + @Requirement( + "A_21327#1", + sourceSpecification = "gemSpec_IDP_Frontend", + rationale = "Usage of idToken Payload / idToken is not persisted / " + + "since we have automatic memory management, we can't delete the token. " + + "Due to the use of frameworks we have sensitive data as immutable objects and hence " + + "cannot override it" + ) return IdpAuthFlowResult( accessToken = idpTokenResult.decryptedAccessToken, ssoToken = redirectSsoToken, @@ -347,6 +355,7 @@ class IdpBasicUseCase( sourceSpecification = "gemSpec_IDP_Frontend", rationale = "Fetch and check challenge." ) + suspend fun fetchAndCheckUnsignedChallenge( url: String, codeChallenge: String, @@ -401,6 +410,17 @@ class IdpBasicUseCase( pukSigKey: JWSPublicKey, redirectUri: String ): IdpTokenResult { + @Requirement( + "O.Cryp_3#2", + "O.Cryp_4#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "AES Key-Generation and one time usage" + ) + @Requirement( + "GS-A_4389#1", + sourceSpecification = "gemSpec_Krypt", + rationale = "AES Key-Generation and one time usage" + ) val symmetricalKey = generateRandomAES256Key() val keyVerifier = buildKeyVerifier( diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt index 589df88b..467da011 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt index b4726107..c61adc8a 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt index 0c39cd3a..64078dc6 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt index 9e0a21f3..1b31c962 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -384,6 +384,11 @@ class IdpUseCase( sourceSpecification = "gemSpec_IDP_Frontend", rationale = "External authentication (fast track)" ) + @Requirement( + "O.Plat_10#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Follow redirect" + ) suspend fun authenticateWithExternalAppAuthorization( uri: URI ) { @@ -576,7 +581,26 @@ class IdpUseCase( lateinit var privateKeyOfSecureElementEntry: PrivateKey lateinit var signatureObjectOfSecureElementEntry: Signature - + @Requirement( + "O.Cryp_1#2", + "O.Cryp_4#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Signature via ecdh ephemeral-static (one time usage)" + ) + @Requirement( + "O.Cryp_6", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Persisted cryptographic keys are created within the devices key store. " + + "Temporal keys are discarded as soon as usage is no longer needed." + ) + @Requirement( + "O.Cryp_7", + sourceSpecification = "BSI-eRp-ePA", + rationale = "As Brainpool256R1 is not available within key store but enforced by BSI where possible, " + + "we use secure enclave encryption only for biometric authentication. " + + "Everywhere else, cryptographic operations are ephemeral or use the eGK " + + "as a secure execution environment." + ) try { privateKeyOfSecureElementEntry = ( cryptoProvider.keyStoreInstance() diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/HtmlTemplate.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/HtmlTemplate.kt index 960ba713..f5f5f17f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/HtmlTemplate.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/HtmlTemplate.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.invoice.model -import de.gematik.ti.erp.app.fhir.parser.toFormattedDate +import de.gematik.ti.erp.app.utils.toFormattedDate import de.gematik.ti.erp.app.prescription.model.SyncedTaskData object PkvHtmlTemplate { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/InvoiceData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/InvoiceData.kt index db0a2957..c46a084e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/InvoiceData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/model/InvoiceData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,8 +18,9 @@ package de.gematik.ti.erp.app.invoice.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.prescription.model.SyncedTaskData +import de.gematik.ti.erp.app.utils.createDMPayload import kotlinx.datetime.Instant object InvoiceData { @@ -41,6 +42,7 @@ object InvoiceData { data class PKVInvoice( val profileId: String, val taskId: String, + val accessCode: String, val timestamp: Instant, val pharmacyOrganization: SyncedTaskData.Organization, val practitionerOrganization: SyncedTaskData.Organization, @@ -48,7 +50,8 @@ object InvoiceData { var patient: SyncedTaskData.Patient, val medicationRequest: SyncedTaskData.MedicationRequest, val whenHandedOver: FhirTemporal?, - val invoice: Invoice + val invoice: Invoice, + val dmcPayload: String = createDMPayload(listOf("ChargeItem/$taskId?ac=$accessCode")) ) data class Invoice( diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceLocalDataSource.kt index 9296cd9d..747bf31f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceLocalDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -90,7 +90,7 @@ class InvoiceLocalDataSource( extractInvoiceKBVAndErpPrBundle( bundle, - process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> extractInvoiceBundle( invoiceBundle, processDispense = { whenHandedOver -> @@ -132,7 +132,7 @@ class InvoiceLocalDataSource( } } }, - save = { taskId, timeStamp, pharmacy, invoice, whenHandedOver -> + save = { _, timeStamp, pharmacy, invoice, whenHandedOver -> invoiceEntity = queryFirst("taskId = $0", taskId) ?: run { copyToRealm(PKVInvoiceEntityV1()).also { profile.invoices += it @@ -148,6 +148,7 @@ class InvoiceLocalDataSource( invoiceEntity.apply { this.parent = profile this.taskId = taskId + this.accessCode = accessCode this.timestamp = timeStamp.toRealmInstant() this.pharmacyOrganization = pharmacy this.invoice = invoice @@ -364,7 +365,7 @@ class InvoiceLocalDataSource( } } - fun PKVInvoiceEntityV1.toPKVInvoice(): InvoiceData.PKVInvoice = + private fun PKVInvoiceEntityV1.toPKVInvoice(): InvoiceData.PKVInvoice = InvoiceData.PKVInvoice( profileId = this.parent?.id ?: "", timestamp = this.timestamp.toInstant(), @@ -446,6 +447,7 @@ class InvoiceLocalDataSource( bvg = this.medicationRequest?.bvg ), taskId = this.taskId, + accessCode = this.accessCode, whenHandedOver = this.whenHandedOver, invoice = InvoiceData.Invoice( totalAdditionalFee = this.invoice?.totalAdditionalFee ?: 0.0, @@ -493,7 +495,7 @@ class InvoiceLocalDataSource( } } - fun ChargeableItemV1.toChargeableItem() = InvoiceData.ChargeableItem( + private fun ChargeableItemV1.toChargeableItem() = InvoiceData.ChargeableItem( description = when (this.descriptionTypeV1) { DescriptionTypeV1.PZN -> InvoiceData.ChargeableItem.Description.PZN(this.description) DescriptionTypeV1.HMNR -> InvoiceData.ChargeableItem.Description.HMNR(this.description) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRemoteDataSource.kt index 60c107a0..4eaea1b9 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepository.kt index a3590c8a..ccf038d4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCase.kt index 862a3aaa..22d830d0 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/invoice/usecase/InvoiceUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt similarity index 92% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt index 0fac0936..90c97d0c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/PharmacyDirectCommunication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,6 +19,7 @@ package de.gematik.ti.erp.app.pharmacy import de.gematik.ti.erp.app.BCProvider +import de.gematik.ti.erp.app.Requirement import org.bouncycastle.asn1.ASN1EncodableVector import org.bouncycastle.asn1.ASN1ObjectIdentifier import org.bouncycastle.asn1.ASN1PrintableString @@ -48,7 +49,12 @@ import javax.crypto.spec.OAEPParameterSpec import javax.crypto.spec.PSource const val OidRecipientMail = "1.2.276.0.76.4.173" // komle-recipient-emails - +@Requirement( + "A_22778#2", + "A_22779#2", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Build and encrypt direct redeem message with pharmacy`s certificate" +) fun buildDirectPharmacyMessage( message: String, recipientCertificates: List @@ -75,7 +81,12 @@ fun buildDirectPharmacyMessage( val jcaConverter = JcaX509CertificateConverter().apply { setProvider(BCProvider) } - + @Requirement( + "GS-A_4389#3", + "GS-A_4390", + sourceSpecification = "gemSpec_Krypt", + rationale = "Build and encrypt direct redeem message with pharmacy`s certificate" + ) recipientCertificates .filterByRSAPublicKey() .forEach { recipientCert -> diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt similarity index 98% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt index 928b16bc..f81b6f8f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/model/PharmacyData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/DefaultPharmacyRepository.kt similarity index 78% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/DefaultPharmacyRepository.kt index b6d4e80f..cc0acbf5 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/DefaultPharmacyRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,39 +19,38 @@ package de.gematik.ti.erp.app.pharmacy.repository import de.gematik.ti.erp.app.DispatchProvider -import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData -import kotlinx.coroutines.flow.flowOn import de.gematik.ti.erp.app.fhir.model.PharmacyServices import de.gematik.ti.erp.app.fhir.model.extractBinaryCertificatesAsBase64 import de.gematik.ti.erp.app.fhir.model.extractPharmacyServices import de.gematik.ti.erp.app.pharmacy.model.OverviewPharmacyData +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import io.github.aakira.napier.Napier import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.withContext -import javax.inject.Inject -class PharmacyRepository @Inject constructor( +class DefaultPharmacyRepository( private val remoteDataSource: PharmacyRemoteDataSource, private val localDataSource: PharmacyLocalDataSource, private val dispatchers: DispatchProvider -) { - suspend fun searchPharmacies( +) : PharmacyRepository { + override suspend fun searchPharmacies( names: List, filter: Map ): Result = remoteDataSource.searchPharmacies(names, filter) - .map { + .map { jsonElement -> extractPharmacyServices( - bundle = it, - onError = { element, cause -> + bundle = jsonElement, + onError = { it, cause -> Napier.e(cause) { - element.toString() + it.toString() } } ) } - suspend fun searchPharmaciesByBundle( + override suspend fun searchPharmaciesByBundle( bundleId: String, offset: Int, count: Int @@ -73,7 +72,7 @@ class PharmacyRepository @Inject constructor( } } - suspend fun searchBinaryCerts( + override suspend fun searchBinaryCerts( locationId: String ): Result> = withContext(dispatchers.IO) { @@ -86,7 +85,7 @@ class PharmacyRepository @Inject constructor( } } - suspend fun redeemPrescriptionDirectly( + override suspend fun redeemPrescriptionDirectly( url: String, message: ByteArray, pharmacyTelematikId: String, @@ -99,37 +98,37 @@ class PharmacyRepository @Inject constructor( transactionId = transactionId ) - fun loadOftenUsedPharmacies() = + override fun loadOftenUsedPharmacies() = localDataSource.loadOftenUsedPharmacies().flowOn(dispatchers.IO) - fun loadFavoritePharmacies() = + override fun loadFavoritePharmacies() = localDataSource.loadFavoritePharmacies().flowOn(dispatchers.IO) - suspend fun saveOrUpdateOftenUsedPharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { + override suspend fun saveOrUpdateOftenUsedPharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { withContext(dispatchers.IO) { localDataSource.saveOrUpdateOftenUsedPharmacy(pharmacy) } } - suspend fun deleteOverviewPharmacy(overviewPharmacy: OverviewPharmacyData.OverviewPharmacy) { + override suspend fun deleteOverviewPharmacy(overviewPharmacy: OverviewPharmacyData.OverviewPharmacy) { withContext(dispatchers.IO) { localDataSource.deleteOverviewPharmacy(overviewPharmacy) } } - suspend fun saveOrUpdateFavoritePharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { + override suspend fun saveOrUpdateFavoritePharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { withContext(dispatchers.IO) { localDataSource.saveOrUpdateFavoritePharmacy(pharmacy) } } - suspend fun deleteFavoritePharmacy(favoritePharmacy: PharmacyUseCaseData.Pharmacy) { + override suspend fun deleteFavoritePharmacy(favoritePharmacy: PharmacyUseCaseData.Pharmacy) { withContext(dispatchers.IO) { localDataSource.deleteFavoritePharmacy(favoritePharmacy) } } - suspend fun searchPharmacyByTelematikId( + override suspend fun searchPharmacyByTelematikId( telematikId: String ): Result = withContext(dispatchers.IO) { @@ -144,10 +143,10 @@ class PharmacyRepository @Inject constructor( } } - fun isPharmacyInFavorites(pharmacy: PharmacyUseCaseData.Pharmacy): Flow = + override fun isPharmacyInFavorites(pharmacy: PharmacyUseCaseData.Pharmacy): Flow = localDataSource.isPharmacyInFavorites(pharmacy).flowOn(dispatchers.IO) - suspend fun markAsRedeemed(taskId: String) { + override suspend fun markAsRedeemed(taskId: String) { localDataSource.markAsRedeemed(taskId) } } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt similarity index 97% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt index f8be321d..9c1fc852 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -33,9 +33,8 @@ import io.realm.kotlin.query.Sort import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import kotlinx.datetime.Clock -import javax.inject.Inject -class PharmacyLocalDataSource @Inject constructor( +class PharmacyLocalDataSource( private val realm: Realm ) { suspend fun deleteOverviewPharmacy(overviewPharmacy: OverviewPharmacyData.OverviewPharmacy) { diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyMockRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyMockRepository.kt new file mode 100644 index 00000000..c1375951 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyMockRepository.kt @@ -0,0 +1,1992 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.pharmacy.repository + +import de.gematik.ti.erp.app.fhir.model.PharmacyServices +import de.gematik.ti.erp.app.fhir.model.extractPharmacyServices +import de.gematik.ti.erp.app.fhir.model.json +import de.gematik.ti.erp.app.pharmacy.model.OverviewPharmacyData +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData +import io.github.aakira.napier.Napier +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOf + +@Suppress("LargeClass") +class PharmacyMockRepository : PharmacyRepository { + + override suspend fun searchPharmacies(names: List, filter: Map): Result { + return Result.success(extractedPharmacies) + } + + override suspend fun searchPharmaciesByBundle(bundleId: String, offset: Int, count: Int): Result { + return Result.success(extractedPharmacies) + } + + override suspend fun searchBinaryCerts(locationId: String): Result> { + return Result.success(emptyList()) + } + + override suspend fun redeemPrescriptionDirectly( + url: String, + message: ByteArray, + pharmacyTelematikId: String, + transactionId: String + ): Result { + return Result.success(Unit) + } + + override fun loadOftenUsedPharmacies(): Flow> { + return flowOf(emptyList()) + } + + override fun loadFavoritePharmacies(): Flow> { + return flowOf(emptyList()) + } + + @Suppress("EmptyFunctionBlock") + override suspend fun saveOrUpdateOftenUsedPharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { + } + + @Suppress("EmptyFunctionBlock") + override suspend fun deleteOverviewPharmacy(overviewPharmacy: OverviewPharmacyData.OverviewPharmacy) { + } + + @Suppress("EmptyFunctionBlock") + override suspend fun saveOrUpdateFavoritePharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) { + } + + @Suppress("EmptyFunctionBlock") + override suspend fun deleteFavoritePharmacy(favoritePharmacy: PharmacyUseCaseData.Pharmacy) { + } + + override suspend fun searchPharmacyByTelematikId(telematikId: String): Result { + return Result.success(extractedPharmacies) + } + + override fun isPharmacyInFavorites(pharmacy: PharmacyUseCaseData.Pharmacy): Flow { + return flowOf(true) + } + + @Suppress("EmptyFunctionBlock") + override suspend fun markAsRedeemed(taskId: String) { + } + + private val jsonStringMocked = """{ + "id": "49b6b9fd-eec7-41f3-b624-cc99d46fb828", + "meta": { + "lastUpdated": "2023-08-31T12:18:10.94674676+02:00" + }, + "resourceType": "Bundle", + "type": "searchset", + "total": 20, + "link": [ + { + "relation": "self", + "url": "Bundle49b6b9fd-eec7-41f3-b624-cc99d46fb828" + } + ], + "entry": [ + { + "resource": { + "id": "6bb01538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 01" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.201" + } + ], + "name": "ZoTI_01_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb02538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 02" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.202" + } + ], + "name": "ZoTI_02_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb03538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 03" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.203" + } + ], + "name": "ZoTI_03_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb04538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 04" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.204" + } + ], + "name": "ZoTI_04_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 300 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb05538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 05" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.205" + } + ], + "name": "ZoTI_05_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb06538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "2d1f1f35-d03d-4932-a78a-67715cbb7963", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb06538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 06" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.206" + } + ], + "name": "ZoTI_06_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb07538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 07" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.207" + } + ], + "name": "ZoTI_07_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb08538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 08" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.208" + } + ], + "name": "ZoTI_08_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb09538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 09" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.209" + } + ], + "name": "ZoTI_09_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb10538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "fe9a01e8-d702-4b9d-a997-096eca057b74", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb10538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 10" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.210" + } + ], + "name": "ZoTI_10_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb11538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "0991992b-b3fd-4f3e-a331-d4f0e2856185", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb11538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 11" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.211" + } + ], + "name": "ZoTI_11_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb12538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "ae48f60e-9c17-4610-a0c4-d1f7ac6abb5b", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb12538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 12" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.212" + } + ], + "name": "ZoTI_12_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb13538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "e63f85da-3c1a-4f16-8059-45321bec107f", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb13538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 13" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.213" + } + ], + "name": "ZoTI_13_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb14538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "bb022669-f8fc-424a-8bfa-e9b5e8102333", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb14538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 14" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.214" + } + ], + "name": "ZoTI_14_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb15538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 15" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.215" + } + ], + "name": "ZoTI_15_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb16538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 16" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.216" + } + ], + "name": "ZoTI_16_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb17538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "0f4ae22e-f717-47b1-893e-1d41684c8579", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb17538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 17" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.217" + } + ], + "name": "ZoTI_17_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb18538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 18" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.218" + } + ], + "name": "ZoTI_18_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/pick_up/", + "use": "mobile", + "rank": 100 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb19538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "2" + }, + "resourceType": "Location", + "contained": [ + { + "id": "72ab1d02-d3e2-4af1-891f-a476c23eaf44", + "resourceType": "HealthcareService", + "active": true, + "coverageArea": [ + { + "extension": [ + { + "url": "https://ngda.de/fhir/extensions/ServiceCoverageRange", + "valueQuantity": { + "value": 10000, + "unit": "m" + } + } + ] + } + ], + "location": [ + { + "reference": "/Location/6bb1 2023-08-31 12:18:11.626 28938-31101 OkHttp de.gematik.ti.erp.app.test D 9538-5924-4be3-98ff-7475d27aee4f" + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "498", + "display": "Mobile Services" + } + ] + } + ] + } + ], + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 19" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.219" + } + ], + "name": "ZoTI_19_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "telecom": [ + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/delivery_only", + "use": "mobile", + "rank": 300 + }, + { + "system": "other", + "value": "https://erp-pharmacy-serviceprovider.dev.gematik.solutions/local_delivery/?req=", + "use": "mobile", + "rank": 200 + } + ], + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "PHARM", + "display": "pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + }, + { + "resource": { + "id": "6bb20538-5924-4be3-98ff-7475d27aee4f", + "meta": { + "lastUpdated": "2023-08-07T10:48:51.845+02:00", + "versionId": "3" + }, + "resourceType": "Location", + "address": { + "type": "physical", + "line": [ + "ZoTIstr. 20" + ], + "postalCode": "10117", + "city": "ZoTI-Town", + "country": "D" + }, + "hoursOfOperation": [ + { + "daysOfWeek": [ + "mon", + "tue", + "wed", + "thu", + "fri" + ], + "openingTime": "08:00:00", + "closingTime": "18:00:00" + } + ], + "identifier": [ + { + "system": "https://gematik.de/fhir/NamingSystem/TelematikID", + "value": "3-01.2.2023001.16.220" + } + ], + "name": "ZoTI_20_TEST-ONLY", + "position": { + "latitude": 13.387627883956709, + "longitude": 52.5226398750957 + }, + "status": "active", + "type": [ + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/service-type", + "code": "DELEGATOR", + "display": "eRX Token Receiver" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "OUTPHARM", + "display": "outpatient pharmacy" + } + ] + }, + { + "coding": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-RoleCode", + "code": "MOBL", + "display": "Mobile Services" + } + ] + } + ] + }, + "search": { + "mode": "match" + } + } + ] +}""" + private val jsonMockedData = json.parseToJsonElement(jsonStringMocked) + private val extractedPharmacies = + extractPharmacyServices( + bundle = jsonMockedData, + onError = { jsonElement, cause -> + Napier.e(cause) { + jsonElement.toString() + } + } + ) +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt similarity index 98% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt index f15098b4..1ff617b1 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt new file mode 100644 index 00000000..eb5a6bd5 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/PharmacyRepository.kt @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +@file:Suppress("NewLineAtEndOfFile") + +package de.gematik.ti.erp.app.pharmacy.repository + +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData +import de.gematik.ti.erp.app.fhir.model.PharmacyServices +import de.gematik.ti.erp.app.pharmacy.model.OverviewPharmacyData +import kotlinx.coroutines.flow.Flow + +interface PharmacyRepository { + suspend fun searchPharmacies( + names: List, + filter: Map + ): Result + + suspend fun searchPharmaciesByBundle( + bundleId: String, + offset: Int, + count: Int + ): Result + + suspend fun searchBinaryCerts( + locationId: String + ): Result> + + suspend fun redeemPrescriptionDirectly( + url: String, + message: ByteArray, + pharmacyTelematikId: String, + transactionId: String + ): Result + + fun loadOftenUsedPharmacies(): Flow> + + fun loadFavoritePharmacies(): Flow> + + suspend fun saveOrUpdateOftenUsedPharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) + + suspend fun deleteOverviewPharmacy(overviewPharmacy: OverviewPharmacyData.OverviewPharmacy) + + suspend fun saveOrUpdateFavoritePharmacy(pharmacy: PharmacyUseCaseData.Pharmacy) + + suspend fun deleteFavoritePharmacy(favoritePharmacy: PharmacyUseCaseData.Pharmacy) + + suspend fun searchPharmacyByTelematikId(telematikId: String): Result + + fun isPharmacyInFavorites(pharmacy: PharmacyUseCaseData.Pharmacy): Flow + + suspend fun markAsRedeemed(taskId: String) +} diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt similarity index 98% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt index 7ff6f797..93ba5d03 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/ShippingContactRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt similarity index 97% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt index a8e08d25..e586de02 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/repository/model/CommunicationPayloadInbox.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt similarity index 90% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt index 725ba9e6..1801224c 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyDirectRedeemUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.pharmacy.usecase +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.pharmacy.buildDirectPharmacyMessage import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import org.bouncycastle.cert.X509CertificateHolder @@ -35,6 +36,12 @@ class PharmacyDirectRedeemUseCase( } } + @Requirement( + "A_22778#1", + "A_22779#1", + sourceSpecification = "gemSpec_eRp_FdV", + rationale = "Start Redeem without TI." + ) suspend fun redeemPrescriptionDirectly( url: String, message: String, diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt similarity index 91% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt index 382e3fe0..4d01a999 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyMapsUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,10 +19,12 @@ package de.gematik.ti.erp.app.pharmacy.usecase import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.PharmacyInitialResultsPerPage +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.mapToUseCasePharmacies import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import de.gematik.ti.erp.app.settings.model.SettingsData -import de.gematik.ti.erp.app.settings.usecase.SettingsUseCase +import de.gematik.ti.erp.app.settings.repository.SettingsRepository import kotlinx.coroutines.withContext const val PharmacyMapNextResultsPerPage = 50 @@ -30,14 +32,14 @@ private const val PharmacyMapMaxResults = 120 class PharmacyMapsUseCase( private val repository: PharmacyRepository, - private val settingsUseCase: SettingsUseCase, + private val settingsRepository: SettingsRepository, private val dispatchers: DispatchProvider ) { suspend fun searchPharmacies( searchData: PharmacyUseCaseData.SearchData ): List = withContext(dispatchers.IO) { - settingsUseCase.savePharmacySearch( + settingsRepository.savePharmacySearch( SettingsData.PharmacySearch( name = searchData.name, locationEnabled = searchData.locationMode !is PharmacyUseCaseData.LocationMode.Disabled, diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt similarity index 95% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt index b5c10065..c19d435f 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/PharmacyOverviewUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -20,6 +20,7 @@ package de.gematik.ti.erp.app.pharmacy.usecase import de.gematik.ti.erp.app.DispatchProvider import de.gematik.ti.erp.app.pharmacy.model.OverviewPharmacyData +import de.gematik.ti.erp.app.pharmacy.usecase.mapper.mapToUseCasePharmacies import de.gematik.ti.erp.app.pharmacy.repository.PharmacyRepository import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData import kotlinx.coroutines.flow.Flow diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/mapper/PharmacyUseCaseDataMapper.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/mapper/PharmacyUseCaseDataMapper.kt new file mode 100644 index 00000000..c271f1c7 --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/mapper/PharmacyUseCaseDataMapper.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ +package de.gematik.ti.erp.app.pharmacy.usecase.mapper + +import de.gematik.ti.erp.app.fhir.model.LocalPharmacyService +import de.gematik.ti.erp.app.fhir.model.Pharmacy +import de.gematik.ti.erp.app.pharmacy.usecase.model.PharmacyUseCaseData + +// can't be modified; the backend will always return 80 entries on the first page +const val PharmacyInitialResultsPerPage = 80 +const val PharmacyNextResultsPerPage = 10 + +fun List.mapToUseCasePharmacies(): List = + map { pharmacy -> + PharmacyUseCaseData.Pharmacy( + id = pharmacy.id, + name = pharmacy.name, + address = pharmacy.address.let { + "${it.lines.joinToString()}\n${it.postalCode} ${it.city}" + }, + location = pharmacy.location, + distance = null, + contacts = pharmacy.contacts, + provides = pharmacy.provides, + openingHours = (pharmacy.provides.find { it is LocalPharmacyService } as LocalPharmacyService).openingHours, + telematikId = pharmacy.telematikId + ) + } diff --git a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt similarity index 97% rename from android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt index 2d7f4e58..5f986e2d 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/pharmacy/usecase/model/PharmacyUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -15,10 +15,8 @@ * limitations under the Licence. * */ - package de.gematik.ti.erp.app.pharmacy.usecase.model -import android.os.Parcelable import androidx.compose.runtime.Immutable import androidx.compose.runtime.Stable import de.gematik.ti.erp.app.fhir.model.DeliveryPharmacyService @@ -29,12 +27,10 @@ import de.gematik.ti.erp.app.fhir.model.PharmacyContacts import de.gematik.ti.erp.app.fhir.model.PharmacyService import de.gematik.ti.erp.app.fhir.model.PickUpPharmacyService import kotlinx.datetime.Instant -import kotlinx.parcelize.Parcelize private const val DefaultRadiusInMeter = 999 * 1000.0 object PharmacyUseCaseData { - @Parcelize @Immutable data class Filter( val nearBy: Boolean = false, @@ -42,7 +38,7 @@ object PharmacyUseCaseData { val onlineService: Boolean = false, val openNow: Boolean = false, val directRedeem: Boolean = false - ) : Parcelable { + ) { fun isAnySet(): Boolean = nearBy || deliveryService || onlineService || openNow || directRedeem } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/TaskModule.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/TaskModule.kt index 373268f4..075ad776 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/TaskModule.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/TaskModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/ScannedTaskData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/ScannedTaskData.kt index b4896815..dc08cb13 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/ScannedTaskData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/ScannedTaskData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/SyncedTaskData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/SyncedTaskData.kt index 8a709bc7..d425a3ba 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/SyncedTaskData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/model/SyncedTaskData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,10 +19,12 @@ package de.gematik.ti.erp.app.prescription.model import de.gematik.ti.erp.app.db.entities.v1.task.CommunicationProfileV1 -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.toStartOfDayInUTC import kotlinx.datetime.Clock import kotlinx.datetime.Instant import kotlin.time.Duration +import kotlin.time.Duration.Companion.days import kotlin.time.Duration.Companion.minutes val CommunicationWaitStateDelta: Duration = 10.minutes @@ -88,7 +90,9 @@ object SyncedTaskData { LaterRedeemable(medicationRequest.multiplePrescriptionInfo.start) } - expiresOn != null && expiresOn < now && status != TaskStatus.Completed -> Expired(expiresOn) + // expiration date is issue day + 3 months until 0:00 AM on that day + expiresOn != null && expiresOn <= now.toStartOfDayInUTC() && status != TaskStatus.Completed -> + Expired(expiresOn) status == TaskStatus.Ready && accessCode != null && communications.any { it.profile == CommunicationProfile.ErxCommunicationDispReq } && @@ -104,8 +108,12 @@ object SyncedTaskData { } status == TaskStatus.Ready -> Ready( - expiresOn = requireNotNull(expiresOn), - acceptUntil = requireNotNull(acceptUntil) + // Expires on "expiresOn"-day at 0:00 AM. + // Minus 1 day to use it as the last possible day of redeemability + expiresOn = requireNotNull(expiresOn?.minus(1.days)), + // Not Redeemable at the cost of the healthinsurancecompany (HI) on this day at 0:00 AM + // Minus 1 day to use it as the last possible day of redeemability at the cost of the HI + acceptUntil = requireNotNull(acceptUntil?.minus(1.days)) ) status == TaskStatus.InProgress -> InProgress(lastModified = this.lastModified) @@ -132,7 +140,7 @@ object SyncedTaskData { * See [isActive] for a decision it this prescription should be shown in the "Active" or "Archive" tab. */ fun redeemState(now: Instant = Clock.System.now(), delta: Duration = CommunicationWaitStateDelta): RedeemState { - val expired = (expiresOn != null && expiresOn <= now) + val expired = (expiresOn != null && expiresOn <= now.toStartOfDayInUTC()) val redeemableLater = medicationRequest.multiplePrescriptionInfo.indicator && medicationRequest.multiplePrescriptionInfo.start?.let { it > now @@ -156,9 +164,9 @@ object SyncedTaskData { } fun isActive(now: Instant = Clock.System.now()): Boolean { - val notExpired = (expiresOn != null && now <= expiresOn) || expiresOn == null + val expired = expiresOn != null && expiresOn <= now.toStartOfDayInUTC() val allowedStatus = status == TaskStatus.Ready || status == TaskStatus.InProgress - return notExpired && allowedStatus + return !expired && allowedStatus } fun isDirectAssignment() = diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskLocalDataSource.kt index c6ac6863..fcf5a27d 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskLocalDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -51,7 +51,7 @@ import de.gematik.ti.erp.app.fhir.model.extractKBVBundle import de.gematik.ti.erp.app.fhir.model.extractMedicationDispense import de.gematik.ti.erp.app.fhir.model.extractTask import de.gematik.ti.erp.app.fhir.model.extractTaskAndKBVBundle -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.prescription.model.ScannedTaskData import de.gematik.ti.erp.app.prescription.model.SyncedTaskData import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRemoteDataSource.kt index 3ab9114d..681d0b6e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -54,7 +54,7 @@ class TaskRemoteDataSource( ) = safeApiCall( errorMessage = "Error getting medication dispenses" ) { - val id = "https://gematik.de/fhir/NamingSystem/PrescriptionID|$taskId" + val id = "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId|$taskId" service.bundleOfMedicationDispenses(profileId, id = id) } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRepository.kt index 8df2c39d..14abb896 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/prescription/repository/TaskRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/model/ProfilesData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/model/ProfilesData.kt index a606f6f6..9f24b686 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/model/ProfilesData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/model/ProfilesData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepository.kt index 3d083647..98e26667 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/ProtocolModule.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/ProtocolModule.kt index ce5255a3..ee17135f 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/ProtocolModule.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/ProtocolModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,15 +18,15 @@ package de.gematik.ti.erp.app.protocol -import de.gematik.ti.erp.app.protocol.repository.AuditEventLocalDataSource import de.gematik.ti.erp.app.protocol.repository.AuditEventRemoteDataSource import de.gematik.ti.erp.app.protocol.repository.AuditEventsRepository +import de.gematik.ti.erp.app.protocol.usecase.AuditEventsUseCase import org.kodein.di.DI import org.kodein.di.bindProvider import org.kodein.di.instance val protocolModule = DI.Module("protocolModule") { - bindProvider { AuditEventsRepository(instance(), instance(), instance()) } - bindProvider { AuditEventLocalDataSource(instance()) } + bindProvider { AuditEventsRepository(instance()) } bindProvider { AuditEventRemoteDataSource(instance()) } + bindProvider { AuditEventsUseCase(instance(), instance()) } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/model/AuditEventData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/model/AuditEventData.kt index edc9f4da..eefe1d37 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/model/AuditEventData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/model/AuditEventData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,8 +23,14 @@ import kotlinx.datetime.Instant object AuditEventData { data class AuditEvent( val auditId: String, - val medicationText: String?, + val taskId: String?, val description: String, val timestamp: Instant ) + + data class AuditEventMappingResult( + val auditEvents: List, + val bundleId: String, + val bundleResultCount: Int + ) } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventLocalDataSource.kt deleted file mode 100644 index 369eedc2..00000000 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventLocalDataSource.kt +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright (c) 2023 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -package de.gematik.ti.erp.app.protocol.repository - -import androidx.paging.Pager -import androidx.paging.PagingConfig -import androidx.paging.PagingData -import androidx.paging.PagingSource -import androidx.paging.PagingState -import de.gematik.ti.erp.app.db.entities.v1.AuditEventEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.ProfileEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.task.SyncedTaskEntityV1 -import de.gematik.ti.erp.app.db.queryFirst -import de.gematik.ti.erp.app.db.toInstant -import de.gematik.ti.erp.app.db.toRealmInstant -import de.gematik.ti.erp.app.db.tryWrite -import de.gematik.ti.erp.app.fhir.model.extractAuditEvents -import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier -import de.gematik.ti.erp.app.protocol.model.AuditEventData -import io.realm.kotlin.Realm -import io.realm.kotlin.ext.query -import io.realm.kotlin.query.max -import io.realm.kotlin.types.RealmInstant -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.map -import kotlinx.serialization.json.JsonElement -import kotlin.math.max -import kotlin.math.min - -// max page size within ui -private const val AuditEventsMaxPageSize = 25 - -class AuditEventLocalDataSource( - private val realm: Realm -) { - suspend fun saveAuditEvents(profileId: ProfileIdentifier, events: JsonElement): Int = - realm.tryWrite { - val profile = requireNotNull( - queryFirst( - "id = $0", - profileId - ) - ) { "No profile with id = $profileId found!" } - - val totalAuditEventsInBundle = extractAuditEvents(events) { id, taskId, description, timestamp -> - val entity = copyToRealm( - AuditEventEntityV1().apply { - this.id = id - this.text = description - this.timestamp = timestamp.value.toRealmInstant() - this.taskId = taskId - this.profile = profile - } - ) - - profile.auditEvents += entity - } - - totalAuditEventsInBundle - } - - fun latestAuditEventTimestamp(profileId: ProfileIdentifier) = - realm.query("profile.id = $0", profileId) - .max("timestamp") - .asFlow() - .map { - it?.toInstant() - } - - data class AuditPagingKey(val offset: Int) - - inner class AuditPagingSource(val profileId: ProfileIdentifier) : - PagingSource() { - private val profile = realm.query("id = $0", profileId).first() - - override fun getRefreshKey(state: PagingState): AuditPagingKey? = - null - - override suspend fun load(params: LoadParams): - LoadResult { - val count = params.loadSize - val key = params.key ?: AuditPagingKey(0) - - val events = requireNotNull(profile.find()).auditEvents - val result = events.asReversed().subList(key.offset, min(key.offset + count, events.size)) - - val nextKey = if (result.size == count) { - AuditPagingKey( - key.offset + result.size - ) - } else { - null - } - val prevKey = if (key.offset == 0) null else key.copy(offset = max(0, key.offset - count)) - - val taskIds = result.distinctBy { it.taskId }.map { it.taskId } - - val medicationTexts = taskIds.associateWith { taskId -> - taskId?.let { - realm.queryFirst("taskId = $0", it)?.medicationRequest?.medication?.text - } - } - - return LoadResult.Page( - data = result.map { - AuditEventData.AuditEvent( - auditId = it.id, - medicationText = it.taskId?.let { taskId -> - medicationTexts[taskId] - }, - description = it.text, - timestamp = it.timestamp.toInstant() - ) - }, - nextKey = nextKey, - prevKey = prevKey, - itemsBefore = if (prevKey != null) count else 0, - itemsAfter = if (nextKey != null) count else 0 - ) - } - } - - fun auditEvents(profileId: ProfileIdentifier): Flow> = - Pager( - @Suppress("MagicNumber") - PagingConfig( - pageSize = AuditEventsMaxPageSize, - initialLoadSize = AuditEventsMaxPageSize * 2, - maxSize = AuditEventsMaxPageSize * 3 - ), - pagingSourceFactory = { AuditPagingSource(profileId) } - ).flow -} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventRemoteDataSource.kt index 37526142..80ae374e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -22,22 +22,21 @@ import androidx.compose.ui.text.intl.Locale import de.gematik.ti.erp.app.api.ErpService import de.gematik.ti.erp.app.api.safeApiCall import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier +import kotlinx.serialization.json.JsonElement class AuditEventRemoteDataSource( private val service: ErpService ) { suspend fun getAuditEvents( - profileId: ProfileIdentifier, - lastKnownUpdate: String?, count: Int? = null, - offset: Int? = null - ) = safeApiCall( + offset: Int? = null, + profileId: ProfileIdentifier + ): Result = safeApiCall( errorMessage = "Error getting all audit events" ) { service.getAuditEvents( profileId = profileId, language = Locale.current.language, - lastKnownDate = lastKnownUpdate, count = count, offset = offset ) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepository.kt index 90600913..47894b52 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,42 +18,97 @@ package de.gematik.ti.erp.app.protocol.repository -import de.gematik.ti.erp.app.DispatchProvider -import de.gematik.ti.erp.app.api.ResourcePaging +import de.gematik.ti.erp.app.fhir.model.mapCatching +import de.gematik.ti.erp.app.fhir.parser.contained +import de.gematik.ti.erp.app.fhir.parser.containedArrayOrNull +import de.gematik.ti.erp.app.fhir.parser.containedString +import de.gematik.ti.erp.app.fhir.parser.filterWith +import de.gematik.ti.erp.app.fhir.parser.findAll +import de.gematik.ti.erp.app.fhir.parser.stringValue import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier -import kotlinx.coroutines.flow.first -import kotlinx.coroutines.flow.flowOn -import kotlinx.coroutines.withContext -import kotlinx.datetime.Instant - -private const val AuditEventsMaxPageSize = 50 +import de.gematik.ti.erp.app.protocol.model.AuditEventData +import de.gematik.ti.erp.app.utils.asFhirInstant +import io.github.aakira.napier.Napier +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.jsonPrimitive +/** + * + */ class AuditEventsRepository( - private val remoteDataSource: AuditEventRemoteDataSource, - private val localDataSource: AuditEventLocalDataSource, - private val dispatchers: DispatchProvider -) : ResourcePaging(dispatchers, AuditEventsMaxPageSize) { - override val tag: String = "AuditEventsRepository" - - suspend fun downloadAuditEvents(profileId: ProfileIdentifier) = downloadPaged(profileId) + private val remoteDataSource: AuditEventRemoteDataSource +) { - fun auditEvents(profileId: ProfileIdentifier) = localDataSource.auditEvents(profileId).flowOn(dispatchers.IO) - - override suspend fun downloadResource( + suspend fun downloadAuditEvents( profileId: ProfileIdentifier, - timestamp: String?, - count: Int? - ): Result> = + count: Int?, + offset: Int? + ) = remoteDataSource.getAuditEvents( profileId = profileId, - lastKnownUpdate = timestamp, - count = count - ).mapCatching { fhirBundle -> - withContext(dispatchers.IO) { - ResourceResult(localDataSource.saveAuditEvents(profileId, fhirBundle), Unit) + count = count, + offset = offset + ).map { + extractAuditEvents( + bundle = it, + onError = { element, cause -> + Napier.e(cause) { + element.toString() + } + } + ) + } + + private fun extractAuditEvents( + bundle: JsonElement, + onError: (JsonElement, Exception) -> Unit = { _, _ -> } + ): AuditEventData.AuditEventMappingResult { + val bundleTotal = bundle.containedArrayOrNull("entry")?.size ?: 0 + val bundleId = bundle.containedString("id") + val resources = bundle + .findAll(listOf("entry", "resource")) + + val auditEvents = resources.mapCatching(onError) { resource -> + val id = resource.containedString("id") + val text = resource.contained("text").containedString("div") + val taskId = resource + .findAll(listOf("entity", "what", "identifier")) + .filterWith( + "system", + stringValue("https://gematik.de/fhir/NamingSystem/PrescriptionID") + ) + .firstOrNull() + ?.containedString("value") + ?: resource + .findAll(listOf("entity", "what", "identifier")) + .filterWith( + "system", + stringValue("https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId") + ) + .firstOrNull() + ?.containedString("value") + + val timestamp = requireNotNull(resource.contained("recorded").jsonPrimitive.asFhirInstant()) { + "Audit event field `recorded` missing" } + + val description = text.removeSurrounding( + "
", + "
" + ) + + AuditEventData.AuditEvent( + auditId = id, + taskId = taskId, + description = description, + timestamp = timestamp.value + ) } - override suspend fun syncedUpTo(profileId: ProfileIdentifier): Instant? = - localDataSource.latestAuditEventTimestamp(profileId).first() + return AuditEventData.AuditEventMappingResult( + auditEvents = auditEvents.toList(), + bundleId = bundleId, + bundleResultCount = bundleTotal + ) + } } diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/AuditEventsUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/AuditEventsUseCase.kt new file mode 100644 index 00000000..5e6443aa --- /dev/null +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/AuditEventsUseCase.kt @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.protocol.usecase + +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import androidx.paging.PagingSource +import androidx.paging.PagingState +import de.gematik.ti.erp.app.DispatchProvider +import de.gematik.ti.erp.app.profiles.repository.ProfileIdentifier + +import de.gematik.ti.erp.app.protocol.model.AuditEventData +import de.gematik.ti.erp.app.protocol.repository.AuditEventsRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn + +import kotlinx.coroutines.withContext +import kotlin.math.max + +const val AuditEventsInitialResultsPerPage = 50 +const val AuditEventsNextResultsPerPage = 25 + +class AuditEventsUseCase( + private val auditRepository: AuditEventsRepository, + private val dispatchers: DispatchProvider +) { + + fun loadAuditEventsPaged( + profileId: ProfileIdentifier + ): Flow> { + return Pager( + PagingConfig( + pageSize = AuditEventsNextResultsPerPage, + initialLoadSize = AuditEventsInitialResultsPerPage, + maxSize = AuditEventsInitialResultsPerPage * 2 + ), + pagingSourceFactory = { AuditEventPagingSource(profileId) } + ).flow.flowOn(dispatchers.IO) + } + suspend fun loadAuditEvents(profileId: ProfileIdentifier): List = + withContext(dispatchers.IO) { + val initialResult = auditRepository.downloadAuditEvents( + profileId, + null, + null + ).getOrThrow() + + if (initialResult.bundleResultCount == AuditEventsInitialResultsPerPage) { + val auditEvents = initialResult.auditEvents.toMutableList() + + var offset = initialResult.bundleResultCount + var shouldContinue = true + + while (shouldContinue) { + val result = auditRepository.downloadAuditEvents( + profileId, + offset = offset, + count = AuditEventsNextResultsPerPage + ).getOrThrow() + + if (result.bundleResultCount < AuditEventsNextResultsPerPage) { + shouldContinue = false + } + + auditEvents += result.auditEvents + offset += result.bundleResultCount + } + + auditEvents + } else { + initialResult.auditEvents + } + } + + data class AuditEventPagingKey(val offset: Int) + + inner class AuditEventPagingSource(private val profileId: ProfileIdentifier) : + PagingSource() { + + override fun getRefreshKey( + state: PagingState + ): AuditEventPagingKey? = null + + override suspend fun load( + params: LoadParams + ): LoadResult { + val count = params.loadSize + + when (params) { + is LoadParams.Refresh -> { + return auditRepository.downloadAuditEvents(profileId, count, 0) + .map { + LoadResult.Page( + data = it.auditEvents, + nextKey = if (it.bundleResultCount == AuditEventsInitialResultsPerPage) { + AuditEventPagingKey( + it.bundleResultCount + ) + } else { + null + }, + prevKey = null + ) + }.getOrElse { LoadResult.Error(it) } + } + + is LoadParams.Append, is LoadParams.Prepend -> { + val key = params.key!! + + return auditRepository.downloadAuditEvents(profileId, offset = key.offset, count = count).map { + val nextKey = if (it.bundleResultCount == count) { + AuditEventPagingKey( + key.offset + it.bundleResultCount + ) + } else { + null + } + val prevKey = if (key.offset == 0) null else key.copy(offset = max(0, key.offset - count)) + + LoadResult.Page( + data = it.auditEvents, + nextKey = nextKey, + prevKey = prevKey, + itemsBefore = if (prevKey != null) count else 0, + itemsAfter = if (nextKey != null) count else 0 + ) + }.getOrElse { LoadResult.Error(it) } + } + } + } + } +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt index 78655913..1117f804 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/GeneralSettings.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/PharmacySettings.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/PharmacySettings.kt index f92d7790..bb121fad 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/PharmacySettings.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/PharmacySettings.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt index 2919c052..e55e408b 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/model/SettingsData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.settings.model +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.secureRandomInstance import java.security.MessageDigest @@ -56,6 +57,12 @@ object SettingsData { val hash: ByteArray val salt: ByteArray + @Requirement( + "O.Pass_5", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Passwords are hashed with a hash function that complies with current " + + "security standards and using appropriate salts." + ) constructor(password: String) { salt = ByteArray(32).apply { secureRandomInstance().nextBytes(this) } hash = hashWithSalt(password, salt) @@ -71,6 +78,12 @@ object SettingsData { return hash.contentEquals(this.hash) } + @Requirement( + "O.Pass_5#1", + sourceSpecification = "BSI-eRp-ePA", + rationale = "one-way hash function that take arbitrary-sized data and " + + "output a fixed-length hash value." + ) private fun hashWithSalt(password: String, salt: ByteArray): ByteArray { val combined = password.toByteArray() + salt return MessageDigest.getInstance("SHA-256").digest(combined) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt index 9e9dc06e..a4756d55 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt index 0cf40469..3f2c93f1 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Toasts.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/DMUtils.kt similarity index 65% rename from android/src/main/java/de/gematik/ti/erp/app/utils/compose/Toasts.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/DMUtils.kt index 38bc5dee..57f7c7e7 100644 --- a/android/src/main/java/de/gematik/ti/erp/app/utils/compose/Toasts.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/DMUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -16,9 +16,13 @@ * */ -package de.gematik.ti.erp.app.utils.compose +package de.gematik.ti.erp.app.utils -import android.content.Context -import android.widget.Toast +import org.jose4j.json.internal.json_simple.JSONArray +import org.jose4j.json.internal.json_simple.JSONObject -fun createToastShort(context: Context, text: String) = Toast.makeText(context, text, Toast.LENGTH_SHORT).show() +fun createDMPayload(data: List): String { + val urls = JSONArray(data) + val rootObject = JSONObject(mapOf("urls" to urls)) + return rootObject.toString() +} diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverter.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/TemporalConverter.kt similarity index 94% rename from common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverter.kt rename to common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/TemporalConverter.kt index 01e38e9f..0769d961 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverter.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/utils/TemporalConverter.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -16,8 +16,10 @@ * */ -package de.gematik.ti.erp.app.fhir.parser +package de.gematik.ti.erp.app.utils +import de.gematik.ti.erp.app.fhir.parser.Year +import de.gematik.ti.erp.app.fhir.parser.YearMonth import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.contentOrNull import kotlinx.datetime.Instant @@ -94,7 +96,10 @@ sealed interface FhirTemporal { fun Instant.toFormattedDateTime(): String? = this.toLocalDateTime(TimeZone.currentSystemDefault()) .toJavaLocalDateTime().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.SHORT)) - +fun Instant.toStartOfDayInUTC(): Instant { + val currentLocalDateTime = this.toLocalDateTime(TimeZone.currentSystemDefault()) + return currentLocalDateTime.date.atStartOfDayIn(TimeZone.UTC) +} fun Instant.toFormattedDate(): String? = this.toLocalDateTime(TimeZone.currentSystemDefault()) .toJavaLocalDateTime().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT)) fun Instant.asFhirTemporal() = FhirTemporal.Instant(this) diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/CertUtils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/CertUtils.kt index a7c57e2c..7bac510b 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/CertUtils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/CertUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/ClientCrypto.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/ClientCrypto.kt index 4d278b7e..71d8dfa4 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/ClientCrypto.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/ClientCrypto.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -116,6 +116,11 @@ class VauChannelSpec constructor( /** * Encrypt raw request data as the inner request. */ + @Requirement( + "A_20161-01", + sourceSpecification = "gemSpec_Krypt", + rationale = "Request encryption" + ) fun encryptRawVauRequest( innerHttp: ByteArray, @@ -193,7 +198,6 @@ class VauChannelSpec constructor( userpseudonym: String, publicKey: ECPublicKey, baseUrl: HttpUrl, - cryptoConfig: VauCryptoConfig = defaultCryptoConfig ): Pair { val bearer = requireNotNull( diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Crypto.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Crypto.kt index 1e701e69..01054444 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Crypto.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Crypto.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,7 @@ package de.gematik.ti.erp.app.vau +import de.gematik.ti.erp.app.Requirement import org.bouncycastle.crypto.digests.SHA256Digest import org.bouncycastle.crypto.generators.HKDFBytesGenerator import org.bouncycastle.crypto.params.HKDFParameters @@ -63,6 +64,11 @@ class VauEciesSpec constructor( */ val aesSize: Int ) { + @Requirement( + "GS-A_4389#2", + sourceSpecification = "gemSpec_Krypt", + rationale = "AES key generation defaults for initialization vector and key size." + ) companion object { @JvmField val V1 = VauEciesSpec( @@ -77,6 +83,11 @@ class VauEciesSpec constructor( /** * Refer to gemSpec_Krypt `A_20161-01` */ +@Requirement( + "GS-A_4389#4", + sourceSpecification = "gemSpec_Krypt", + rationale = "AES key generation" +) object Ecies { internal fun generateCipher( ivSpec: IvParameterSpec, diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/OCSPUtils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/OCSPUtils.kt index 2155d807..68972192 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/OCSPUtils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/OCSPUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Utils.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Utils.kt index 820fc61e..d3147406 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Utils.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/Utils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/VauService.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/VauService.kt index dd0be230..e98c864e 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/VauService.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/VauService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,11 +18,17 @@ package de.gematik.ti.erp.app.vau.api +import de.gematik.ti.erp.app.Requirement import de.gematik.ti.erp.app.vau.api.model.UntrustedCertList import de.gematik.ti.erp.app.vau.api.model.UntrustedOCSPList import retrofit2.Response import retrofit2.http.GET +@Requirement( + "O.Purp_8#2", + sourceSpecification = "BSI-eRp-ePA", + rationale = "Interface of vau service" +) interface VauService { @GET("CertList") suspend fun getCertList(): Response diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauModels.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauModels.kt index a99ac481..20037adb 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauModels.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauModels.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauSerializers.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauSerializers.kt index bb7152f0..3049f8fe 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauSerializers.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/api/model/VauSerializers.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauLocalDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauLocalDataSource.kt index d50bb8db..09bc8069 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauLocalDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRemoteDataSource.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRemoteDataSource.kt index c082b0b1..9a5174a6 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRemoteDataSource.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRepository.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRepository.kt index fe861d6e..9769e161 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRepository.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/repository/VauRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreConfig.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreConfig.kt index e811c749..edb16af9 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreConfig.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreConfig.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreUseCase.kt b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreUseCase.kt index 562bf6d2..e29cad2c 100644 --- a/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreUseCase.kt +++ b/common/src/commonMain/kotlin/de/gematik/ti/erp/app/vau/usecase/TruststoreUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -61,6 +61,12 @@ typealias TrustedTruststoreProvider = ( timestamp: Instant ) -> TrustedTruststore +@Requirement( + "O.Auth_11", + sourceSpecification = "BSI-eRp-ePA", + rationale = "We use TLS Pinning and a Trust Store for VAU communication. " + + "See NetworkModule and TruststoreUseCase for implementation." +) class TruststoreUseCase( private val config: TruststoreConfig, private val repository: VauRepository, diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/CoroutineTestRule.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/CoroutineTestRule.kt index e208ec08..eb3baabf 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/CoroutineTestRule.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/CoroutineTestRule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/api/ResourcePagingTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/api/ResourcePagingTest.kt index be8e699a..e5680834 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/api/ResourcePagingTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/api/ResourcePagingTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverterTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverterTest.kt index 4660bec1..a18d6028 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverterTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/RealmInstantConverterTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/SchemaTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/SchemaTest.kt index 725c0f23..eceb3e71 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/SchemaTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/SchemaTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/TestDB.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/TestDB.kt index 3bbd4ee6..baac9325 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/TestDB.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/TestDB.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/DelegatesTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/DelegatesTest.kt index 3ae18757..15724e2f 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/DelegatesTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/DelegatesTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,9 +18,9 @@ package de.gematik.ti.erp.app.db.entities -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.Year -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import kotlinx.datetime.Instant import kotlin.random.Random import kotlin.test.Test diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtilsTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtilsTest.kt index a0ba0925..c577e739 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtilsTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/EntityUtilsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SettingsEntityV1Test.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SettingsEntityV1Test.kt index 97c51fb9..7a6c0acf 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SettingsEntityV1Test.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SettingsEntityV1Test.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SyncedTaskEntityV1Test.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SyncedTaskEntityV1Test.kt index d5f39970..a7bc5278 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SyncedTaskEntityV1Test.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/db/entities/v1/SyncedTaskEntityV1Test.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -69,7 +69,6 @@ class SyncedTaskEntityV1Test : TestDB() { PractitionerEntityV1::class, ScannedTaskEntityV1::class, SyncedTaskEntityV1::class, - AuditEventEntityV1::class, IdpAuthenticationDataEntityV1::class, AddressEntityV1::class, InsuranceInformationEntityV1::class, diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapperTest.kt deleted file mode 100644 index 8b63829a..00000000 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/AuditEventMapperTest.kt +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2023 gematik GmbH - * - * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by - * the European Commission - subsequent versions of the EUPL (the Licence); - * You may not use this work except in compliance with the Licence. - * You may obtain a copy of the Licence at: - * - * https://joinup.ec.europa.eu/software/page/eupl - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the Licence is distributed on an "AS IS" basis, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the Licence for the specific language governing permissions and - * limitations under the Licence. - * - */ - -@file:Suppress("ktlint:max-line-length") - -package de.gematik.ti.erp.app.fhir.model - -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal -import kotlinx.datetime.Instant -import kotlinx.serialization.json.Json -import java.io.File -import kotlin.test.Test -import kotlin.test.assertEquals - -private val testBundle by lazy { - File("$ResourceBasePath/audit_events_bundle.json").readText() -} -private val testAuditEventVersion12 by lazy { - File("$ResourceBasePath/audit_events_bundle_version_1_2.json").readText() -} - -class AuditEventMapperTest { - private class AuditEvent( - val id: String, - val taskId: String?, - val description: String, - val timestamp: Instant - ) - - @Suppress("MaxLineLength") - private val events = mapOf( - 0 to AuditEvent( - id = "01eb7f56-6820-a140-abdb-34aa9f2ab6ea", - taskId = null, - description = "Zacharias Zebra hat eine Liste mit Medikament-Informationen heruntergeladen.", - timestamp = Instant.parse("2022-01-13T15:44:15.816+00:00") - ), - 2 to AuditEvent( - id = "01eb7f56-75dc-6850-9729-d94c0839ab3b", - taskId = "169.000.000.000.026.84", - description = "Praxis Rainer Graf d' AgóstinoTEST-ONLY hat das Rezept mit der ID 169.000.000.000.026.84 eingestellt.", - timestamp = Instant.parse("2022-01-13T15:48:06.226+00:00") - ), - 7 to AuditEvent( - id = "01eb7f56-862a-e830-e470-120f0137c54e", - taskId = "169.000.000.000.026.84", - description = "Zacharias Zebra hat das Rezept mit der ID 169.000.000.000.026.84 heruntergeladen.", - timestamp = Instant.parse("2022-01-13T15:52:39.806+00:00") - ) - ) - - private val auditEventsVersion12 = mapOf( - 0 to AuditEvent( - id = "9361863d-fec0-4ba9-8776-7905cf1b0cfa", - taskId = null, - description = "Praxis Dr. Müller, Bahnhofstr. 78 hat ein E-Rezept 160.123.456.789.123.58 eingestellt", - timestamp = Instant.parse("2022-04-27T08:04:27.434Z") - ) - ) - - @Test - fun `parse audit events`() { - var index = 0 - - extractAuditEvents( - Json.parseToJsonElement(testBundle) - ) { id, taskId, description, timestamp -> - events[index]?.let { ev -> - assertEquals(ev.id, id) - assertEquals(ev.taskId, taskId) - assertEquals(ev.description, description) - assertEquals(ev.timestamp, timestamp.value) - } - - index++ - } - - assertEquals(50, index) - } - - @Test - fun `parse audit events version 1_2`() { - extractAuditEvents( - Json.parseToJsonElement(testAuditEventVersion12) - ) { id, taskId, description, timestamp -> - auditEventsVersion12[0]?.let { ev -> - assertEquals(ev.id, id) - assertEquals(ev.taskId, taskId) - assertEquals(ev.description, description) - assertEquals(ev.timestamp.asFhirTemporal(), timestamp) - } - } - } -} diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapperTest.kt index feef42cf..a1be7d5d 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommonRessourceMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapperTest.kt index 515a711a..e5bb19c3 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/CommunicationMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -20,8 +20,8 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import de.gematik.ti.erp.app.fhir.parser.contained import de.gematik.ti.erp.app.fhir.parser.containedString import kotlinx.datetime.Instant @@ -45,7 +45,7 @@ class CommunicationMapperTest { accessCode = "accessCode$JsonSymbols", recipientTID = "recipientTID$JsonSymbols", payload = CommunicationPayload( - version = "1", + version = 1, supplyOptionsType = "onPremise", name = "Anton Miller", address = listOf("Some Street", "1234", JsonSymbols), @@ -79,7 +79,7 @@ class CommunicationMapperTest { @Suppress("MaxLineLength") assertEquals( - "{\"version\":\"1\",\"supplyOptionsType\":\"onPremise\",\"name\":\"Anton Miller\",\"address\":[\"Some Street\",\"1234\",\"$JsonSymbolsEscaped\"],\"hint\":\"Oh no\",\"phone\":\"132342546547\"}", + "{\"version\":1,\"supplyOptionsType\":\"onPremise\",\"name\":\"Anton Miller\",\"address\":[\"Some Street\",\"1234\",\"$JsonSymbolsEscaped\"],\"hint\":\"Oh no\",\"phone\":\"132342546547\"}", payload ) } diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapperTest.kt index 405947cf..c238fabe 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/InvoiceMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import de.gematik.ti.erp.app.invoice.model.InvoiceData import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json @@ -35,7 +35,7 @@ class InvoiceMapperTest { fun `process chargeItem pzn 1`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_1) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.424.187.927.272.20", taskId) val erpBinary = extractBinary(erpPrBundle) @@ -118,9 +118,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 2`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_2) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.457.180.497.994.96", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -201,9 +203,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 3`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_3) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.279.187.481.423.80", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -298,9 +302,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 5`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_5) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.625.688.123.368.48", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -381,9 +387,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 6`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_6) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.280.604.133.110.12", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -464,9 +472,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 7`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_7) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.339.908.107.779.64", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -561,9 +571,11 @@ class InvoiceMapperTest { fun `process chargeItem pzn 8`() { val bundle = Json.parseToJsonElement(chargeItem_pzn_8) - extractInvoiceKBVAndErpPrBundle(bundle) { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle) { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.108.757.032.088.60", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -659,9 +671,11 @@ class InvoiceMapperTest { fun `process chargeItem compounding`() { val bundle = Json.parseToJsonElement(chargeItem_compounding) - extractInvoiceKBVAndErpPrBundle(bundle) { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle) { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.858.310.624.061.76", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) @@ -759,9 +773,11 @@ class InvoiceMapperTest { fun `process chargeItem freetext`() { val bundle = Json.parseToJsonElement(chargeItem_freetext) - extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, invoiceBundle, kbvBundle, erpPrBundle -> + extractInvoiceKBVAndErpPrBundle(bundle, process = { taskId, accessCode, invoiceBundle, kbvBundle, erpPrBundle -> assertEquals("200.334.138.469.717.92", taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", accessCode) + val erpBinary = extractBinary(erpPrBundle) val invoiceBinary = extractBinary(invoiceBundle) val kbvBinary = extractBinary(kbvBundle) diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapperTest.kt index 5a2bc50f..1f915baa 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/MedicationDispenseMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -19,8 +19,8 @@ package de.gematik.ti.erp.app.fhir.model import de.gematik.ti.erp.app.fhir.parser.findAll -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapperTest.kt index fcb0c519..fcc9ff31 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/PharmacyMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion102Test.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion102Test.kt index 033a5598..f9eac6ae 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion102Test.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion102Test.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,9 +18,9 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.FhirTemporal +import de.gematik.ti.erp.app.utils.FhirTemporal import de.gematik.ti.erp.app.fhir.parser.Year -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json import kotlin.test.Test diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion110Test.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion110Test.kt index 4cb0a3a4..4d3a347f 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion110Test.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/RessourceMapperVersion110Test.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json import kotlin.test.Test diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapperTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapperTest.kt index 42b3f83e..ad1c5b69 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapperTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TaskMapperTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,7 +18,7 @@ package de.gematik.ti.erp.app.fhir.model -import de.gematik.ti.erp.app.fhir.parser.asFhirTemporal +import de.gematik.ti.erp.app.utils.asFhirTemporal import kotlinx.datetime.Instant import kotlinx.datetime.LocalDate import kotlinx.serialization.json.Json diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TestData.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TestData.kt index 1d8e310f..532cef54 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TestData.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/model/TestData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ComparatorTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ComparatorTest.kt index 548a19d4..b4a8d904 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ComparatorTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ComparatorTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ConverterTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ConverterTest.kt index 8fab322e..98835b28 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ConverterTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ConverterTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/FormatterTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/FormatterTest.kt index 5a456974..f5cf70f9 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/FormatterTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/FormatterTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ParserTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ParserTest.kt index 92ee17b7..e8ab9bb9 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ParserTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/ParserTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverterTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverterTest.kt index cd3f0ab6..68030ff5 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverterTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TemporalConverterTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -18,6 +18,8 @@ package de.gematik.ti.erp.app.fhir.parser +import de.gematik.ti.erp.app.utils.FhirTemporal +import de.gematik.ti.erp.app.utils.toFhirTemporal import kotlin.test.Test import kotlin.test.assertEquals diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TestData.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TestData.kt index c6ae595a..73c281d6 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TestData.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/fhir/parser/TestData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicDataTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicDataTest.kt index 8c64b553..abef258f 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicDataTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicDataTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepositoryTest.kt index b06a2be2..0d9e45ba 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepositoryTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepositoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -24,7 +24,6 @@ import de.gematik.ti.erp.app.CoroutineTestRule import de.gematik.ti.erp.app.db.TestDB import de.gematik.ti.erp.app.db.ACTUAL_SCHEMA_VERSION import de.gematik.ti.erp.app.db.entities.v1.AddressEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.AuditEventEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpAuthenticationDataEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpConfigurationEntityV1 import de.gematik.ti.erp.app.db.entities.v1.PasswordEntityV1 @@ -150,7 +149,6 @@ class CommonIdpRepositoryTest : TestDB() { ScannedTaskEntityV1::class, IdpAuthenticationDataEntityV1::class, IdpConfigurationEntityV1::class, - AuditEventEntityV1::class, SettingsEntityV1::class, PharmacySearchEntityV1::class, PasswordEntityV1::class, diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCaseTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCaseTest.kt index adbd4f10..a90661ac 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCaseTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCaseTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpIntegrationTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpIntegrationTest.kt index 06bf0ab1..a1a2b0b7 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpIntegrationTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpIntegrationTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepositoryTest.kt index 0fe87cb7..e6b74a0a 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepositoryTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/invoice/repository/InvoiceRepositoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -23,7 +23,6 @@ import de.gematik.ti.erp.app.api.ErpService import de.gematik.ti.erp.app.db.ACTUAL_SCHEMA_VERSION import de.gematik.ti.erp.app.db.TestDB import de.gematik.ti.erp.app.db.entities.v1.AddressEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.AuditEventEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpAuthenticationDataEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpConfigurationEntityV1 import de.gematik.ti.erp.app.db.entities.v1.PasswordEntityV1 @@ -55,7 +54,6 @@ import io.mockk.MockKAnnotations import io.mockk.impl.annotations.MockK import io.realm.kotlin.Realm import io.realm.kotlin.RealmConfiguration -import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.first import kotlinx.coroutines.test.runTest import kotlinx.datetime.Instant @@ -102,7 +100,6 @@ class InvoiceRepositoryTest : TestDB() { ScannedTaskEntityV1::class, IdpAuthenticationDataEntityV1::class, IdpConfigurationEntityV1::class, - AuditEventEntityV1::class, SettingsEntityV1::class, PharmacySearchEntityV1::class, PasswordEntityV1::class, @@ -130,7 +127,6 @@ class InvoiceRepositoryTest : TestDB() { profileRepository = ProfilesRepository(coroutineRule.dispatchers, realm) } - @OptIn(ExperimentalCoroutinesApi::class) @Test fun `save invoices and load invoice`() { val chargeItemByIdBundle = Json.parseToJsonElement(chargeItem_freetext) @@ -144,6 +140,7 @@ class InvoiceRepositoryTest : TestDB() { val invoice = invoiceRepository.invoices(testProfileId).first()[0] assertEquals("200.334.138.469.717.92", invoice.taskId) + assertEquals("abd4afed9f3f458114fc3407878213e110f238d1afa919fbed7282abbef68bfd", invoice.accessCode) assertEquals(36.15, invoice.invoice.totalBruttoAmount) assertEquals(Instant.parse("2023-07-07T23:30:00Z"), invoice.timestamp) diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/CardUtilitiesTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/CardUtilitiesTest.kt index 30152618..b17d0a5b 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/CardUtilitiesTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/CardUtilitiesTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/KeyDerivationFunctionTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/KeyDerivationFunctionTest.kt index b61af839..abb5e5fb 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/KeyDerivationFunctionTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/KeyDerivationFunctionTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/PaceInfoTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/PaceInfoTest.kt index d5a3187e..277c2b06 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/PaceInfoTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/PaceInfoTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/SecureMessagingTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/SecureMessagingTest.kt index bec59b9b..a2f5bd5e 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/SecureMessagingTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/SecureMessagingTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/card/Version2Test.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/card/Version2Test.kt index 12f10dd7..1cc40c26 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/card/Version2Test.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/card/Version2Test.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/CommandApduTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/CommandApduTest.kt index 332d0902..34227a57 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/CommandApduTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/CommandApduTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/GeneralAuthenticateCommandTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/GeneralAuthenticateCommandTest.kt index 5ac6e517..50510145 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/GeneralAuthenticateCommandTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/GeneralAuthenticateCommandTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ManageSecurityEnvironmentCommandTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ManageSecurityEnvironmentCommandTest.kt index 23fdd206..a2894287 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ManageSecurityEnvironmentCommandTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ManageSecurityEnvironmentCommandTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ReadCommandTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ReadCommandTest.kt index 33a94a30..b7beed34 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ReadCommandTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ReadCommandTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ResponseApduTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ResponseApduTest.kt index 4dc1b7ae..7d88f207 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ResponseApduTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/ResponseApduTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/SelectCommandTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/SelectCommandTest.kt index 214061e6..20c9af78 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/SelectCommandTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/SelectCommandTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestChannel.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestChannel.kt index c8cefdb3..0ddf53bb 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestChannel.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestResource.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestResource.kt index 9294db2d..83ca3c18 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestResource.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/command/TestResource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/FileIdentifierTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/FileIdentifierTest.kt index 72238858..292ee9c8 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/FileIdentifierTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/FileIdentifierTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/ShortFileIdentifierTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/ShortFileIdentifierTest.kt index 0eca6c76..f72d4008 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/ShortFileIdentifierTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/nfc/identifier/ShortFileIdentifierTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepositoryTest.kt index b5fb0dcb..b5be16e9 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepositoryTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/profiles/repository/ProfilesRepositoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -22,7 +22,6 @@ import de.gematik.ti.erp.app.CoroutineTestRule import de.gematik.ti.erp.app.db.TestDB import de.gematik.ti.erp.app.db.ACTUAL_SCHEMA_VERSION import de.gematik.ti.erp.app.db.entities.v1.AddressEntityV1 -import de.gematik.ti.erp.app.db.entities.v1.AuditEventEntityV1 import de.gematik.ti.erp.app.db.entities.v1.IdpAuthenticationDataEntityV1 import de.gematik.ti.erp.app.db.entities.v1.PasswordEntityV1 import de.gematik.ti.erp.app.db.entities.v1.PharmacySearchEntityV1 @@ -98,7 +97,6 @@ class ProfilesRepositoryTest : TestDB() { QuantityEntityV1::class, ScannedTaskEntityV1::class, IdpAuthenticationDataEntityV1::class, - AuditEventEntityV1::class, SettingsEntityV1::class, PharmacySearchEntityV1::class, PasswordEntityV1::class, diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepositoryTest.kt new file mode 100644 index 00000000..3095aa33 --- /dev/null +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/protocol/repository/AuditEventsRepositoryTest.kt @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.protocol.repository + +import de.gematik.ti.erp.app.CoroutineTestRule +import de.gematik.ti.erp.app.fhir.model.ResourceBasePath +import io.mockk.MockKAnnotations +import io.mockk.coEvery +import io.mockk.impl.annotations.MockK +import kotlinx.coroutines.test.runTest +import kotlinx.datetime.Instant +import kotlinx.serialization.json.Json +import org.junit.Rule +import java.io.File +import kotlin.test.BeforeTest +import kotlin.test.Test +import kotlin.test.assertEquals + +private val testBundle by lazy { + File("$ResourceBasePath/audit_events_bundle.json").readText() +} +private val testAuditEventVersion12 by lazy { + File("$ResourceBasePath/audit_events_bundle_version_1_2.json").readText() +} + +@get:Rule +val coroutineRule = CoroutineTestRule() + +class AuditEventsRepositoryTest { + + @MockK + lateinit var remoteDataSource: AuditEventRemoteDataSource + private lateinit var auditEventsRepository: AuditEventsRepository + private class AuditEvent( + val id: String, + val taskId: String?, + val description: String, + val timestamp: Instant + ) + + private val events = mapOf( + 0 to AuditEvent( + id = "01eb7f56-6820-a140-abdb-34aa9f2ab6ea", + taskId = null, + description = "Zacharias Zebra hat eine Liste mit Medikament-Informationen heruntergeladen.", + timestamp = Instant.parse("2022-01-13T15:44:15.816+00:00") + ), + 2 to AuditEvent( + id = "01eb7f56-75dc-6850-9729-d94c0839ab3b", + taskId = "169.000.000.000.026.84", + description = "Praxis Rainer Graf d' AgóstinoTEST-ONLY hat das Rezept" + + " mit der ID 169.000.000.000.026.84 eingestellt.", + timestamp = Instant.parse("2022-01-13T15:48:06.226+00:00") + ), + 7 to AuditEvent( + id = "01eb7f56-862a-e830-e470-120f0137c54e", + taskId = "169.000.000.000.026.84", + description = "Zacharias Zebra hat das Rezept mit der ID 169.000.000.000.026.84 heruntergeladen.", + timestamp = Instant.parse("2022-01-13T15:52:39.806+00:00") + ) + ) + + private val auditEventsVersion12 = mapOf( + 0 to AuditEvent( + id = "9361863d-fec0-4ba9-8776-7905cf1b0cfa", + taskId = "160.123.456.789.123.58", + description = "Praxis Dr. Müller, Bahnhofstr. 78 hat ein E-Rezept 160.123.456.789.123.58 eingestellt", + timestamp = Instant.parse("2022-04-27T08:04:27.434Z") + ) + ) + + @BeforeTest + fun setUp() { + MockKAnnotations.init(this) + auditEventsRepository = AuditEventsRepository(remoteDataSource) + } + + @Test + fun `parse audit events`() { + val auditEventsJson = Json.parseToJsonElement(testBundle) + coEvery { remoteDataSource.getAuditEvents(any(), any(), any()) } coAnswers { + Result.success( + auditEventsJson + ) + } + runTest { + val auditEventMappingResult = auditEventsRepository + .downloadAuditEvents("", null, null).getOrThrow() + assertEquals(50, auditEventMappingResult.auditEvents.size) + + assertEquals(events[0]?.id, auditEventMappingResult.auditEvents[0].auditId) + assertEquals(events[0]?.taskId, auditEventMappingResult.auditEvents[0].taskId) + assertEquals(events[0]?.description, auditEventMappingResult.auditEvents[0].description) + assertEquals(events[0]?.timestamp, auditEventMappingResult.auditEvents[0].timestamp) + + assertEquals(events[2]?.id, auditEventMappingResult.auditEvents[2].auditId) + assertEquals(events[2]?.taskId, auditEventMappingResult.auditEvents[2].taskId) + assertEquals(events[2]?.description, auditEventMappingResult.auditEvents[2].description) + assertEquals(events[2]?.timestamp, auditEventMappingResult.auditEvents[2].timestamp) + + assertEquals(events[7]?.id, auditEventMappingResult.auditEvents[7].auditId) + assertEquals(events[7]?.taskId, auditEventMappingResult.auditEvents[7].taskId) + assertEquals(events[7]?.description, auditEventMappingResult.auditEvents[7].description) + assertEquals(events[7]?.timestamp, auditEventMappingResult.auditEvents[7].timestamp) + } + } + + @Test + fun `parse audit events version 1_2`() { + val auditEventsJson = Json.parseToJsonElement(testAuditEventVersion12) + coEvery { remoteDataSource.getAuditEvents(any(), any(), any()) } coAnswers { + Result.success(auditEventsJson) + } + + runTest { + val auditEventMappingResult = auditEventsRepository + .downloadAuditEvents("", null, null).getOrThrow() + + assertEquals(1, auditEventMappingResult.auditEvents.size) + + assertEquals(auditEventsVersion12[0]?.id, auditEventMappingResult.auditEvents[0].auditId) + assertEquals(auditEventsVersion12[0]?.taskId, auditEventMappingResult.auditEvents[0].taskId) + assertEquals(auditEventsVersion12[0]?.description, auditEventMappingResult.auditEvents[0].description) + assertEquals(auditEventsVersion12[0]?.timestamp, auditEventMappingResult.auditEvents[0].timestamp) + } + } +} diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt index 7c696989..a74d3a93 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/settings/repository/SettingsRepositoryTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/utils/DMUtilsTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/utils/DMUtilsTest.kt new file mode 100644 index 00000000..fa79acac --- /dev/null +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/utils/DMUtilsTest.kt @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.app.utils + +import kotlin.test.Test +import kotlin.test.assertEquals + +class DMUtilsTest { + @Test + fun `create dm payload from list of urls`() { + val urls = listOf("ChargeItem/01234?ac=98765", "ChargeItem/98765?ac=01234") + assertEquals( + "{\"urls\":[\"ChargeItem/01234?ac=98765\",\"ChargeItem/98765?ac=01234\"]}", + createDMPayload(urls) + ) + } +} diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/AdapterTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/AdapterTest.kt index d1324aff..4da252a5 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/AdapterTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/AdapterTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CertUtilsTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CertUtilsTest.kt index d365de16..52664146 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CertUtilsTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CertUtilsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/ClientCryptoTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/ClientCryptoTest.kt index 8c5edd1d..10d15fc1 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/ClientCryptoTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/ClientCryptoTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CryptoTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CryptoTest.kt index 41db89a5..e4c22549 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CryptoTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/CryptoTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/OCSPUtilsTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/OCSPUtilsTest.kt index 03a10e40..41709a04 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/OCSPUtilsTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/OCSPUtilsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/TestData.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/TestData.kt index f8bbf50a..c67a77c8 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/TestData.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/TestData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/UtilsTest.kt b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/UtilsTest.kt index c0a5841c..8841433a 100644 --- a/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/UtilsTest.kt +++ b/common/src/commonTest/kotlin/de/gematik/ti/erp/app/vau/UtilsTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/commonTest/resources/fhir/pkv/PZN-Verordnung_Nr_7.json b/common/src/commonTest/resources/fhir/pkv/PZN-Verordnung_Nr_7.json index d82a9aec..a5679465 100644 --- a/common/src/commonTest/resources/fhir/pkv/PZN-Verordnung_Nr_7.json +++ b/common/src/commonTest/resources/fhir/pkv/PZN-Verordnung_Nr_7.json @@ -12,7 +12,8 @@ }, "identifier": [ { - "system": "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId" + "system": "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_PrescriptionId", + "value": "200.339.908.107.779.64" }, { "system": "https://gematik.de/fhir/erp/NamingSystem/GEM_ERP_NS_AccessCode", diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/Constants.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/Constants.kt index 7a24cf29..19855955 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/Constants.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/Constants.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt index cda40d74..9133d2cd 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/SecureRandomProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/RealmModule.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/RealmModule.kt index 340e8f67..60b384d2 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/RealmModule.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/RealmModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/VauModule.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/VauModule.kt index a076b898..acfb5138 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/VauModule.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/di/VauModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt index f748ddcf..778b901d 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpCryptoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt index 6ca8c084..d9a1c747 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpDeviceInfoProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt index 5f9d5f1e..9c90490e 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpPreferenceProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/utils/FileUtils.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/utils/FileUtils.kt index 2f2aec99..134c2668 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/utils/FileUtils.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/utils/FileUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt index 20f93c03..6548559a 100644 --- a/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt +++ b/common/src/desktopMain/kotlin/de/gematik/ti/erp/app/vau/interceptor/VauChannelInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/config/dependency-check/suppressions.xml b/config/dependency-check/suppressions.xml new file mode 100644 index 00000000..140debfe --- /dev/null +++ b/config/dependency-check/suppressions.xml @@ -0,0 +1,19 @@ + + + + + ^pkg:maven/org\.jetbrains\.kotlinx/kotlinx\-coroutines\-play\-services@.*$ + CVE-2020-22475 + + + + ^pkg:maven/org\.jetbrains\.kotlinx/kotlinx\-coroutines\-play\-services@.*$ + CVE-2022-39349 + + \ No newline at end of file diff --git a/config/detekt/baseline.xml b/config/detekt/baseline.xml index bb538fa6..b73a3cfd 100644 --- a/config/detekt/baseline.xml +++ b/config/detekt/baseline.xml @@ -371,6 +371,7 @@ TooManyFunctions:IdpRepository.kt$IdpRepository TooManyFunctions:PrescriptionDetailScreen.kt$de.gematik.ti.erp.app.prescription.ui.PrescriptionDetailScreen.kt TooManyFunctions:SettingsScreen.kt$de.gematik.ti.erp.app.settings.ui.SettingsScreen.kt + TooManyFunctions:TemporalConverter.kt$de.gematik.ti.erp.app.utils.TemporalConverter.kt TopLevelPropertyNaming:ClientCrypto.kt$private const val byteSpace: Byte = 32 TopLevelPropertyNaming:HeadersInterceptor.kt$private const val invalidAccessTokenHeader = "Www-Authenticate" TopLevelPropertyNaming:HeadersInterceptor.kt$private const val invalidAccessTokenValue = "Bearer realm='prescriptionserver.telematik', error='invalACCESS_TOKEN'" diff --git a/desktop/build.gradle.kts b/desktop/build.gradle.kts index 82dcdf93..fe6a976d 100644 --- a/desktop/build.gradle.kts +++ b/desktop/build.gradle.kts @@ -108,6 +108,9 @@ kotlin { implementation(retrofit2KotlinXSerialization) implementation(okhttp3("okhttp")) implementation(okhttp3("logging-interceptor")) + // Work around vulnerable Okio version 3.1.0 (CVE-2023-3635). + // Can be removed when Retrofit releases a new version >2.9.0. + implementation(okio) } database { compileOnly(realm) diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/DownloadUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/DownloadUseCase.kt index e1953027..842609e0 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/DownloadUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/DownloadUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/JWSConverterFactory.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/JWSConverterFactory.kt index 231e020b..b6bd513e 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/JWSConverterFactory.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/JWSConverterFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/Main.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/Main.kt index 7212c95e..e1183445 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/Main.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/Main.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt index 4ef778e4..639b8414 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/api/ErpService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/cardwall/AuthenticationUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/cardwall/AuthenticationUseCase.kt index bfe72bf1..78395ead 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/cardwall/AuthenticationUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/cardwall/AuthenticationUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -49,6 +49,13 @@ import kotlinx.coroutines.launch import java.io.IOException import kotlin.coroutines.cancellation.CancellationException +@Requirement( + "GS-A_4368#6", + "GS-A_4367#7", + sourceSpecification = "gemSpec_Krypt", + rationale = "Seed length is defined with 256 Bits" + // TODO Update this req. when using the health card for random number generation is also implemented for Android. +) private const val SEED_LENGTH = 256 enum class AuthenticationState { @@ -116,7 +123,7 @@ class AuthenticationUseCase( private val idpUseCase: IdpUseCase ) { @Requirement( - "GS-A_4367#1", + "GS-A_4367#2", "GS-A_4368#1", sourceSpecification = "gemSpec_Krypt", rationale = "Random numbers are generated using the RNG of the health card." + @@ -152,7 +159,7 @@ class AuthenticationUseCase( } @Requirement( - "GS-A_4367#2", + "GS-A_4367#3", "GS-A_4368#2", sourceSpecification = "gemSpec_Krypt", rationale = "Random numbers are generated using the RNG of the health card." + @@ -219,7 +226,7 @@ class AuthenticationUseCase( } @Requirement( - "GS-A_4367#3", + "GS-A_4367#4", "GS-A_4368#3", sourceSpecification = "gemSpec_Krypt", rationale = "Random numbers are generated using the RNG of the health card." + diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/App.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/App.kt index dfed45ae..462d49e2 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/App.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/App.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/ClosableScaffold.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/ClosableScaffold.kt index 30a492ce..92354a3b 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/ClosableScaffold.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/ClosableScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Common.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Common.kt index db414a3e..d856f609 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Common.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Common.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Dialog.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Dialog.kt index fce2ec3e..c3ec4a49 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Dialog.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Dialog.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Divider.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Divider.kt index 5666f2f0..1c837a74 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Divider.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Divider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Hints.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Hints.kt index d4ef1fb8..298dca9f 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Hints.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Hints.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/OverlayPopup.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/OverlayPopup.kt index 38f6841e..289d5716 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/OverlayPopup.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/OverlayPopup.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Splittable.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Splittable.kt index 8a17777b..8d4dd874 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Splittable.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/Splittable.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/pinning/Pinning.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/pinning/Pinning.kt index 7e982066..883e02fd 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/pinning/Pinning.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/pinning/Pinning.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/StringResource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/StringResource.kt index da3b8fa5..59511e0f 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/StringResource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/StringResource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/Translatable.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/Translatable.kt index acb8b849..ad058062 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/Translatable.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/strings/Translatable.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Color.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Color.kt index b8c48c05..1f90ca8e 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Color.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Color.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/PaddingDefaults.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/PaddingDefaults.kt index 0ef5576d..520edb9f 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/PaddingDefaults.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/PaddingDefaults.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Theme.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Theme.kt index cc41ecd3..31f3d771 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Theme.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Theme.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Type.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Type.kt index b9cdd7fd..8efb0da5 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Type.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/common/theme/Type.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/di/CommunicationModule.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/di/CommunicationModule.kt index 6e5374c3..21292178 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/di/CommunicationModule.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/di/CommunicationModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/CommunicationRepository.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/CommunicationRepository.kt index 509d257f..fa156795 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/CommunicationRepository.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/CommunicationRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/LocalDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/LocalDataSource.kt index 101b9b57..13f8be77 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/LocalDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/LocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/RemoteDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/RemoteDataSource.kt index 2470e404..cf50fa17 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/RemoteDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/RemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/SimpleCommunication.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/SimpleCommunication.kt index 9b595fff..be814a26 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/SimpleCommunication.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/repository/SimpleCommunication.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationScreen.kt index 301079b2..46c46542 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationViewModel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationViewModel.kt index cb3c5921..089b9530 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationViewModel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/CommunicationViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/model/CommunicationScreenData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/model/CommunicationScreenData.kt index 0e6f2421..01b94620 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/model/CommunicationScreenData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/ui/model/CommunicationScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/CommunicationUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/CommunicationUseCase.kt index 4f15e598..a2f16ad0 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/CommunicationUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/CommunicationUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/model/CommunicationUseCaseData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/model/CommunicationUseCaseData.kt index 40135cd3..105dc6e6 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/model/CommunicationUseCaseData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/communication/usecase/model/CommunicationUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/FhirConverterFactory.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/FhirConverterFactory.kt index 5ac6bda0..95467864 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/FhirConverterFactory.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/FhirConverterFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/PrefixedLogger.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/PrefixedLogger.kt index c6b8f743..81ae57e1 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/PrefixedLogger.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/PrefixedLogger.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/SafeApiCall.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/SafeApiCall.kt index fe21dac5..f8cd64ba 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/SafeApiCall.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/core/SafeApiCall.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/FhirMapper.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/FhirMapper.kt index e021cf1b..6c2c0386 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/FhirMapper.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/FhirMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/KBVCodeMapping.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/KBVCodeMapping.kt index 44eca4c3..99be28bf 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/KBVCodeMapping.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/fhir/KBVCodeMapping.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt index ef099a2c..6e5c5409 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/IdpService.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt index aca7464e..c2aa64ac 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/BasicData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt index 8fd5c24b..505e32ac 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/api/models/Serializers.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/di/IdpModule.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/di/IdpModule.kt index 073fc8c2..5154bd39 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/di/IdpModule.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/di/IdpModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt index b777a029..57d9713e 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpLocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt index e496e64c..28c3caf1 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt index 76924921..ab497f93 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/repository/IdpRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt index 0149038e..06de2730 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpBasicUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -372,7 +372,6 @@ class IdpBasicUseCase( return redirect } - suspend fun fetchAndCheckUnsignedChallenge( url: String, codeChallenge: String, @@ -428,7 +427,6 @@ class IdpBasicUseCase( Json.parseToJsonElement(json).jsonObject["njwt"]!!.jsonPrimitive.content } } - suspend fun buildSignedChallenge( challengeBody: String, healthCardCertificate: ByteArray, diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt index 4683fe5d..9ffc5b56 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/idp/usecase/IdpUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/CredentialsTextField.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/CredentialsTextField.kt index 94d51378..d1917e8b 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/CredentialsTextField.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/CredentialsTextField.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardScreen.kt index 95c93848..3afa37fc 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardViewModel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardViewModel.kt index 4b315bd8..51f04452 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardViewModel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/LoginWithHealthCardViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/model/LoginWithHealthCard.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/model/LoginWithHealthCard.kt index 73387633..6c55619b 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/model/LoginWithHealthCard.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/login/ui/model/LoginWithHealthCard.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/repository/LocalDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/repository/LocalDataSource.kt index d9ffd8e2..2b72a527 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/repository/LocalDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/repository/LocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/LoggedInScreenScaffold.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/LoggedInScreenScaffold.kt index 02026a6f..e719a3af 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/LoggedInScreenScaffold.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/LoggedInScreenScaffold.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreen.kt index cae821e1..b179a06e 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreenViewModel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreenViewModel.kt index 46169d87..ae0551da 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreenViewModel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/MainScreenViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/model/MainScreenData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/model/MainScreenData.kt index b75d0d39..736d98f1 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/model/MainScreenData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/main/ui/model/MainScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/navigation/ui/Navigation.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/navigation/ui/Navigation.kt index 5417cddd..3ad116a0 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/navigation/ui/Navigation.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/navigation/ui/Navigation.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/di/NetworkModule.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/di/NetworkModule.kt index d86a6662..8e280361 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/di/NetworkModule.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/di/NetworkModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/BearerHeaderInterceptor.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/BearerHeaderInterceptor.kt index 34422de2..e56a2455 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/BearerHeaderInterceptor.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/BearerHeaderInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/HeaderInterceptor.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/HeaderInterceptor.kt index f523efd4..da76d12e 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/HeaderInterceptor.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/network/interceptor/HeaderInterceptor.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardChannel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardChannel.kt index 1e588e25..c94a4aaa 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardChannel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardSecureChannel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardSecureChannel.kt index 2a1bcb54..9ba8aaca 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardSecureChannel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcCardSecureChannel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcHealthCard.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcHealthCard.kt index 97ca203c..889a6d66 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcHealthCard.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/nfc/model/card/NfcHealthCard.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/di/PrescriptionModule.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/di/PrescriptionModule.kt index 55c55ae2..b74b587d 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/di/PrescriptionModule.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/di/PrescriptionModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt index c92dad28..add16e78 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/LocalDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt index 5afd2fe0..5e7b8c6a 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/PrescriptionRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt index 83e814c9..65bc0095 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/RemoteDataSource.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleAuditEvent.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleAuditEvent.kt index 1d55a735..69c27765 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleAuditEvent.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleAuditEvent.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleMedicationDispense.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleMedicationDispense.kt index 3af2411c..4a7e23b0 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleMedicationDispense.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleMedicationDispense.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleTask.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleTask.kt index cc56cebf..12c683c7 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleTask.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/repository/model/SimpleTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionDetailScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionDetailScreen.kt index ce7214a1..e9f7826d 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionDetailScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionDetailScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreen.kt index 5a327d89..e9b22355 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionViewModel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionViewModel.kt index 2e01aa88..884ea2dc 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionViewModel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/PrescriptionViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt index 02f7250b..b9961507 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/ui/model/PrescriptionScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionMapper.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionMapper.kt index 943a554e..fffe4dce 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionMapper.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionMapper.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt index 6a67963f..2833ca2d 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/PrescriptionUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt index d5e0eab0..2ff4545d 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/prescription/usecase/model/PrescriptionUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/di/ProtocolModule.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/di/ProtocolModule.kt index 9a998110..c13ae6b4 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/di/ProtocolModule.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/di/ProtocolModule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/repository/model/ProtocolRepository.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/repository/model/ProtocolRepository.kt index 35ec1148..92cd651f 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/repository/model/ProtocolRepository.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/repository/model/ProtocolRepository.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolScreen.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolScreen.kt index cc46f602..610b43fa 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolScreen.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolScreen.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolViewModel.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolViewModel.kt index e12267f8..973c458c 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolViewModel.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/ProtocolViewModel.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/model/ProtocolScreenData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/model/ProtocolScreenData.kt index 48407936..ac97d875 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/model/ProtocolScreenData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/ui/model/ProtocolScreenData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCase.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCase.kt index ffbdbc5b..4ad22fd2 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCase.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCase.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCaseData.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCaseData.kt index 3531f2fe..c494c0d5 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCaseData.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/protocol/usecase/ProtocolUseCaseData.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt index 0cf40469..3f2c93f1 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/Bytes.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/CryptoUtils.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/CryptoUtils.kt index aaade038..d12eeb81 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/CryptoUtils.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/CryptoUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/FhirUtils.kt b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/FhirUtils.kt index ac72b482..000e79d0 100644 --- a/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/FhirUtils.kt +++ b/desktop/src/jvmMain/kotlin/de/gematik/ti/erp/app/utils/FhirUtils.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/gradle.properties b/gradle.properties index a9b5db0e..5c74efd6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ buildkonfig.flavor=googleTuInternal # VERSION_CODE=1 VERSION_NAME=1.0 -USER_AGENT=eRp-App-Android/1.14.0 GMTIK/eRezeptApp +USER_AGENT=eRp-App-Android/1.16.1 GMTIK/eRezeptApp # DATA_PROTECTION_LAST_UPDATED = 2022-01-06 # diff --git a/keystore/debug.keystore b/keystore/debug.keystore deleted file mode 100644 index 0c8c4774..00000000 Binary files a/keystore/debug.keystore and /dev/null differ diff --git a/plugins/dependencies/settings.gradle.kts b/plugins/dependencies/settings.gradle.kts index ceb312e0..240be2f2 100644 --- a/plugins/dependencies/settings.gradle.kts +++ b/plugins/dependencies/settings.gradle.kts @@ -10,7 +10,6 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() - jcenter() mavenCentral() } } diff --git a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/AppDependenciesPlugin.kt b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/AppDependenciesPlugin.kt index 8983b940..bfacbe9f 100644 --- a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/AppDependenciesPlugin.kt +++ b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/AppDependenciesPlugin.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); @@ -136,6 +136,7 @@ class AppDependenciesPlugin : Plugin { object Test { const val runner = "androidx.test:runner:1.5.2" + const val shotRunner = "com.karumi.shot.ShotTestRunner:6.0.0" const val orchestrator = "androidx.test:orchestrator:1.4.2" const val services = "androidx.test.services:test-services:1.4.2" const val archCore = "androidx.arch.core:core-testing:2.1.0" @@ -174,6 +175,11 @@ class AppDependenciesPlugin : Plugin { const val retrofit2KotlinXSerialization = "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0" fun okhttp3(module: String) = "com.squareup.okhttp3:$module:4.10.0" + + // To work around a vulnerable Okio version 3.1.0 (CVE-2023-3635) we include a newer, non-vulnerable version + // to be selected by Gradle instead instead of the old one. Can be removed as soon as Retrofit releases a + // new version >2.9.0. + const val okio = "com.squareup.okio:okio:3.4.0" object Test { val mockWebServer = okhttp3("mockwebserver") } @@ -203,6 +209,7 @@ class AppDependenciesPlugin : Plugin { object Test { const val ui = "androidx.compose.ui:ui-test:$composeVersion" + const val uiManifest = "androidx.compose.ui:ui-test-manifest:$composeVersion" const val junit4 = "androidx.compose.ui:ui-test-junit4:$composeVersion" } } @@ -220,6 +227,7 @@ class AppDependenciesPlugin : Plugin { const val junit4 = "junit:junit:4.13.2" const val snakeyaml = "org.yaml:snakeyaml:1.30" const val json = "org.json:json:20220924" + const val shotTests = "com.karumi:shot:6.0.0" } } } diff --git a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Overriding.kt b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Overriding.kt index fd4e389d..87a8ef28 100644 --- a/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Overriding.kt +++ b/plugins/dependencies/src/main/kotlin/de/gematik/ti/erp/Overriding.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/plugins/resource-generation/settings.gradle.kts b/plugins/resource-generation/settings.gradle.kts index ceb312e0..240be2f2 100644 --- a/plugins/resource-generation/settings.gradle.kts +++ b/plugins/resource-generation/settings.gradle.kts @@ -10,7 +10,6 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() - jcenter() mavenCentral() } } diff --git a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/ResourceGenerationPlugin.kt b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/ResourceGenerationPlugin.kt index 2084165d..ad62191a 100644 --- a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/ResourceGenerationPlugin.kt +++ b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/ResourceGenerationPlugin.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/networkSecurityConfigGen/AndroidNetworkConfigGeneratorTask.kt b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/networkSecurityConfigGen/AndroidNetworkConfigGeneratorTask.kt index 7d95ebd9..b3e7cc31 100644 --- a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/networkSecurityConfigGen/AndroidNetworkConfigGeneratorTask.kt +++ b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/networkSecurityConfigGen/AndroidNetworkConfigGeneratorTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/stringResGen/AndroidStringResourceGeneratorTask.kt b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/stringResGen/AndroidStringResourceGeneratorTask.kt index 9b09f9b0..350113cd 100644 --- a/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/stringResGen/AndroidStringResourceGeneratorTask.kt +++ b/plugins/resource-generation/src/main/kotlin/de/gematik/ti/erp/stringResGen/AndroidStringResourceGeneratorTask.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/plugins/technical-requirements-plugin/build.gradle.kts b/plugins/technical-requirements-plugin/build.gradle.kts new file mode 100644 index 00000000..dc5b1d61 --- /dev/null +++ b/plugins/technical-requirements-plugin/build.gradle.kts @@ -0,0 +1,21 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + `kotlin-dsl` + `java-gradle-plugin` +} + +tasks.withType() { + kotlinOptions.jvmTarget = "17" +} + +dependencies { + implementation("com.android.tools.build:gradle:7.2.0") +} + +gradlePlugin { + plugins.register("TechnicalRequirementsPlugin") { + id = "de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin" + implementationClass = "de.gematik.ti.erp.gradleplugins.TechnicalRequirementsPlugin" + } +} diff --git a/plugins/technical-requirements-plugin/settings.gradle.kts b/plugins/technical-requirements-plugin/settings.gradle.kts new file mode 100644 index 00000000..240be2f2 --- /dev/null +++ b/plugins/technical-requirements-plugin/settings.gradle.kts @@ -0,0 +1,15 @@ +pluginManagement { + repositories { + google() + gradlePluginPortal() + mavenCentral() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) + repositories { + google() + mavenCentral() + } +} diff --git a/plugins/technical-requirements-plugin/src/main/kotlin/de/gematik/ti/erp/gradleplugins/TechnicalRequirementsPlugin.kt b/plugins/technical-requirements-plugin/src/main/kotlin/de/gematik/ti/erp/gradleplugins/TechnicalRequirementsPlugin.kt new file mode 100644 index 00000000..2bf631b0 --- /dev/null +++ b/plugins/technical-requirements-plugin/src/main/kotlin/de/gematik/ti/erp/gradleplugins/TechnicalRequirementsPlugin.kt @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2024 gematik GmbH + * + * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by + * the European Commission - subsequent versions of the EUPL (the Licence); + * You may not use this work except in compliance with the Licence. + * You may obtain a copy of the Licence at: + * + * https://joinup.ec.europa.eu/software/page/eupl + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the Licence is distributed on an "AS IS" basis, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the Licence for the specific language governing permissions and + * limitations under the Licence. + * + */ + +package de.gematik.ti.erp.gradleplugins + +import org.gradle.api.Plugin +import org.gradle.api.Project + +import java.io.File + +class TechnicalRequirementsPlugin : Plugin { + var project: Project? = null + override fun apply(project: Project) { + this.project = project + project.tasks.register("generateTechnicalRequirementsMarkdown") { + doLast { + val sourceDirs = setOf( + File(project.rootDir.path + "/android/src/main/java/de/gematik/ti/erp/app"), + File(project.rootDir.path + "/common/src/commonMain/kotlin/de/gematik/ti/erp/app") + ) + // println(sourceDirs) + processSourceDirectory(sourceDirs) + } + } + } + + private fun processSourceDirectory(sourceDirs: Set) { + val allAnnotations = mutableListOf() + + for (sourceDir in sourceDirs) { + val files = sourceDir.walk().filter { it.isFile } + + files.forEach { file -> + val annotationData = findAnnotationsInFile(file) + annotationData.forEach { + // println(it) + } + allAnnotations.addAll(annotationData) + } + } + + generateHtmlReport(allAnnotations) + } + + private fun findAnnotationsInFile(file: File): MutableList { + val foundAnnotations = mutableListOf() + + val content = file.readText() + + val projectRootDir = project?.rootDir?.canonicalPath ?: file.parentFile.canonicalPath + val relativePath = file.canonicalPath.removePrefix(projectRootDir) + val fileName = relativePath.removePrefix(File.separator) + val matches = ANNOTATION_REGEX.findAll(content) + for (match in matches) { + val annotationText = match.value + // println(annotationText) + val startLine = content.substring(0, match.range.first).count { it == '\n' } + 1 + + val requirements = parseRequirements(annotationText) + val specificationValue = parseSpecification(annotationText) + val rationaleValue = parseRationale(annotationText) + + for (requirement in requirements) { + foundAnnotations.add( + AnnotationData( + fileName, + startLine, + requirement, + specificationValue, + rationaleValue + ) + ) + } + } + + return foundAnnotations + } + + private fun parseRequirements(annotationText: String): List { + val matches = REQUIREMENT_REGEX.findAll(annotationText) + val requirements = mutableListOf() + + for (match in matches) { + val requirement = match.groupValues[1] + if (!isSpecification(requirement)) { + requirements.add(requirement) + } + } + return requirements + } + + private fun isSpecification(text: String): Boolean { + // Add any other specification values that should be excluded here + val excludedSpecifications = setOf( + "gemSpec_eRp_FdV", + "BSI-eRp-ePA", + "gemF_Tokenverschlüsselung", + "gemSpec_IDP_Frontend", + "gemSpec_Krypt", + "unused", + "gemF_Biometrie", + "E-Rezept-App-Authentifizierungskonzept.pdf" + ) + return text in excludedSpecifications + } + + private fun parseSpecification(annotationText: String): String { + val match = SPEC_REGEX.find(annotationText) + return extractTextInsideQuotes(match?.value ?: "") + } + + private fun parseRationale(annotationText: String): String { + val match = RATIONALE_REGEX.find(annotationText) + println(annotationText) + println(match?.value ?: "_________") + + return match?.value ?: "" + } + + private fun extractTextInsideQuotes(input: String): String { + return QUOTES_REGEX.find(input)?.value?.replace("\"", "") ?: "" + } + + companion object { + private val ANNOTATION_REGEX = Regex("""@Requirement\([^)]*\)""", RegexOption.MULTILINE) + val REQUIREMENT_REGEX = Regex("""\s*"([a-zA-Z_][a-zA-Z0-9_#-.]*)"\s*,?\s*""") + private val SPEC_REGEX = Regex("""sourceSpecification\s*=\s*"(.*?)"""") + private val RATIONALE_REGEX = Regex("""rationale\s*=\s*[^)]*""", RegexOption.MULTILINE) + private val QUOTES_REGEX = Regex(""""(.*?)"""") + } + + private fun generateHtmlReport(annotationList: List) { + val specifications = annotationList.map { it.specification }.distinct() + + val htmlBuilder = StringBuilder() + + htmlBuilder.append("") + htmlBuilder.append("") + htmlBuilder.append("") + htmlBuilder.append("") + htmlBuilder.append("Technical Requirements Report") + + htmlBuilder.append("") + htmlBuilder.append("") + + htmlBuilder.append("

Technical Requirements Report

") + + htmlBuilder.append("
    ") + for (specification in specifications) { + htmlBuilder.append("
  • ") + htmlBuilder.append("

    $specification

    ") + htmlBuilder.append("
      ") + val annotationDataList = annotationList.filter { it.specification == specification } + .sortedWith(compareBy { it.requirement }.thenBy { it.extractSuffixNumber() ?: 0 }) + for (data in annotationDataList) { + htmlBuilder.append("
    • ") + htmlBuilder.append( + "

      " + + "${data.requirement}

      " + ) + htmlBuilder.append("
      ${data.toHTML()}
      ") + htmlBuilder.append("
    • ") + } + htmlBuilder.append("
    ") + htmlBuilder.append("
  • ") + } + htmlBuilder.append("
") + + htmlBuilder.append("") + htmlBuilder.append("") + + htmlBuilder.append("") + + htmlBuilder.append("") + + val outputFile = File(project?.rootDir?.path + "/technical_requirements_report.html") + if (!outputFile.exists()) { + outputFile.createNewFile() + } + outputFile.writeText(htmlBuilder.toString()) + } +} + +data class AnnotationData( + val fileName: String, + val line: Int, + val requirement: String, + val specification: String, + val rationale: String, + val suffixNumber: Int = 0 // Default value for requirements without a suffix + +) { + + @Suppress("MagicNumber") + fun extractSuffixNumber(): Int { + val suffixIndex = requirement.indexOf('#') + return if (suffixIndex != -1 && suffixIndex < requirement.length - 1) { + requirement.substring(suffixIndex + 1).toIntOrNull() ?: 0 + } else { + 0 + } + } + fun toHTML(): String { + return """ +

Filename

+

$fileName

+

Line

+

$line

+

Description

+

${formatDescription(rationale)}

+ """.trimIndent() + } + + private fun formatDescription(description: String): String { + return description + .replace("rationale =", "") + .replace("\"", "") + .replace("+", " ") + .replace("\n", "
") + .removeSuffix(")") + } +} diff --git a/rules/src/main/kotlin/de/gematik/ti/erp/CustomRuleSetProvider.kt b/rules/src/main/kotlin/de/gematik/ti/erp/CustomRuleSetProvider.kt index 416198ff..eca100a6 100644 --- a/rules/src/main/kotlin/de/gematik/ti/erp/CustomRuleSetProvider.kt +++ b/rules/src/main/kotlin/de/gematik/ti/erp/CustomRuleSetProvider.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/rules/src/main/kotlin/de/gematik/ti/erp/LicenceRule.kt b/rules/src/main/kotlin/de/gematik/ti/erp/LicenceRule.kt index fd6c8f54..5e5263a4 100644 --- a/rules/src/main/kotlin/de/gematik/ti/erp/LicenceRule.kt +++ b/rules/src/main/kotlin/de/gematik/ti/erp/LicenceRule.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/rules/src/test/kotlin/de/gematik/ti/erp/LicenceRuleTest.kt b/rules/src/test/kotlin/de/gematik/ti/erp/LicenceRuleTest.kt index 56c22c03..d1476645 100644 --- a/rules/src/test/kotlin/de/gematik/ti/erp/LicenceRuleTest.kt +++ b/rules/src/test/kotlin/de/gematik/ti/erp/LicenceRuleTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/settings.gradle.kts b/settings.gradle.kts index 8dd4e3ea..5f522dda 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -16,8 +16,10 @@ pluginManagement { } } } + includeBuild("plugins/dependencies") includeBuild("plugins/resource-generation") + includeBuild("plugins/technical-requirements-plugin") } dependencyResolutionManagement { @@ -28,7 +30,6 @@ dependencyResolutionManagement { google() mavenCentral() maven ("https://jitpack.io") - jcenter() } } @@ -50,6 +51,6 @@ includeBuild("smartcard-wrapper") { // } //} -include(":android", ":desktop", ":common") +include("android", "desktop", "common", "plugins:technical-requirements-plugin") rootProject.name = "E-Rezept" diff --git a/smartcard-wrapper/settings.gradle.kts b/smartcard-wrapper/settings.gradle.kts index ceb312e0..240be2f2 100644 --- a/smartcard-wrapper/settings.gradle.kts +++ b/smartcard-wrapper/settings.gradle.kts @@ -10,7 +10,6 @@ dependencyResolutionManagement { repositoriesMode.set(RepositoriesMode.PREFER_SETTINGS) repositories { google() - jcenter() mavenCentral() } } diff --git a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Card.kt b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Card.kt index 21ffef24..5bca8c5b 100644 --- a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Card.kt +++ b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Card.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardFactory.kt b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardFactory.kt index ed05442c..12c5cb27 100644 --- a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardFactory.kt +++ b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardFactory.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardReader.kt b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardReader.kt index 893fc51b..e45164cb 100644 --- a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardReader.kt +++ b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/CardReader.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence); diff --git a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Workarounds.kt b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Workarounds.kt index 4e9c3626..38bff582 100644 --- a/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Workarounds.kt +++ b/smartcard-wrapper/src/main/kotlin/de/gematik/ti/erp/app/smartcard/Workarounds.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 gematik GmbH + * Copyright (c) 2024 gematik GmbH * * Licensed under the EUPL, Version 1.2 or – as soon they will be approved by * the European Commission - subsequent versions of the EUPL (the Licence);