Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ describe('EndorsementApprovalComponent', () => {
expect(emittedFiscal!.businessAreaComment).toBe('New approval');
});

it('should set planFiscalStatusCode to DRAFT if endorsement removed', async () => {
spyOn<any>(component, 'confirmRevertToDraft').and.returnValue(Promise.resolve(true));
it('should set planFiscalStatusCode to PROPOSED if endorsement removed', async () => {
spyOn<any>(component, 'confirmRevertToProposed').and.returnValue(Promise.resolve(true));

const emitSpy = spyOn(component.saveEndorsement, 'emit');
component.fiscal = {
Expand All @@ -155,7 +155,7 @@ describe('EndorsementApprovalComponent', () => {
await component.onSave();

const emittedFiscal = emitSpy.calls.mostRecent()!.args[0];
expect(emittedFiscal!.planFiscalStatusCode?.planFiscalStatusCode).toBe(FiscalStatuses.DRAFT);
expect(emittedFiscal!.planFiscalStatusCode?.planFiscalStatusCode).toBe(FiscalStatuses.PROPOSED);
});

it('should disable the form', () => {
Expand Down Expand Up @@ -259,9 +259,8 @@ describe('EndorsementApprovalComponent', () => {
expect(component.isSaving).toBeFalse();
});

it('resets to DRAFT and clears fields when endorsement removed (confirm = true)', async () => {
// Arrange (shouldResetToDraft → endorsementRemoved = true, status not DRAFT/PROPOSED)
spyOn<any>(component, 'confirmRevertToDraft').and.returnValue(Promise.resolve(true));
it('resets to PROPOSED and clears fields when endorsement removed (confirm = true)', async () => {
spyOn<any>(component, 'confirmRevertToProposed').and.returnValue(Promise.resolve(true));
const emitSpy = spyOn(component.saveEndorsement, 'emit');

component.fiscal = {
Expand All @@ -285,11 +284,9 @@ describe('EndorsementApprovalComponent', () => {
const { args } = emitSpy.calls.mostRecent();
const payload = args[0] as ProjectFiscal;

// Forced DRAFT
expect(payload.planFiscalStatusCode.planFiscalStatusCode).toBe(FiscalStatuses.DRAFT);
// Approval forced false
expect(payload.isApprovedInd).toBeFalse();

// Forced PROPOSED
expect(payload.planFiscalStatusCode.planFiscalStatusCode).toBe(FiscalStatuses.PROPOSED);

// Endorsement cleared
expect(payload.endorserName).toBeUndefined();
expect(payload.endorsementTimestamp).toBeUndefined();
Expand All @@ -298,21 +295,12 @@ describe('EndorsementApprovalComponent', () => {
expect(payload.endorsementEvalTimestamp).toBeUndefined();
expect(payload.endorserUserGuid).toBeUndefined();
expect(payload.endorserUserUserid).toBeUndefined();

// Approval cleared
expect(payload.approvedTimestamp).toBeUndefined();
expect(payload.approverName).toBeUndefined();
expect(payload.approverUserGuid).toBeUndefined();
expect(payload.approverUserUserid).toBeUndefined();
expect(payload.businessAreaComment).toBeUndefined();

// Audit cleared per current implementation
expect(payload.endorseApprUpdateUserid).toBeUndefined();
expect(payload.endorseApprUpdatedTimestamp).toBeUndefined();
});

it('resets to DRAFT and clears fields when approval removed (confirm = true)', async () => {
spyOn<any>(component, 'confirmRevertToDraft').and.returnValue(Promise.resolve(true));
it('resets to proposed and clears fields when approval removed (confirm = true)', async () => {
spyOn<any>(component, 'confirmRevertToProposed').and.returnValue(Promise.resolve(true));
const emitSpy = spyOn(component.saveEndorsement, 'emit');

component.fiscal = {
Expand All @@ -333,23 +321,17 @@ describe('EndorsementApprovalComponent', () => {
const { args } = emitSpy.calls.mostRecent();
const payload = args[0] as ProjectFiscal;

expect(payload.planFiscalStatusCode.planFiscalStatusCode).toBe(FiscalStatuses.DRAFT);
expect(payload.planFiscalStatusCode.planFiscalStatusCode).toBe(FiscalStatuses.PROPOSED);
expect(payload.isApprovedInd).toBeFalse();
expect(payload.approvedTimestamp).toBeUndefined();
expect(payload.approverName).toBeUndefined();
expect(payload.approverUserGuid).toBeUndefined();
expect(payload.approverUserUserid).toBeUndefined();
expect(payload.businessAreaComment).toBeUndefined();
expect(payload.endorserName).toBeUndefined();
expect(payload.endorsementTimestamp).toBeUndefined();
expect(payload.endorsementCode).toEqual({ endorsementCode: EndorsementCode.NOT_ENDORS });
expect(payload.endorsementComment).toBeUndefined();
expect(payload.endorseApprUpdateUserid).toBeUndefined();
expect(payload.endorseApprUpdatedTimestamp).toBeUndefined();
});

it('does not emit when user cancels the revert confirmation (shouldResetToDraft = true)', async () => {
spyOn<any>(component, 'confirmRevertToDraft').and.returnValue(Promise.resolve(false));
it('does not emit when user cancels the revert confirmation', async () => {
spyOn<any>(component, 'confirmRevertToProposed').and.returnValue(Promise.resolve(false));
const emitSpy = spyOn(component.saveEndorsement, 'emit');

component.fiscal = {
Expand All @@ -367,8 +349,8 @@ describe('EndorsementApprovalComponent', () => {
expect(emitSpy).not.toHaveBeenCalled();
});

it('calls confirmRevertToDraft with the current status when reverting', async () => {
const confirmSpy = spyOn<any>(component, 'confirmRevertToDraft').and.returnValue(Promise.resolve(true));
it('calls confirmRevertToProposed with the current status when reverting', async () => {
const confirmSpy = spyOn<any>(component, 'confirmRevertToProposed').and.returnValue(Promise.resolve(true));
const emitSpy = spyOn(component.saveEndorsement, 'emit');

component.fiscal = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,11 @@ export class EndorsementApprovalComponent implements OnChanges, OnInit {
const endorsementRemoved = !formValue.endorseFiscalActivity;
const approvalRemoved = !formValue.approveFiscalActivity;
const currentStatusCode = this.fiscal?.planFiscalStatusCode?.planFiscalStatusCode;
const shouldResetToDraft =
(endorsementRemoved || approvalRemoved) &&
currentStatusCode !== FiscalStatuses.DRAFT &&
currentStatusCode !== FiscalStatuses.PROPOSED;
const resetToProposedEndorsementRemoved = endorsementRemoved && currentStatusCode !== FiscalStatuses.DRAFT && currentStatusCode !== FiscalStatuses.PROPOSED;
const resetToProposedApprovalRemoved = approvalRemoved && currentStatusCode !== FiscalStatuses.DRAFT && currentStatusCode !== FiscalStatuses.PROPOSED;

if (shouldResetToDraft) {
const confirmed = await this.confirmRevertToDraft(currentStatusCode ?? '');
if (resetToProposedEndorsementRemoved || resetToProposedApprovalRemoved) {
const confirmed = await this.confirmRevertToProposed(currentStatusCode ?? '');
if (!confirmed) return; // user cancelled
}

Expand Down Expand Up @@ -182,25 +180,29 @@ export class EndorsementApprovalComponent implements OnChanges, OnInit {
endorseApprUpdatedTimestamp: currentUtc,
};

// Status logic: (return to DRAFT if removed and not DRAFT/PROPOSED)
// if reverting to draft, clear out endorsement/approval fields
if (shouldResetToDraft) {
updatedFiscal.planFiscalStatusCode = { planFiscalStatusCode: FiscalStatuses.DRAFT };
updatedFiscal.isApprovedInd = false;
// Status logic: (return to PROPOSED if removed and not DRAFT/PROPOSED)
// if reverting to proposed, clear out endorsement or approval fields depending on which has been unselected
if (resetToProposedEndorsementRemoved) {
updatedFiscal.planFiscalStatusCode = { planFiscalStatusCode: FiscalStatuses.PROPOSED };
updatedFiscal.endorserName = undefined;
updatedFiscal.endorsementTimestamp = undefined;
updatedFiscal.endorsementCode = { endorsementCode: EndorsementCode.NOT_ENDORS };
updatedFiscal.endorsementComment = undefined;
updatedFiscal.endorsementEvalTimestamp = undefined;
updatedFiscal.endorserUserGuid = undefined;
updatedFiscal.endorserUserUserid = undefined;
updatedFiscal.endorseApprUpdateUserid = undefined;
updatedFiscal.endorseApprUpdatedTimestamp = undefined;
}

if (resetToProposedApprovalRemoved) {
updatedFiscal.planFiscalStatusCode = { planFiscalStatusCode: FiscalStatuses.PROPOSED };
updatedFiscal.isApprovedInd = false;
updatedFiscal.approvedTimestamp = undefined;
updatedFiscal.approverName = undefined;
updatedFiscal.approverUserGuid = undefined;
updatedFiscal.approverUserUserid = undefined;
updatedFiscal.businessAreaComment = undefined;
updatedFiscal.endorseApprUpdateUserid = undefined;
updatedFiscal.endorseApprUpdatedTimestamp = undefined;
}

this.saveEndorsement.emit(updatedFiscal);
Expand Down Expand Up @@ -269,18 +271,18 @@ export class EndorsementApprovalComponent implements OnChanges, OnInit {
}
}

async confirmRevertToDraft(currentStatusCode: string): Promise<boolean> {
async confirmRevertToProposed(currentStatusCode: string): Promise<boolean> {
if (!currentStatusCode) return false;

// Parse status to plain English if it is IN_PROG
// The remaining status do not require such parsing
const currentStatus = currentStatusCode === 'IN_PROG' ? "In Progress" : capitalizeFirstLetter(currentStatusCode);
const message = `You are about to change the status of this Fiscal Activity from ${currentStatus} to Draft. Do you wish to continue?`
const message = `You are about to change the status of this Fiscal Activity from ${currentStatus} to Proposed. Do you wish to continue?`

const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: {
indicator: 'confirm-fiscal-status-update',
title: `Confirm Change to Draft`,
title: `Confirm Change to Proposed`,
message: message
},
width: '600px',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ public class ProjectFiscalService implements CommonService {
private static final Map<String, Set<String>> VALID_TRANSITIONS = Map.of(
DRAFT, Set.of(DRAFT, PROPOSED, PREPARED, CANCELLED),
PROPOSED, Set.of(DRAFT, PROPOSED, PREPARED, CANCELLED),
PREPARED, Set.of(DRAFT, PREPARED, IN_PROG, CANCELLED),
IN_PROG, Set.of(DRAFT, COMPLETE, CANCELLED, IN_PROG),
PREPARED, Set.of(DRAFT, PROPOSED, PREPARED, IN_PROG, CANCELLED),
IN_PROG, Set.of(DRAFT, PROPOSED, COMPLETE, CANCELLED, IN_PROG),
COMPLETE, Set.of(COMPLETE),
CANCELLED, Set.of(CANCELLED)
);
Expand Down
Loading