Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add delete fiscal #471

Merged
merged 1 commit into from
Jan 31, 2025
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
@@ -1,6 +1,8 @@
<div class="dialog-container">
<div class="title-bar">
{{ dialogUsage === 'confirm-cancel' ? 'Confirm Cancel' : 'Duplicate Found' }}
{{ dialogUsage === 'confirm-cancel' ? 'Confirm Cancel' :
dialogUsage === 'confirm-delete' ? 'Confirm Delete' :
'Duplicate Found' }}
</div>
<div class="dialog-content">
<div class="icon-and-text">
Expand All @@ -12,6 +14,10 @@
<p *ngIf="dialogUsage === 'duplicate-project'">
This Project already exists:<br />
</p>
<p *ngIf="dialogUsage === 'confirm-delete'">
Are you sure you want to delete this fiscal year?<br />
This action cannot be undone.
</p>
</div>
</div>
<div class="footer">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</div>
</mat-expansion-panel-header>
<mat-menu #menu="matMenu">
<button mat-menu-item>
<button mat-menu-item (click)="deleteFiscalYear(fiscalForms[i])" [disabled]="isUndeletable(fiscalForms[i])">
Delete Fiscal Year
</button>
<button mat-menu-item >
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import { CodeTableServices } from 'src/app/services/code-table-services';
import { MatSnackBar } from '@angular/material/snack-bar';
import { FormBuilder } from '@angular/forms';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ConfirmationDialogComponent } from 'src/app/components/confirmation-dialog/confirmation-dialog.component';

const mockProjectService = {
getProjectFiscalsByProjectGuid: jasmine.createSpy('getProjectFiscalsByProjectGuid').and.returnValue(
of({ _embedded: { projectFiscals: [{ fiscalYear: 2023, projectFiscalName: 'Test Fiscal' }] } })
),
updateProjectFiscal: jasmine.createSpy('updateProjectFiscal').and.returnValue(of({})),
createProjectFiscal: jasmine.createSpy('createProjectFiscal').and.returnValue(of({})),
deleteProjectFiscalByProjectPlanFiscalGuid: jasmine.createSpy('deleteProjectFiscalByProjectPlanFiscalGuid').and.returnValue(of({})), // ✅ Add this line

};

const mockCodeTableServices = {
Expand All @@ -30,7 +33,7 @@ describe('ProjectFiscalsComponent', () => {

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ProjectFiscalsComponent, BrowserAnimationsModule],
imports: [ProjectFiscalsComponent, BrowserAnimationsModule, ConfirmationDialogComponent],
providers: [
{ provide: ActivatedRoute, useValue: { snapshot: { queryParamMap: { get: () => 'test-guid' } } } },
{ provide: ProjectService, useValue: mockProjectService },
Expand Down Expand Up @@ -198,4 +201,85 @@ describe('ProjectFiscalsComponent', () => {

expect(() => component.onCancelFiscal(0)).not.toThrow();
});

it('should open confirmation dialog when deleting a fiscal year', () => {
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(true) // Simulate user clicking "Confirm"
} as any);

component.projectFiscals = [{ projectPlanFiscalGuid: 'test-guid' }];
component.deleteFiscalYear({ value: component.projectFiscals[0] });

expect(component.dialog.open).toHaveBeenCalledWith(ConfirmationDialogComponent, {
data: { indicator: 'confirm-delete' },
width: '500px',
});
});

it('should delete a fiscal year after confirmation', () => {
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(true) // Simulate user clicking "Confirm"
} as any);
spyOn(component, 'loadProjectFiscals');

mockProjectService.deleteProjectFiscalByProjectPlanFiscalGuid = jasmine.createSpy().and.returnValue(of({}));

component.projectFiscals = [{ projectPlanFiscalGuid: 'test-guid' }];
component.deleteFiscalYear({ value: component.projectFiscals[0] });

expect(mockProjectService.deleteProjectFiscalByProjectPlanFiscalGuid).toHaveBeenCalledWith('test-guid', 'test-guid');
expect(mockSnackBar.open).toHaveBeenCalledWith(
component.messages.projectFiscalDeletedSuccess,
'OK',
{ duration: 5000, panelClass: 'snackbar-success' }
);
expect(component.loadProjectFiscals).toHaveBeenCalledWith(true);
});

