168 lines
5.8 KiB
TypeScript
168 lines
5.8 KiB
TypeScript
/**
|
|
* Copyright since 2025 Mifos Initiative
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
import { Component, OnInit, inject } from '@angular/core';
|
|
import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
|
import { catchError, of } from 'rxjs';
|
|
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
|
import { OrganizationService } from '../organization.service';
|
|
|
|
const BRANCH_TYPES = [
|
|
{ value: 'HEAD_OFFICE', label: 'Head Office' },
|
|
{ value: 'BRANCH', label: 'Branch' },
|
|
{ value: 'REGIONAL_OFFICE', label: 'Regional Office' },
|
|
{ value: 'ZONAL_OFFICE', label: 'Zonal Office' }
|
|
];
|
|
|
|
/**
|
|
* The real-world operational fields behind a branch — code, address, contact, type and working
|
|
* hours — kept as their own screen on top of the stock Manage Offices flow, since m_office (the
|
|
* core Fineract entity) was deliberately left untouched. Pick an office, fill in what real-world
|
|
* UCB branch setup expects, save.
|
|
*/
|
|
@Component({
|
|
selector: 'mifosx-branch-profile',
|
|
templateUrl: './branch-profile.component.html',
|
|
styleUrls: ['./branch-profile.component.scss'],
|
|
imports: [...STANDALONE_SHARED_IMPORTS]
|
|
})
|
|
export class BranchProfileComponent implements OnInit {
|
|
private formBuilder = inject(UntypedFormBuilder);
|
|
private organizationService = inject(OrganizationService);
|
|
|
|
branchTypes = BRANCH_TYPES;
|
|
|
|
offices: any[] = [];
|
|
selectedOfficeId: number | null = null;
|
|
form: UntypedFormGroup;
|
|
|
|
loadingOffices = true;
|
|
loadingProfile = false;
|
|
saving = false;
|
|
errorMsg = '';
|
|
successMsg = '';
|
|
lastUpdated: any = null;
|
|
|
|
ngOnInit(): void {
|
|
this.form = this.formBuilder.group({
|
|
branchCode: [''],
|
|
branchType: [null],
|
|
address: [''],
|
|
pincode: [''],
|
|
contactPhone: [''],
|
|
contactEmail: [''],
|
|
workingHoursStart: [''],
|
|
workingHoursEnd: [''],
|
|
workingDays: [''],
|
|
ifscCode: [''],
|
|
micrCode: [''],
|
|
latitude: [null],
|
|
longitude: [null]
|
|
});
|
|
|
|
this.organizationService
|
|
.getBranchProfiles()
|
|
.pipe(
|
|
catchError((err: any) => {
|
|
this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not load branches.';
|
|
return of([]);
|
|
})
|
|
)
|
|
.subscribe((res: any[]) => {
|
|
this.loadingOffices = false;
|
|
this.offices = res || [];
|
|
if (this.offices.length === 1) {
|
|
this.selectOffice(this.offices[0].officeId);
|
|
}
|
|
});
|
|
}
|
|
|
|
selectOffice(officeId: number): void {
|
|
this.selectedOfficeId = officeId;
|
|
this.loadingProfile = true;
|
|
this.errorMsg = '';
|
|
this.successMsg = '';
|
|
this.organizationService
|
|
.getBranchProfile(officeId)
|
|
.pipe(
|
|
catchError((err: any) => {
|
|
this.loadingProfile = false;
|
|
this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not load this branch.';
|
|
return of(null);
|
|
})
|
|
)
|
|
.subscribe((res: any) => {
|
|
this.loadingProfile = false;
|
|
if (!res) return;
|
|
this.form.patchValue({
|
|
branchCode: res.branchCode ?? '',
|
|
branchType: res.branchType ?? null,
|
|
address: res.address ?? '',
|
|
pincode: res.pincode ?? '',
|
|
contactPhone: res.contactPhone ?? '',
|
|
contactEmail: res.contactEmail ?? '',
|
|
workingHoursStart: res.workingHoursStart ?? '',
|
|
workingHoursEnd: res.workingHoursEnd ?? '',
|
|
workingDays: res.workingDays ?? '',
|
|
ifscCode: res.ifscCode ?? '',
|
|
micrCode: res.micrCode ?? '',
|
|
latitude: res.latitude ?? null,
|
|
longitude: res.longitude ?? null
|
|
});
|
|
this.lastUpdated = res.updatedByUsername ? { by: res.updatedByUsername, at: res.updatedAt } : null;
|
|
this.form.markAsPristine();
|
|
// Reflect the just-loaded office in the list so the selector stays accurate without a reload.
|
|
const idx = this.offices.findIndex((o) => o.officeId === officeId);
|
|
if (idx >= 0) this.offices[idx] = res;
|
|
});
|
|
}
|
|
|
|
officeLabel(o: any): string {
|
|
return o.branchCode ? `${o.officeName} (${o.branchCode})` : o.officeName;
|
|
}
|
|
|
|
submit(): void {
|
|
if (this.saving || !this.selectedOfficeId) return;
|
|
this.saving = true;
|
|
this.errorMsg = '';
|
|
this.successMsg = '';
|
|
this.organizationService
|
|
.updateBranchProfile(this.selectedOfficeId, this.form.value)
|
|
.pipe(
|
|
catchError((err: any) => {
|
|
this.saving = false;
|
|
this.errorMsg = err?.error?.errors?.[0]?.defaultUserMessage ?? 'Could not save this branch.';
|
|
return of(null);
|
|
})
|
|
)
|
|
.subscribe((res: any) => {
|
|
this.saving = false;
|
|
if (!res) return;
|
|
if (res.rollbackTransaction) {
|
|
// Parked for checker approval - the branch profile has not actually changed yet.
|
|
this.successMsg = 'Branch profile update has been submitted for approval.';
|
|
this.form.markAsPristine();
|
|
return;
|
|
}
|
|
this.successMsg = 'Branch profile saved.';
|
|
this.form.markAsPristine();
|
|
// The response is now a CommandProcessingResult, not the updated row (the write goes through
|
|
// the command pipeline) - reload the saved row from the server instead of patching state from
|
|
// this response.
|
|
this.organizationService.getBranchProfile(this.selectedOfficeId!).subscribe((updated: any) => {
|
|
if (!updated) return;
|
|
this.lastUpdated = updated.updatedByUsername
|
|
? { by: updated.updatedByUsername, at: updated.updatedAt }
|
|
: null;
|
|
const idx = this.offices.findIndex((o) => o.officeId === this.selectedOfficeId);
|
|
if (idx >= 0) this.offices[idx] = updated;
|
|
});
|
|
});
|
|
}
|
|
}
|