DDS: Agent settlement (Agent Tran), Close Party account UI, reports UI, Party-Savings link field
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
|
||||
<div class="dr-container">
|
||||
<div class="dr-header">
|
||||
<button mat-stroked-button [routerLink]="['../']" class="dr-back">
|
||||
<i class="fas fa-arrow-left"></i> Deposits
|
||||
</button>
|
||||
<h2 class="dr-header__title">DDS Reports</h2>
|
||||
</div>
|
||||
|
||||
@for (group of reportGroups; track group.title) {
|
||||
<div class="dr-group">
|
||||
<div class="dr-group__title">{{ group.title }}</div>
|
||||
<div class="dr-grid">
|
||||
@for (report of group.reports; track report) {
|
||||
<a class="dr-card" [routerLink]="['view', report]">
|
||||
<div class="dr-card__icon">
|
||||
<i class="fas fa-file-alt"></i>
|
||||
</div>
|
||||
<div class="dr-card__title">{{ report }}</div>
|
||||
<i class="fas fa-chevron-right dr-card__arrow"></i>
|
||||
</a>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -0,0 +1,97 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
$primary: #0f766e;
|
||||
|
||||
.dr-container {
|
||||
max-width: 1080px;
|
||||
margin: 0 auto;
|
||||
padding: 24px 16px;
|
||||
}
|
||||
|
||||
.dr-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
&__title {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.dr-back {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.dr-group {
|
||||
margin-bottom: 24px;
|
||||
|
||||
&__title {
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
color: $primary;
|
||||
font-weight: 700;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.dr-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.dr-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
background: var(--md-sys-color-surface, #fff);
|
||||
border: 1px solid rgb(0 0 0 / 8%);
|
||||
border-radius: 8px;
|
||||
padding: 12px 14px;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: box-shadow 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: $primary;
|
||||
font-size: 16px;
|
||||
flex: none;
|
||||
}
|
||||
|
||||
&__title {
|
||||
flex: 1;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
&__arrow {
|
||||
color: rgb(0 0 0 / 30%);
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 900px) {
|
||||
.dr-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 600px) {
|
||||
.dr-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
/** Angular Imports */
|
||||
import { Component } from '@angular/core';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
/**
|
||||
* DDS Reports hub component.
|
||||
*
|
||||
* Lists every DDS report from the legacy Reports menu, grouped the same
|
||||
* way (As-On-Date, Interest, Daily/Balance/Master, Transaction). Each
|
||||
* links to the shared report viewer, parameterised by report name.
|
||||
*
|
||||
* UI only for now: no report actually queries the backend yet — see
|
||||
* ReportViewerComponent.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-dds-reports',
|
||||
templateUrl: './dds-reports.component.html',
|
||||
styleUrls: ['./dds-reports.component.scss'],
|
||||
imports: [...STANDALONE_SHARED_IMPORTS]
|
||||
})
|
||||
export class DdsReportsComponent {
|
||||
reportGroups = [
|
||||
{
|
||||
title: 'As On Date',
|
||||
reports: [
|
||||
'Supplementary-DDS (As On)',
|
||||
'Agent Check List',
|
||||
'Party Check List-As On',
|
||||
'Party Balance',
|
||||
'Agent Wise Balance',
|
||||
'Agent Wise Monthly Collection',
|
||||
'Commission Register',
|
||||
'Collection Summary Agent Wise',
|
||||
'Close Party Ac Register',
|
||||
'Agent Partywise Daily Collection',
|
||||
'Daily Collection Balance',
|
||||
'Interest Certificate',
|
||||
'Mature Date Wise Report'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Interest',
|
||||
reports: [
|
||||
'Party Int. Register',
|
||||
'Commission Register'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Daily / Balance / Master',
|
||||
reports: [
|
||||
'Daily Collection Report',
|
||||
'Balance Summary',
|
||||
'Master Data Export'
|
||||
]
|
||||
},
|
||||
{
|
||||
title: 'Transaction',
|
||||
reports: ['Transaction Register']
|
||||
},
|
||||
{
|
||||
title: 'Statements',
|
||||
reports: ['Agent Commission Statement']
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
|
||||
<div class="rv-container">
|
||||
<div class="rv-header">
|
||||
<button mat-stroked-button [routerLink]="['../../']" class="rv-back">
|
||||
<i class="fas fa-arrow-left"></i> DDS Reports
|
||||
</button>
|
||||
<h2 class="rv-header__title">{{ reportName }}</h2>
|
||||
</div>
|
||||
|
||||
<div class="rv-card">
|
||||
<form [formGroup]="filterForm">
|
||||
<div class="rv-grid">
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>From Date</mat-label>
|
||||
<input matInput required [matDatepicker]="fromPicker" formControlName="fromDate" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="fromPicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #fromPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>To Date</mat-label>
|
||||
<input matInput required [matDatepicker]="toPicker" formControlName="toDate" />
|
||||
<mat-datepicker-toggle matIconSuffix [for]="toPicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #toPicker></mat-datepicker>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>Agent From</mat-label>
|
||||
<input matInput type="number" formControlName="agentFrom" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>Agent To</mat-label>
|
||||
<input matInput type="number" formControlName="agentTo" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>Party From</mat-label>
|
||||
<input matInput type="number" formControlName="partyFrom" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field appearance="outline" class="rv-field">
|
||||
<mat-label>Party To</mat-label>
|
||||
<input matInput type="number" formControlName="partyTo" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<div class="rv-action-bar">
|
||||
<button mat-raised-button type="button" (click)="exit()">Exit</button>
|
||||
<button mat-raised-button color="primary" type="button" [disabled]="filterForm.invalid" (click)="runReport()">
|
||||
<i class="fas fa-play" style="margin-right: 6px"></i> Run Report
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@if (hasRun) {
|
||||
<div class="rv-results">
|
||||
@if (!available) {
|
||||
<p class="rv-empty">{{ unavailableMessage }}</p>
|
||||
} @else if (rows.length === 0) {
|
||||
<p class="rv-empty">No rows matched these filters.</p>
|
||||
} @else {
|
||||
<div class="rv-table-scroll">
|
||||
<table class="rv-table">
|
||||
<thead>
|
||||
<tr>
|
||||
@for (column of columns; track column) {
|
||||
<th>{{ column }}</th>
|
||||
}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@for (row of rows; track row) {
|
||||
<tr>
|
||||
@for (column of columns; track column) {
|
||||
<td>{{ row[column] }}</td>
|
||||
}
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,103 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
$primary: #0f766e;
|
||||
|
||||
.rv-container {
|
||||
max-width: 1100px;
|
||||
margin: 0 auto;
|
||||
padding: 24px 16px;
|
||||
}
|
||||
|
||||
.rv-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16px;
|
||||
margin-bottom: 20px;
|
||||
|
||||
&__title {
|
||||
margin: 0;
|
||||
font-size: 22px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.rv-back {
|
||||
color: $primary;
|
||||
}
|
||||
|
||||
.rv-card {
|
||||
background: var(--md-sys-color-surface, #fff);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 8px rgb(0 0 0 / 8%);
|
||||
padding: 20px 24px 24px;
|
||||
}
|
||||
|
||||
.rv-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
gap: 8px 16px;
|
||||
}
|
||||
|
||||
.rv-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.rv-action-bar {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 12px;
|
||||
margin-top: 20px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid rgb(0 0 0 / 8%);
|
||||
}
|
||||
|
||||
.rv-results {
|
||||
margin-top: 20px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid rgb(0 0 0 / 8%);
|
||||
}
|
||||
|
||||
.rv-empty {
|
||||
color: rgb(0 0 0 / 50%);
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
padding: 24px 0;
|
||||
}
|
||||
|
||||
.rv-table-scroll {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.rv-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
white-space: nowrap;
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.04em;
|
||||
color: rgb(0 0 0 / 55%);
|
||||
padding: 8px 10px;
|
||||
border-bottom: 2px solid rgb(0 0 0 / 10%);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 8px 10px;
|
||||
border-bottom: 1px solid rgb(0 0 0 / 6%);
|
||||
}
|
||||
}
|
||||
|
||||
@media (width <= 900px) {
|
||||
.rv-grid {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
/** Angular Imports */
|
||||
import { Component, inject } from '@angular/core';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
/** Custom Services */
|
||||
import { OrganizationService } from 'app/organization/organization.service';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
|
||||
/**
|
||||
* Generic DDS report viewer.
|
||||
*
|
||||
* One shared screen for all 13+ DDS reports — the report name comes from
|
||||
* the route and is mapped to a backend report key. Every report in the
|
||||
* legacy system shared the same basic filter shape (date, agent range,
|
||||
* party range), so this avoids building a bespoke screen per report - the
|
||||
* backend returns a generic {columns, rows} shape this renders as one
|
||||
* table regardless of which report it is.
|
||||
*
|
||||
* One legacy report (Close Party Ac Register) has no corresponding data in
|
||||
* the backend yet - Party accounts have no closed/open status at all. Run
|
||||
* Report still calls through, and the backend's `available: false` +
|
||||
* message is shown instead of a table.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-dds-report-viewer',
|
||||
templateUrl: './report-viewer.component.html',
|
||||
styleUrls: ['./report-viewer.component.scss'],
|
||||
imports: [...STANDALONE_SHARED_IMPORTS]
|
||||
})
|
||||
export class ReportViewerComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private organizationService = inject(OrganizationService);
|
||||
private dateUtils = inject(Dates);
|
||||
|
||||
private static readonly REPORT_KEYS: Record<string, string> = {
|
||||
'Supplementary-DDS (As On)': 'SUPPLEMENTARY_DDS',
|
||||
'Agent Check List': 'AGENT_CHECK_LIST',
|
||||
'Party Check List-As On': 'PARTY_CHECK_LIST',
|
||||
'Party Balance': 'PARTY_BALANCE',
|
||||
'Agent Wise Balance': 'AGENT_WISE_BALANCE',
|
||||
'Agent Wise Monthly Collection': 'AGENT_WISE_MONTHLY_COLLECTION',
|
||||
'Commission Register': 'COMMISSION_REGISTER',
|
||||
'Collection Summary Agent Wise': 'COLLECTION_SUMMARY_AGENT_WISE',
|
||||
'Close Party Ac Register': 'CLOSE_PARTY_AC_REGISTER',
|
||||
'Agent Partywise Daily Collection': 'AGENT_PARTYWISE_DAILY_COLLECTION',
|
||||
'Daily Collection Balance': 'DAILY_COLLECTION_REPORT',
|
||||
'Interest Certificate': 'INTEREST_CERTIFICATE',
|
||||
'Mature Date Wise Report': 'MATURE_DATE_WISE',
|
||||
'Party Int. Register': 'PARTY_INTEREST_REGISTER',
|
||||
'Daily Collection Report': 'DAILY_COLLECTION_REPORT',
|
||||
'Balance Summary': 'BALANCE_SUMMARY',
|
||||
'Master Data Export': 'MASTER_DATA_EXPORT',
|
||||
'Transaction Register': 'TRANSACTION_REGISTER',
|
||||
'Agent Commission Statement': 'AGENT_COMMISSION_STATEMENT'
|
||||
};
|
||||
|
||||
reportName: string = this.route.snapshot.paramMap.get('reportName') || 'Report';
|
||||
|
||||
hasRun = false;
|
||||
available = true;
|
||||
unavailableMessage = '';
|
||||
columns: string[] = [];
|
||||
rows: Array<Record<string, any>> = [];
|
||||
|
||||
filterForm: UntypedFormGroup = this.formBuilder.group({
|
||||
fromDate: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
toDate: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
agentFrom: [1],
|
||||
agentTo: [99999],
|
||||
partyFrom: [1],
|
||||
partyTo: [99999999]
|
||||
});
|
||||
|
||||
runReport(): void {
|
||||
const reportKey = ReportViewerComponent.REPORT_KEYS[this.reportName];
|
||||
if (!reportKey) {
|
||||
return;
|
||||
}
|
||||
const raw = this.filterForm.getRawValue();
|
||||
|
||||
this.organizationService
|
||||
.runDdsReport(reportKey, {
|
||||
fromDate: this.dateUtils.getDate(raw.fromDate),
|
||||
toDate: this.dateUtils.getDate(raw.toDate),
|
||||
agentFrom: raw.agentFrom,
|
||||
agentTo: raw.agentTo,
|
||||
partyFrom: raw.partyFrom,
|
||||
partyTo: raw.partyTo
|
||||
})
|
||||
.subscribe((result: any) => {
|
||||
this.available = result.available;
|
||||
this.unavailableMessage = result.message || '';
|
||||
this.columns = result.columns || [];
|
||||
this.rows = result.rows || [];
|
||||
this.hasRun = true;
|
||||
});
|
||||
}
|
||||
|
||||
exit(): void {
|
||||
this.router.navigate(['../../'], { relativeTo: this.route });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user