Files
fhir2padnext/config_schemas.py
Alexander Domene 8650bd09a3 added tests
2025-10-27 08:19:13 +01:00

395 lines
14 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
JSON Schema definitions for configuration file validation.
"""
from typing import Any, Dict, List
# JSON Schema for header_config.json
HEADER_CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Header Configuration",
"description": "Configuration for static header fields in PADneXt XML",
"type": "object",
"properties": {
"nachrichtentyp_version": {
"type": "string",
"description": "Version of the message type",
"default": "1.0"
},
"rechnungsersteller_name": {
"type": "string",
"description": "Name of the billing entity"
},
"rechnungsersteller_kundennr": {
"type": "string",
"description": "Customer number of billing entity"
},
"rechnungsersteller_strasse": {
"type": "string",
"description": "Street address of billing entity"
},
"rechnungsersteller_plz": {
"type": "string",
"description": "Postal code of billing entity",
"pattern": "^[0-9]{5}$"
},
"rechnungsersteller_ort": {
"type": "string",
"description": "City of billing entity"
},
"rechnungsersteller_iknr": {
"type": "string",
"description": "IK number of billing entity (optional)"
},
"leistungserbringer_id": {
"type": "string",
"description": "ID of the service provider"
},
"leistungserbringer_titel": {
"type": "string",
"description": "Title of service provider (optional)"
},
"leistungserbringer_vorname": {
"type": "string",
"description": "First name of service provider"
},
"leistungserbringer_name": {
"type": "string",
"description": "Last name of service provider"
},
"empfaenger_anrede": {
"type": "string",
"description": "Salutation for recipient"
},
"empfaenger_vorname": {
"type": "string",
"description": "First name of recipient"
},
"empfaenger_name": {
"type": "string",
"description": "Last name of recipient"
},
"empfaenger_strasse": {
"type": "string",
"description": "Street address of recipient"
},
"empfaenger_plz": {
"type": "string",
"description": "Postal code of recipient"
},
"empfaenger_ort": {
"type": "string",
"description": "City of recipient"
},
"empfaenger_gebdatum": {
"type": "string",
"description": "Birth date of recipient",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
},
"behandelter_anrede": {
"type": "string",
"description": "Salutation for patient"
},
"behandelter_vorname": {
"type": "string",
"description": "First name of patient"
},
"behandelter_name": {
"type": "string",
"description": "Last name of patient"
},
"behandelter_gebdatum": {
"type": "string",
"description": "Birth date of patient",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
},
"behandelter_geschlecht": {
"type": "string",
"description": "Gender of patient",
"enum": ["m", "w", "u"]
},
"versicherter_anrede": {
"type": "string",
"description": "Salutation for insured person"
},
"versicherter_vorname": {
"type": "string",
"description": "First name of insured person"
},
"versicherter_name": {
"type": "string",
"description": "Last name of insured person"
},
"versicherter_gebdatum": {
"type": "string",
"description": "Birth date of insured person",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
},
"versicherter_geschlecht": {
"type": "string",
"description": "Gender of insured person",
"enum": ["m", "w", "u"]
},
"behandlungsart": {
"type": "string",
"description": "Type of treatment",
"pattern": "^[0-5]$"
},
"vertragsart": {
"type": "string",
"description": "Type of contract",
"pattern": "^[0-9]{1,3}$"
},
"aktenzeichen": {
"type": "string",
"description": "File reference (optional)"
},
"diagnose_text": {
"type": "string",
"description": "Diagnosis text"
},
"diagnose_datum": {
"type": "string",
"description": "Diagnosis date",
"pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"
},
"eabgabe": {
"type": "string",
"description": "Electronic submission (optional)"
},
"aisaktenzeichen": {
"type": "string",
"description": "AIS file reference (optional)"
},
"aisendbetrag": {
"type": "string",
"description": "AIS total amount (optional)"
}
},
"additionalProperties": True # Allow additional fields for flexibility
}
# JSON Schema for placeholder_config.json
PLACEHOLDER_CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Placeholder Configuration",
"description": "Fallback values for missing required fields",
"type": "object",
"properties": {
"rechnungsersteller": {
"type": "object",
"properties": {
"name": {"type": "string"},
"plz": {"type": "string", "pattern": "^[0-9]{5}$"},
"ort": {"type": "string"},
"strasse": {"type": "string"}
},
"required": ["name", "plz", "ort", "strasse"]
},
"leistungserbringer": {
"type": "object",
"properties": {
"vorname": {"type": "string"},
"name": {"type": "string"},
"titel": {"type": ["string", "null"]}
},
"required": ["vorname", "name"]
},
"empfaenger": {
"type": "object",
"properties": {
"anrede": {"type": "string"},
"vorname": {"type": "string"},
"name": {"type": "string"},
"plz": {"type": "string"},
"ort": {"type": "string"},
"strasse": {"type": "string"},
"gebdatum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"},
"geschlecht": {"type": "string", "enum": ["m", "w", "u"]}
},
"required": ["anrede", "vorname", "name", "plz", "ort", "strasse", "gebdatum"]
},
"behandelter": {
"type": "object",
"properties": {
"anrede": {"type": ["string", "null"]},
"vorname": {"type": "string"},
"name": {"type": "string"},
"gebdatum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"},
"geschlecht": {"type": "string", "enum": ["m", "w", "u"]}
},
"required": ["vorname", "name", "gebdatum", "geschlecht"]
},
"versicherter": {
"type": "object",
"properties": {
"anrede": {"type": "string"},
"vorname": {"type": "string"},
"name": {"type": "string"},
"gebdatum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"},
"geschlecht": {"type": "string", "enum": ["m", "w", "u"]}
},
"required": ["anrede", "vorname", "name", "gebdatum", "geschlecht"]
},
"rechnung": {
"type": "object",
"properties": {
"eabgabe": {"type": ["string", "null"]},
"aisaktenzeichen": {"type": ["string", "null"]},
"aisendbetrag": {"type": ["string", "null"]}
}
},
"abrechnungsfall": {
"type": "object",
"properties": {
"behandlungsart": {"type": "string", "pattern": "^[0-5]$"},
"vertragsart": {"type": "string", "pattern": "^[0-9]{1,3}$"}
},
"required": ["behandlungsart", "vertragsart"]
},
"zeitraum": {
"type": "object",
"properties": {
"startdatum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"},
"endedatum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"}
},
"required": ["startdatum", "endedatum"]
},
"goziffer": {
"type": "object",
"properties": {
"go": {"type": "string", "enum": ["GOAE", "UVGOAE", "EBM", "GOZ"]},
"ziffer": {"type": "string", "maxLength": 8, "minLength": 1},
"datum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"}
},
"required": ["go", "ziffer", "datum"]
},
"diagnose": {
"type": "object",
"properties": {
"datum": {"type": "string", "pattern": "^[0-9]{4}-[0-9]{2}-[0-9]{2}$"}
},
"required": ["datum"]
}
},
"required": ["rechnungsersteller", "leistungserbringer", "goziffer"],
"additionalProperties": True
}
# JSON Schema for mapping_config.json
MAPPING_CONFIG_SCHEMA = {
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Mapping Configuration",
"description": "Mapping rules from FHIR resources to PAD positions",
"type": "object",
"properties": {
"resources": {
"type": "object",
"description": "Resource type to position mappings",
"additionalProperties": {
"type": "object",
"properties": {
"target": {
"type": "string",
"description": "Target PAD element type",
"enum": ["goziffer"]
},
"fields": {
"type": "object",
"description": "Field mappings",
"additionalProperties": {
"type": "object",
"properties": {
"source": {
"type": "string",
"description": "Source field path in FHIR resource"
},
"default": {
"type": "string",
"description": "Default value if source is missing"
},
"required": {
"type": "boolean",
"description": "Whether this field is required"
},
"placeholder": {
"type": "string",
"description": "Placeholder value for required fields"
},
"translate": {
"type": "object",
"description": "Code translation rules",
"properties": {
"source_system_field": {"type": "string"},
"source_code_field": {"type": "string"}
}
}
}
}
}
},
"required": ["target", "fields"]
}
}
},
"required": ["resources"]
}
def validate_config(config: Dict[str, Any], schema: Dict[str, Any], config_name: str) -> List[str]:
"""
Validate configuration against JSON schema.
Args:
config: The configuration dict to validate
schema: The JSON schema to validate against
config_name: Name of the config for error messages
Returns:
List of validation warnings (non-fatal issues)
Raises:
ValueError: If validation fails with errors
Example:
>>> config = {"rechnungsersteller": {...}}
>>> warnings = validate_config(config, PLACEHOLDER_CONFIG_SCHEMA, "placeholder_config")
"""
warnings = []
try:
import jsonschema
except ImportError:
warnings.append(f"jsonschema not available - skipping {config_name} validation")
warnings.append("Install with: pip install jsonschema")
return warnings
try:
jsonschema.validate(config, schema)
except jsonschema.ValidationError as e:
# Collect detailed error information
error_path = " -> ".join(str(p) for p in e.path) if e.path else "root"
error_msg = f"Validation error in {config_name} at {error_path}: {e.message}"
raise ValueError(error_msg) from e
except jsonschema.SchemaError as e:
raise ValueError(f"Invalid schema for {config_name}: {e.message}") from e
return warnings
def validate_header_config(config: Dict[str, Any]) -> List[str]:
"""Validate header configuration."""
return validate_config(config, HEADER_CONFIG_SCHEMA, "header_config")
def validate_placeholder_config(config: Dict[str, Any]) -> List[str]:
"""Validate placeholder configuration."""
return validate_config(config, PLACEHOLDER_CONFIG_SCHEMA, "placeholder_config")
def validate_mapping_config(config: Dict[str, Any]) -> List[str]:
"""Validate mapping configuration."""
return validate_config(config, MAPPING_CONFIG_SCHEMA, "mapping_config")