Skip to content

Commit

Permalink
Add update new DB contracts rates and tests for flag on and off.
Browse files Browse the repository at this point in the history
  • Loading branch information
JasonLin0991 committed Sep 7, 2023
1 parent 11992ba commit 6eed285
Show file tree
Hide file tree
Showing 2 changed files with 285 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ import { testCMSUser, testStateUser } from '../../testHelpers/userHelpers'
import type {
FeatureFlagLDConstant,
FlagValue,
} from 'app-web/src/common-code/featureFlags'
} from '../../../../app-web/src/common-code/featureFlags'
import { testLDService } from '../../testHelpers/launchDarklyHelpers'
import { must } from '../../testHelpers'
import { getProgramsFromState, must } from '../../testHelpers'
import { submitContract } from '../../postgres/contractAndRates/submitContract'
import type { HealthPlanFormDataType } from 'app-web/src/common-code/healthPlanFormDataType'
import type {
HealthPlanFormDataType,
RateInfoType,
StateCodeType,
} from 'app-web/src/common-code/healthPlanFormDataType'
import * as add_sha from '../../handlers/add_sha'

const flagValueTestParameters: {
flagName: FeatureFlagLDConstant
Expand All @@ -49,6 +54,13 @@ describe.each(flagValueTestParameters)(
const cmsUser = testCMSUser()
const mockLDService = testLDService({ [flagName]: flagValue })

beforeEach(() => {
jest.resetAllMocks()
jest.spyOn(add_sha, 'calculateSHA256').mockImplementation(() => {
return Promise.resolve('mockSHA256')
})
})

it('updates valid scalar fields in the formData', async () => {
const server = await constructTestPostgresServer({
ldService: mockLDService,
Expand Down Expand Up @@ -126,6 +138,209 @@ describe.each(flagValueTestParameters)(
)
})

it('creates, updates, and deletes rates in the contract', async () => {
const server = await constructTestPostgresServer({
ldService: mockLDService,
})
const createdDraft = await createTestHealthPlanPackage(server)
const ratePrograms = getProgramsFromState(
createdDraft.stateCode as StateCodeType
)

// Create 2 rate data for insertion
const rate1: RateInfoType = {
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
rateDocuments: [
{
name: 'rateDocument.pdf',
s3URL: 's3://bucketname/key/supporting-documents',
documentCategories: ['RATES' as const],
sha256: 'rate1-sha',
},
],
rateAmendmentInfo: undefined,
rateCapitationType: undefined,
rateCertificationName: undefined,
supportingDocuments: [],
//We only want one rate ID and use last program in list to differentiate from programID if possible.
rateProgramIDs: [ratePrograms.reverse()[0].id],
actuaryContacts: [
{
name: 'test name',
titleRole: 'test title',
email: 'email@example.com',
actuarialFirm: 'MERCER' as const,
actuarialFirmOther: '',
},
],
packagesWithSharedRateCerts: [],
}

const rate2 = {
rateType: 'NEW' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
rateDocuments: [
{
name: 'rateDocument.pdf',
s3URL: 's3://bucketname/key/supporting-documents',
documentCategories: ['RATES' as const],
sha256: 'rate2-sha',
},
],
rateAmendmentInfo: undefined,
rateCapitationType: undefined,
rateCertificationName: undefined,
supportingDocuments: [],
//We only want one rate ID and use last program in list to differentiate from programID if possible.
rateProgramIDs: [ratePrograms.reverse()[0].id],
actuaryContacts: [
{
name: 'test name',
titleRole: 'test title',
email: 'email@example.com',
actuarialFirm: 'MERCER' as const,
actuarialFirmOther: '',
},
],
packagesWithSharedRateCerts: [],
}

// update that draft form data.
const formData: HealthPlanFormDataType = Object.assign(
latestFormData(createdDraft),
{
rateInfos: [rate1, rate2],
}
)

// convert to base64 proto
const updatedB64 = domainToBase64(formData)

// update the DB contract
const updateResult = await server.executeOperation({
query: UPDATE_HEALTH_PLAN_FORM_DATA,
variables: {
input: {
pkgID: createdDraft.id,
healthPlanFormData: updatedB64,
},
},
})

expect(updateResult.errors).toBeUndefined()

const updatedHealthPlanPackage =
updateResult.data?.updateHealthPlanFormData.pkg

const updatedFormData = latestFormData(updatedHealthPlanPackage)

// Expect our rates to be in the contract from our database
expect(updatedFormData).toEqual(
expect.objectContaining({
...formData,
updatedAt: expect.any(Date),
rateInfos: expect.arrayContaining([
expect.objectContaining({
...rate1,
id: expect.any(String),
rateCertificationName: expect.any(String),
}),
expect.objectContaining({
...rate2,
id: expect.any(String),
rateCertificationName: expect.any(String),
}),
]),
})
)

const rate3 = {
rateType: 'AMENDMENT' as const,
rateDateStart: new Date(Date.UTC(2025, 5, 1)),
rateDateEnd: new Date(Date.UTC(2026, 4, 30)),
rateDateCertified: new Date(Date.UTC(2025, 3, 15)),
rateDocuments: [],
rateAmendmentInfo: undefined,
rateCapitationType: undefined,
rateCertificationName: undefined,
supportingDocuments: [],
//We only want one rate ID and use last program in list to differentiate from programID if possible.
rateProgramIDs: [ratePrograms.reverse()[0].id],
actuaryContacts: [],
packagesWithSharedRateCerts: [],
}

// Update first rate and remove second from contract and add a new rate.
const formData2: HealthPlanFormDataType = Object.assign(
latestFormData(updatedHealthPlanPackage),
{
rateInfos: [
// updating the actuary on the first rate
{
...updatedFormData.rateInfos[0],
actuaryContacts: [
{
name: 'New actuary',
titleRole: 'Better title',
email: 'actuary@example.com',
actuarialFirm: 'OPTUMAS' as const,
actuarialFirmOther: '',
},
],
},
{
...rate3,
},
],
}
)

const secondUpdatedB64 = domainToBase64(formData2)

// update the DB contract again
const updateResult2 = await server.executeOperation({
query: UPDATE_HEALTH_PLAN_FORM_DATA,
variables: {
input: {
pkgID: createdDraft.id,
healthPlanFormData: secondUpdatedB64,
},
},
})

expect(updateResult2.errors).toBeUndefined()

const updatedHealthPlanPackage2 =
updateResult2.data?.updateHealthPlanFormData.pkg

const updatedFormData2 = latestFormData(updatedHealthPlanPackage2)

// Expect our rates to be updated
expect(updatedFormData2).toEqual(
expect.objectContaining({
...formData2,
updatedAt: expect.any(Date),
rateInfos: expect.arrayContaining([
expect.objectContaining({
...formData2.rateInfos[0],
id: expect.any(String),
rateCertificationName: expect.any(String),
}),
expect.objectContaining({
...formData2.rateInfos[1],
id: expect.any(String),
rateCertificationName: expect.any(String),
}),
]),
})
)
})

it('updates relational fields such as documents and contacts', async () => {
const server = await constructTestPostgresServer({
ldService: mockLDService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ import {
} from '../attributeHelper'
import type { LDService } from '../../launchDarkly/launchDarkly'
import { GraphQLError } from 'graphql/index'
import { convertSortToDomainRate } from './contractAndRates/resolverHelpers'
import type {
ContractType,
DraftContractType,
} from '../../domain-models/contractAndRates'

type ProtectedFieldType = Pick<
UnlockedHealthPlanFormDataType,
Expand Down Expand Up @@ -181,38 +186,69 @@ export function updateHealthPlanFormDataResolver(
throw new UserInputError(errMessage)
}

// Update contract draft revision
const updateResult = await store.updateDraftContract({
contractID: input.pkgID,
formData: {
...unlockedFormData,
...unlockedFormData.contractAmendmentInfo
?.modifiedProvisions,
managedCareEntities: unlockedFormData.managedCareEntities,
stateContacts: unlockedFormData.stateContacts,
supportingDocuments: unlockedFormData.documents.map(
(doc) => {
return {
name: doc.name,
s3URL: doc.s3URL,
sha256: doc.sha256,
id: doc.id,
}
}
),
contractDocuments: unlockedFormData.contractDocuments.map(
(doc) => {
return {
name: doc.name,
s3URL: doc.s3URL,
sha256: doc.sha256,
id: doc.id,
// Check for any rate updates
const updateDraftContractRates = await convertSortToDomainRate(
contractWithHistory as DraftContractType,
unlockedFormData
)

if (updateDraftContractRates instanceof Error) {
const errMessage = `Error converting rate. Message: ${updateDraftContractRates.message}`
logError('updateHealthPlanFormData', errMessage)
setErrorAttributesOnActiveSpan(errMessage, span)
throw new GraphQLError(errMessage, {
extensions: {
code: 'INTERNAL_SERVER_ERROR',
},
})
}

const shouldUpdateRates =
updateDraftContractRates.updateRateRevisions?.length ||
updateDraftContractRates.connectOrCreate?.length ||
updateDraftContractRates.disconnectRates?.length

let updateResult: ContractType | Error

// Update if there are rates to update else update contract only
// No way of updating rates and contract data at the same time currently
if (shouldUpdateRates) {
updateResult = await store.updateDraftContractRates(
updateDraftContractRates
)
} else {
// Update contract draft revision
updateResult = await store.updateDraftContract({
contractID: input.pkgID,
formData: {
...unlockedFormData,
...unlockedFormData.contractAmendmentInfo
?.modifiedProvisions,
managedCareEntities:
unlockedFormData.managedCareEntities,
stateContacts: unlockedFormData.stateContacts,
supportingDocuments: unlockedFormData.documents.map(
(doc) => {
return {
name: doc.name,
s3URL: doc.s3URL,
sha256: doc.sha256,
id: doc.id,
}
}
}
),
// TODO - can add rate fields here when updateHPP handles rates as well
},
})
),
contractDocuments:
unlockedFormData.contractDocuments.map((doc) => {
return {
name: doc.name,
s3URL: doc.s3URL,
sha256: doc.sha256,
id: doc.id,
}
}),
},
})
}

if (updateResult instanceof Error) {
const errMessage = `Error updating form data: ${input.pkgID}:: ${updateResult.message}`
Expand Down

0 comments on commit 6eed285

Please sign in to comment.