Search in sources :

Example 1 with Entry

use of org.mitre.synthea.world.concepts.HealthRecord.Entry in project synthea by synthetichealth.

the class CostsTest method testUpdatedCostsbyKnownCode.

@Test
public void testUpdatedCostsbyKnownCode() {
    // These tests test some costs added in the August 2020 Costs Update.
    // Test an updated medication cost.
    // 993452,816.12,1014.45,1237.68,1 ML denosumab 60 MG/ML Prefilled Syringe (Prolia)
    Code code = new Code("RxNorm", "993452", "1 ML denosumab 60 MG/ML Prefilled Syringe (Prolia)");
    double minCost = 816.12;
    double maxCost = 1237.68;
    Entry fakeEntry = person.record.medicationStart(time, code.display, true);
    fakeEntry.codes.add(code);
    double cost = Costs.determineCostOfEntry(fakeEntry, person);
    // At this point there is no state set, so there is no geogeaphic factor applied.
    assertTrue(cost <= maxCost);
    assertTrue(cost >= minCost);
    // Now test cost with adjustment factor.
    person.attributes.put(Person.STATE, "California");
    double adjFactor = 1.0227;
    cost = Costs.determineCostOfEntry(fakeEntry, person);
    assertTrue(cost <= (maxCost * adjFactor));
    assertTrue(cost >= (minCost * adjFactor));
    // Test an updated procedure cost.
    // 48387007,235,962.5,1690,"Incision of trachea (procedure)
    code = new Code("SNOMED", "48387007", "Incision of trachea (procedure)");
    minCost = 235;
    maxCost = 1690;
    fakeEntry = person.record.procedure(time, code.display);
    fakeEntry.codes.add(code);
    cost = Costs.determineCostOfEntry(fakeEntry, person);
    adjFactor = 1.2010;
    assertTrue(cost <= (maxCost * adjFactor));
    assertTrue(cost >= (minCost * adjFactor));
}
Also used : Entry(org.mitre.synthea.world.concepts.HealthRecord.Entry) Code(org.mitre.synthea.world.concepts.HealthRecord.Code) Test(org.junit.Test)

Example 2 with Entry

use of org.mitre.synthea.world.concepts.HealthRecord.Entry in project synthea by synthetichealth.

the class CostsTest method testCostByUnknownCode.

@Test
public void testCostByUnknownCode() {
    Code code = new Code("RxNorm", "111111111111111111", "Exaplitol");
    Entry fakeMedication = person.record.medicationStart(time, code.display, false);
    fakeMedication.codes.add(code);
    double cost = Costs.determineCostOfEntry(fakeMedication, person);
    double expectedCost = Config.getAsDouble("generate.costs.default_medication_cost");
    // assert the cost is within $0.01
    assertEquals(expectedCost, cost, 0.01);
}
Also used : Entry(org.mitre.synthea.world.concepts.HealthRecord.Entry) Code(org.mitre.synthea.world.concepts.HealthRecord.Code) Test(org.junit.Test)

Example 3 with Entry

use of org.mitre.synthea.world.concepts.HealthRecord.Entry in project synthea by synthetichealth.

the class CostsTest method testCostByCodeWithDifferentSystem.

@Test
public void testCostByCodeWithDifferentSystem() {
    Code code = new Code("SNOMED-CT", "705129", "Fake SNOMED with the same code as an RxNorm code");
    Entry fakeProcedure = person.record.procedure(time, code.display);
    fakeProcedure.codes.add(code);
    // it's the same number as above, but a procedure not a medication,
    // so we don't expect the same result
    double cost = Costs.determineCostOfEntry(fakeProcedure, person);
    double expectedCost = Config.getAsDouble("generate.costs.default_procedure_cost");
    // assert the cost is within $0.01
    assertEquals(expectedCost, cost, 0.01);
}
Also used : Entry(org.mitre.synthea.world.concepts.HealthRecord.Entry) Code(org.mitre.synthea.world.concepts.HealthRecord.Code) Test(org.junit.Test)

Example 4 with Entry

use of org.mitre.synthea.world.concepts.HealthRecord.Entry in project synthea by synthetichealth.

the class CostsTest method testSupplyCostByKnownCode.

@Test
public void testSupplyCostByKnownCode() {
    Code code = new Code("SNOMED", "337388004", "Blood glucose testing strips");
    double minCost = 8.32;
    double maxCost = 8.32;
    Entry fakeSupply = person.record.useSupply(time, code, 1);
    fakeSupply.codes.add(code);
    double cost = Costs.determineCostOfEntry(fakeSupply, person);
    // at this point person has no state set, so there won't be a geographic factor applied
    assertTrue(cost <= maxCost);
    assertTrue(cost >= minCost);
    person.attributes.put(Person.STATE, "Massachusetts");
    double adjFactor = 0.8183;
    cost = Costs.determineCostOfEntry(fakeSupply, person);
    assertTrue(cost <= (maxCost * adjFactor));
    assertTrue(cost >= (minCost * adjFactor));
}
Also used : Entry(org.mitre.synthea.world.concepts.HealthRecord.Entry) Code(org.mitre.synthea.world.concepts.HealthRecord.Code) Test(org.junit.Test)

