Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into mcr-4052-reimplmenet-…
Browse files Browse the repository at this point in the history
…unlock
  • Loading branch information
haworku committed Apr 24, 2024
2 parents a4403ee + 254a6c7 commit 2d107f9
Show file tree
Hide file tree
Showing 25 changed files with 1,412 additions and 361 deletions.
111 changes: 65 additions & 46 deletions services/app-api/src/postgres/contractAndRates/unlockContract.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,13 @@ type UnlockContractArgsType = {
// * set relationships based on last submission
async function unlockContract(
client: PrismaClient,
args: UnlockContractArgsType
args: UnlockContractArgsType,
linkRatesFF?: boolean
): Promise<ContractType | NotFoundError | Error> {
const { contractID, unlockedByUserID, unlockReason } = args

try {
return await client.$transaction(async (tx) => {
// This finds the child rates for this submission.
// A child rate is a rate that shares a submit info with this contract.
// technically only a rate that is _initially_ submitted with a contract
// is a child rate, but we should never allow re-submission so this simpler
// query that doesn't try to filter to initial revisions works.
const childRates = await tx.rateTable.findMany({
where: {
revisions: {
some: {
submitInfo: {
submittedContracts: {
some: {
contractID: contractID,
},
},
},
},
},
},
})

const currentDateTime = new Date()
// create the unlock info to be shared across all submissions.
const unlockInfo = await tx.updateInfoTable.create({
Expand All @@ -53,18 +33,6 @@ async function unlockContract(
},
})

// unlock child rates with that unlock info
for (const childRate of childRates) {
const unlockRate = await unlockRateInDB(
tx,
childRate.id,
unlockInfo.id
)
if (unlockRate instanceof Error) {
throw unlockRate
}
}

// get the last submitted rev in order to unlock it
const currentRev = await tx.contractRevisionTable.findFirst({
where: {
Expand Down Expand Up @@ -132,19 +100,70 @@ async function unlockContract(
)
}

const previouslySubmittedRateIDs = currentRev.rateRevisions.map(
(c) => c.rateRevision.rateID
)
const childRateIDs: string[] = []
if (linkRatesFF) {
// This finds the child rates for this submission.
// A child rate is a rate that shares a submit info with this contract.
// technically only a rate that is _initially_ submitted with a contract
// is a child rate, but we should never allow re-submission so this simpler
// query that doesn't try to filter to initial revisions works.
const childRates = await tx.rateTable.findMany({
where: {
revisions: {
some: {
submitInfo: {
submittedContracts: {
some: {
contractID: contractID,
},
},
},
},
},
},
})

for (const childRate of childRates) {
childRateIDs.push(childRate.id)
}
} else {
// without linked rates, we push all the valid rate revisions attached to the contract revision
for (const rrev of currentRev.rateRevisions) {
childRateIDs.push(rrev.rateRevision.rateID)
}
}

// find the rates in the last submission package:
const lastSubmission = currentRev.relatedSubmisions[0]
const thisContractsRatePackages =
lastSubmission.submissionPackages.filter(
(p) => p.contractRevisionID === currentRev.id
// unlock child rates with that unlock info
for (const childRateID of childRateIDs) {
const unlockRate = await unlockRateInDB(
tx,
childRateID,
unlockInfo.id,
linkRatesFF
)
const relatedRateIDs = thisContractsRatePackages.map(
(p) => p.rateRevision.rateID
)
if (unlockRate instanceof Error) {
throw unlockRate
}
}

const relatedRateIDs: string[] = []
if (linkRatesFF) {
// find the rates in the last submission package:
const lastSubmission = currentRev.relatedSubmisions[0]
const thisContractsRatePackages =
lastSubmission.submissionPackages.filter(
(p) => p.contractRevisionID === currentRev.id
)

for (const ratePackage of thisContractsRatePackages) {
relatedRateIDs.push(ratePackage.rateRevision.rateID)
}
} else {
for (const rateRev of currentRev.rateRevisions) {
relatedRateIDs.push(rateRev.rateRevision.rateID)
}
}

await tx.contractRevisionTable.create({
data: {
contract: {
Expand All @@ -156,7 +175,7 @@ async function unlockContract(
connect: { id: unlockInfo.id },
},
draftRates: {
connect: previouslySubmittedRateIDs.map((cID) => ({
connect: relatedRateIDs.map((cID) => ({
id: cID,
})),
},
Expand Down
41 changes: 24 additions & 17 deletions services/app-api/src/postgres/contractAndRates/unlockRate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ type UnlockRateArgsType = {
async function unlockRateInDB(
tx: PrismaTransactionType,
rateID: string,
unlockInfoID: string
unlockInfoID: string,
linkRatesFF?: boolean
): Promise<string | Error> {
// find the current rate revision in order to create a new unlocked revision
const currentRev = await tx.rateRevisionTable.findFirst({
Expand Down Expand Up @@ -87,6 +88,8 @@ async function unlockRateInDB(
)
}

// old way to find connected contracts
//TODO: with linked rates on, find them via package submission
const previouslySubmittedContractIDs = currentRev.contractRevisions.map(
(c) => c.contractRevision.contractID
)
Expand Down Expand Up @@ -177,25 +180,29 @@ async function unlockRateInDB(
},
})

// add DraftContract connections to the Rate
const lastSubmission = currentRev.relatedSubmissions[0]
const submissionConnections = lastSubmission.submissionPackages.filter(
(p) => p.rateRevisionID === currentRev.id
)
const newDraftConnections = []
for (const submissionConnection of submissionConnections) {
newDraftConnections.push({
contractID: submissionConnection.contractRevision.contractID,
rateID: currentRev.rateID,
ratePosition: submissionConnection.ratePosition,
// Unlock rate will only ever by run after the linked rates FF is enabled
// we only need to set draft rates explicitly in that case, when doing a rate
// unlock UNDER a contract unlock, the contract will set the draft rates correctly.
if (linkRatesFF) {
// add DraftContract connections to the Rate
const lastSubmission = currentRev.relatedSubmissions[0]
const submissionConnections = lastSubmission.submissionPackages.filter(
(p) => p.rateRevisionID === currentRev.id
)
const newDraftConnections = []
for (const submissionConnection of submissionConnections) {
newDraftConnections.push({
contractID: submissionConnection.contractRevision.contractID,
rateID: currentRev.rateID,
ratePosition: submissionConnection.ratePosition,
})
}
await tx.draftRateJoinTable.createMany({
data: newDraftConnections,
skipDuplicates: true,
})
}

await tx.draftRateJoinTable.createMany({
data: newDraftConnections,
skipDuplicates: true,
})

return currentRev.id
}

Expand Down
6 changes: 4 additions & 2 deletions services/app-api/src/postgres/postgresStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,8 @@ type Store = {
submitRate: (args: SubmitRateArgsType) => Promise<RateType | Error>

unlockContract: (
args: UnlockContractArgsType
args: UnlockContractArgsType,
linkRatesFF?: boolean
) => Promise<ContractType | Error>

unlockRate: (args: UnlockRateArgsType) => Promise<RateType | Error>
Expand Down Expand Up @@ -189,7 +190,8 @@ function NewPostgresStore(client: PrismaClient): Store {
findAllRatesWithHistoryBySubmitInfo(client),
submitContract: (args) => submitContract(client, args),
submitRate: (args) => submitRate(client, args),
unlockContract: (args) => unlockContract(client, args),
unlockContract: (args, linkRatesFF) =>
unlockContract(client, args, linkRatesFF),
unlockRate: (args) => unlockRate(client, args),
}
}
Expand Down
3 changes: 2 additions & 1 deletion services/app-api/src/resolvers/configureResolvers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ export function configureResolvers(
unlockHealthPlanPackage: unlockHealthPlanPackageResolver(
store,
emailer,
emailParameterStore
emailParameterStore,
launchDarkly
),
updateContract: updateContract(store),
updateDraftContractRates: updateDraftContractRates(store),
Expand Down
30 changes: 27 additions & 3 deletions services/app-api/src/resolvers/contract/submitContract.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -646,11 +646,19 @@ describe('submitContract', () => {
})

it('handles unlock and editing rates', async () => {
const stateServer = await constructTestPostgresServer()
const ldService = testLDService({
'link-rates': true,
'rate-edit-unlock': true,
})
const stateServer = await constructTestPostgresServer({
ldService,
})

const cmsServer = await constructTestPostgresServer({
context: {
user: testCMSUser(),
},
ldService,
})

console.info('1.')
Expand Down Expand Up @@ -724,11 +732,19 @@ describe('submitContract', () => {
})

it('checks parent rates on update', async () => {
const stateServer = await constructTestPostgresServer()
const ldService = testLDService({
'link-rates': true,
'rate-edit-unlock': true,
})
const stateServer = await constructTestPostgresServer({
ldService,
})

const cmsServer = await constructTestPostgresServer({
context: {
user: testCMSUser(),
},
ldService,
})

console.info('1.')
Expand Down Expand Up @@ -833,11 +849,19 @@ describe('submitContract', () => {

it('can remove a child unlocked rate', async () => {
//TODO: make a child rate, submit and unlock, then remove it.
const stateServer = await constructTestPostgresServer()
const ldService = testLDService({
'link-rates': true,
'rate-edit-unlock': true,
})
const stateServer = await constructTestPostgresServer({
ldService,
})

const cmsServer = await constructTestPostgresServer({
context: {
user: testCMSUser(),
},
ldService,
})

console.info('1.')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,22 @@ import {
} from '../attributeHelper'
import type { EmailParameterStore } from '../../parameterStore'
import { GraphQLError } from 'graphql'
import type { LDService } from '../../launchDarkly/launchDarkly'

// unlockHealthPlanPackageResolver is a state machine transition for HealthPlanPackage
export function unlockHealthPlanPackageResolver(
store: Store,
emailer: Emailer,
emailParameterStore: EmailParameterStore
emailParameterStore: EmailParameterStore,
launchDarkly: LDService
): MutationResolvers['unlockHealthPlanPackage'] {
return async (_parent, { input }, context) => {
const { user, span } = context
const { unlockedReason, pkgID } = input
setResolverDetailsOnActiveSpan('unlockHealthPlanPackage', user, span)
span?.setAttribute('mcreview.package_id', pkgID)
const featureFlags = await launchDarkly.allFlags(context)
const linkRatesFF = featureFlags?.['link-rates'] === true

// This resolver is only callable by CMS users
if (!isCMSUser(user)) {
Expand Down Expand Up @@ -81,11 +85,14 @@ export function unlockHealthPlanPackageResolver(
}

// Now, unlock the contract!
const unlockContractResult = await store.unlockContract({
contractID: contract.id,
unlockReason: unlockedReason,
unlockedByUserID: user.id,
})
const unlockContractResult = await store.unlockContract(
{
contractID: contract.id,
unlockReason: unlockedReason,
unlockedByUserID: user.id,
},
linkRatesFF
)
if (unlockContractResult instanceof Error) {
const errMessage = `Failed to unlock contract revision with ID: ${contract.id}; ${unlockContractResult.message}`
logError('unlockHealthPlanPackage', errMessage)
Expand Down
Loading

0 comments on commit 2d107f9

Please sign in to comment.