it('should show error snackbar if deletion fails', () => {
spyOn(component.dialog, 'open').and.returnValue({
afterClosed: () => of(true) // Simulate user clicking "Confirm"
} as any);

mockProjectService.deleteProjectFiscalByProjectPlanFiscalGuid = jasmine.createSpy().and.returnValue(
throwError(() => new Error('API Error'))
);

component.projectFiscals = [{ projectPlanFiscalGuid: 'test-guid' }];
component.deleteFiscalYear({ value: component.projectFiscals[0] });

expect(mockSnackBar.open).toHaveBeenCalledWith(
component.messages.projectFiscalDeletedFailure,
'OK',
{ duration: 5000, panelClass: 'snackbar-error' }
);
});

it('should reload fiscal years if projectPlanFiscalGuid is missing', () => {
spyOn(component, 'loadProjectFiscals');

component.deleteFiscalYear({ value: { projectPlanFiscalGuid: null } });

expect(component.loadProjectFiscals).toHaveBeenCalledWith(true);
});

it('should return true for isUndeletable if isApprovedInd is true', () => {
const form = { value: { isApprovedInd: true } };
expect(component.isUndeletable(form)).toBe(true);
});

it('should return false for isUndeletable if isApprovedInd is false', () => {
const form = { value: { isApprovedInd: false } };
expect(component.isUndeletable(form)).toBe(false);
});

it('should return false for isUndeletable if isApprovedInd is undefined', () => {
const form = { value: {} };
expect(component.isUndeletable(form)).toBe(false);
});

it('should return false for isUndeletable if form is null', () => {
expect(component.isUndeletable(null)).toBe(false);
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { Messages } from 'src/app/utils/messages';
import { CodeTableServices } from 'src/app/services/code-table-services';
import { MatMenuModule } from '@angular/material/menu';
import { Observable } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
import { ConfirmationDialogComponent } from 'src/app/components/confirmation-dialog/confirmation-dialog.component';

@Component({
selector: 'app-project-fiscals',
Expand Down Expand Up @@ -47,6 +49,8 @@ export class ProjectFiscalsComponent implements OnInit {
private codeTableService: CodeTableServices,
private readonly fb: FormBuilder,
private readonly snackbarService: MatSnackBar,
public readonly dialog: MatDialog,

) {}

ngOnInit(): void {
Expand Down Expand Up @@ -118,7 +122,9 @@ export class ProjectFiscalsComponent implements OnInit {
fiscalReportedSpendAmount: [fiscal?.fiscalReportedSpendAmount ?? ''],
cfsActualSpend: [fiscal?.cfsActualSpend || ''],
fiscalForecastAmount: [fiscal?.fiscalForecastAmount || ''],
fiscalActualAmount: [fiscal?.fiscalActualAmount || '']
fiscalActualAmount: [fiscal?.fiscalActualAmount || ''],
projectPlanFiscalGuid: [fiscal?.projectPlanFiscalGuid || ''],
isApprovedInd: [fiscal?.isApprovedInd || false]
});

return form;
Expand Down Expand Up @@ -229,7 +235,7 @@ export class ProjectFiscalsComponent implements OnInit {
submittedByUserGuid: updatedData.submittedByUserGuid,
submittedByUserUserid: updatedData.submittedByUserUserid,
submissionTimestamp: updatedData.submissionTimestamp,
isApprovedInd: isUpdate ? updatedData.isApprovedInd : true,
isApprovedInd: isUpdate ? updatedData.isApprovedInd : false,
isDelayedInd: isUpdate ? updatedData.isDelayedInd : false,
fiscalForecastAmount: updatedData.fiscalForecastAmount,
totalCostEstimateAmount: updatedData.totalCostEstimateAmount,
Expand Down Expand Up @@ -278,4 +284,43 @@ export class ProjectFiscalsComponent implements OnInit {
});
}
}

deleteFiscalYear(form: any) {
const formData = form.value;
if (formData.projectPlanFiscalGuid) {
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
data: { indicator: 'confirm-delete' },
width: '500px',
});

dialogRef.afterClosed().subscribe((confirmed: boolean) => {
if (confirmed) {
this.projectService.deleteProjectFiscalByProjectPlanFiscalGuid(this.projectGuid, formData.projectPlanFiscalGuid)
.subscribe({
next: () => {
this.snackbarService.open(
this.messages.projectFiscalDeletedSuccess,
'OK',
{ duration: 5000, panelClass: 'snackbar-success' }
);
this.loadProjectFiscals(true);
},
error: () => {
this.snackbarService.open(
this.messages.projectFiscalDeletedFailure,
'OK',
{ duration: 5000, panelClass: 'snackbar-error' }
);
}
});
}
});
} else{
this.loadProjectFiscals(true);
}
}

