Skip to content

Conversation

@mohan-13
Copy link
Member

Summary

This PR adds configurable concept code and location resolution for PACS integration orders.

Key Changes:

Concept Code Resolver

Resolves concept codes from OpenMRS orders using a priority-based fallback mechanism:

Resolution Algorithm:

  1. Priority-based search: Iterates through configured code sources in priority order (configured via concept.code.resolver.source.priority, e.g., "PACS Procedure Code, LOINC, ICD-10, SNOMED")
  2. Mapping validation: For each priority source, searches concept mappings that:
    • Have map type = "SAME-AS"
    • Contain non-blank/non-retired code
    • Match the current priority source name
  3. Fallback strategy: If no valid code found in first priority source, tries next source in list until match found or all sources exhausted
  4. Code meaning extraction: Uses term name if available, otherwise falls back to concept's fully specified English name → any English name → first available name
  5. Coding system: Extracts from source's HL7 code, falls back to source name

Output: HL7CodedElement with code identifier, text description, and coding system designator

Location Resolver

Resolves source and fulfilling locations for orders using tag-based filtering and attribute lookup:

Source Location (Visit Location) Resolution:

  1. Tag-based check: Examines encounter location for "Visit Location" tag
  2. Hierarchy traversal: If encounter location lacks tag, calls OpenMRS API to traverse location hierarchy and find parent location with "Visit Location" tag
  3. Validation: Ensures encounter and location are present, throws exception if missing

Fulfilling Location Resolution:

  1. Attribute lookup: Searches order attributes for REQUESTED_LOCATION attribute (configurable via order.requested.location.attribute.name)
  2. Fallback: If no requested location attribute found, uses source location as fulfilling location
  3. Type validation: Validates that attribute value is of type OrderLocation

Output: OrderLocationInfo containing both fulfilling and source LocationDTOs (UUID, name, display)

Supporting Infrastructure

  • OpenMRS REST API integration: Enhanced OpenMRSService with methods to fetch order details, traverse location hierarchy, and query location by UUID
  • Model definitions: Added 17+ DTOs for order details, concepts, mappings, locations, attributes
  • Exception handling: Custom exceptions for resolution failures
  • Comprehensive testing: 379 test cases for ConceptCodeResolver, 298 for LocationResolver covering edge cases, validation, and fallback scenarios

Configuration Properties:

  • concept.code.resolver.source.priority: Comma-separated list of code sources (default: "PACS Procedure Code")
  • order.requested.location.attribute.name: Attribute name for requested location (default: "REQUESTED_LOCATION")

return null;
}

java.util.Map<String, Object> responseMap = ObjectMapperRepository.objectMapper.readValue(response, java.util.Map.class);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mapper can be removed.
String response = webClient.get(URI.create(url), Map.class); can be used on line #73

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, good catch. will refactor

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

}

private OrderConceptMapping findMappingBySameAsType(OrderConcept concept, String sourceNameToMatch) {
for (OrderConceptMapping mapping : concept.getMappings()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick : I believe stream would make it more readable

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with a loop. otherwise, we will have use stream.filter() to filter out empty conceptmaptype, and if not SAME_AS, and also concept source.

}

private OrderConceptMapping findMappingBySameAsType(OrderConcept concept, String sourceNameToMatch) {
for (OrderConceptMapping mapping : concept.getMappings()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am ok with a loop. otherwise, we will have use stream.filter() to filter out empty conceptmaptype, and if not SAME_AS, and also concept source.

liquibase.change-log=classpath:db/changelog/liquibase.xml

enable.scheduling=true
enable.scheduling=true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are using spring scheduling? thought we were using quartz

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this repo seems to be using Spring Scheduler. https://github.com/Bahmni/pacs-integration/blob/master/pacs-integration-webapp/src/main/java/org/bahmni/module/pacsintegration/atomfeed/ScheduledTasks.java.

The tasks are just defined in a table named as quartz_cron_scheduler

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We definitely used Quartz here in the past. I am not sure if thats still applicable or was changed some point of time. Check QuartzCronScheduler.java

@mohan-13 mohan-13 merged commit 68fd2b2 into master Dec 12, 2025
2 checks passed
@mohan-13 mohan-13 deleted the BAH-4336 branch December 12, 2025 06:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants