Skip to content

Feat(global temp): include in-office procedures in global templates#7980

Open
alexwillingham wants to merge 6 commits into
developfrom
alex/otr-2087-global-templates-add-procedures
Open

Feat(global temp): include in-office procedures in global templates#7980
alexwillingham wants to merge 6 commits into
developfrom
alex/otr-2087-global-templates-add-procedures

Conversation

@alexwillingham

@alexwillingham alexwillingham commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

OTR-2087: Global templates -- Add Procedures

🤖 Claude generated this code, but I reviewed it carefully and edited it.

The description below is from Claude also.

Summary

Mirrors the in-house labs template pattern for the in-office Procedures feature, with the linked-structure cross-refs adapted to procedures' shape: a procedure ServiceRequest carries reasonReference into encounter diagnosis Conditions and supportingInfo into CPT-code Procedures, so the template snapshot has to preserve those links to round-trip.

Test coverage added

Mirroring the in-house labs work:

  • apply-procedures.test.ts — 9 unit tests on the procedure-plan builder: reference rewrite, drop semantics when the target section is skipped, intent/status/tag transitions, sparse plan handling.
  • admin-create-template.test.ts — 7 tests on isValidProcedureServiceRequest: includable-status set, exclusion of deleted procedures (entered-in-error / revoked), the procedure meta-tag requirement, the non-ServiceRequest fallthrough.
  • apply-template.test.ts — 6 makeCreateRequests procedure-plan tests: action propagation, end-to-end cross-ref rewrite into fullUrls in the same transaction, drop semantics when diagnoses/CPT sections are skipped, sparse-plan handling.
  • apply-template.test.ts — 2 validation tests pin the skip/append-only constraint.
  • ApplyTemplate.test.tsx — 2 component tests cover the procedure section card (CPT/diagnosis text + form fields visible, Overwrite hidden) and the empty-procedures case where the section is suppressed.

Generated by Claude Code

claude added 3 commits June 4, 2026 01:12
Mirrors the in-house labs template pattern for the in-office Procedures
feature, with the linked-structure cross-refs adapted to procedures'
shape: a procedure ServiceRequest carries reasonReference into encounter
diagnosis Conditions and supportingInfo into CPT-code Procedures.

