diff --git a/app/components/Form/ProjectMilestoneReportFormSummary.tsx b/app/components/Form/ProjectMilestoneReportFormSummary.tsx index 0c8832c257..9d87560c20 100644 --- a/app/components/Form/ProjectMilestoneReportFormSummary.tsx +++ b/app/components/Form/ProjectMilestoneReportFormSummary.tsx @@ -105,9 +105,44 @@ const ProjectMilestoneReportFormSummary: React.FC = ({ // Set the formSchema and formData based on showing the diff or not const milestoneFormDiffObject = renderDiff ? getMilestoneFilteredSchema( - milestoneReport.formByJsonSchemaName.jsonSchema - .schema as JSONSchema7, - milestoneReport + { + ...(milestoneReport.formByJsonSchemaName.jsonSchema + .schema as JSONSchema7), + properties: { + ...( + milestoneReport.formByJsonSchemaName.jsonSchema + .schema as JSONSchema7 + ).properties, + ...(milestoneReport.newFormData.calculatedHoldbackAmount !== + null + ? { + calculatedHoldbackAmount: { + title: "Holdback Amount This Milestone", + type: "number", + }, + } + : {}), + ...(milestoneReport.newFormData.calculatedGrossAmount !== null + ? { + calculatedGrossAmount: { + title: "Gross Payment Amount This Milestone", + type: "number", + }, + } + : {}), + ...(milestoneReport.newFormData.calculatedNetAmount !== null + ? { + calculatedNetAmount: { + title: "Net Payment Amount This Milestone", + type: "number", + }, + } + : {}), + }, + }, + { + ...milestoneReport, + } ) : { formSchema: milestoneReport.formByJsonSchemaName.jsonSchema.schema, @@ -131,6 +166,43 @@ const ProjectMilestoneReportFormSummary: React.FC = ({ } )?.node?.newFormData; + const updatedUiSchema = { + ...projectMilestoneUiSchema, + calculatedHoldbackAmount: { + "ui:widget": "NumberWidget", + hideOptional: true, + isMoney: true, + }, + calculatedGrossAmount: { + "ui:widget": "NumberWidget", + hideOptional: true, + isMoney: true, + }, + calculatedNetAmount: { + "ui:widget": "NumberWidget", + hideOptional: true, + isMoney: true, + }, + }; + + // Clone milestoneFormDiffObject and overwrite the titles + const titleMap = { + adjustedGrossAmount: "Gross Payment Amount This Milestone (Adjusted)", + adjustedNetAmount: "Net Payment Amount This Milestone (Adjusted)", + adjustedHoldBackAmount: "Holdback Amount This Milestone (Adjusted)", + }; + const clonedMilestoneFormDiffObject = JSON.parse( + JSON.stringify(milestoneFormDiffObject) + ); + Object.entries(titleMap).forEach(([key, title]) => { + if ( + clonedMilestoneFormDiffObject.formData[key] !== null && + clonedMilestoneFormDiffObject.formSchema.properties[key] + ) { + clonedMilestoneFormDiffObject.formSchema.properties[key].title = + title; + } + }); return (
@@ -160,8 +232,8 @@ const ProjectMilestoneReportFormSummary: React.FC = ({ tagName={"dl"} theme={readOnlyTheme} fields={renderDiff ? customFields : fields} - schema={milestoneFormDiffObject.formSchema as JSONSchema7} - uiSchema={projectMilestoneUiSchema} + schema={clonedMilestoneFormDiffObject.formSchema as JSONSchema7} + uiSchema={updatedUiSchema} formData={milestoneFormDiffObject.formData} formContext={{ operation: milestoneReport.operation, @@ -184,6 +256,7 @@ const ProjectMilestoneReportFormSummary: React.FC = ({ }, [ isFirstRevision, isOnAmendmentsAndOtherRevisionsPage, + latestCommittedMilestoneFormChanges?.edges, renderDiff, sortedMilestoneReports, ]); diff --git a/app/cypress/e2e/cif/project-revision/create-first-project-revision.cy.js b/app/cypress/e2e/cif/project-revision/create-first-project-revision.cy.js index c0b8ae4059..007ecbcf10 100644 --- a/app/cypress/e2e/cif/project-revision/create-first-project-revision.cy.js +++ b/app/cypress/e2e/cif/project-revision/create-first-project-revision.cy.js @@ -104,6 +104,13 @@ describe("when creating a project, the project page", () => { ); cy.contains("Changes saved").should("be.visible"); cy.get('[aria-label*="Report Due Date"').contains(/Jun(\.)? 16, 1991/i); + cy.get('[aria-label="Gross Payment Amount This Milestone"]').contains( + "$60.00" + ); + cy.get('[aria-label="Net Payment Amount This Milestone"]').contains( + "$48.00" + ); + cy.get('[aria-label="Holdback Amount This Milestone"]').contains("$12.00"); cy.happoAndAxe("Project milestone reports Form", "filled", "main"); cy.findByRole("button", { name: /^submit/i }).click(); diff --git a/app/tests/unit/components/Form/ProjectMilestoneReportFormSummary.test.tsx b/app/tests/unit/components/Form/ProjectMilestoneReportFormSummary.test.tsx index 8297a4b163..40f143dc97 100644 --- a/app/tests/unit/components/Form/ProjectMilestoneReportFormSummary.test.tsx +++ b/app/tests/unit/components/Form/ProjectMilestoneReportFormSummary.test.tsx @@ -33,6 +33,7 @@ const mockQueryPayload = { id: "Test Reporting Requirement ID - 1", isPristine: false, newFormData: { + totalEligibleExpenses: 1000, description: "charmander", projectId: 1, reportingRequirementIndex: 1, @@ -40,6 +41,12 @@ const mockQueryPayload = { reportDueDate: "2020-01-10T23:59:59.999-07:00", reportingRequirementId: 1, hasExpenses: true, + calculatedNetAmount: 111, + calculatedGrossAmount: 999, + calculatedHoldbackAmount: 888, + adjustedNetAmount: 11, + adjustedGrossAmount: 99, + adjustedHoldBackAmount: 88, }, operation: "UPDATE", formChangeByPreviousFormChangeId: { @@ -141,5 +148,228 @@ describe("The Project Milestone Report Form Summary", () => { // report due date diff expect(screen.getByText(/Jan[.]? 1, 2020/i)).toBeInTheDocument(); expect(screen.getByText(/Jan[.]? 10, 2020/i)).toBeInTheDocument(); + + // total eligible expenses + expect( + screen.getByText("Total Eligible Expenses (optional)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$1,000\.00/i)).toBeInTheDocument(); + + // calculated values + expect( + screen.getByText("Gross Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$999\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$888\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$111\.00/i)).toBeInTheDocument(); + + // adjusted values + expect( + screen.getByText("Gross Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$99\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$11\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$88\.00/i)).toBeInTheDocument(); + }); + + const latestCommittedData = { + latestCommittedMilestoneFormChanges: { + edges: [ + { + node: { + newFormData: { + totalEligibleExpenses: 1000, + description: "charmander", + projectId: 1, + reportingRequirementIndex: 1, + reportType: "General", + reportDueDate: "2020-01-10T23:59:59.999-07:00", + reportingRequirementId: 1, + hasExpenses: true, + calculatedGrossAmount: 567, + calculatedNetAmount: 789, + calculatedHoldbackAmount: 891, + adjustedNetAmount: 89, + adjustedGrossAmount: 67, + adjustedHoldBackAmount: 91, + }, + }, + }, + ], + }, + }; + + const mockQueryPayloadLatestCommitted = { + ...mockQueryPayload, + ProjectRevision() { + const originalProjectRevision = mockQueryPayload.ProjectRevision(); + const modifiedProjectRevision = { + ...originalProjectRevision, + latestCommittedMilestoneFormChanges: { + edges: [ + { + node: { + newFormData: + latestCommittedData.latestCommittedMilestoneFormChanges + .edges[0].node.newFormData, + }, + }, + ], + }, + }; + return modifiedProjectRevision; + }, + }; + + it("Displays diffs of the data fields that were updated and shows latest committed values", () => { + componentTestingHelper.defaultQueryResolver = + mockQueryPayloadLatestCommitted; + componentTestingHelper.loadQuery(mockQueryPayloadLatestCommitted); + componentTestingHelper.renderComponent(); + + // calculated values + expect( + screen.getByText("Gross Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$567\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$999\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$789\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$888\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$891\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$111\.00/i)).toBeInTheDocument(); + + // adjusted values + expect( + screen.getByText("Gross Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$99\.00/i)).toBeInTheDocument(); + + expect(screen.getByText(/\$89\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$11\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$67\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$88\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$91\.00/i)).toBeInTheDocument(); + }); + const mockQueryPayloadWithDiffs = { + Form() { + return { + jsonSchema: milestoneProdSchema, + }; + }, + ProjectRevision() { + const result = { + isFirstRevision: false, + summaryMilestoneFormChanges: { + edges: [ + { + node: { + id: "Test Reporting Requirement ID - 1", + isPristine: false, + newFormData: { + totalEligibleExpenses: 1000, + description: "charmander", + projectId: 1, + reportingRequirementIndex: 1, + reportType: "General", + reportDueDate: "2020-01-10T23:59:59.999-07:00", + reportingRequirementId: 1, + hasExpenses: true, + calculatedNetAmount: 221, + calculatedGrossAmount: 222, + calculatedHoldbackAmount: 223, + adjustedNetAmount: 21, + adjustedGrossAmount: 22, + adjustedHoldBackAmount: 23, + }, + operation: "UPDATE", + formChangeByPreviousFormChangeId: { + newFormData: { + description: "bulbasaur", + projectId: 1, + reportingRequirementIndex: 1, + reportDueDate: "2020-01-01T13:59:59.999-07:00", + reportType: "Advanced", + reportingRequirementId: 1, + hasExpenses: true, + calculatedNetAmount: 111, + calculatedGrossAmount: 112, + calculatedHoldbackAmount: 113, + adjustedNetAmount: 11, + adjustedGrossAmount: 12, + adjustedHoldBackAmount: 13, + }, + }, + formDataRecordId: 1, + }, + }, + ], + }, + }; + return result; + }, + }; + + it("Displays diffs of the data fields that were updated and the old values", () => { + componentTestingHelper.defaultQueryResolver = mockQueryPayloadWithDiffs; + componentTestingHelper.loadQuery(mockQueryPayloadWithDiffs); + componentTestingHelper.renderComponent(); + + // calculated values + expect( + screen.getByText("Gross Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$222\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$112\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$221\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$111\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone") + ).toBeInTheDocument(); + expect(screen.getByText(/\$223\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$113\.00/i)).toBeInTheDocument(); + + // adjusted values + expect( + screen.getByText("Gross Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$22\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$12\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Net Payment Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$23\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$13\.00/i)).toBeInTheDocument(); + expect( + screen.getByText("Holdback Amount This Milestone (Adjusted)") + ).toBeInTheDocument(); + expect(screen.getByText(/\$21\.00/i)).toBeInTheDocument(); + expect(screen.getByText(/\$11\.00/i)).toBeInTheDocument(); }); });