Contract + Rates History: History log
```typescript!
type OldContractType = {
id?: string,
status?: statusSchema,
stateCode?: string,
mccrsID?: string,
stateNumber: number,
// This is a draft contract revision, if the status of
// the contract is draft, then this field will have data.
draftRevision?: ContractRevisionWithRatesType,
// These are all the submitted revisions on the contract. The original plan was to make this into the history of the contract. On a SUBMITTED or RESUBMITTED contract, the first (latest) revision would be used to display the summary pages.
revisions: ContractRevisionWithRatesType[]
}
type ContractRevisionWithRatesType = {
id: string,
contract: {
id: string,
stateCode: string,
stateNumber: number,
},
submitInfo?: UpdateInfoType,
unlockInfo?: UpdateInfoType,
createdAt: Date,
updatedAt: Date,
formData: ContractFormDataType,
rateRevisions: RateRevisionType
}
type RateRevisionWithContractsType = {
id: string,
rate: {
id: string,
stateCode: string,
stateNumber: number,
createdAt: Date,
},
submitInfo?: UpdateInfoType,
unlockInfo?: UpdateInfoType,
createdAt: Date,
updatedAt: Date,
formData: ContractFormDataType,
contractRevisions: ContractRevisionType
}
// This interface is used in contractWithHistoryToDomainModel to build the data object that we then turn into contract.revisions
interface ContractRevisionSet {
contractRev: ContractRevisionTableWithFormData
submitInfo: UpdateInfoTableWithUpdater
unlockInfo: UpdateInfoTableWithUpdater | undefined
rateRevisions: RateRevisionTableWithFormData[]
}
/**
* For contract history we would re-implement MacRae's work in contractWithHistoryToDomainModel that was commentted out.
*
* The issue we had with his implemenatin was that every rate change was also pushed into contract.revisions as a ContractRevisionWithRatesType using the same contract data that the rate change belong to. This resulted in contract.revisions having duplicate contractRevisions with different rate data.
*
* This caused issues with the frontend apollo cache because we used duplicate contract revision ids to create new revisions for rate changes. The cache uses the id to identify which records in the cache to update. This overwrote the history.
*
* I think using that same implementation will work, instead of using ContractRevisionSet to build contract.revision we just push the ContractRevison and RateRevision in. We also change the field contract.revisions to contract.history or add the new history field to the contract type.
*
* My thought is that the backend shouldn't be in charge of building a change history. The backend should collect all the data needed to display it and leave it to the frontend to figure out how to display the data.
*
* UI can change on the fly, but if our data is complete we wont have to change the API.
**/
type NewContractType = {
id?: string,
status?: statusSchema,
stateCode?: string,
mccrsID?: string,
stateNumber: number,
draftRevision?: ContractRevisionWithRatesType[],,
revisions: ContractRevisionWithRatesType[],
history: History[]
}
type History = (ContractRevisionWithRatesType | RateRevisionWithContractsType) []
/**
* There are some key events we will need to show on the history from the Submission summary history. I like to think of it as history from the contract persepctive.
* - submit contract
* - unlock contract
* - updateRate
* - unlock Rate
* - submit Rate
*
* Since we create a new revision for any unlock or submit of a contract or a rate we should have a record for every change for both. The two question we need to figure out are:
* How do we order contract.history?
* - We can order by submit info for each record in the history.
* - When rates and contracts are submitted together the dates will be the same. We can leave how to interpret this to the frontend.
*
* How do we figure out when a rate is linked or unlinked?
* - This is strictly a UI change history we need to display
* - We know a rate has to be created along with a contract (unless the UI changes). So the earliest rateRevision's connected contractRevision from the join table would be the contract that this rate was created from.
* - When we use "includeRateFormData" query for the rateRevision on a contractRevision we could also have it include the first contractRevision on the rate.
**/
const includeRateFormData = {
submitInfo: includeUpdateInfo,
unlockInfo: includeUpdateInfo,
rate: {
include: {
revisions: {
orderBy: {
createdAt: 'asc'
},
take: 1
}
}
},
...
/**
*
**/
```
Implementation Details
- Add a new function to parse out history to add to ContractType in the `history` field.
- This could be place in `contractWithHistoryToDomainModel`
- Update DomainTypes and GraphQL types with `history` (if protos still exist, we will have to add `history` to protos).
- Refactor frontend change history UI to use `contract.history` instead of `contract.revision`
Pros
- No database changes.
- Little impact to Types
- (I think) Implementaion would be fast since there is no changes to the DB and this new field has little effect on other data.
- Errors in parsing out history could be quickly fixed without migrations.
- Flexable if we need to make changes or add new actions to the history.
Cons
- A lot of brittle code that has to parse a lot of data
- Hard to understand how to parse data into a history.
- Finding linked rates would be diffcult.
Q
* Maybe we just compute this, we know rate entries in the table are updates to one of the rates for this contract.
* can we trust the status of the thing more, rn the FE is double checking the revisions list as a source of truth,
* Also possible to keep history parallel to revisions.