395 lines
14 KiB
Python
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")
|