admin-create-template captures chart procedures (filtered to includable
statuses so entered-in-error/revoked ones don't leak in) and materializes
each as a plan ServiceRequest in List.contained. The plan preserves the
procedure form's full payload - category (procedureType), performerType,
bodySite, and the dozen extensions for technique/medication/etc - and
remaps reasonReference/supportingInfo through oldIdToNewIdMap so they
point at the template's contained Conditions and CPT Procedures.

admin-get-template-detail parses procedure plans into TemplateProcedurePlan
with inline {code, display} (plus modifiers, matching the in-house labs
TemplateCptCodeInfo shape) for the linked diagnoses and CPT codes, so the
UI never has to walk the FHIR graph.

apply-template materializes procedure plans via a small builder
(apply-procedures.ts) which rewrites cross-refs through a contained-id ->
urn:uuid fullUrl map built during makeCreateRequests. CPT-Procedure creates
moved into the mini-transaction so the procedure plan's supportingInfo
fullUrls resolve atomically in the same FHIR transaction. References whose
target section is set to 'skip' get dropped on the rewritten request.

Section actions: 'procedures' added to TemplateSectionKey,
TEMPLATE_SECTIONS_IN_ORDER, and TEMPLATE_SECTION_DEFAULT_ACTIONS (append),
with the section constrained to skip/append (no overwrite) so applying a
template never silently wipes a provider's existing procedure
documentation.

UI: TemplatePreviewDialog and GlobalTemplateDetailPage each render a
Procedures section. The preview lays out the procedure type as a subtitle
subheading with the details left-indented underneath - uppercase-caption
"CPT codes" and "Diagnoses" labels above the shared CodeList rendering,
followed by a compact label/value list of the procedure-form fields the
template actually carried (Yes/No for booleans, free-text blocks inline
with their label, multi-line content via whiteSpace: pre-wrap).

Tests: 9 unit tests pin the procedure-plan builder (apply-procedures.ts)
- reference rewrite, drop semantics when a target section is skipped,
status/intent/tag transitions, sparse plan handling. 2 validation tests
cover the skip/append-only constraint. 2 EHR component tests cover the
section card (codes/fields visible, Overwrite hidden) and the empty
template case.
The in-house labs work landed isValidInHouseLabServiceRequest tests in
admin-create-template.test.ts and a makeCreateRequests block in
apply-template.test.ts that exercised every action-combination overlap
between the labs section and CPT Codes. The procedure-plan code added
in this branch had unit tests for its builder (apply-procedures.test.ts)
but no equivalent coverage for the capture filter or for the
makeCreateRequests integration. Filled the gap:

admin-create-template.test.ts gains 7 isValidProcedureServiceRequest
tests pinning the includable-status set, exclusion of deleted procedures
(entered-in-error / revoked), the procedure meta-tag requirement, and
the non-ServiceRequest fallthrough.

apply-template.test.ts gains 6 makeCreateRequests procedure-plan tests:
- procedures='skip' emits no SR
- procedures='append' emits one chart-data-shaped SR per plan with the
  procedure meta tag (not the plan tag) and a urn:uuid fullUrl
- reasonReference / supportingInfo are rewritten to the fullUrls of the
  new live Condition / CPT Procedure in the same transaction
- diagnoses='skip' drops reasonReference rather than leaking the
  template-stub id
- cptCodes='skip' drops supportingInfo for the same reason
- a sparse plan (no cross-refs) produces a clean SR without empty arrays
A reuse / simplification pass surfaced several places the diff had
re-implemented existing helpers or duplicated structure inside itself.
Folded those in so the procedures code reads like the rest of the
templates surface area:

- apply-procedures.ts uses resourceHasTagSystem from utils instead of an
  inline meta?.tag?.some() probe.
- buildLiveProcedureRequest returns BatchInputPostRequest<ServiceRequest>
  directly. The droppedReasonReferences / droppedSupportingInfo counters
  were only consulted in tests, never operationally - removed.
- admin-create-template lifts TEMPLATE_INCLUDABLE_SR_STATUSES to a
  module-level constant; isValidInHouseLabServiceRequest and
  isValidProcedureServiceRequest share the same allow-list instead of
  redefining it inline.
- admin-get-template-detail imports CPT_CODE_SYSTEM from utils instead of
  hard-coding 'http://www.ama-assn.org/go/cpt', and walks the template's
  contained array once to build conditionById and cptProcedureById
  together instead of two sequential passes.
- TemplatePreviewDialog's ProcedurePlanFields collapses the parallel
  rows[] / blocks[] arrays into one list with a multiline flag, removing
  the duplicate filter+render logic for free-text vs single-line fields.
- A new getProcedureDisplayFields(plan) helper in src/helpers/templates.ts
  carries the 12-field display list; the apply-template preview and the
  admin detail page both consume it instead of inlining the same 12 rows
  twice.
pare down giant comment

Signed-off-by: alexwillingham <awillingham@masslight.com>
Comment thread packages/zambdas/src/ehr/apply-template/apply-procedures.ts
…lder

Per PR review: apply-template's buildLiveProcedureRequest was duplicating
the procedure ServiceRequest construction logic, so any future change to
the procedure feature (new extension, different status default, refined
codings) would have needed two edits to land in both the chart-data save
path and the template apply path.

Refactored so the apply-template path now flows through the same
createProcedureServiceRequest builder save-chart-data uses:

- Pulled the procedure-form field reader (extension/coding extraction)
  out of makeProceduresDTOFromFhirResources into a named export,
  readProcedureFormFieldsFromServiceRequest. Both the chart-data reader
  and apply-template now call it; the read shape stays in one place too.
- Taught createProcedureServiceRequest to pass `urn:uuid:`-prefixed
  resourceIds through verbatim on reasonReference / supportingInfo. Plain
  ids still get the FHIR resource-type prefix, so save-chart-data keeps
  emitting `Condition/<id>` while apply-template can emit
  `urn:uuid:<...>` and have the FHIR transaction resolve the link to the
  Conditions and CPT Procedures it's creating alongside.
- buildLiveProcedureRequest now reads the plan's form payload via the
  shared reader, encodes the remapped fullUrls into the DiagnosisDTO /
  CPTCodeDTO resourceId slots, delegates the ServiceRequest construction
  to the shared builder, and just adds the urn:uuid fullUrl so other
  resources in the transaction can reference the new procedure.

The plan→DTO conversion drops uncanonical codings (no system, or unknown
system) and rebuilds the extension list in canonical order — both are
desirable, since the template should never persist non-canonical data
through the apply path. Updated the unit test fixtures to use canonical
systems and adjusted assertions accordingly.
Comment thread packages/zambdas/src/ehr/apply-template/apply-procedures.ts Outdated
…pply

Per PR review: silently falling back to undefined when the ISO timestamp
generation fails hides the bug. now() can only return an invalid
DateTime under truly broken conditions, but if it ever does we'd rather
fail loudly than ship a procedure with no documentedDateTime.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot reviewed 14 out of 14 changed files in this pull request and generated no comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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.

3 participants