Example 5 with Entry

use of org.mitre.synthea.world.concepts.HealthRecord.Entry in project synthea by synthetichealth.

the class CSVExporter method claim.

/**
 * Write a single claim to claims.csv.
 *
 * @param claim The claim to be exported.
 * @throws IOException if any IO error occurs.
 */
private void claim(RandomNumberGenerator rand, Claim claim, Encounter encounter, String encounterID, long time) throws IOException {
    // Id,PATIENTID,PROVIDERID,PRIMARYPATIENTINSURANCEID,SECONDARYPATIENTINSURANCEID,
    // DEPARTMENTID,PATIENTDEPARTMENTID,DIAGNOSIS1,DIAGNOSIS2,DIAGNOSIS3,DIAGNOSIS4,
    // DIAGNOSIS5,DIAGNOSIS6,DIAGNOSIS7,DIAGNOSIS8,REFERRINGPROVIDERID,APPOINTMENTID,
    // CURRENTILLNESSDATE,SERVICEDATE,SUPERVISINGPROVIDERID,STATUS1,STATUS2,STATUSP,
    // OUTSTANDING1,OUTSTANDING2,OUTSTANDINGP,LASTBILLEDDATE1,LASTBILLEDDATE2,LASTBILLEDDATEP,
    // HEALTHCARECLAIMTYPEID1,HEALTHCARECLAIMTYPEID2
    // Institutional or Professional?
    boolean institutional = true;
    if (encounter.provider != null) {
        institutional = encounter.provider.institutional;
    }
    StringBuilder s = new StringBuilder();
    // Claim Id. Should be a number.
    String claimId = rand.randUUID().toString();
    s.append(claimId).append(',');
    // PATIENTID
    s.append(claim.person.attributes.get(Person.ID)).append(',');
    // Provider, should not be null.
    if (encounter.clinician != null) {
        s.append(encounter.clinician.getResourceID()).append(',');
    } else {
        s.append(',');
    }
    // PRIMARYPATIENTINSURANCEID
    if (encounter.claim.payer == null || encounter.claim.payer == Payer.noInsurance) {
        // 0 == No Insurance
        s.append("0,");
    } else {
        s.append(claim.payer.getResourceID()).append(',');
    }
    // SECONDARYPATIENTINSURANCEID (0 default if none)
    if (encounter.claim.secondaryPayer == null || encounter.claim.secondaryPayer == Payer.noInsurance) {
        s.append("0,");
    } else {
        s.append(claim.secondaryPayer.getResourceID()).append(',');
    }
    // DEPARTMENTID
    String departmentId = claimDepartmentCode(encounter, claim.person);
    s.append(departmentId).append(',');
    s.append(departmentId).append(',');
    // Diagnosis codes and illness onset
    int dxCode = 0;
    Long[] onset = new Long[8];
    String[] diagnosisCodes = new String[8];
    if (encounter.reason != null) {
        diagnosisCodes[dxCode] = encounter.reason.code;
        onset[dxCode] = claim.person.record.presentOnset(diagnosisCodes[dxCode]);
        dxCode++;
    }
    Iterator<HealthRecord.Entry> items = encounter.conditions.iterator();
    while ((dxCode < diagnosisCodes.length) && items.hasNext()) {
        Entry item = items.next();
        diagnosisCodes[dxCode] = item.codes.get(0).code;
        onset[dxCode] = claim.person.record.presentOnset(diagnosisCodes[dxCode]);
        dxCode++;
    }
    if (dxCode == 0) {
        // There must be a diagnosis code, if there aren't any (e.g. wellness visit
        // where nothing is wrong) then add the encounter code.
        diagnosisCodes[dxCode] = encounter.codes.get(0).code;
        onset[dxCode] = claim.person.record.presentOnset(diagnosisCodes[dxCode]);
    }
    for (String diagnosisCode : diagnosisCodes) {
        if (diagnosisCode != null && !diagnosisCode.isEmpty()) {
            s.append(diagnosisCode).append(',');
        } else {
            s.append(',');
        }
    }
    Long onsetIllness = encounter.start;
    for (Long onsetTime : onset) {
        if (onsetTime != null && onsetTime < onsetIllness) {
            onsetIllness = onsetTime;
        }
    }
    // TODO REFERRINGPROVIDERID
    s.append(',');
    // APPOINTMENTID
    s.append(encounterID).append(',');
    // CURRENTILLNESSDATE
    s.append(iso8601Timestamp(onsetIllness)).append(',');
    // SERVICEDATE
    s.append(iso8601Timestamp(encounter.start)).append(',');
    // SUPERVISINGPROVIDERID
    if (encounter.clinician != null) {
        s.append(encounter.clinician.getResourceID()).append(',');
    } else {
        s.append(',');
    }
    if (time > encounter.stop) {
        // STATUS1 for Payer1
        s.append("CLOSED,");
        // STATUS2 for Payer2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            s.append("CLOSED,");
        } else {
            s.append(',');
        }
        // STATUSP for Patient as Payer
        s.append("CLOSED,");
        // OUTSTANDING1
        s.append("0,");
        // OUTSTANDING2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            s.append("0,");
        } else {
            s.append(',');
        }
        // OUTSTANDINGP
        s.append("0,");
        // LASTBILLEDDATE1
        s.append(iso8601Timestamp(encounter.stop)).append(',');
        // LASTBILLEDDATE2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            s.append(iso8601Timestamp(encounter.stop)).append(',');
        } else {
            s.append(',');
        }
        // LASTBILLEDDATEP
        s.append(iso8601Timestamp(encounter.stop)).append(',');
    } else {
        // TODO this may not get triggered
        // STATUS1 for Payer1
        s.append("BILLED,");
        // STATUS2 for Payer2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            s.append("BILLED,");
        } else {
            s.append(',');
        }
        // STATUSP for Patient as Payer
        s.append("BILLED,");
        // OUTSTANDING1 (TODO this should be the outstanding payer balance)
        s.append(String.format(Locale.US, "%.2f", encounter.claim.getCoveredCost())).append(',');
        // OUTSTANDING2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            // TODO this is not correct
            s.append(String.format(Locale.US, "%.2f", encounter.claim.getCoveredCost())).append(',');
        } else {
            s.append(',');
        }
        // OUTSTANDINGP (TODO this should be the outstanding patient balance)
        double patientCost = claim.getTotalClaimCost() - claim.getCoveredCost();
        s.append(String.format(Locale.US, "%.2f", patientCost)).append(',');
        // LASTBILLEDDATE1
        s.append(iso8601Timestamp(encounter.start)).append(',');
        // LASTBILLEDDATE2
        if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
            s.append(iso8601Timestamp(encounter.start)).append(',');
        } else {
            s.append(',');
        }
        // LASTBILLEDDATEP
        s.append(iso8601Timestamp(encounter.start)).append(',');
    }
    // HEALTHCARECLAIMTYPEID1
    if (institutional) {
        s.append("2,");
    } else {
        s.append("1,");
    }
    // HEALTHCARECLAIMTYPEID2
    if (claim.secondaryPayer != null && claim.secondaryPayer != Payer.noInsurance) {
        if (institutional) {
            s.append('2');
        } else {
            s.append('1');
        }
    } else {
        s.append('0');
    }
    s.append(NEWLINE);
    write(s.toString(), claims);
    // Main Claim
    simulateClaimProcess(rand, claim, claimId, encounter, encounterID, claim.mainEntry, diagnosisCodes, departmentId, true);
    // Each Entry...
    for (int i = 0; i < claim.items.size(); i++) {
        Claim.ClaimEntry claimEntry = claim.items.get(i);
        Entry entry = claimEntry.entry;
        if ((entry instanceof HealthRecord.Procedure) || (entry instanceof HealthRecord.Immunization) || (entry instanceof HealthRecord.Medication)) {
            simulateClaimProcess(rand, claim, claimId, encounter, encounterID, claimEntry, diagnosisCodes, departmentId, false);
        }
    }
}
Also used : Procedure(org.mitre.synthea.world.concepts.HealthRecord.Procedure) Entry(org.mitre.synthea.world.concepts.HealthRecord.Entry) HealthRecord(org.mitre.synthea.world.concepts.HealthRecord) AtomicLong(java.util.concurrent.atomic.AtomicLong) Medication(org.mitre.synthea.world.concepts.HealthRecord.Medication) Claim(org.mitre.synthea.world.concepts.Claim)

