feat: add Current Account module, DIP verification, charges integration, and translations
- Current Account module with full CRUD, transactions, charges, hold/release, block/unblock - Current Products management under Products module - DIP mobile number verification with real API call to /lookup/check - Sanctions verification dialog - Charges support for Current Account (chargeAppliesTo=5) in create/edit - Fixed permissions from SAVINGSACCOUNT to CURRENTACCOUNT across all current account components - Added all missing translation keys for Current Account in en-US.json Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
73aa69ee02
commit
0a32d7135e
+108
@@ -0,0 +1,108 @@
|
||||
<!--
|
||||
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="container">
|
||||
<mat-card>
|
||||
<form [formGroup]="editTransactionForm" (ngSubmit)="submit()">
|
||||
<mat-card-content class="layout-column">
|
||||
<mat-form-field (click)="dueDatePicker.open()">
|
||||
<mat-label>{{ 'labels.inputs.Transaction Date' | translate }}</mat-label>
|
||||
<input
|
||||
matInput
|
||||
[min]="minDate"
|
||||
[max]="maxDate"
|
||||
[matDatepicker]="dueDatePicker"
|
||||
formControlName="transactionDate"
|
||||
required
|
||||
/>
|
||||
<mat-datepicker-toggle matSuffix [for]="dueDatePicker"></mat-datepicker-toggle>
|
||||
<mat-datepicker #dueDatePicker></mat-datepicker>
|
||||
@if (editTransactionForm.controls.transactionDate.hasError('required')) {
|
||||
<mat-error>
|
||||
{{ 'labels.inputs.Transaction Date' | translate }} {{ 'labels.commons.is' | translate }}
|
||||
<strong>{{ 'labels.commons.required' | translate }}</strong>
|
||||
</mat-error>
|
||||
}
|
||||
</mat-form-field>
|
||||
|
||||
<mifosx-input-amount
|
||||
[currency]="currency"
|
||||
[isRequired]="true"
|
||||
[inputFormControl]="editTransactionForm.controls.transactionAmount"
|
||||
[inputLabel]="'Transaction Amount'"
|
||||
>
|
||||
</mifosx-input-amount>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Payment Type' | translate }}</mat-label>
|
||||
<mat-select formControlName="paymentTypeId">
|
||||
@for (paymentType of paymentTypeOptions; track paymentType) {
|
||||
<mat-option [value]="paymentType.id">
|
||||
{{ paymentType.name }}
|
||||
</mat-option>
|
||||
}
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<div class="flex-fill">
|
||||
<span class="expandcollapsebutton m-l-10 m-t-40 flex-75" (click)="addPaymentDetails()">
|
||||
<mat-slide-toggle>
|
||||
<div [className]="showPaymentDetails ? 'enabled' : 'disabled'">
|
||||
<span class="m-l-10">{{ 'labels.inputs.Show Payment Details' | translate }}</span>
|
||||
</div>
|
||||
</mat-slide-toggle>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@if (editTransactionForm.controls['accountNumber']) {
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Account Number' | translate }}</mat-label>
|
||||
<input type="number" formControlName="accountNumber" matInput />
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@if (editTransactionForm.controls['checkNumber']) {
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Cheque' | translate }}</mat-label>
|
||||
<input type="number" formControlName="checkNumber" matInput />
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@if (editTransactionForm.controls['routingCode']) {
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Routing Code' | translate }}</mat-label>
|
||||
<input formControlName="routingCode" matInput />
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@if (editTransactionForm.controls['receiptNumber']) {
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Receipt Number' | translate }}</mat-label>
|
||||
<input formControlName="receiptNumber" matInput />
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
@if (editTransactionForm.controls['bankNumber']) {
|
||||
<mat-form-field>
|
||||
<mat-label>{{ 'labels.inputs.Bank' | translate }}</mat-label>
|
||||
<input formControlName="bankNumber" matInput />
|
||||
</mat-form-field>
|
||||
}
|
||||
|
||||
<mat-card-actions class="layout-row layout-xs-column layout-align-center gap-5px">
|
||||
<button type="button" mat-raised-button [routerLink]="['../']">
|
||||
{{ 'labels.buttons.Cancel' | translate }}
|
||||
</button>
|
||||
<button mat-raised-button color="primary" [disabled]="!editTransactionForm.valid">
|
||||
{{ 'labels.buttons.Submit' | translate }}
|
||||
</button>
|
||||
</mat-card-actions>
|
||||
</mat-card-content>
|
||||
</form>
|
||||
</mat-card>
|
||||
</div>
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
.container {
|
||||
width: 37rem;
|
||||
}
|
||||
+164
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* 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, OnInit, inject } from '@angular/core';
|
||||
import {
|
||||
UntypedFormGroup,
|
||||
UntypedFormBuilder,
|
||||
Validators,
|
||||
UntypedFormControl,
|
||||
ReactiveFormsModule
|
||||
} from '@angular/forms';
|
||||
import { Router, ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
|
||||
/** Custom Services */
|
||||
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { Currency } from 'app/shared/models/general.model';
|
||||
import { InputAmountComponent } from '../../../../shared/input-amount/input-amount.component';
|
||||
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
/**
|
||||
* Edit Transaction component.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-edit-transaction',
|
||||
templateUrl: './edit-transaction.component.html',
|
||||
styleUrls: ['./edit-transaction.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
InputAmountComponent,
|
||||
MatSlideToggle
|
||||
]
|
||||
})
|
||||
export class EditTransactionComponent implements OnInit {
|
||||
private formBuilder = inject(UntypedFormBuilder);
|
||||
private route = inject(ActivatedRoute);
|
||||
private router = inject(Router);
|
||||
private dateUtils = inject(Dates);
|
||||
private currentAccountsService = inject(CurrentAccountsService);
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
/** Minimum Due Date allowed. */
|
||||
minDate = new Date(2000, 0, 1);
|
||||
/** Maximum Due Date allowed. */
|
||||
maxDate = new Date();
|
||||
/** Current account transaction form. */
|
||||
editTransactionForm: UntypedFormGroup;
|
||||
/** current account transaction payment options. */
|
||||
paymentTypeOptions: {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
isCashPayment: boolean;
|
||||
position: number;
|
||||
}[];
|
||||
/** Flag to enable payment details fields. */
|
||||
showPaymentDetails: Boolean = false;
|
||||
/** current account's Id */
|
||||
currentAccountId: string;
|
||||
/** Transaction Template */
|
||||
transactionTemplateData: any;
|
||||
currency: Currency;
|
||||
|
||||
/**
|
||||
* Retrieves the Current Account transaction template data from `resolve`.
|
||||
* @param {FormBuilder} formBuilder Form Builder.
|
||||
* @param {CurrentAccountsService} currentAccountsService Current Accounts Service.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
* @param {Dates} dateUtils Date Utils.
|
||||
* @param {Router} router Router for navigation.
|
||||
* @param {SettingsService} settingsService Setting service
|
||||
*/
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentAccountTransactionTemplate: any }) => {
|
||||
this.transactionTemplateData = data.currentAccountTransactionTemplate;
|
||||
if (data.currentAccountTransactionTemplate.currency) {
|
||||
this.currency = data.currentAccountTransactionTemplate.currency;
|
||||
}
|
||||
this.paymentTypeOptions = this.transactionTemplateData.paymentTypeOptions;
|
||||
});
|
||||
this.currentAccountId = this.route.snapshot.params['currentAccountId'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the Current Account account transaction form when component loads.
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.maxDate = this.settingsService.businessDate;
|
||||
this.createEditTransactionForm();
|
||||
this.editTransactionForm.patchValue({
|
||||
transactionDate: this.transactionTemplateData.date && new Date(this.transactionTemplateData.date),
|
||||
transactionAmount: this.transactionTemplateData.amount,
|
||||
paymentTypeId: this.transactionTemplateData.paymentTypeId
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to create the Current Account Transaction Form.
|
||||
*/
|
||||
createEditTransactionForm() {
|
||||
this.editTransactionForm = this.formBuilder.group({
|
||||
transactionDate: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
transactionAmount: [
|
||||
'',
|
||||
Validators.required
|
||||
],
|
||||
paymentTypeId: ['']
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to add payment detail fields to the UI.
|
||||
*/
|
||||
addPaymentDetails() {
|
||||
this.showPaymentDetails = !this.showPaymentDetails;
|
||||
if (this.showPaymentDetails) {
|
||||
this.editTransactionForm.addControl('accountNumber', new UntypedFormControl(''));
|
||||
this.editTransactionForm.addControl('checkNumber', new UntypedFormControl(''));
|
||||
this.editTransactionForm.addControl('routingCode', new UntypedFormControl(''));
|
||||
this.editTransactionForm.addControl('receiptNumber', new UntypedFormControl(''));
|
||||
this.editTransactionForm.addControl('bankNumber', new UntypedFormControl(''));
|
||||
} else {
|
||||
this.editTransactionForm.removeControl('accountNumber');
|
||||
this.editTransactionForm.removeControl('checkNumber');
|
||||
this.editTransactionForm.removeControl('routingCode');
|
||||
this.editTransactionForm.removeControl('receiptNumber');
|
||||
this.editTransactionForm.removeControl('bankNumber');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to submit the transaction details.
|
||||
*/
|
||||
submit() {
|
||||
const editTransactionFormData = this.editTransactionForm.value;
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const prevTransactionDate: Date = this.editTransactionForm.value.transactionDate;
|
||||
if (editTransactionFormData.transactionDate instanceof Date) {
|
||||
editTransactionFormData.transactionDate = this.dateUtils.formatDate(prevTransactionDate, dateFormat);
|
||||
}
|
||||
const data = {
|
||||
...editTransactionFormData,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.currentAccountsService
|
||||
.executeCurrentAccountTransactionsCommand(this.currentAccountId, 'modify', data, this.transactionTemplateData.id)
|
||||
.subscribe((res) => {
|
||||
this.router.navigate(['../'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
}
|
||||
+33
@@ -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/.
|
||||
-->
|
||||
|
||||
<mat-card class="container">
|
||||
<div class="back-button">
|
||||
<button type="button" color="primary" mat-raised-button [routerLink]="['../../']">
|
||||
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>Back
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div *ngIf="pentahoUrl; else noData" class="pdf-container">
|
||||
<iframe [src]="pentahoUrl" class="pdf-iframe"></iframe>
|
||||
</div>
|
||||
|
||||
<ng-template #noData>
|
||||
<div class="error-message">
|
||||
<h3>Unable to Load Receipt</h3>
|
||||
<p>The transaction receipt could not be loaded. This may be due to:</p>
|
||||
<ul>
|
||||
<li>Missing or incomplete report configuration</li>
|
||||
<li>Report generation service unavailable</li>
|
||||
<li>Invalid transaction data</li>
|
||||
</ul>
|
||||
<p><strong>Please contact your system administrator for assistance.</strong></p>
|
||||
<p class="console-hint">Technical details may be available in the browser console (F12).</p>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-card>
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
.container {
|
||||
max-width: 50rem;
|
||||
margin: 0 auto;
|
||||
|
||||
.back-button {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.pdf-container {
|
||||
width: 100%;
|
||||
height: calc(100vh - 250px);
|
||||
min-height: 600px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
background-color: #525659;
|
||||
|
||||
.pdf-iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
.error-message {
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
background-color: #fff3cd;
|
||||
border: 1px solid #ffc107;
|
||||
border-radius: 4px;
|
||||
margin: 1rem 0;
|
||||
|
||||
h3 {
|
||||
color: #856404;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
ul {
|
||||
text-align: left;
|
||||
display: inline-block;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.console-hint {
|
||||
font-size: 0.875rem;
|
||||
color: #6c757d;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
* 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, OnInit, OnDestroy, inject } from '@angular/core';
|
||||
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';
|
||||
import { ActivatedRoute, RouterLink } from '@angular/router';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
import { HttpResponse } from '@angular/common/http';
|
||||
|
||||
/**
|
||||
* View Transaction Reciept Component
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-view-reciept',
|
||||
templateUrl: './view-reciept.component.html',
|
||||
styleUrls: ['./view-reciept.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent
|
||||
]
|
||||
})
|
||||
export class ViewRecieptComponent implements OnInit, OnDestroy {
|
||||
private sanitizer = inject(DomSanitizer);
|
||||
private route = inject(ActivatedRoute);
|
||||
|
||||
/** trusted resource url for pentaho output */
|
||||
pentahoUrl: SafeResourceUrl | null = null;
|
||||
/** Transaction Reciept Data */
|
||||
transactionRecieptData: HttpResponse<Blob>;
|
||||
/** Blob URL for cleanup */
|
||||
private blobUrl: string | null = null;
|
||||
|
||||
/**
|
||||
* Fetches transaction reciept `resolve`
|
||||
* @param {DomSanitizer} sanitizer DOM Sanitizer
|
||||
* @param {ActivatedRoute} route Activated Route
|
||||
*/
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentAccountTransactionReciept: HttpResponse<Blob> }) => {
|
||||
this.transactionRecieptData = data.currentAccountTransactionReciept;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
if (!this.transactionRecieptData || !this.transactionRecieptData.body) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentType = this.transactionRecieptData.headers.get('Content-Type');
|
||||
const file = new Blob([this.transactionRecieptData.body], { type: contentType });
|
||||
|
||||
if (file.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.blobUrl = URL.createObjectURL(file);
|
||||
this.pentahoUrl = this.sanitizer.bypassSecurityTrustResourceUrl(this.blobUrl);
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
if (this.blobUrl) {
|
||||
URL.revokeObjectURL(this.blobUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
<!--
|
||||
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/.
|
||||
-->
|
||||
|
||||
<p>{{ 'labels.heading.current-account-transaction-datatable-tab works' | translate }}!</p>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* 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 } from '@angular/core';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-current-account-transaction-datatable-tab',
|
||||
templateUrl: './current-accounts-transaction-datatable-tab.component.html',
|
||||
styleUrls: ['./current-accounts-transaction-datatable-tab.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS
|
||||
]
|
||||
})
|
||||
export class CurrentAccountTransactionDatatableTabComponent {
|
||||
constructor() {}
|
||||
}
|
||||
+128
@@ -0,0 +1,128 @@
|
||||
<!--
|
||||
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="container transaction-buttons m-b-20 align-end-center gap-2percent" align="end">
|
||||
@if (
|
||||
!(
|
||||
transactionData.interestedPostedAsOn === false &&
|
||||
(transactionData.transactionType.id === 17 || transactionData.transactionType.id === 3)
|
||||
)
|
||||
) {
|
||||
<span>
|
||||
<span *mifosxHasPermission="'ADJUSTTRANSACTION_CURRENTACCOUNT'">
|
||||
@if (
|
||||
transactionData.transactionType.value === 'Transfer' ||
|
||||
transactionData.reversed === 'true' ||
|
||||
transactionData.transactionType.id === 3 ||
|
||||
transactionData.transactionType.id === 17
|
||||
) {
|
||||
<button mat-raised-button color="primary" [routerLink]="'edit'">
|
||||
<fa-icon icon="edit" class="m-r-10"></fa-icon>{{ 'labels.buttons.Edit' | translate }}
|
||||
</button>
|
||||
}
|
||||
</span>
|
||||
</span>
|
||||
}
|
||||
@if (!transactionData.reversed && transactionData.transactionType.amountHold) {
|
||||
<span>
|
||||
<button
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
*mifosxHasPermission="'RELEASEAMOUNT_CURRENTACCOUNT'"
|
||||
(click)="releaseAmount()"
|
||||
>
|
||||
<fa-icon icon="lock-open" class="m-r-10"></fa-icon>{{ 'labels.buttons.Release Amount' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
@if (allowUndo()) {
|
||||
<span>
|
||||
<button
|
||||
mat-raised-button
|
||||
color="warn"
|
||||
*mifosxHasPermission="'UNDOTRANSACTION_CURRENTACCOUNT'"
|
||||
(click)="undoTransaction()"
|
||||
>
|
||||
<fa-icon icon="undo" class="m-r-10"></fa-icon>{{ 'labels.buttons.Undo' | translate }}
|
||||
</button>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="container">
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="layout-row-wrap card-content">
|
||||
<div class="flex-100" [ngClass]="transactionColor()"></div>
|
||||
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Id' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50">
|
||||
{{ transactionData.id }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Transaction Type' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50">
|
||||
{{ transactionData.transactionType.value | translateKey: 'catalogs' }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Transaction Date' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50">
|
||||
{{ transactionData.date | dateFormat }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Currency' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50">
|
||||
{{ transactionData.currency.displayLabel }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Amount' | translate }}
|
||||
</div>
|
||||
|
||||
<div class="flex-50">
|
||||
{{ transactionData.amount | currency: transactionData.currency.code : 'symbol-narrow' : '1.2-2' }}
|
||||
</div>
|
||||
|
||||
@if (transactionData.note) {
|
||||
<div class="flex-50 mat-body-strong">
|
||||
{{ 'labels.inputs.Note' | translate }}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (transactionData.note) {
|
||||
<div class="flex-50">
|
||||
{{ transactionData.note }}
|
||||
</div>
|
||||
}
|
||||
|
||||
@if (transactionData.paymentDetailData) {
|
||||
<mifosx-transaction-payment-detail [paymentDetailData]="transactionData.paymentDetailData">
|
||||
</mifosx-transaction-payment-detail>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="layout-row layout-align-center gap-2percent column-on-mobile">
|
||||
<button type="button" mat-raised-button color="primary" [routerLink]="['../../']">
|
||||
{{ 'labels.buttons.Back' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</div>
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
@use 'assets/styles/helper';
|
||||
@use 'assets/styles/colours' as *;
|
||||
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.card-content {
|
||||
div {
|
||||
margin: 1rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
mifosx-transaction-payment-detail {
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.transaction-buttons {
|
||||
margin-top: 3%;
|
||||
}
|
||||
|
||||
.active {
|
||||
background-color: $status-active;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.linked {
|
||||
background-color: $status-approved;
|
||||
height: 4px;
|
||||
}
|
||||
|
||||
.undo {
|
||||
background-color: $status-active-overdue;
|
||||
height: 4px;
|
||||
}
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* 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 { MatDialog } from '@angular/material/dialog';
|
||||
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
||||
import { Dates } from 'app/core/utils/dates';
|
||||
import { ReleaseAmountDialogComponent } from 'app/current-accounts/current-account-view/custom-dialogs/release-amount-dialog/release-amount-dialog.component';
|
||||
import { UndoTransactionDialogComponent } from 'app/current-accounts/current-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component';
|
||||
import { CurrentAccountsService } from 'app/current-accounts/current-accounts.service';
|
||||
import { SettingsService } from 'app/settings/settings.service';
|
||||
import { NgClass, CurrencyPipe } from '@angular/common';
|
||||
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
||||
import { TransactionPaymentDetailComponent } from '../../../../../shared/transaction-payment-detail/transaction-payment-detail.component';
|
||||
import { DateFormatPipe } from '../../../../../pipes/date-format.pipe';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-current-account-transaction-general-tab',
|
||||
templateUrl: './current-accounts-transaction-general-tab.component.html',
|
||||
styleUrls: ['./current-accounts-transaction-general-tab.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
FaIconComponent,
|
||||
NgClass,
|
||||
TransactionPaymentDetailComponent,
|
||||
CurrencyPipe,
|
||||
DateFormatPipe
|
||||
]
|
||||
})
|
||||
export class CurrentAccountTransactionGeneralTabComponent {
|
||||
private currentAccountsService = inject(CurrentAccountsService);
|
||||
private route = inject(ActivatedRoute);
|
||||
private dateUtils = inject(Dates);
|
||||
private router = inject(Router);
|
||||
dialog = inject(MatDialog);
|
||||
private settingsService = inject(SettingsService);
|
||||
|
||||
accountId: string;
|
||||
transactionId: string;
|
||||
transactionData: any;
|
||||
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { currentAccountTransaction: any }) => {
|
||||
this.accountId = this.route.parent.snapshot.params['currentAccountId'];
|
||||
this.transactionData = data.currentAccountTransaction;
|
||||
});
|
||||
}
|
||||
|
||||
allowUndo(): boolean {
|
||||
if (this.transactionData.reversed && this.transactionData.transactionType.amountHold) {
|
||||
return false;
|
||||
}
|
||||
return !this.transactionData.reversed;
|
||||
}
|
||||
|
||||
releaseAmount(): void {
|
||||
const releaseAmountDialogRef = this.dialog.open(ReleaseAmountDialogComponent);
|
||||
releaseAmountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.confirm) {
|
||||
const data = {};
|
||||
this.currentAccountsService
|
||||
.executeCurrentAccountTransactionsCommand(this.accountId, 'releaseAmount', data, this.transactionData.id)
|
||||
.subscribe(() => {
|
||||
this.router.navigate(['../..'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
undoTransaction(): void {
|
||||
const undoTransactionAccountDialogRef = this.dialog.open(UndoTransactionDialogComponent);
|
||||
undoTransactionAccountDialogRef.afterClosed().subscribe((response: any) => {
|
||||
if (response.confirm) {
|
||||
const locale = this.settingsService.language.code;
|
||||
const dateFormat = this.settingsService.dateFormat;
|
||||
const data = {
|
||||
transactionDate: this.dateUtils.formatDate(
|
||||
this.transactionData.date && new Date(this.transactionData.date),
|
||||
dateFormat
|
||||
),
|
||||
transactionAmount: 0,
|
||||
dateFormat,
|
||||
locale
|
||||
};
|
||||
this.currentAccountsService
|
||||
.executeCurrentAccountTransactionsCommand(this.accountId, 'undo', data, this.transactionData.id)
|
||||
.subscribe(() => {
|
||||
this.router.navigate(['../..'], { relativeTo: this.route });
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
transactionColor(): string {
|
||||
if (this.transactionData.reversed) {
|
||||
return 'undo';
|
||||
}
|
||||
return 'active';
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
<!--
|
||||
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="tab-container mat-typography">
|
||||
<mifosx-entity-datatable-tab
|
||||
entityType="Current Account Transaction"
|
||||
[entityId]="entityId"
|
||||
[multiRowDatatableFlag]="multiRowDatatableFlag"
|
||||
[entityDatatable]="entityDatatable"
|
||||
>
|
||||
</mifosx-entity-datatable-tab>
|
||||
</div>
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 { ActivatedRoute } from '@angular/router';
|
||||
import { EntityDatatableTabComponent } from '../../../../../shared/tabs/entity-datatable-tab/entity-datatable-tab.component';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-datatable-transaction-tab',
|
||||
templateUrl: './datatable-transaction-tab.component.html',
|
||||
styleUrls: ['./datatable-transaction-tab.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
EntityDatatableTabComponent
|
||||
]
|
||||
})
|
||||
export class DatatableTransactionTabComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
|
||||
/** Transaction Id */
|
||||
entityId: string;
|
||||
/** Current Account Datatable */
|
||||
entityDatatable: any;
|
||||
/** Multi Row Datatable Flag */
|
||||
multiRowDatatableFlag: boolean;
|
||||
constructor() {
|
||||
this.entityId = this.route.parent.parent.snapshot.paramMap.get('id');
|
||||
this.route.data.subscribe((data: { transactionDatatable: any }) => {
|
||||
this.entityDatatable = data.transactionDatatable;
|
||||
this.multiRowDatatableFlag = this.entityDatatable.columnHeaders[0].columnName === 'id' ? true : false;
|
||||
});
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
<!--
|
||||
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="container">
|
||||
<nav mat-tab-nav-bar class="navigation-tabs" [tabPanel]="tabPanel">
|
||||
<a
|
||||
mat-tab-link
|
||||
[routerLink]="['./general']"
|
||||
routerLinkActive
|
||||
#general="routerLinkActive"
|
||||
[active]="general.isActive"
|
||||
>
|
||||
{{ 'labels.heading.General' | translate }}
|
||||
</a>
|
||||
@for (entityDatatable of entityDatatables; track entityDatatable) {
|
||||
<a
|
||||
mat-tab-link
|
||||
[routerLink]="['./datatables', entityDatatable.registeredTableName]"
|
||||
routerLinkActive
|
||||
#datatable="routerLinkActive"
|
||||
[active]="datatable.isActive"
|
||||
*mifosxHasPermission="'READ_' + entityDatatable.registeredTableName"
|
||||
>
|
||||
{{ entityDatatable.registeredTableName }}
|
||||
</a>
|
||||
}
|
||||
</nav>
|
||||
|
||||
<mat-tab-nav-panel #tabPanel>
|
||||
<router-outlet></router-outlet>
|
||||
</mat-tab-nav-panel>
|
||||
</div>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
.container {
|
||||
max-width: 37rem;
|
||||
|
||||
.content {
|
||||
div {
|
||||
margin: 1rem 0;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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, RouterLinkActive, RouterLink, RouterOutlet } from '@angular/router';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { MatTabNav, MatTabLink, MatTabNavPanel } from '@angular/material/tabs';
|
||||
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
|
||||
|
||||
@Component({
|
||||
selector: 'mifosx-view-transaction',
|
||||
templateUrl: './view-transaction.component.html',
|
||||
styleUrls: ['./view-transaction.component.scss'],
|
||||
imports: [
|
||||
...STANDALONE_SHARED_IMPORTS,
|
||||
MatTabNav,
|
||||
MatTabLink,
|
||||
RouterLinkActive,
|
||||
MatTabNavPanel,
|
||||
RouterOutlet
|
||||
]
|
||||
})
|
||||
export class ViewTransactionComponent {
|
||||
private route = inject(ActivatedRoute);
|
||||
dialog = inject(MatDialog);
|
||||
|
||||
/** Transaction data. */
|
||||
transactionData: any;
|
||||
|
||||
accountId: any;
|
||||
/** Transaction Data Tables */
|
||||
entityDatatables: any;
|
||||
|
||||
/**
|
||||
* @param {Router} router Router for navigation.
|
||||
* @param {MatDialog} dialog Dialog reference.
|
||||
*/
|
||||
constructor() {
|
||||
this.route.data.subscribe((data: { transactionDatatables: any }) => {
|
||||
this.accountId = this.route.snapshot.params['currentAccountId'];
|
||||
this.entityDatatables = data.transactionDatatables;
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user