55from pydantic import ValidationError
66
77from nrlf .core .codes import SpineErrorConcept
8- from nrlf .core .constants import CATEGORY_ATTRIBUTES , ODS_SYSTEM , REQUIRED_CREATE_FIELDS
8+ from nrlf .core .constants import (
9+ CATEGORY_ATTRIBUTES ,
10+ ODS_SYSTEM ,
11+ REQUIRED_CREATE_FIELDS ,
12+ TYPE_ATTRIBUTES ,
13+ TYPE_CATEGORIES ,
14+ )
915from nrlf .core .errors import ParseError
1016from nrlf .core .logger import LogReference , logger
1117from nrlf .core .types import DocumentReference , OperationOutcomeIssue , RequestQueryType
@@ -117,8 +123,10 @@ def validate(self, data: Dict[str, Any] | DocumentReference):
117123 self ._validate_identifiers (resource )
118124 self ._validate_relates_to (resource )
119125 self ._validate_ssp_asid (resource )
126+ self ._validate_type (resource )
120127 self ._validate_category (resource )
121128 self ._validate_author (resource )
129+ self ._validate_type_category_mapping (resource )
122130 if resource .content [0 ].extension :
123131 self ._validate_content_extension (resource )
124132
@@ -337,6 +345,40 @@ def _validate_ssp_asid(self, model: DocumentReference):
337345 )
338346 return
339347
348+ def _validate_type (self , model : DocumentReference ):
349+ """
350+ Validate the type field contains an appropriate coding system, code and display.
351+ """
352+ logger .log (LogReference .VALIDATOR001 , step = "type" )
353+
354+ if len (model .type .coding ) > 1 :
355+ self .result .add_error (
356+ issue_code = "invalid" ,
357+ error_code = "INVALID_RESOURCE" ,
358+ diagnostics = f"Invalid type coding length: { len (model .type [0 ].coding )} Type Coding must only contain a single value" ,
359+ field = f"type.coding" ,
360+ )
361+ return
362+
363+ coding = model .type .coding [0 ]
364+ if coding .system != "http://snomed.info/sct" :
365+ self .result .add_error (
366+ issue_code = "value" ,
367+ error_code = "INVALID_RESOURCE" ,
368+ diagnostics = f"Invalid type system: { coding .system } Type system must be 'http://snomed.info/sct'" ,
369+ field = "type.coding[0].system" ,
370+ )
371+ return
372+
373+ type_attributes = TYPE_ATTRIBUTES .get (type_id , {})
374+ if coding .display != type_attributes .get ("display" ):
375+ self .result .add_error (
376+ issue_code = "value" ,
377+ error_code = "INVALID_RESOURCE" ,
378+ diagnostics = f"type code '{ coding .code } ' must have a display value of '{ type_attributes .get ('display' )} '" ,
379+ field = "type.coding[0].display" ,
380+ )
381+
340382 def _validate_category (self , model : DocumentReference ):
341383 """
342384 Validate the category field contains an appropriate coding system, code and display.
@@ -369,17 +411,17 @@ def _validate_category(self, model: DocumentReference):
369411 issue_code = "value" ,
370412 error_code = "INVALID_RESOURCE" ,
371413 diagnostics = f"Invalid category system: { coding .system } Category system must be 'http://snomed.info/sct'" ,
372- field = f "category[0].coding[{ 0 } ].system" ,
414+ field = "category[0].coding[0 ].system" ,
373415 )
374416 return
375417
376- category_id = f"http://snomed.info/sct |{ coding .code } "
418+ category_id = f"{ coding . system } |{ coding .code } "
377419 if category_id not in CATEGORY_ATTRIBUTES .keys ():
378420 self .result .add_error (
379421 issue_code = "value" ,
380422 error_code = "INVALID_RESOURCE" ,
381423 diagnostics = f"Invalid category code: { coding .code } Category must be a member of the England-NRLRecordCategory value set (https://fhir.nhs.uk/England/CodeSystem/England-NRLRecordCategory)" ,
382- field = f "category[0].coding[{ 0 } ].code" ,
424+ field = "category[0].coding[0 ].code" ,
383425 )
384426 return
385427
@@ -389,7 +431,26 @@ def _validate_category(self, model: DocumentReference):
389431 issue_code = "value" ,
390432 error_code = "INVALID_RESOURCE" ,
391433 diagnostics = f"category code '{ coding .code } ' must have a display value of '{ category_attributes .get ('display' )} '" ,
392- field = f"category[0].coding[{ 0 } ].display" ,
434+ field = "category[0].coding[0].display" ,
435+ )
436+
437+ def _validate_type_category_mapping (self , model : DocumentReference ):
438+ """
439+ Validate the type field contains an appropriate coding system, code and display.
440+ """
441+ logger .log (LogReference .VALIDATOR001 , step = "type_category_mapping" )
442+
443+ type_coding = model .type .coding [0 ]
444+ type_id = f"{ type_coding .system } |{ type_coding .code } "
445+ category_coding = model .category [0 ].coding [0 ]
446+ category_id = f"{ category_coding .system } |{ category_coding .code } "
447+
448+ if not TYPE_CATEGORIES .get (type_id ):
449+ self .result .add_error (
450+ issue_code = "value" ,
451+ error_code = "INVALID_RESOURCE" ,
452+ diagnostics = f"type ({ type_id } ) does not map to the category: { category_id } " ,
453+ field = f"type.coding[0].display" ,
393454 )
394455
395456 def _validate_content_extension (self , model : DocumentReference ):
0 commit comments