added tests
This commit is contained in:
394
config_schemas.py
Normal file
394
config_schemas.py
Normal file
@@ -0,0 +1,394 @@
|
||||
#!/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")
|
||||
Reference in New Issue
Block a user