diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.html b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.html index 79213afe10..dfe1fc6a01 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.html +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.html @@ -68,6 +68,7 @@

Enforcement status

summaryListId="enforcementOverviewDetails" summaryListRowId="enforcement_court" [actionEnabled]="hasAccountMaintenancePermission ? true : false" + (actionClick)="handleChangeEnforcementCourt()" > Enforcement court diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.spec.ts b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.spec.ts index bcace27490..5d41d0ad94 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.spec.ts +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.spec.ts @@ -31,4 +31,13 @@ describe('FinesAccDefendantDetailsEnforcementTab', () => { expect(event.preventDefault).toHaveBeenCalled(); expect(eventEmitterSpy).toHaveBeenCalled(); }); + + it('should emit the current enforcement court id when handleChangeEnforcementCourt is called', () => { + const eventEmitterSpy = vi.spyOn(component.changeEnforcementCourt, 'emit'); + component.hasAccountMaintenancePermission = true; + + component.handleChangeEnforcementCourt(); + + expect(eventEmitterSpy).toHaveBeenCalledWith(123); + }); }); diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.ts b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.ts index 19ec837685..8fbe51ef71 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.ts +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component.ts @@ -39,6 +39,7 @@ export class FinesAccDefendantDetailsEnforcementTab { @Input() hasAccountMaintenancePermission: boolean = false; @Input() hasEnterEnforcementPermission: boolean = false; @Output() addEnforcementOverride = new EventEmitter(); + @Output() changeEnforcementCourt = new EventEmitter(); /** * Emits an event to add an enforcement override if the user has the necessary permissions and there is no existing enforcement override result. @@ -53,4 +54,13 @@ export class FinesAccDefendantDetailsEnforcementTab { this.addEnforcementOverride.emit(); } } + + /** + * Emits the current enforcement court id when the user can change it. + */ + public handleChangeEnforcementCourt(): void { + if (this.hasAccountMaintenancePermission) { + this.changeEnforcementCourt.emit(this.tabData.enforcement_overview.enforcement_court?.court_id ?? null); + } + } } diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.html b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.html index 39396c237f..4276da373e 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.html +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.html @@ -206,6 +206,7 @@

Business Unit:

