Skip to main content
Glama
chargeitemdefinitionapply.test.ts24.9 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { ContentType } from '@medplum/core'; import type { ChargeItem, ChargeItemDefinition } from '@medplum/fhirtypes'; import express from 'express'; import request from 'supertest'; import { initApp, shutdownApp } from '../../app'; import { loadTestConfig } from '../../config/loader'; import { initTestAuth } from '../../test.setup'; const app = express(); let accessToken: string; describe('ChargeItemDefinition Apply', () => { beforeAll(async () => { const config = await loadTestConfig(); await initApp(app, config); accessToken = await initTestAuth(); }); afterAll(async () => { await shutdownApp(); }); test('Happy path - Apply ChargeItemDefinition', async () => { // 1. Create a patient const patient = await request(app) .post(`/fhir/R4/Patient`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Patient', name: [{ given: ['Test'], family: 'Patient' }], }); expect(patient.status).toBe(201); // 2. Create an encounter const encounter = await request(app) .post(`/fhir/R4/Encounter`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Encounter', status: 'in-progress', class: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'AMB', display: 'ambulatory', }, subject: { reference: `Patient/${patient.body.id}`, }, }); expect(encounter.status).toBe(201); // 3. Create a ChargeItemDefinition const chargeItemDefinition = await request(app) .post(`/fhir/R4/ChargeItemDefinition`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItemDefinition', status: 'active', url: 'http://example.org/fhir/ChargeItemDefinition/example', code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99213', display: 'Office/outpatient visit est', }, ], }, propertyGroup: [ { priceComponent: [ { type: 'base', amount: { value: 100, currency: 'USD', }, }, ], }, ], }); expect(chargeItemDefinition.status).toBe(201); // 4. Create a draft ChargeItem first const draftChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-01-01T12:00:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99213', display: 'Office/outpatient visit est', }, ], }, }); expect(draftChargeItem.status).toBe(201); // 5. Apply the ChargeItemDefinition to the draft ChargeItem using its reference const applyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${draftChargeItem.body.id}`, }, }, ], }); // 6. Verify the result expect(applyResult.status).toBe(200); const chargeItem = applyResult.body as ChargeItem; expect(chargeItem.resourceType).toBe('ChargeItem'); expect(chargeItem.id).toBe(draftChargeItem.body.id); // 7. Verify price override was applied expect(chargeItem.priceOverride).toBeDefined(); expect(chargeItem.priceOverride?.value).toBe(100); expect(chargeItem.priceOverride?.currency).toBe('USD'); // 8. Verify subject and context expect(chargeItem.subject.reference).toBe(`Patient/${patient.body.id}`); expect(chargeItem.context).toBeDefined(); expect(chargeItem.context?.reference).toBe(`Encounter/${encounter.body.id}`); }); test('Apply ChargeItemDefinition with service-code based surcharge', async () => { // 1. Create a patient const patient = await request(app) .post(`/fhir/R4/Patient`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Patient', name: [{ given: ['Service'], family: 'CodeTest' }], }); expect(patient.status).toBe(201); // 2. Create an encounter const encounter = await request(app) .post(`/fhir/R4/Encounter`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Encounter', status: 'in-progress', class: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'AMB', display: 'ambulatory', }, subject: { reference: `Patient/${patient.body.id}`, }, }); expect(encounter.status).toBe(201); // 3. Create a ChargeItemDefinition with code-specific surcharge const chargeItemDefinitionBody: ChargeItemDefinition = { resourceType: 'ChargeItemDefinition', status: 'active', url: 'http://example.org/fhir/ChargeItemDefinition/code-based-pricing', title: 'Code-Based Pricing Model', code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99214', display: 'Complex office visit', }, ], }, propertyGroup: [ { priceComponent: [ { type: 'base', code: { text: 'Standard Service Fee', }, amount: { value: 120, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Complex case surcharge for 99214', expression: "%resource.code.coding.where(system='http://www.ama-assn.org/go/cpt' and code='99214').exists()", }, ], priceComponent: [ { type: 'surcharge', code: { text: 'Higher Complexity Case (99214)', }, amount: { value: 35, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Medical decision making surcharge', expression: 'true', // Always applies for test }, ], priceComponent: [ { type: 'surcharge', code: { text: 'Medical Decision Making', }, factor: 0.15, // 15% surcharge }, ], }, ], }; const chargeItemDefinition = await request(app) .post(`/fhir/R4/ChargeItemDefinition`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send(chargeItemDefinitionBody); expect(chargeItemDefinition.status).toBe(201); // 4. Create a draft ChargeItem with 99214 code const draftChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-01-05T14:00:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99214', display: 'Complex office visit', }, ], }, }); expect(draftChargeItem.status).toBe(201); // 5. Apply the ChargeItemDefinition to the draft ChargeItem const applyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${draftChargeItem.body.id}`, }, }, ], }); // 6. Verify the result expect(applyResult.status).toBe(200); const chargeItem = applyResult.body as ChargeItem; expect(chargeItem.resourceType).toBe('ChargeItem'); expect(chargeItem.id).toBe(draftChargeItem.body.id); // 7. Verify price calculation // Base price: $120 // 99214-specific surcharge: $35 (fixed amount) // Medical decision making surcharge: $18 (15% of base) // Expected final price: $120 + $35 + $18 = $173 expect(chargeItem.priceOverride).toBeDefined(); expect(chargeItem.priceOverride?.value).toBe(173); expect(chargeItem.priceOverride?.currency).toBe('USD'); }); test('Apply ChargeItemDefinition with multiple discount types', async () => { // 1. Create a patient const patient = await request(app) .post(`/fhir/R4/Patient`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Patient', name: [{ given: ['Discount'], family: 'TestCase' }], }); expect(patient.status).toBe(201); // 2. Create an encounter const encounter = await request(app) .post(`/fhir/R4/Encounter`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Encounter', status: 'in-progress', class: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'AMB', display: 'ambulatory', }, subject: { reference: `Patient/${patient.body.id}`, }, }); expect(encounter.status).toBe(201); // 3. Create a ChargeItemDefinition with various discount types const chargeItemDefinitionBody: ChargeItemDefinition = { resourceType: 'ChargeItemDefinition', status: 'active', url: 'http://example.org/fhir/ChargeItemDefinition/discount-pricing', title: 'Discount Pricing Model', code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99213', display: 'Office visit', }, ], }, propertyGroup: [ { priceComponent: [ { type: 'base', code: { text: 'Standard Service Fee', }, amount: { value: 200, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Insurance contract discount', expression: 'true', }, ], priceComponent: [ { type: 'discount', code: { text: 'Insurance Contract Rate', }, factor: 0.2, }, ], }, { applicability: [ { description: 'Senior citizen discount', expression: 'true', }, ], priceComponent: [ { type: 'discount', code: { text: 'Senior Discount', }, amount: { value: 25, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Preventive care discount', expression: "%resource.code.coding.where(system='http://www.ama-assn.org/go/cpt' and code='99213').exists()", }, ], priceComponent: [ { type: 'discount', code: { text: 'Preventive Care Discount', }, factor: 0.05, }, ], }, ], }; const chargeItemDefinition = await request(app) .post(`/fhir/R4/ChargeItemDefinition`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send(chargeItemDefinitionBody); expect(chargeItemDefinition.status).toBe(201); // 4. Create a draft ChargeItem const draftChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-01-15T10:30:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://www.ama-assn.org/go/cpt', code: '99213', display: 'Office visit', }, ], }, }); expect(draftChargeItem.status).toBe(201); // 5. Apply the ChargeItemDefinition to the draft ChargeItem const applyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${draftChargeItem.body.id}`, }, }, ], }); // 6. Verify the result expect(applyResult.status).toBe(200); const chargeItem = applyResult.body as ChargeItem; expect(chargeItem.resourceType).toBe('ChargeItem'); expect(chargeItem.id).toBe(draftChargeItem.body.id); // 7. Verify price calculation // Base price: $200 // Insurance contract discount: $40 (20% of base) // Senior discount: $25 (fixed amount) // Preventive care discount: $10 (5% of base) // Expected final price: $200 - $40 - $25 - $10 = $125 expect(chargeItem.priceOverride).toBeDefined(); expect(chargeItem.priceOverride?.value).toBe(125); expect(chargeItem.priceOverride?.currency).toBe('USD'); }); test('Apply ChargeItemDefinition with base price applicability', async () => { // Create a patient const patient = await request(app) .post(`/fhir/R4/Patient`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Patient', name: [{ given: ['Base'], family: 'Applicability' }], }); expect(patient.status).toBe(201); // Create an encounter const encounter = await request(app) .post(`/fhir/R4/Encounter`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Encounter', status: 'in-progress', class: { system: 'http://terminology.hl7.org/CodeSystem/v3-ActCode', code: 'AMB', display: 'ambulatory', }, subject: { reference: `Patient/${patient.body.id}`, }, }); expect(encounter.status).toBe(201); // Create a ChargeItemDefinition with base price applicability const chargeItemDefinitionBody: ChargeItemDefinition = { resourceType: 'ChargeItemDefinition', status: 'active', url: 'http://example.org/fhir/ChargeItemDefinition/base-price-applicability', title: 'Base Price Applicability Model', propertyGroup: [ { applicability: [ { description: 'Base price only applies for new patients', expression: "%resource.code.coding.where(system='http://example.org/codes' and code='new-patient').exists()", }, ], priceComponent: [ { type: 'base', code: { text: 'New Patient Fee', }, amount: { value: 150, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Base price only applies for established patients', expression: "%resource.code.coding.where(system='http://example.org/codes' and code='established-patient').exists()", }, ], priceComponent: [ { type: 'base', code: { text: 'Established Patient Fee', }, amount: { value: 100, currency: 'USD', }, }, ], }, { applicability: [ { description: 'Apply to all visits', expression: 'true', }, ], priceComponent: [ { type: 'surcharge', code: { text: 'Standard Facility Fee', }, amount: { value: 25, currency: 'USD', }, }, ], }, ], }; const chargeItemDefinition = await request(app) .post(`/fhir/R4/ChargeItemDefinition`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send(chargeItemDefinitionBody); expect(chargeItemDefinition.status).toBe(201); // Create a ChargeItem for a new patient const newPatientChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-03-15T14:00:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://example.org/codes', code: 'new-patient', display: 'New Patient Visit', }, ], }, }); expect(newPatientChargeItem.status).toBe(201); // Apply the ChargeItemDefinition to the new patient ChargeItem const newPatientApplyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${newPatientChargeItem.body.id}`, }, }, ], }); // Verify new patient pricing expect(newPatientApplyResult.status).toBe(200); const newPatientResult = newPatientApplyResult.body as ChargeItem; expect(newPatientResult.resourceType).toBe('ChargeItem'); expect(newPatientResult.id).toBe(newPatientChargeItem.body.id); // New Patient base price: $150 // Standard Facility Fee: $25 // Expected total: $175 expect(newPatientResult.priceOverride).toBeDefined(); expect(newPatientResult.priceOverride?.value).toBe(175); expect(newPatientResult.priceOverride?.currency).toBe('USD'); // Create a ChargeItem for an established patient const establishedPatientChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-03-15T14:00:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://example.org/codes', code: 'established-patient', display: 'Established Patient Visit', }, ], }, }); expect(establishedPatientChargeItem.status).toBe(201); // Apply the ChargeItemDefinition to the established patient ChargeItem const establishedPatientApplyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${establishedPatientChargeItem.body.id}`, }, }, ], }); // Verify established patient pricing expect(establishedPatientApplyResult.status).toBe(200); const establishedPatientResult = establishedPatientApplyResult.body as ChargeItem; // Established Patient base price: $100 // Standard Facility Fee: $25 // Expected total: $125 expect(establishedPatientResult.priceOverride).toBeDefined(); expect(establishedPatientResult.priceOverride?.value).toBe(125); expect(establishedPatientResult.priceOverride?.currency).toBe('USD'); // Create a ChargeItem with no matching code const otherChargeItem = await request(app) .post(`/fhir/R4/ChargeItem`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'ChargeItem', status: 'draft', subject: { reference: `Patient/${patient.body.id}`, }, context: { reference: `Encounter/${encounter.body.id}`, }, occurrenceDateTime: '2023-03-15T14:00:00Z', performingOrganization: { reference: 'Organization/example', }, code: { coding: [ { system: 'http://example.org/codes', code: 'other-service', display: 'Other Service', }, ], }, }); expect(otherChargeItem.status).toBe(201); // Apply the ChargeItemDefinition to the other ChargeItem const otherApplyResult = await request(app) .post(`/fhir/R4/ChargeItemDefinition/${chargeItemDefinition.body.id}/$apply`) .set('Authorization', 'Bearer ' + accessToken) .set('Content-Type', ContentType.FHIR_JSON) .send({ resourceType: 'Parameters', parameter: [ { name: 'chargeItem', valueReference: { reference: `ChargeItem/${otherChargeItem.body.id}`, }, }, ], }); expect(otherApplyResult.status).toBe(200); const otherResult = otherApplyResult.body as ChargeItem; expect(otherResult.priceOverride?.value).toBe(150); expect(otherResult.priceOverride?.currency).toBe('USD'); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server