Skip to content

Commit

Permalink
Merge branch 'master' into aea-3936-update-epsat-default-nomnated-pha…
Browse files Browse the repository at this point in the history
…rmacy
  • Loading branch information
JackSpagnoliNHS authored Sep 18, 2024
2 parents 82afdd1 + 417be9c commit 5ceaec3
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 15 deletions.
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion packages/coordinator/src/services/validation/claim-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ export function verifyClaim(
return [errors.createResourceTypeIssue("Claim")]
}

const incorrectValueErrors = []
const incorrectValueErrors: Array<fhir.OperationOutcomeIssue> = []

validateReimbursementAuthority(claim, incorrectValueErrors)

const practitionerRole = getContainedPractitionerRoleViaReference(
claim,
Expand Down Expand Up @@ -69,3 +71,22 @@ export function verifyClaim(

return incorrectValueErrors
}

function validateReimbursementAuthority(claim: fhir.Claim, incorrectValueErrors: Array<fhir.OperationOutcomeIssue>) {
const insurance = claim.insurance
if (insurance.length !== 1) {
incorrectValueErrors.push(
errors.invalidArrayLengthIssue("Claim.insurance", insurance.length, 1)
)
return
}

const authority = insurance[0].coverage.identifier.value

const approvedAuthorities = ["T1450", "RQFZ1"]
if (!approvedAuthorities.includes(authority)) {
incorrectValueErrors.push(
errors.createClaimInvalidValueIssue("insurance[0].coverage.identifier.value", ...approvedAuthorities)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,88 @@ describe("verifyClaim", () => {
const result = verifyClaim(invalidClaim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0].diagnostics).toEqual("The claim is missing the required endorsement code.")
})

test("accepts a claim against NHS BSA (T1450)", () => {
const claim = {...validClaim}
claim.insurance[0].coverage = coverageWithValue("T1450")

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result).toHaveLength(0)
})

test("accepts a claim against NWSSP (RQFZ1)", () => {
const claim = {...validClaim}
claim.insurance[0].coverage = coverageWithValue("RQFZ1")

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result).toHaveLength(0)
})

test("raise an error if the claim is not against NHS BSA or NWSSP", () => {
const claim = {...validClaim}
claim.insurance[0].coverage = coverageWithValue("invalid")

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0]).toEqual({
severity: "error",
code: "value",
diagnostics: "Claim.insurance[0].coverage.identifier.value must be one of: 'T1450', 'RQFZ1'.",
expression: ["Claim.insurance[0].coverage.identifier.value"]
})
})

test("raise an error if no insurance is provided in the claim", () => {
const claim = {...validClaim}
claim.insurance = []

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0]).toEqual(arrayLengthError(0))
})

test("raise an error if more than one insurance is provided in the claim", () => {
const claim = {...validClaim}
claim.insurance = [claim.insurance[0], claim.insurance[0]]

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0]).toEqual(arrayLengthError(2))
})

test("raise an error if BSA ODS is lowercase", () => {
const claim = {...validClaim}
claim.insurance[0].coverage = coverageWithValue("t1450")

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0]).toEqual({
severity: "error",
code: "value",
diagnostics: "Claim.insurance[0].coverage.identifier.value must be one of: 'T1450', 'RQFZ1'.",
expression: ["Claim.insurance[0].coverage.identifier.value"]
})
})

test("raise an error if NWSSP ODS is lowercase", () => {
const claim = {...validClaim}
claim.insurance[0].coverage = coverageWithValue("rqfz1")

const result = verifyClaim(claim, DISPENSING_USER_SCOPE, "test_sds_user_id", "test_sds_role_id")
expect(result[0]).toEqual({
severity: "error",
code: "value",
diagnostics: "Claim.insurance[0].coverage.identifier.value must be one of: 'T1450', 'RQFZ1'.",
expression: ["Claim.insurance[0].coverage.identifier.value"]
})
})
})

const arrayLengthError = (length: number) => ({
severity: "error",
code: "invalid",
diagnostics: `Expected 1 item(s) in Claim.insurance, but received ${length}.`
})

const coverageWithValue = (value: string) => ({
identifier: {
system: "https://fhir.nhs.uk/Id/ods-organization-code",
value: value
}
})
24 changes: 24 additions & 0 deletions packages/models/errors/validation-errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,27 @@ export function createMissingDosageSequenceInstructions(): fhir.OperationOutcome
}
}
}

export function invalidArrayLengthIssue(
fhirPath: string,
actualLength: number,
expectedLength: number
): fhir.OperationOutcomeIssue {
return {
severity: "error",
code: fhir.IssueCodes.INVALID,
diagnostics: `Expected ${expectedLength} item(s) in ${fhirPath}, but received ${actualLength}.`
}
}

export function createClaimInvalidValueIssue(
fieldName: string,
...allowedFieldValues: Array<string>
): fhir.OperationOutcomeIssue {
return {
severity: "error",
code: fhir.IssueCodes.VALUE,
diagnostics: `Claim.${fieldName} must be one of: ${allowedFieldValues.map(v => "'" + v + "'").join(", ")}.`,
expression: [`Claim.${fieldName}`]
}
}
2 changes: 1 addition & 1 deletion packages/tool/site/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@types/crypto-js": "^4.2.2",
"@types/fhir": "^0.0.41",
"@types/pretty": "^2.0.3",
"@types/react": "^18.3.6",
"@types/react": "^18.3.7",
"@types/react-dom": "^18.3.0",
"@types/uuid": "^10.0.0",
"@types/webpack": "^5.28.5",
Expand Down
16 changes: 8 additions & 8 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ semver = "^3.0.2"
gitpython = "^3.1.43"
pytest = "^8.3.3"
requests = "^2.32.3"
boto3 = "^1.35.19"
boto3 = "^1.35.21"
argparse = "^1.4.0"
pre-commit = "^3.5.0"

Expand Down

0 comments on commit 5ceaec3

Please sign in to comment.