Adds sponsor-dd and sponsor-dd-reconciliation feature modules, a shared customer search dialog, and wires them into routing/shell/ organization screens alongside cashier and deposit-request updates.
177 lines
4.7 KiB
TypeScript
177 lines
4.7 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 { Router, RouterModule } from '@angular/router';
|
|
import { FormsModule } from '@angular/forms';
|
|
import { MatCardModule } from '@angular/material/card';
|
|
import { MatButtonModule } from '@angular/material/button';
|
|
import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
|
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
|
import { FaIconComponent } from '@fortawesome/angular-fontawesome';
|
|
import { SponsorDDReconciliationService } from '../sponsor-dd-reconciliation.service';
|
|
|
|
@Component({
|
|
selector: 'mifosx-reco-batch-upload',
|
|
standalone: true,
|
|
imports: [
|
|
CommonModule,
|
|
RouterModule,
|
|
FormsModule,
|
|
MatCardModule,
|
|
MatButtonModule,
|
|
MatSnackBarModule,
|
|
MatProgressBarModule,
|
|
FaIconComponent
|
|
],
|
|
templateUrl: './reco-batch-upload.component.html',
|
|
styles: [
|
|
`
|
|
.upload-container {
|
|
padding: 24px;
|
|
max-width: 600px;
|
|
margin: 0 auto;
|
|
}
|
|
.header-row {
|
|
margin-bottom: 24px;
|
|
}
|
|
.header-row h2 {
|
|
margin: 0 0 4px 0;
|
|
font-size: 24px;
|
|
font-weight: 600;
|
|
color: #1e293b;
|
|
}
|
|
.header-row p {
|
|
margin: 0;
|
|
color: #64748b;
|
|
font-size: 14px;
|
|
}
|
|
.mat-mdc-card {
|
|
border-radius: 12px;
|
|
border: 1px solid #e2e8f0;
|
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
|
|
padding: 32px;
|
|
}
|
|
.dropzone {
|
|
border: 2px dashed #cbd5e1;
|
|
border-radius: 8px;
|
|
padding: 40px 20px;
|
|
text-align: center;
|
|
background-color: #f8fafc;
|
|
cursor: pointer;
|
|
transition:
|
|
border-color 0.2s,
|
|
background-color 0.2s;
|
|
}
|
|
.dropzone:hover {
|
|
border-color: #7c3aed;
|
|
background-color: #f1f5f9;
|
|
}
|
|
.dropzone-icon {
|
|
font-size: 48px;
|
|
color: #94a3b8;
|
|
margin-bottom: 16px;
|
|
}
|
|
.file-details {
|
|
margin-top: 24px;
|
|
padding: 16px;
|
|
background-color: #f1f5f9;
|
|
border-radius: 6px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
}
|
|
.file-name {
|
|
font-weight: 500;
|
|
color: #334155;
|
|
}
|
|
.file-size {
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
}
|
|
.actions {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 12px;
|
|
margin-top: 24px;
|
|
}
|
|
.progress-section {
|
|
margin-top: 24px;
|
|
text-align: center;
|
|
}
|
|
.progress-text {
|
|
font-size: 12px;
|
|
color: #64748b;
|
|
margin-top: 8px;
|
|
}
|
|
`
|
|
]
|
|
})
|
|
export class RecoBatchUploadComponent {
|
|
private recoService = inject(SponsorDDReconciliationService);
|
|
private router = inject(Router);
|
|
private snackBar = inject(MatSnackBar);
|
|
|
|
selectedFile: File | null = null;
|
|
loading = false;
|
|
progressMessage = '';
|
|
|
|
onFileSelected(event: any): void {
|
|
const file = event.target.files[0];
|
|
if (file) {
|
|
this.selectedFile = file;
|
|
}
|
|
}
|
|
|
|
triggerFileSelect(fileInput: HTMLInputElement): void {
|
|
fileInput.click();
|
|
}
|
|
|
|
onSubmit(): void {
|
|
if (!this.selectedFile) return;
|
|
|
|
this.loading = true;
|
|
this.progressMessage = 'Reading file and preparing upload payload...';
|
|
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
const fileContent = reader.result as string;
|
|
this.progressMessage = 'Uploading clearing scroll for processing...';
|
|
|
|
this.recoService
|
|
.uploadClearingScroll({
|
|
fileName: this.selectedFile!.name,
|
|
fileContent: fileContent
|
|
})
|
|
.subscribe({
|
|
next: (res) => {
|
|
this.snackBar.open(
|
|
`Reconciliation batch processed successfully. ${res.successCount} matched, ${res.mismatchCount} exceptions.`,
|
|
'Close',
|
|
{ duration: 7000 }
|
|
);
|
|
this.router.navigate([
|
|
'/sponsor-dd-reconciliation/batches',
|
|
res.id
|
|
]);
|
|
},
|
|
error: (err) => {
|
|
this.loading = false;
|
|
this.progressMessage = '';
|
|
this.snackBar.open('Reconciliation failed: ' + (err.error?.message || err.message), 'Close', {
|
|
duration: 6000
|
|
});
|
|
}
|
|
});
|
|
};
|
|
|
|
reader.readAsDataURL(this.selectedFile); // Reads as Base64 Data URL, which our backend decodes safely.
|
|
}
|
|
}
|