Skip to content

Commit

Permalink
Merge branch 'master' into feature/query-management
Browse files Browse the repository at this point in the history
  • Loading branch information
olusegz07 committed Sep 26, 2024
2 parents 1477eca + 3f620d9 commit 12aeecf
Show file tree
Hide file tree
Showing 24 changed files with 384 additions and 244 deletions.
4 changes: 4 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## RELEASE NOTES

### Version 7.0.66
**EXUI-2148** Additional checks on task completion from session storage
**EXUI-2057** A frozen screen is seen when attempting to complete a current task...

### Version 7.0.65
**EXUI-2320** Intermittent missing call of search for completable

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { ValidPageListCaseFieldsService } from '../services/valid-page-list-case
import { CaseEditComponent } from './case-edit.component';
import { AbstractAppConfig } from '../../../../app.config';
import createSpyObj = jasmine.createSpyObj;
import { EventDetails, Task } from '../../../domain/work-allocation/Task';

describe('CaseEditComponent', () => {
const EVENT_TRIGGER: CaseEventTrigger = createCaseEventTrigger(
Expand Down Expand Up @@ -1167,11 +1168,14 @@ describe('CaseEditComponent', () => {

describe('submitForm', () => {
it('should submit case', () => {
const userInfo = {id: "id"};
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent', caseId: '123456789', userId: '1', createdTimestamp: Date.now()};
mockSessionStorageService.getItem.and.returnValues(JSON.stringify(CLIENT_CONTEXT), JSON.stringify(mockTaskEventCompletionInfo), JSON.stringify({userInfo}))
const mockClass = {
submit: () => of({})
};
spyOn(mockClass, 'submit').and.returnValue(of({
id: 'id',
userInfo: {id: 'id'},
/* tslint:disable:object-literal-key-quotes */
'callback_response_status': 'CALLBACK_HASNOT_COMPLETED',
/* tslint:disable:object-literal-key-quotes */
Expand Down Expand Up @@ -1238,8 +1242,8 @@ describe('CaseEditComponent', () => {
expect(validPageListCaseFieldsService.validPageListCaseFields).toHaveBeenCalled();
expect(formValueService.removeUnnecessaryFields).toHaveBeenCalled();
// check that tasks removed from session storage once event has been completed
expect(mockSessionStorageService.removeItem).toHaveBeenCalledWith('taskToComplete');
expect(mockSessionStorageService.removeItem).toHaveBeenCalledWith('taskEvent');
expect(mockSessionStorageService.removeItem).toHaveBeenCalledWith('clientContext');
expect(mockSessionStorageService.removeItem).toHaveBeenCalledWith('taskEventCompletionInfo');
});

it('should submit the case for a Case Flags submission', () => {
Expand Down Expand Up @@ -1511,46 +1515,64 @@ describe('CaseEditComponent', () => {
});

describe('taskExistsForThisEventAndCase', () => {
const mockEventId = 'testEvent';
const mockCaseId = '123456789';
const mockTaskEvent = {taskId: '123', eventId: 'testEvent'};
const mockEventDetails: EventDetails = { eventId: 'testEvent', caseId: '123456789', userId: '1' };
it('should return false when there is no task present', () => {
expect(component.taskExistsForThisEventAndCase(null, null, mockEventId, mockCaseId)).toBe(false);
expect(component.taskExistsForThisEvent(null, null, mockEventDetails)).toBe(false);
});

it('should return false when there is a task present that does not match the current case', () => {
const mockTask = {id: '123', case_id: '987654321'};
expect(component.taskExistsForThisEventAndCase(mockTask, null, mockEventId, mockCaseId)).toBe(false);
expect(component.taskExistsForThisEvent(mockTask as Task, null, mockEventDetails)).toBe(false);
});

it('should return true when there is a task present that matches the current case when there is no event in session storage', () => {
const mockTask = {id: '123', case_id: '123456789'};
expect(component.taskExistsForThisEventAndCase(mockTask, null, mockEventId, mockCaseId)).toBe(true);
expect(component.taskExistsForThisEvent(mockTask as Task, null, mockEventDetails)).toBe(true);
});

it('should return true when there is a task present that matches the current case and current event', () => {
const mockTask = {id: '123', case_id: '123456789'};
const mockTaskEvent = {taskId: '123', eventId: 'testEvent'};
expect(component.taskExistsForThisEventAndCase(mockTask, mockTaskEvent, mockEventId, mockCaseId)).toBe(true);
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent', caseId: '123456789', userId: '1', createdTimestamp: Date.now()};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(true);
});

it('should return false when there is a task present that matches the current case but does not match the event', () => {
const mockTask = {id: '123', case_id: '123456789'};
const mockTaskEvent = {taskId: '123', eventId: 'testEvent2'};
expect(component.taskExistsForThisEventAndCase(mockTask, mockTaskEvent, mockEventId, mockCaseId)).toBe(false);
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent2', caseId: '123456789', userId: '1', createdTimestamp: Date.now()};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(false);
});

it('should return true when there is a task present that matches the current case, does not match the event but does not match the task associated with the event in session storage', () => {
// highly unlikely to occur but feasible scenario
const mockTask = {id: '123', case_id: '123456789'};
const mockTaskEvent = {taskId: '1234', eventId: 'testEvent2'};
expect(component.taskExistsForThisEventAndCase(mockTask, mockTaskEvent, mockEventId, mockCaseId)).toBe(true);
const mockTaskEventCompletionInfo = {taskId: '1234', eventId: 'testEvent2', caseId: '123456789', userId: '1', createdTimestamp: Date.now()};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(true);
});

it('should return true when there is a task present that matches the current case, matches the event and does not match the task associated with the event in session storage', () => {
const mockTask = {id: '123', case_id: '123456789'};
const mockTaskEvent = {taskId: '123', eventId: 'testEvent'};
expect(component.taskExistsForThisEventAndCase(mockTask, mockTaskEvent, mockEventId, mockCaseId)).toBe(true);
const mockTaskEventCompletionInfo = {taskId: '1234', eventId: 'testEvent', caseId: '123456789', userId: '1', createdTimestamp: Date.now()};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(true);
});

it('should return false when there is a task present that matches the current case, matches the event but does not match the user', () => {
const mockTask = {id: '123', case_id: '123456789'};
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent', caseId: '123456789', userId: '2', createdTimestamp: Date.now()};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(false);
});

it('should return false when there is a task present that matches the current case, matches the event but the timestamp is older than day ago', () => {
const mockTask = {id: '123', case_id: '123456789'};
const dayAndTwoHoursAgo = new Date().getTime() - (26*60*60*1000);
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent', caseId: '123456789', userId: '1', createdTimestamp: dayAndTwoHoursAgo};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(false);
});

it('should return true when there is a task present that matches the current case, matches the event but the timestamp is less than day ago', () => {
const mockTask = {id: '123', case_id: '123456789'};
const twoHoursAgo = new Date().getTime() - (2*60*60*1000);
const mockTaskEventCompletionInfo = {taskId: '123', eventId: 'testEvent', caseId: '123456789', userId: '1', createdTimestamp: twoHoursAgo};
expect(component.taskExistsForThisEvent(mockTask as Task, mockTaskEventCompletionInfo, mockEventDetails)).toBe(true);
});
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ActivatedRoute, Params, Router } from '@angular/router';
import { Observable, Subject, of } from 'rxjs';
import { finalize, switchMap } from 'rxjs/operators';

import { AbstractAppConfig } from '../../../../app.config';
import { Constants } from '../../../commons/constants';
import { ConditionalShowRegistrarService, GreyBarService } from '../../../directives';
import {
Expand All @@ -13,7 +14,8 @@ import {
CaseEventData, CaseEventTrigger, CaseField,
CaseView, Draft, HttpError, Profile
} from '../../../domain';
import { Task, TaskEvent } from '../../../domain/work-allocation/Task';
import { UserInfo } from '../../../domain/user/user-info.model';
import { EventDetails, Task, TaskEventCompletionInfo } from '../../../domain/work-allocation/Task';
import {
AlertService,
FieldsPurger, FieldsUtils, FormErrorService, FormValueService, LoadingService,
Expand All @@ -23,7 +25,6 @@ import { Confirmation, Wizard, WizardPage } from '../domain';
import { EventCompletionParams } from '../domain/event-completion-params.model';
import { CaseNotifier, WizardFactoryService, WorkAllocationService } from '../services';
import { ValidPageListCaseFieldsService } from '../services/valid-page-list-caseFields.service';
import { AbstractAppConfig } from '../../../../app.config';

@Component({
selector: 'ccd-case-edit',
Expand Down Expand Up @@ -244,25 +245,38 @@ export class CaseEditComponent implements OnInit, OnDestroy {
const clientContextStr = this.sessionStorageService.getItem('clientContext');
const userTask = FieldsUtils.getUserTaskFromClientContext(clientContextStr);
const taskInSessionStorage = userTask ? userTask.task_data : null;
let taskEventInSessionStorage: TaskEvent;
const taskStr = this.sessionStorageService.getItem('taskToComplete');
const taskEventStr = this.sessionStorageService.getItem('taskEvent');
if (taskEventStr) {
taskEventInSessionStorage = JSON.parse(taskEventStr);
let taskEventCompletionInfo: TaskEventCompletionInfo;
let userInfo: UserInfo;
const taskEventCompletionStr = this.sessionStorageService.getItem('taskEventCompletionInfo');
const userInfoStr = this.sessionStorageService.getItem('userDetails');
const assignNeeded = this.sessionStorageService.getItem('assignNeeded');
if (taskEventCompletionStr) {
taskEventCompletionInfo = JSON.parse(taskEventCompletionStr);
}
if (userInfoStr) {
userInfo = JSON.parse(userInfoStr);
}
const eventId = this.getEventId(form);
const caseId = this.getCaseId(caseDetails);
if (this.taskExistsForThisEventAndCase(taskInSessionStorage, taskEventInSessionStorage, eventId, caseId)) {
const userId = userInfo.id ? userInfo.id : userInfo.uid;
const eventDetails: EventDetails = {eventId, caseId, userId, assignNeeded};
if (this.taskExistsForThisEvent(taskInSessionStorage, taskEventCompletionInfo, eventDetails)) {
this.abstractConfig.logMessage(`task exist for this event for caseId and eventId as ${caseId} ${eventId}`);
// Show event completion component to perform event completion checks
this.eventCompletionParams = ({
caseId,
eventId,
task: taskInSessionStorage
});
// add taskEvent to link current event with task id
const taskEvent = {eventId, taskId: taskInSessionStorage.id};
this.sessionStorageService.setItem('taskEvent', JSON.stringify(taskEvent));
// add taskEventCompletionInfo again to ensure link current event with task id
// note: previous usage was created here so this is to ensure correct functionality continues
const taskEventCompletionInfo: TaskEventCompletionInfo = {
caseId,
eventId,
userId,
taskId: taskInSessionStorage.id,
createdTimestamp: Date.now()};
this.sessionStorageService.setItem('taskEventCompletionInfo', JSON.stringify(taskEventCompletionInfo));
this.isEventCompletionChecksRequired = true;
} else {
// Task not in session storage, proceed to submit
Expand Down Expand Up @@ -441,9 +455,9 @@ export class CaseEditComponent implements OnInit, OnDestroy {
return this.postCompleteTaskIfRequired();
}),finalize(() => {
this.loadingService.unregister(loadingSpinnerToken);
// on event completion ensure the previous event taskToComplete/taskEvent removed
this.sessionStorageService.removeItem('taskToComplete');
this.sessionStorageService.removeItem('taskEvent')
// on event completion ensure the previous event clientContext/taskEventCompletionInfo removed
this.sessionStorageService.removeItem('clientContext');
this.sessionStorageService.removeItem('taskEventCompletionInfo')
this.isSubmitting = false;
}))
.subscribe(
Expand Down Expand Up @@ -512,21 +526,31 @@ export class CaseEditComponent implements OnInit, OnDestroy {
}
}

// checks whether current taskToComplete relevant for the event
public taskExistsForThisEventAndCase(taskInSessionStorage, taskEvent, eventId, caseId): boolean {
if (!taskInSessionStorage || taskInSessionStorage.case_id !== caseId) {
// checks whether current clientContext relevant for the event
public taskExistsForThisEvent(taskInSessionStorage: Task, taskEventCompletionInfo: TaskEventCompletionInfo, eventDetails: EventDetails): boolean {
if (!taskInSessionStorage || taskInSessionStorage.case_id !== eventDetails.caseId) {
return false;
}
if (!taskEvent) {
if (!taskEventCompletionInfo) {
// if no task event present then there is no task to complete from previous event present
return true;
} else {
if (taskEvent.taskId === taskInSessionStorage.id && taskEvent.eventId !== eventId) {
if (taskEventCompletionInfo.taskId !== taskInSessionStorage.id) {
return true;
} else if ((taskEventCompletionInfo.taskId === taskInSessionStorage.id &&
this.eventDetailsDoNotMatch(taskEventCompletionInfo, eventDetails))
|| this.eventMoreThanDayAgo(taskEventCompletionInfo.createdTimestamp)
) {
// if the session storage not related to event, ignore it and remove
this.sessionStorageService.removeItem('taskToComplete');
this.sessionStorageService.removeItem('taskEvent');
this.sessionStorageService.removeItem('clientContext');
this.sessionStorageService.removeItem('taskEventCompletionInfo');
return false;
}
if (eventDetails.assignNeeded === 'false' && eventDetails.userId !== taskInSessionStorage.assignee) {
// if the user does not match task assignee, assign is now needed
// data cannot be deleted and ignored as it matches understanding
this.sessionStorageService.setItem('assignNeeded', 'true');
}
return true;
}
}
Expand All @@ -549,4 +573,20 @@ export class CaseEditComponent implements OnInit, OnDestroy {
private hasCallbackFailed(response: object): boolean {
return response['callback_response_status'] !== 'CALLBACK_COMPLETED';
}

private eventMoreThanDayAgo(timestamp: number) {
if ((new Date().getTime() - timestamp) > (24*60*60*1000)) {
return true;
}
return false;
}

private eventDetailsDoNotMatch(taskEventCompletionInfo: TaskEventCompletionInfo, eventDetails: EventDetails) {
if (taskEventCompletionInfo.eventId !== eventDetails.eventId
|| taskEventCompletionInfo.caseId !== eventDetails.caseId
|| taskEventCompletionInfo.userId !== eventDetails.userId) {
return true;
}
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { CaseEditWizardGuard } from './services/case-edit-wizard.guard';
import { CaseFlagStateService } from './services/case-flag-state.service';
import { CaseworkerService } from './services/case-worker.service';
import { ValidPageListCaseFieldsService } from './services/valid-page-list-caseFields.service';
import { CaseEventCompletionTaskReassignedComponent } from './case-event-completion';

@NgModule({
imports: [
Expand Down
Loading

0 comments on commit 12aeecf

Please sign in to comment.