[hasAccountMaintenancePermission]="hasPermission('account-maintenance')" [hasEnterEnforcementPermission]="hasPermission('enter-enforcement')" (addEnforcementOverride)="navigateToAddEnforcementOverridePage()" + (changeEnforcementCourt)="navigateToChangeEnforcementCourtPage($event)" > } } diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.spec.ts b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.spec.ts index feaa9c5f9b..a898a6f2a0 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.spec.ts +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.spec.ts @@ -22,6 +22,7 @@ import { FINES_ACC_PARTY_ADD_AMEND_CONVERT_PARTY_TYPES } from '../fines-acc-part import { OPAL_FINES_ACCOUNT_DEFENDANT_DETAILS_PARENT_OR_GUARDIAN_TAB_REF_DATA_MOCK } from '@services/fines/opal-fines-service/mocks/opal-fines-account-defendant-details-parent-or-guardian-tab-ref-data.mock'; import { OPAL_FINES_ACCOUNT_DEFENDANT_DETAILS_FIXED_PENALTY_MOCK } from '@services/fines/opal-fines-service/mocks/opal-fines-account-defendant-details-fixed-penalty.mock'; import { OPAL_FINES_RESULT_REF_DATA_MOCK } from '@services/fines/opal-fines-service/mocks/opal-fines-result-ref-data.mock'; +import { FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS } from '../fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant'; import { beforeEach, describe, expect, it, vi } from 'vitest'; describe('FinesAccDefendantDetailsComponent', () => { @@ -168,6 +169,20 @@ describe('FinesAccDefendantDetailsComponent', () => { ); }); + it('should call router.navigate when navigateToChangeEnforcementCourtPage is called', () => { + component.navigateToChangeEnforcementCourtPage(123); + + expect(routerSpy.navigate).toHaveBeenCalledWith( + [ + `../${FINES_ACC_DEFENDANT_ROUTING_PATHS.children.enforcement}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.root}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.children.change}`, + ], + { + relativeTo: component['activatedRoute'], + state: { currentEnforcementCourtId: 123 }, + }, + ); + }); + it('should fetch the defendant tab data when fragment is changed to defendant', () => { component['refreshFragment$'].next('defendant'); // Subscribe to trigger the pipe execution diff --git a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.ts b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.ts index c8d7f1b673..8e914f5bed 100644 --- a/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.ts +++ b/src/app/flows/fines/fines-acc/fines-acc-defendant-details/fines-acc-defendant-details.component.ts @@ -55,6 +55,7 @@ import { FINES_ACCOUNT_TYPES } from '../../constants/fines-account-types.constan import { IOpalFinesResultRefData } from '@services/fines/opal-fines-service/interfaces/opal-fines-result-ref-data.interface'; import { FinesAccDefendantDetailsEnforcementTab } from './fines-acc-defendant-details-enforcement-tab/fines-acc-defendant-details-enforcement-tab.component'; import { FinesAccSummaryHeaderComponent } from '../fines-acc-summary-header/fines-acc-summary-header.component'; +import { FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS } from '../fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant'; @Component({ selector: 'app-fines-acc-defendant-details', @@ -458,4 +459,21 @@ export class FinesAccDefendantDetailsComponent extends AbstractTabData implement relativeTo: this.activatedRoute, }); } + + /** + * Navigates to the change enforcement court page, preserving the current court id for no-op submissions. + * + * @param currentEnforcementCourtId The current enforcement court id shown on the enforcement tab. + */ + public navigateToChangeEnforcementCourtPage(currentEnforcementCourtId: number | null): void { + this['router'].navigate( + [ + `../${FINES_ACC_DEFENDANT_ROUTING_PATHS.children.enforcement}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.root}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.children.change}`, + ], + { + relativeTo: this.activatedRoute, + state: { currentEnforcementCourtId }, + }, + ); + } } diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-field-errors.constant.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-field-errors.constant.ts new file mode 100644 index 0000000000..2e90730c20 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-field-errors.constant.ts @@ -0,0 +1,10 @@ +import { IFinesAccEnfCourtChangeFieldErrors } from '../interfaces/fines-acc-enf-court-change-field-errors.interface'; + +export const FINES_ACC_ENF_COURT_CHANGE_FIELD_ERRORS: IFinesAccEnfCourtChangeFieldErrors = { + facc_enf_court: { + required: { + message: 'Select an enforcement court', + priority: 1, + }, + }, +}; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant.ts new file mode 100644 index 0000000000..d595f01f1e --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant.ts @@ -0,0 +1,8 @@ +import { IFinesAccEnfCourtChangeRoutingPaths } from '../interfaces/fines-acc-enf-court-change-routing-paths.interface'; + +export const FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS: IFinesAccEnfCourtChangeRoutingPaths = { + root: 'court', + children: { + change: 'change', + }, +}; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-titles.constant.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-titles.constant.ts new file mode 100644 index 0000000000..2f7c2105fb --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-titles.constant.ts @@ -0,0 +1,8 @@ +import { IFinesAccEnfCourtChangeRoutingPaths } from '../interfaces/fines-acc-enf-court-change-routing-paths.interface'; + +export const FINES_ACC_ENF_COURT_CHANGE_ROUTING_TITLES: IFinesAccEnfCourtChangeRoutingPaths = { + root: 'Enforcement court', + children: { + change: 'Change enforcement court', + }, +}; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-success-message.constant.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-success-message.constant.ts new file mode 100644 index 0000000000..e93a6276a5 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/constants/fines-acc-enf-court-change-success-message.constant.ts @@ -0,0 +1 @@ +export const FINES_ACC_ENF_COURT_CHANGE_SUCCESS_MESSAGE = 'Enforcement court changed'; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.html b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.html new file mode 100644 index 0000000000..295d26c703 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.html @@ -0,0 +1,30 @@ + + + +
+ + +
+ + Change + + +
+
diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.spec.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.spec.ts new file mode 100644 index 0000000000..d27c691ee2 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.spec.ts @@ -0,0 +1,42 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ActivatedRoute } from '@angular/router'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { FinesAccEnfCourtChangeFormComponent } from './fines-acc-enf-court-change-form.component'; + +describe('FinesAccEnfCourtChangeFormComponent', () => { + let component: FinesAccEnfCourtChangeFormComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FinesAccEnfCourtChangeFormComponent], + providers: [{ provide: ActivatedRoute, useValue: { snapshot: { params: {}, data: {} } } }], + }).compileComponents(); + + fixture = TestBed.createComponent(FinesAccEnfCourtChangeFormComponent); + component = fixture.componentInstance; + component.accountNumber = '123456'; + component.courtOptions = [{ value: 101, name: 'Test Court (101)' }]; + component.partyName = 'Mr Test PERSON'; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should initialize the enforcement court control as required', () => { + const control = component.form.get('facc_enf_court'); + + expect(control).toBeTruthy(); + expect(control?.hasError('required')).toBe(true); + }); + + it('should emit cancel when handleCancel is called', () => { + const emitSpy = vi.spyOn(component.cancelRequested, 'emit'); + + component.handleCancel(); + + expect(emitSpy).toHaveBeenCalled(); + }); +}); diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.ts new file mode 100644 index 0000000000..dca3d219a2 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component.ts @@ -0,0 +1,67 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { AbstractFormBaseComponent } from '@hmcts/opal-frontend-common/components/abstract/abstract-form-base'; +import { + IAbstractFormBaseFieldErrors, + IAbstractFormBaseForm, +} from '@hmcts/opal-frontend-common/components/abstract/abstract-form-base/interfaces'; +import { IAbstractFormControlErrorMessage } from '@hmcts/opal-frontend-common/components/abstract/interfaces'; +import { AlphagovAccessibleAutocompleteComponent } from '@hmcts/opal-frontend-common/components/alphagov/alphagov-accessible-autocomplete'; +import { IAlphagovAccessibleAutocompleteItem } from '@hmcts/opal-frontend-common/components/alphagov/alphagov-accessible-autocomplete/interfaces'; +import { GovukButtonComponent } from '@hmcts/opal-frontend-common/components/govuk/govuk-button'; +import { GovukCancelLinkComponent } from '@hmcts/opal-frontend-common/components/govuk/govuk-cancel-link'; +import { GovukErrorSummaryComponent } from '@hmcts/opal-frontend-common/components/govuk/govuk-error-summary'; +import { GovukHeadingWithCaptionComponent } from '@hmcts/opal-frontend-common/components/govuk/govuk-heading-with-caption'; +import { FINES_ACC_ENF_COURT_CHANGE_FIELD_ERRORS } from '../constants/fines-acc-enf-court-change-field-errors.constant'; +import { IFinesAccEnfCourtChangeFormState } from '../interfaces/fines-acc-enf-court-change-form-state.interface'; + +@Component({ + selector: 'app-fines-acc-enf-court-change-form', + imports: [ + FormsModule, + ReactiveFormsModule, + AlphagovAccessibleAutocompleteComponent, + GovukButtonComponent, + GovukCancelLinkComponent, + GovukErrorSummaryComponent, + GovukHeadingWithCaptionComponent, + ], + templateUrl: './fines-acc-enf-court-change-form.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, +}) +export class FinesAccEnfCourtChangeFormComponent extends AbstractFormBaseComponent implements OnInit, OnDestroy { + protected override fieldErrors: IAbstractFormBaseFieldErrors = { + ...FINES_ACC_ENF_COURT_CHANGE_FIELD_ERRORS, + }; + protected override formSubmit = new EventEmitter>(); + @Output() public cancelRequested = new EventEmitter(); + public override formControlErrorMessages: IAbstractFormControlErrorMessage = {}; + @Input({ required: true }) public accountNumber!: string; + @Input({ required: true }) public courtOptions!: IAlphagovAccessibleAutocompleteItem[]; + @Input({ required: true }) public partyName!: string; + + /** + * Sets up the enforcement court change form with the required court control. + */ + private setupForm(): void { + this.form = new FormGroup({ + facc_enf_court: new FormControl(null, Validators.required), + }); + } + + /** + * Initializes the form before wiring up the shared form behaviour. + */ + public override ngOnInit(): void { + this.setupForm(); + super.ngOnInit(); + } + + /** + * Emits the cancel action to the parent component. + */ + public handleCancel(): void { + this.cancelRequested.emit(); + } +} diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.html b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.html new file mode 100644 index 0000000000..d53d3eb3db --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.html @@ -0,0 +1,10 @@ +
+ +
diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.spec.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.spec.ts new file mode 100644 index 0000000000..e3be5fe3ef --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.spec.ts @@ -0,0 +1,205 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { signal, WritableSignal } from '@angular/core'; +import { ActivatedRoute, Navigation, Router } from '@angular/router'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { of, throwError } from 'rxjs'; +import { FinesAccEnfCourtChangeComponent } from './fines-acc-enf-court-change.component'; +import { FinesAccountStore } from '../stores/fines-acc.store'; +import { FinesAccPayloadService } from '../services/fines-acc-payload.service'; +import { OpalFines } from '@services/fines/opal-fines-service/opal-fines.service'; +import { UtilsService } from '@hmcts/opal-frontend-common/services/utils-service'; +import { FINES_ACC_DEFENDANT_ROUTING_PATHS } from '../routing/constants/fines-acc-defendant-routing-paths.constant'; +import { FINES_ACC_ENF_COURT_CHANGE_SUCCESS_MESSAGE } from './constants/fines-acc-enf-court-change-success-message.constant'; +import { OPAL_FINES_COURT_REF_DATA_MOCK } from '@services/fines/opal-fines-service/mocks/opal-fines-court-ref-data.mock'; + +describe('FinesAccEnfCourtChangeComponent', () => { + let component: FinesAccEnfCourtChangeComponent; + let fixture: ComponentFixture; + let mockCurrentNavigation: WritableSignal; + const mockCourtRefData = structuredClone(OPAL_FINES_COURT_REF_DATA_MOCK); + const selectedCourt = mockCourtRefData.refData[1]; + const currentCourt = mockCourtRefData.refData[0]; + + const mockAccountStore = { + getAccountNumber: signal('123456'), + party_name: signal('Mr Test PERSON'), + account_id: signal(1001), + base_version: signal('1'), + business_unit_id: signal('2002'), + setSuccessMessage: vi.fn(), + }; + + const mockPayloadService = { + buildEnforcementCourtFormPayload: vi + .fn() + .mockReturnValue({ enforcement_court: { court_id: selectedCourt.court_id } }), + }; + + const mockOpalFinesService = { + patchDefendantAccount: vi.fn().mockReturnValue(of({})), + getCourtPrettyName: vi.fn( + (court: { name: string; court_code: string | number }) => `${court.name} (${court.court_code})`, + ), + }; + + const mockUtilsService = { + scrollToTop: vi.fn(), + }; + + beforeEach(async () => { + vi.clearAllMocks(); + + mockCurrentNavigation = signal({ + extras: { + state: {}, + }, + } as unknown as Navigation); + + await TestBed.configureTestingModule({ + imports: [FinesAccEnfCourtChangeComponent], + providers: [ + { + provide: ActivatedRoute, + useValue: { + snapshot: { + data: { + courtsRefData: mockCourtRefData, + }, + }, + }, + }, + { + provide: Router, + useValue: { + currentNavigation: mockCurrentNavigation, + navigate: vi.fn(), + }, + }, + { provide: FinesAccountStore, useValue: mockAccountStore }, + { provide: FinesAccPayloadService, useValue: mockPayloadService }, + { provide: OpalFines, useValue: mockOpalFinesService }, + { provide: UtilsService, useValue: mockUtilsService }, + ], + }).compileComponents(); + + fixture = TestBed.createComponent(FinesAccEnfCourtChangeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should map route data into autocomplete options', () => { + expect(component.courtOptions).toEqual( + mockCourtRefData.refData.map((court) => ({ + value: court.court_id, + name: `${court.name} (${court.court_code})`, + })), + ); + }); + + it('should patch and navigate on success when the selected court changes', () => { + const routerNavigateSpy = vi.spyOn(component as never, 'routerNavigate'); + + component.handleSubmit({ + formData: { + facc_enf_court: selectedCourt.court_id, + }, + nestedFlow: false, + }); + + expect(mockPayloadService.buildEnforcementCourtFormPayload).toHaveBeenCalledWith({ + facc_enf_court: selectedCourt.court_id, + }); + expect(mockOpalFinesService.patchDefendantAccount).toHaveBeenCalledWith( + 1001, + { enforcement_court: { court_id: selectedCourt.court_id } }, + '1', + '2002', + ); + expect(mockAccountStore.setSuccessMessage).toHaveBeenCalledWith(FINES_ACC_ENF_COURT_CHANGE_SUCCESS_MESSAGE); + expect(routerNavigateSpy).toHaveBeenCalledWith( + FINES_ACC_DEFENDANT_ROUTING_PATHS.children.details, + false, + undefined, + null, + 'enforcement', + ); + }); + + it('should navigate back without patching when the selected court matches the current court', () => { + mockCurrentNavigation.set({ + extras: { + state: { + currentEnforcementCourtId: currentCourt.court_id, + }, + }, + } as unknown as Navigation); + + fixture = TestBed.createComponent(FinesAccEnfCourtChangeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + const routerNavigateSpy = vi.spyOn(component as never, 'routerNavigate'); + + component.handleSubmit({ + formData: { + facc_enf_court: currentCourt.court_id, + }, + nestedFlow: false, + }); + + expect(mockPayloadService.buildEnforcementCourtFormPayload).not.toHaveBeenCalled(); + expect(mockOpalFinesService.patchDefendantAccount).not.toHaveBeenCalled(); + expect(mockAccountStore.setSuccessMessage).not.toHaveBeenCalled(); + expect(routerNavigateSpy).toHaveBeenCalledWith( + FINES_ACC_DEFENDANT_ROUTING_PATHS.children.details, + false, + undefined, + null, + 'enforcement', + ); + }); + + it('should scroll to top on submit error', () => { + mockOpalFinesService.patchDefendantAccount = vi.fn().mockReturnValue(throwError(() => new Error('fail'))); + fixture = TestBed.createComponent(FinesAccEnfCourtChangeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + + const routerNavigateSpy = vi.spyOn(component as never, 'routerNavigate'); + + component.handleSubmit({ + formData: { + facc_enf_court: selectedCourt.court_id, + }, + nestedFlow: false, + }); + + expect(mockUtilsService.scrollToTop).toHaveBeenCalled(); + expect(routerNavigateSpy).not.toHaveBeenCalled(); + }); + + it('should update stateUnsavedChanges when handleUnsavedChanges is called', () => { + component.handleUnsavedChanges(true); + + expect((component as unknown as { stateUnsavedChanges: boolean }).stateUnsavedChanges).toBe(true); + }); + + it('should navigate back to the enforcement tab when cancel is triggered', () => { + const routerNavigateSpy = vi.spyOn(component as never, 'routerNavigate'); + + component.handleCancel(); + + expect(mockAccountStore.setSuccessMessage).not.toHaveBeenCalled(); + expect(routerNavigateSpy).toHaveBeenCalledWith( + FINES_ACC_DEFENDANT_ROUTING_PATHS.children.details, + false, + undefined, + null, + 'enforcement', + ); + }); +}); diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.ts new file mode 100644 index 0000000000..edfc37dea5 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/fines-acc-enf-court-change.component.ts @@ -0,0 +1,121 @@ +import { ChangeDetectionStrategy, Component, inject, OnDestroy } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { catchError, EMPTY, Subject, takeUntil } from 'rxjs'; +import { AbstractFormParentBaseComponent } from '@hmcts/opal-frontend-common/components/abstract/abstract-form-parent-base'; +import { IAbstractFormBaseForm } from '@hmcts/opal-frontend-common/components/abstract/abstract-form-base/interfaces'; +import { IAlphagovAccessibleAutocompleteItem } from '@hmcts/opal-frontend-common/components/alphagov/alphagov-accessible-autocomplete/interfaces'; +import { UtilsService } from '@hmcts/opal-frontend-common/services/utils-service'; +import { FinesAccEnfCourtChangeFormComponent } from './fines-acc-enf-court-change-form/fines-acc-enf-court-change-form.component'; +import { FinesAccountStore } from '../stores/fines-acc.store'; +import { FinesAccPayloadService } from '../services/fines-acc-payload.service'; +import { FINES_ACC_ENF_COURT_CHANGE_SUCCESS_MESSAGE } from './constants/fines-acc-enf-court-change-success-message.constant'; +import { FINES_ACC_DEFENDANT_ROUTING_PATHS } from '../routing/constants/fines-acc-defendant-routing-paths.constant'; +import { IFinesAccEnfCourtChangeFormState } from './interfaces/fines-acc-enf-court-change-form-state.interface'; +import { IOpalFinesCourtRefData } from '@services/fines/opal-fines-service/interfaces/opal-fines-court-ref-data.interface'; +import { OpalFines } from '@services/fines/opal-fines-service/opal-fines.service'; + +@Component({ + selector: 'app-fines-acc-enf-court-change', + templateUrl: './fines-acc-enf-court-change.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, + standalone: true, + imports: [FinesAccEnfCourtChangeFormComponent], +}) +export class FinesAccEnfCourtChangeComponent extends AbstractFormParentBaseComponent implements OnDestroy { + private readonly ngUnsubscribe = new Subject(); + private readonly route = inject(ActivatedRoute); + private readonly navigationRouter = inject(Router); + private readonly finesAccStore = inject(FinesAccountStore); + private readonly finesAccPayloadService = inject(FinesAccPayloadService); + private readonly opalFinesService = inject(OpalFines); + private readonly utilsService = inject(UtilsService); + private readonly currentEnforcementCourtId = this.navigationRouter.currentNavigation()?.extras.state?.[ + 'currentEnforcementCourtId' + ] as number | null | undefined; + + public accountNumber = this.finesAccStore.getAccountNumber() ?? ''; + public partyName = this.finesAccStore.party_name() ?? ''; + public courtOptions: IAlphagovAccessibleAutocompleteItem[] = this.setCourtOptions(); + + /** + * Maps the resolved courts reference data into autocomplete options. + * + * @returns The list of courts formatted for the autocomplete component. + */ + private setCourtOptions(): IAlphagovAccessibleAutocompleteItem[] { + return (this.route.snapshot.data['courtsRefData'] as IOpalFinesCourtRefData).refData.map((court) => ({ + value: court.court_id, + name: this.opalFinesService.getCourtPrettyName(court), + })); + } + + /** + * Navigates back to the enforcement tab and optionally sets the success banner. + * + * @param setSuccessMessage Whether to set the success banner before navigating away. + */ + private navigateToEnforcementTab(setSuccessMessage: boolean): void { + this.stateUnsavedChanges = false; + + if (setSuccessMessage) { + this.finesAccStore.setSuccessMessage(FINES_ACC_ENF_COURT_CHANGE_SUCCESS_MESSAGE); + } + + this.routerNavigate(FINES_ACC_DEFENDANT_ROUTING_PATHS.children.details, false, undefined, null, 'enforcement'); + } + + /** + * Submits the selected enforcement court unless it matches the current value. + * + * @param form The submitted form containing the selected enforcement court. + */ + public handleSubmit(form: IAbstractFormBaseForm): void { + const selectedCourtId = Number(form.formData.facc_enf_court); + + if (selectedCourtId === this.currentEnforcementCourtId) { + this.navigateToEnforcementTab(false); + return; + } + + const payload = this.finesAccPayloadService.buildEnforcementCourtFormPayload(form.formData); + this.opalFinesService + .patchDefendantAccount( + this.finesAccStore.account_id()!, + payload, + this.finesAccStore.base_version()!, + this.finesAccStore.business_unit_id()!, + ) + .pipe( + catchError(() => { + this.utilsService.scrollToTop(); + return EMPTY; + }), + takeUntil(this.ngUnsubscribe), + ) + .subscribe(() => this.navigateToEnforcementTab(true)); + } + + /** + * Navigates back to the enforcement tab without saving changes. + */ + public handleCancel(): void { + this.navigateToEnforcementTab(false); + } + + /** + * Updates the page-level unsaved changes state from the child form. + * + * @param unsavedChanges Whether the form currently has unsaved changes. + */ + public handleUnsavedChanges(unsavedChanges: boolean): void { + this.stateUnsavedChanges = unsavedChanges; + } + + /** + * Completes the destroy notifier used by active subscriptions. + */ + public ngOnDestroy(): void { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } +} diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-field-errors.interface.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-field-errors.interface.ts new file mode 100644 index 0000000000..77ef795e0b --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-field-errors.interface.ts @@ -0,0 +1,9 @@ +import { + IAbstractFormBaseFieldError, + IAbstractFormBaseFieldErrors, +} from '@hmcts/opal-frontend-common/components/abstract/abstract-form-base/interfaces'; +import { IFinesAccEnfCourtChangeFormState } from './fines-acc-enf-court-change-form-state.interface'; + +export type IFinesAccEnfCourtChangeFieldErrors = IAbstractFormBaseFieldErrors & { + [K in keyof IFinesAccEnfCourtChangeFormState]: IAbstractFormBaseFieldError; +}; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form-state.interface.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form-state.interface.ts new file mode 100644 index 0000000000..4eac2c32ed --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form-state.interface.ts @@ -0,0 +1,3 @@ +export interface IFinesAccEnfCourtChangeFormState { + facc_enf_court: number | null; +} diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form.interface.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form.interface.ts new file mode 100644 index 0000000000..e5a4b1bb57 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form.interface.ts @@ -0,0 +1,4 @@ +import { IAbstractFormBaseForm } from '@hmcts/opal-frontend-common/components/abstract/abstract-form-base/interfaces'; +import { IFinesAccEnfCourtChangeFormState } from './fines-acc-enf-court-change-form-state.interface'; + +export type IFinesAccEnfCourtChangeForm = IAbstractFormBaseForm; diff --git a/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-routing-paths.interface.ts b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-routing-paths.interface.ts new file mode 100644 index 0000000000..15bcf97360 --- /dev/null +++ b/src/app/flows/fines/fines-acc/fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-routing-paths.interface.ts @@ -0,0 +1,8 @@ +import { IChildRoutingPaths } from '@hmcts/opal-frontend-common/pages/routing/interfaces'; + +export interface IFinesAccEnfCourtChangeRoutingPaths extends IChildRoutingPaths { + root: string; + children: { + change: string; + }; +} diff --git a/src/app/flows/fines/fines-acc/routing/fines-acc.routes.ts b/src/app/flows/fines/fines-acc/routing/fines-acc.routes.ts index e8420f4f79..ecf7e3eb11 100644 --- a/src/app/flows/fines/fines-acc/routing/fines-acc.routes.ts +++ b/src/app/flows/fines/fines-acc/routing/fines-acc.routes.ts @@ -22,6 +22,9 @@ import { fetchLocalJusticeAreasResolver } from '../../routing/resolvers/fetch-re import { fetchEnforcersResolver } from '../../routing/resolvers/fetch-results-with-params-resolver/fetch-enforcers-resolver'; import { FINES_ACC_ENF_OVERRIDE_ADD_CHANGE_ROUTING_TITLES } from '../fines-acc-enf-override-add-change/constants/fines-acc-enf-override-add-change-routing-titles.constant'; import { FINES_ACC_ENF_OVERRIDE_ADD_CHANGE_ROUTING_PATHS } from '../fines-acc-enf-override-add-change/constants/fines-acc-enf-override-add-change-routing-paths.constant'; +import { FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS } from '../fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-paths.constant'; +import { FINES_ACC_ENF_COURT_CHANGE_ROUTING_TITLES } from '../fines-acc-enf-court-change/constants/fines-acc-enf-court-change-routing-titles.constant'; +import { fetchCourtsResolver } from './resolvers/fetch-courts-resolver/fetch-courts.resolver'; const accRootPermissionIds = FINES_PERMISSIONS; @@ -194,6 +197,23 @@ export const routing: Routes = [ enforcersRefData: fetchEnforcersResolver, }, }, + { + path: `${FINES_ACC_DEFENDANT_ROUTING_PATHS.children.enforcement}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.root}/${FINES_ACC_ENF_COURT_CHANGE_ROUTING_PATHS.children.change}`, + loadComponent: () => + import('../fines-acc-enf-court-change/fines-acc-enf-court-change.component').then( + (c) => c.FinesAccEnfCourtChangeComponent, + ), + canActivate: [routePermissionsGuard, finesAccStateGuard], + canDeactivate: [canDeactivateGuard], + data: { + title: FINES_ACC_ENF_COURT_CHANGE_ROUTING_TITLES.children.change, + routePermissionId: [accRootPermissionIds['account-maintenance']], + }, + resolve: { + title: TitleResolver, + courtsRefData: fetchCourtsResolver, + }, + }, ], }, { diff --git a/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.spec.ts b/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.spec.ts new file mode 100644 index 0000000000..becb6deb52 --- /dev/null +++ b/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.spec.ts @@ -0,0 +1,43 @@ +import { TestBed } from '@angular/core/testing'; +import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { Observable, of } from 'rxjs'; +import { fetchCourtsResolver } from './fetch-courts.resolver'; +import { OpalFines } from '@services/fines/opal-fines-service/opal-fines.service'; +import { FinesAccountStore } from '../../../stores/fines-acc.store'; +import { IOpalFinesCourtRefData } from '@services/fines/opal-fines-service/interfaces/opal-fines-court-ref-data.interface'; + +describe('fetchCourtsResolver', () => { + const executeResolver: ResolveFn = (...resolverParameters) => + TestBed.runInInjectionContext(() => fetchCourtsResolver(...resolverParameters)); + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ + { + provide: OpalFines, + useValue: { + getCourts: vi.fn().mockReturnValue(of({ count: 1, refData: [] })), + }, + }, + { + provide: FinesAccountStore, + useValue: { + business_unit_id: vi.fn().mockReturnValue('123'), + }, + }, + ], + }); + }); + + it('should fetch courts for the current account business unit', () => { + const opalFinesService = TestBed.inject(OpalFines); + const result = executeResolver( + {} as ActivatedRouteSnapshot, + {} as RouterStateSnapshot, + ) as Observable; + + result.subscribe((value: IOpalFinesCourtRefData) => expect(value).toEqual({ count: 1, refData: [] })); + expect(opalFinesService.getCourts).toHaveBeenCalledWith(123); + }); +}); diff --git a/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.ts b/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.ts new file mode 100644 index 0000000000..38912799b5 --- /dev/null +++ b/src/app/flows/fines/fines-acc/routing/resolvers/fetch-courts-resolver/fetch-courts.resolver.ts @@ -0,0 +1,13 @@ +import { ResolveFn } from '@angular/router'; +import { inject } from '@angular/core'; +import { Observable } from 'rxjs'; +import { OpalFines } from '@services/fines/opal-fines-service/opal-fines.service'; +import { IOpalFinesCourtRefData } from '@services/fines/opal-fines-service/interfaces/opal-fines-court-ref-data.interface'; +import { FinesAccountStore } from '../../../stores/fines-acc.store'; + +export const fetchCourtsResolver: ResolveFn = (): Observable => { + const opalFinesService = inject(OpalFines); + const finesAccStore = inject(FinesAccountStore); + + return opalFinesService.getCourts(Number(finesAccStore.business_unit_id())); +}; diff --git a/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.spec.ts b/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.spec.ts index 74a28b2b30..a450eecfcd 100644 --- a/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.spec.ts +++ b/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.spec.ts @@ -14,6 +14,7 @@ import { IOpalFinesAccountDefendantAccountParty } from '../../services/opal-fine import { OPAL_FINES_ACCOUNT_DEFENDANT_ACCOUNT_PARTY_MOCK } from '../../services/opal-fines-service/mocks/opal-fines-account-defendant-account-party.mock'; import { OPAL_FINES_ACCOUNT_DEFENDANT_AT_A_GLANCE_MOCK } from '@services/fines/opal-fines-service/mocks/opal-fines-account-defendant-at-a-glance.mock'; import { IFinesAccAddCommentsFormState } from '../fines-acc-comments-add/interfaces/fines-acc-comments-add-form-state.interface'; +import { IFinesAccEnfCourtChangeFormState } from '../fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form-state.interface'; import { FINES_MAC_MAP_TRANSFORM_ITEMS_CONFIG } from '../../fines-mac/services/fines-mac-payload/constants/fines-mac-map-transform-items-config.constant'; import { MOCK_EMPTY_FINES_ACC_PARTY_ADD_AMEND_CONVERT_FORM_DATA } from '../fines-acc-party-add-amend-convert/mocks/fines-acc-party-add-amend-convert-form-empty.mock'; import { FINES_ACC_MINOR_CREDITOR_DETAILS_HEADER_MOCK } from '../fines-acc-minor-creditor-details/mocks/fines-acc-minor-creditor-details-header.mock'; @@ -545,6 +546,7 @@ describe('FinesAccPayloadService', () => { free_text_note_2: 'Updated note 2', free_text_note_3: 'Updated note 3', }, + enforcement_court: null, enforcement_override: null, }); }); @@ -566,6 +568,7 @@ describe('FinesAccPayloadService', () => { free_text_note_2: null, free_text_note_3: null, }, + enforcement_court: null, enforcement_override: null, }); }); @@ -631,6 +634,22 @@ describe('FinesAccPayloadService', () => { }); }); + describe('buildEnforcementCourtFormPayload', () => { + it('should build the correct payload for an enforcement court change', () => { + const formState: IFinesAccEnfCourtChangeFormState = { + facc_enf_court: 202, + }; + + const result = service.buildEnforcementCourtFormPayload(formState); + + expect(result).toEqual({ + enforcement_court: { + court_id: 202, + }, + }); + }); + }); + describe('transformPaymentTermsPayload', () => { it('should return form structure with nestedFlow false', () => { const mockPaymentTermsData = { diff --git a/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.ts b/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.ts index 06959f87ef..5f4e82f506 100644 --- a/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.ts +++ b/src/app/flows/fines/fines-acc/services/fines-acc-payload.service.ts @@ -27,6 +27,7 @@ import { buildAccountPartyFromFormState } from './utils/fines-acc-payload-build- import { IOpalFinesAccountMinorCreditorDetailsHeader } from '../fines-acc-minor-creditor-details/interfaces/fines-acc-minor-creditor-details-header.interface'; import { IFinesAccEnfOverrideAddChangeFormState } from '../fines-acc-enf-override-add-change/interfaces/fines-acc-enf-override-add-change-form-state.interface'; import { OPAL_FINES_DEFENDANT_ACCOUNT_PATCH_PAYLOAD_DEFAULTS } from '../../services/opal-fines-service/constants/opal-fines-defendant-account-patch-payload-defaults.constant'; +import { IFinesAccEnfCourtChangeFormState } from '../fines-acc-enf-court-change/interfaces/fines-acc-enf-court-change-form-state.interface'; @Injectable({ providedIn: 'root', @@ -210,6 +211,23 @@ export class FinesAccPayloadService { }; } + /** + * Transforms the given IFinesAccEnfCourtChangeFormState into an update payload + * for the defendant account API. + * + * @param formState - The form state containing the enforcement court data + * @returns The transformed payload for updating the defendant account + */ + public buildEnforcementCourtFormPayload( + formState: IFinesAccEnfCourtChangeFormState, + ): IOpalFinesUpdateDefendantAccountPayload { + return { + enforcement_court: { + court_id: Number(formState.facc_enf_court), + }, + }; + } + /** * Transforms the given finesMacPayload object by applying the transformations diff --git a/src/app/flows/fines/services/opal-fines-service/constants/opal-fines-defendant-account-patch-payload-defaults.constant.ts b/src/app/flows/fines/services/opal-fines-service/constants/opal-fines-defendant-account-patch-payload-defaults.constant.ts index b9fb0ce6fd..5e3a45c17e 100644 --- a/src/app/flows/fines/services/opal-fines-service/constants/opal-fines-defendant-account-patch-payload-defaults.constant.ts +++ b/src/app/flows/fines/services/opal-fines-service/constants/opal-fines-defendant-account-patch-payload-defaults.constant.ts @@ -2,5 +2,6 @@ import { IOpalFinesUpdateDefendantAccountPayload } from '../interfaces/opal-fine export const OPAL_FINES_DEFENDANT_ACCOUNT_PATCH_PAYLOAD_DEFAULTS: IOpalFinesUpdateDefendantAccountPayload = { comment_and_notes: null, + enforcement_court: null, enforcement_override: null, }; diff --git a/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account-enforcement-court.interface.ts b/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account-enforcement-court.interface.ts new file mode 100644 index 0000000000..ef515645ef --- /dev/null +++ b/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account-enforcement-court.interface.ts @@ -0,0 +1,3 @@ +export interface IOpalFinesUpdateDefendantAccountEnforcementCourt { + court_id: number; +} diff --git a/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account.interface.ts b/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account.interface.ts index 09d92d1f52..2126cebb42 100644 --- a/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account.interface.ts +++ b/src/app/flows/fines/services/opal-fines-service/interfaces/opal-fines-update-defendant-account.interface.ts @@ -1,10 +1,12 @@ import { IOpalFinesUpdateDefendantAccountCommentsNotes } from './opal-fines-update-defendant-account-comments-notes.interface'; +import { IOpalFinesUpdateDefendantAccountEnforcementCourt } from './opal-fines-update-defendant-account-enforcement-court.interface'; import { IOpalFinesUpdateDefendantAccountEnforcementOverride } from './opal-fines-update-defendant-account-enforcement-override.interface'; /** * Interface for the payload to update a defendant account *Subject to change */ export interface IOpalFinesUpdateDefendantAccountPayload { - comment_and_notes: IOpalFinesUpdateDefendantAccountCommentsNotes | null; - enforcement_override: IOpalFinesUpdateDefendantAccountEnforcementOverride | null; + comment_and_notes?: IOpalFinesUpdateDefendantAccountCommentsNotes | null; + enforcement_court?: IOpalFinesUpdateDefendantAccountEnforcementCourt | null; + enforcement_override?: IOpalFinesUpdateDefendantAccountEnforcementOverride | null; }