Aggregations

Entry (org.mitre.synthea.world.concepts.HealthRecord.Entry)19 Code (org.mitre.synthea.world.concepts.HealthRecord.Code)11 Test (org.junit.Test)7 Encounter (org.mitre.synthea.world.concepts.HealthRecord.Encounter)7 Procedure (org.mitre.synthea.world.concepts.HealthRecord.Procedure)7 ArrayList (java.util.ArrayList)6 Medication (org.mitre.synthea.world.concepts.HealthRecord.Medication)6 CarePlan (org.mitre.synthea.world.concepts.HealthRecord.CarePlan)3 File (java.io.File)2 Path (java.nio.file.Path)2 LinkedList (java.util.LinkedList)2 HealthRecord (org.mitre.synthea.world.concepts.HealthRecord)2 ImagingStudy (org.mitre.synthea.world.concepts.HealthRecord.ImagingStudy)2 Observation (org.mitre.synthea.world.concepts.HealthRecord.Observation)2 Report (org.mitre.synthea.world.concepts.HealthRecord.Report)2 JsonObject (com.google.gson.JsonObject)1 Template (freemarker.template.Template)1 TemplateException (freemarker.template.TemplateException)1 StringWriter (java.io.StringWriter)1 BigDecimal (java.math.BigDecimal)1