122 lines
3.3 KiB
TypeScript
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);
|
|
}
|
|
}
|