isUndeletable(form: any): boolean {
return !!form?.value?.isApprovedInd;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -283,5 +283,36 @@ it('should handle errors when creating a project fiscal', () => {
const req = httpMock.expectOne(`http://mock-api.com/wfprev-api/projects/${projectGuid}/projectFiscals/${projectPlanFiscalGuid}`);
req.flush('Error', { status: 500, statusText: 'Server Error' });
});

it('should delete a project fiscal', () => {
const projectGuid = '12345';
const projectPlanFiscalGuid = 'fiscal-6789';

service.deleteProjectFiscalByProjectPlanFiscalGuid(projectGuid, projectPlanFiscalGuid).subscribe((response) => {
expect(response).toBeTruthy(); // Expect a success response
});

const req = httpMock.expectOne(`http://mock-api.com/wfprev-api/projects/${projectGuid}/projectFiscals/${projectPlanFiscalGuid}`);
expect(req.request.method).toBe('DELETE'); // Ensure DELETE method is used
expect(req.request.headers.get('Authorization')).toBe('Bearer mock-token'); // Check Authorization header
req.flush({}); // Simulate successful deletion response
});

it('should handle errors when deleting a project fiscal', () => {
const projectGuid = '12345';
const projectPlanFiscalGuid = 'fiscal-6789';

service.deleteProjectFiscalByProjectPlanFiscalGuid(projectGuid, projectPlanFiscalGuid).subscribe({
next: () => fail('Should have failed with an error'),
error: (error) => {
expect(error.message).toBe('Failed to delete project fiscals'); // Check error message
}
});

const req = httpMock.expectOne(`http://mock-api.com/wfprev-api/projects/${projectGuid}/projectFiscals/${projectPlanFiscalGuid}`);
req.flush('Error', { status: 500, statusText: 'Server Error' }); // Simulate server error response
});



});
Original file line number Diff line number Diff line change
Expand Up @@ -133,4 +133,21 @@ export class ProjectService {
})
);
}

deleteProjectFiscalByProjectPlanFiscalGuid(projectGuid: string, projectPlanFiscalGuid: string): Observable<any> {
const baseUrl = `${this.appConfigService.getConfig().rest['wfprev']}/wfprev-api/projects`;
const url = `${baseUrl}/${projectGuid}/projectFiscals/${projectPlanFiscalGuid}`;

return this.httpClient.delete(url, {
headers: {
Authorization: `Bearer ${this.tokenService.getOauthToken()}`,
}
}).pipe(
map((response: any) => response),
catchError((error) => {
console.error("Error delete project fiscals", error);
return throwError(() => new Error("Failed to delete project fiscals"));
})
);
}
}
2 changes: 2 additions & 0 deletions client/wfprev-war/src/main/angular/src/app/utils/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,6 @@ export const Messages = {
projectFiscalCreatedFailure: 'Create Project Fiscal Failed',
projectFiscalUpdatedSuccess: 'Project Fiscal Updated Successfully',
projectFiscalUpdatedFailure: 'Project Fiscal Updated Failed',
projectFiscalDeletedSuccess: 'Project Fiscal Deleted Successfully',
projectFiscalDeletedFailure: 'Project Fiscal Deleted Failed',
};
Loading