From fed8bbfca7ab771b80de3e22697dd3ba13d793d1 Mon Sep 17 00:00:00 2001 From: Patrick Sun Date: Thu, 29 Apr 2021 10:39:12 +1000 Subject: [PATCH] upload lender automatically if there is already a match. --- src/app/app.module.ts | 4 +- .../lender-uploads.component.html | 7 -- src/app/models/Pay.In.AAA.Row.model.ts | 21 +++++ src/app/models/pay-in.model.ts | 1 + src/app/models/upload.analysis.model.ts | 4 +- src/app/observable/pay.in.observable.ts | 13 ++++ .../lender-aaa-income.component.html | 18 +++++ .../lender-aaa-income.component.scss | 0 .../lender-aaa-income.component.spec.ts | 25 ++++++ .../lender-aaa-income.component.ts | 77 +++++++++++++++++++ src/app/pay-in/pay-in.component.html | 4 +- src/app/pay-in/pay-in.component.ts | 36 +++++++-- .../upload-detail.component.html | 8 +- .../upload-detail/upload-detail.component.ts | 24 +++--- 14 files changed, 210 insertions(+), 32 deletions(-) create mode 100644 src/app/observable/pay.in.observable.ts create mode 100644 src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html create mode 100644 src/app/pay-in/lender-aaa-income/lender-aaa-income.component.scss create mode 100644 src/app/pay-in/lender-aaa-income/lender-aaa-income.component.spec.ts create mode 100644 src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6d65ead..b0b4b08 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -101,6 +101,7 @@ import { LoanSelectComponent } from './loan-select/loan-select.component'; import {PopupModule} from '@progress/kendo-angular-popup'; import { LoansAllComponent } from './loans-all/loans-all.component'; import {LenderNameService} from './service/lender-name.service'; +import { LenderAaaIncomeComponent } from './pay-in/lender-aaa-income/lender-aaa-income.component'; @@ -170,7 +171,8 @@ export function initializeApp(appConfig: AppConfig): () => Promise { LoanCardComponent, UploadingProgressCardComponent, LoanSelectComponent, - LoansAllComponent + LoansAllComponent, + LenderAaaIncomeComponent ], imports: [ BrowserModule, diff --git a/src/app/lender-uploads/lender-uploads.component.html b/src/app/lender-uploads/lender-uploads.component.html index a893873..b060c61 100644 --- a/src/app/lender-uploads/lender-uploads.component.html +++ b/src/app/lender-uploads/lender-uploads.component.html @@ -9,13 +9,6 @@ (uploadProgress)="uploadProgress($event)" [showFileList]="false" [saveUrl]="uploadSaveUrl"> - - - - - - -
diff --git a/src/app/models/Pay.In.AAA.Row.model.ts b/src/app/models/Pay.In.AAA.Row.model.ts index 27f081c..87b57c4 100644 --- a/src/app/models/Pay.In.AAA.Row.model.ts +++ b/src/app/models/Pay.In.AAA.Row.model.ts @@ -1,6 +1,8 @@ +import {PayInModel} from './pay-in.model'; export class PayInAAARowModel { + private Lender = 'AAA'; public Period: Date; public LoanNumber: string; public Settlement: Date; @@ -8,6 +10,8 @@ export class PayInAAARowModel { public Balance: number; public InTrail: number; + public matchedPayIn?: PayInModel | -1; + constructor(payload: Partial){ this.Period = new Date(payload.Period); this.LoanNumber = payload.LoanNumber || ''; @@ -15,5 +19,22 @@ export class PayInAAARowModel { this.LoanAmount = payload.LoanAmount || 0; this.Balance = payload.Balance || 0; this.InTrail = payload.InTrail || 0; + this.matchedPayIn = payload.matchedPayIn || -1; + } + + public asPayIn(): PayInModel { + if ( this.matchedPayIn !== undefined && this.matchedPayIn !== -1 ) { + return this.matchedPayIn; + } + const pi = new PayInModel({}); + pi.Lender = this.Lender; + pi.LoanNumber = this.LoanNumber; + pi.Amount = this.LoanAmount; + pi.Settlement = this.Settlement; + pi.IncomeAmount = this.InTrail; + pi.IncomeType = 'Trail'; + pi.Ts = this.Period; + + return pi; } } diff --git a/src/app/models/pay-in.model.ts b/src/app/models/pay-in.model.ts index d85ff29..f809568 100644 --- a/src/app/models/pay-in.model.ts +++ b/src/app/models/pay-in.model.ts @@ -40,6 +40,7 @@ export class PayInModel { } this.UploadId = payload.UploadId; } + } diff --git a/src/app/models/upload.analysis.model.ts b/src/app/models/upload.analysis.model.ts index c942c38..3a2b8d0 100644 --- a/src/app/models/upload.analysis.model.ts +++ b/src/app/models/upload.analysis.model.ts @@ -6,7 +6,7 @@ import {PayInAAARowModel} from './Pay.In.AAA.Row.model'; export class UploadAnalysisModel { public Id: number; - public Funders: string[]; + public Lender: string; public Mime: string; public PayIn: PayInModel[]; @@ -18,7 +18,7 @@ export class UploadAnalysisModel { constructor(payload: Partial){ this.Id = payload.Id || 0 ; - this.Funders = payload.Funders || []; + this.Lender = payload.Lender || ''; this.Mime = payload.Mime || ''; if ( payload.PayIn && payload.PayIn.length > 0 ) { this.PayIn = []; diff --git a/src/app/observable/pay.in.observable.ts b/src/app/observable/pay.in.observable.ts new file mode 100644 index 0000000..977bac8 --- /dev/null +++ b/src/app/observable/pay.in.observable.ts @@ -0,0 +1,13 @@ +import {BehaviorSubject} from 'rxjs'; +import {PayInModel} from '../models/pay-in.model'; + + +export class PayInObservable extends BehaviorSubject { + constructor() { + super(null); + } + + Next(pis: PayInModel[]): void { + super.next(pis); + } +} diff --git a/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html new file mode 100644 index 0000000..b1ffc25 --- /dev/null +++ b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html @@ -0,0 +1,18 @@ + + + + AAA + + + + + + + + + + + {{ dataItem.matchedPayIn === -1? 'Not matched': dataItem.matchedPayIn.Id}} + + + diff --git a/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.scss b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.spec.ts b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.spec.ts new file mode 100644 index 0000000..0bc2561 --- /dev/null +++ b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.spec.ts @@ -0,0 +1,25 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { LenderAaaIncomeComponent } from './lender-aaa-income.component'; + +describe('LenderAaaIncomeComponent', () => { + let component: LenderAaaIncomeComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ LenderAaaIncomeComponent ] + }) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(LenderAaaIncomeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts new file mode 100644 index 0000000..e082497 --- /dev/null +++ b/src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts @@ -0,0 +1,77 @@ +import {Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output} from '@angular/core'; +import {UploadAnalysisModel} from '../../models/upload.analysis.model'; +import {CellCloseEvent} from '@progress/kendo-angular-grid'; +import {PayInAAARowModel} from '../../models/Pay.In.AAA.Row.model'; +import {PayInModel} from '../../models/pay-in.model'; +import {Subject} from 'rxjs'; + + +@Component({ + selector: 'app-lender-aaa-income', + templateUrl: './lender-aaa-income.component.html', + styleUrls: ['./lender-aaa-income.component.scss'] +}) +export class LenderAaaIncomeComponent implements OnInit, OnChanges { + private Lender = 'AAA'; + @Input() public analysis = new UploadAnalysisModel({}); + @Input() newPayInUpdate: PayInModel; + @Output() Selected: EventEmitter = new EventEmitter(); + public data: PayInAAARowModel[] = []; + private payInCandidates: PayInModel[] = []; + constructor() { } + + ngOnInit(): void { + this.analysis.AAA.forEach(v => { + v.matchedPayIn = this.matchPayIn(v); + this.data.push(new PayInAAARowModel(v)); + v.InTrail = 20; + this.data.push(new PayInAAARowModel(v)); + }); + console.log(this); + } + + ngOnChanges(changes): void { + if (changes.newPayInUpdate){ + this.data.forEach(v => { + if ( this.isMatch(v, changes.newPayInUpdate.currentValue) ){ + v.matchedPayIn = changes.newPayInUpdate.currentValue; + } + }); + } + } + + public onCellClick(event: CellCloseEvent): void{ + this.Selected.emit(event.dataItem.asPayIn()); + } + + private matchPayIn(v: PayInAAARowModel): PayInModel | -1 { + const idx = this.payInCandidates.findIndex( pi => this.isMatch(v, pi) ); + if ( idx === -1 ) { return -1; } + return this.payInCandidates[idx]; + } + + private isMatch( v: PayInAAARowModel, pi: PayInModel): boolean { + if ( v === null || pi === null ){ + return false; + } + return v.LoanNumber === pi.LoanNumber && + this.Lender === pi.Lender && + v.InTrail === pi.IncomeAmount && + 'Trail' === pi.IncomeType; + } + + @Input() set payIn(pis: PayInModel[]) { + this.payInCandidates = []; + pis.forEach( v => this.payInCandidates.push(new PayInModel(v))); + + this.data.forEach( v => { + v.matchedPayIn = this.matchPayIn(v); + }); + + console.log ('new payin comes in'); + } + + get PayIn(): PayInModel[] { + return this.payInCandidates; + } +} diff --git a/src/app/pay-in/pay-in.component.html b/src/app/pay-in/pay-in.component.html index 9251c3e..4082342 100644 --- a/src/app/pay-in/pay-in.component.html +++ b/src/app/pay-in/pay-in.component.html @@ -58,8 +58,8 @@ + [data]="lenderListView | async" + [loading]="lenderNameService.loading"> diff --git a/src/app/pay-in/pay-in.component.ts b/src/app/pay-in/pay-in.component.ts index 110d672..6172380 100644 --- a/src/app/pay-in/pay-in.component.ts +++ b/src/app/pay-in/pay-in.component.ts @@ -14,7 +14,7 @@ import {LoanModel} from '../models/loan.model'; import {LoanSingleService} from '../service/loan.single.service'; import {PayInModelEx} from '../models/pay-in-ex.model'; import {Observable} from 'rxjs'; -import {FunderNameService} from '../service/funder.name.service'; +import {LenderNameService} from '../service/lender-name.service'; @@ -33,6 +33,7 @@ export class PayInComponent implements OnInit { public filterLoan = new LoanModel({}); @Input() filter: PayInListFilterModel = new PayInListFilterModel({}); @Output() errorOccurred = new EventEmitter(); + @Output() Updated = new EventEmitter(); @ViewChild('filterDialog', {static: true}) filterDialog: PopupIncomeFilterComponent; @ViewChild('grid', {static: true}) grid: GridComponent; private privateLoadDataNow = false; @@ -53,16 +54,16 @@ export class PayInComponent implements OnInit { }; public loading = false; - public funderListView: Observable; + public lenderListView: Observable; private debouncedLoadFilteredData = () => {}; constructor(private pis: PayInService, private lss: LoanSingleService, private router: Router, - private funderListService: FunderNameService) { - this.funderListView = this.funderListService; - this.funderListService.query(); + private lenderNameService: LenderNameService) { + this.lenderListView = this.lenderNameService; + this.lenderNameService.query(); } ngOnInit(): void { @@ -190,8 +191,10 @@ export class PayInComponent implements OnInit { const pi = this.buildPayInForSave(v, isNew); this.lss.savePayIn(pi, isNew).subscribe( (resp: PayInModelEx) => { - this.Loan.cuPayIn( new PayInModel(resp)); - this.updatePiInGrid(new PayInModelEx(resp)); + const model = new PayInModelEx(resp); + this.Loan.cuPayIn( model); + this.updatePiInGrid(model); + this.Updated.emit(model); }, err => { // TODO: this.errorOccurred.emit('Error saving Income'); @@ -316,9 +319,26 @@ export class PayInComponent implements OnInit { } } - public ScrollTo(row: number): void { + private ScrollTo(row: number): void { this.grid.scrollTo({ row}); this.grid.focusCell(row + 1, 1 ); this.gridSelection = [row]; } + + public selectOrAddPayIn(pi: PayInModel): void{ + const row = this.gridData.data.findIndex( v => { + return v.LoanNumber === pi.LoanNumber && + v.Lender === pi.Lender && + v.IncomeAmount === pi.IncomeAmount && + v.IncomeType === pi.IncomeType; + }); + + if ( row >= 0 ) { // we found it + this.ScrollTo(row); + } else{ + this.incomeFormGroup = this.createFormGroup(new PayInModelEx(pi)); + // this.closeEditor(this.grid); + this.grid.addRow(this.incomeFormGroup); + } + } } diff --git a/src/app/upload-detail/upload-detail.component.html b/src/app/upload-detail/upload-detail.component.html index f761365..9fdb008 100644 --- a/src/app/upload-detail/upload-detail.component.html +++ b/src/app/upload-detail/upload-detail.component.html @@ -52,7 +52,12 @@
-
No result analyzed
+
AI has no results
+ +
@@ -74,6 +79,7 @@ [showLoanColumn]="true" [LoadDataNow] = "true" [pageable]="false" + (Updated)="onNewPayInUpdate($event)" > diff --git a/src/app/upload-detail/upload-detail.component.ts b/src/app/upload-detail/upload-detail.component.ts index 90dbb68..233d6ab 100644 --- a/src/app/upload-detail/upload-detail.component.ts +++ b/src/app/upload-detail/upload-detail.component.ts @@ -5,9 +5,9 @@ import {UploadAnalysisModel} from '../models/upload.analysis.model'; import {UploadMetaModel} from '../models/uploadMetaModel'; import {FloatingActionButtonComponent} from '@progress/kendo-angular-buttons'; import {DrawerSelectEvent, TabStripComponent} from '@progress/kendo-angular-layout'; -import {PayInAAARowModel} from '../models/Pay.In.AAA.Row.model'; -import {CellCloseEvent} from '@progress/kendo-angular-grid'; import {PayInComponent} from '../pay-in/pay-in.component'; +import {PayInModel} from '../models/pay-in.model'; +import {Subject} from 'rxjs'; @@ -25,8 +25,9 @@ export class UploadDetailComponent implements OnInit, AfterViewInit { @ViewChild('tabs', {static: true}) tab: TabStripComponent; @ViewChild('PayIn', {static: false}) payIn: PayInComponent; - // 'http://africau.edu/images/default/sample.pdf'; - public uploadAsPicUrl = ''; + public newPayInUpdateSubject = new Subject(); + + public uploadAsPicUrl = ''; // 'http://africau.edu/images/default/sample.pdf'; public uploadAsPdfUrl = ''; public initAnimation = false; public iframeLoaded = false; @@ -45,7 +46,7 @@ export class UploadDetailComponent implements OnInit, AfterViewInit { public tabText: string[] = ['Preview', 'Content', 'Analysis']; public tabTitle: string[] = this.tabText; - public analysisAAA: PayInAAARowModel[] = []; + constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) { this.uploadAsPicUrl = location.origin + 'assets/img/no_preview.jpg'; @@ -79,9 +80,6 @@ export class UploadDetailComponent implements OnInit, AfterViewInit { this.us.getUploadAnalysis(this.uploadId).subscribe( resp => { this.ua = new UploadAnalysisModel(resp); - this.ua.AAA.forEach(v => { - this.analysisAAA.push(new PayInAAARowModel(v)); - }); this.uploadId = this.ua.Id; this.analysisIsDone = true; }, err => { @@ -172,8 +170,12 @@ export class UploadDetailComponent implements OnInit, AfterViewInit { this.fabOffset = {x: '10px', y: s}; } - public onCellClick(event: CellCloseEvent): void{ - console.log('cell-click', event.dataItem, event, this.payIn); - this.payIn.ScrollTo(2); + public onSelected(pi: PayInModel): void{ + this.payIn.selectOrAddPayIn(pi); } + + public onNewPayInUpdate( pi: PayInModel): void { + this.newPayInUpdateSubject.next(pi); + } + }