Files
cbsnexora/src/app/rbi-circulars/gl-mapping-dialog.component.ts
T

122 lines
3.3 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, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog';
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
import { GlAccount } from 'app/gl-reports/gl-reports-data';
import { GlDateRange, glValueForCodes } from 'app/gl-reports/gl-reports.compute';
import { RETURN_SCALE, glAccountsForPicker } from './gl-mapping';
export interface GlMappingDialogData {
returnCode: string;
lineLabel: string;
/** The figure currently printed on the return, in thousands. */
filedValue: number | null;
selected: string[];
range: GlDateRange;
branchCode: string;
}
/**
* Lets a user pin one or more GL accounts to a single return line, showing live what
* the ledger would produce for the selection against the figure currently on the return.
*/
@Component({
selector: 'mifosx-gl-mapping-dialog',
standalone: true,
imports: [
CommonModule,
FormsModule,
MatDialogModule,
FaIconComponent
],
templateUrl: './gl-mapping-dialog.component.html',
styleUrls: ['./gl-mapping-dialog.component.scss']
})
export class GlMappingDialogComponent {
private dialogRef = inject(MatDialogRef<GlMappingDialogComponent>);
data = inject<GlMappingDialogData>(MAT_DIALOG_DATA);
readonly accounts: GlAccount[] = glAccountsForPicker();
search = '';
typeFilter = '';
selected: string[] = [];
readonly types = [
'ASSET',
'LIABILITY',
'INCOME',
'EXPENSE',
'CONTINGENT'
];
constructor() {
this.selected = [...(this.data.selected ?? [])];
}
get filtered(): GlAccount[] {
const q = this.search.trim().toLowerCase();
return this.accounts.filter((a) => {
if (this.typeFilter && a.type !== this.typeFilter) {
return false;
}
if (!q) {
return true;
}
return a.code.includes(q) || a.name.toLowerCase().includes(q) || a.group.toLowerCase().includes(q);
});
}
isSelected(code: string): boolean {
return this.selected.includes(code);
}
toggle(code: string): void {
this.selected = this.isSelected(code) ? this.selected.filter((c) => c !== code) : [
...this.selected,
code
];
}
removeSelected(code: string): void {
this.selected = this.selected.filter((c) => c !== code);
}
clearAll(): void {
this.selected = [];
}
accountName(code: string): string {
return this.accounts.find((a) => a.code === code)?.name ?? code;
}
/** Live ledger figure for the current selection, in the return's scale. */
get derivedValue(): number {
return glValueForCodes(this.selected, this.data.range, this.data.branchCode) / RETURN_SCALE;
}
get variance(): number | null {
return this.data.filedValue == null ? null : this.derivedValue - this.data.filedValue;
}
get matchesFiled(): boolean {
return this.variance !== null && Math.abs(this.variance) < 0.005;
}
save(): void {
this.dialogRef.close(this.selected);
}
cancel(): void {
this.dialogRef.close(undefined);
}
}