| import {PopupModule} from '@progress/kendo-angular-popup'; | import {PopupModule} from '@progress/kendo-angular-popup'; | ||||
| import { LoansAllComponent } from './loans-all/loans-all.component'; | import { LoansAllComponent } from './loans-all/loans-all.component'; | ||||
| import {LenderNameService} from './service/lender-name.service'; | import {LenderNameService} from './service/lender-name.service'; | ||||
| import { LenderAaaIncomeComponent } from './pay-in/lender-aaa-income/lender-aaa-income.component'; | |||||
| LoanCardComponent, | LoanCardComponent, | ||||
| UploadingProgressCardComponent, | UploadingProgressCardComponent, | ||||
| LoanSelectComponent, | LoanSelectComponent, | ||||
| LoansAllComponent | |||||
| LoansAllComponent, | |||||
| LenderAaaIncomeComponent | |||||
| ], | ], | ||||
| imports: [ | imports: [ | ||||
| BrowserModule, | BrowserModule, |
| (uploadProgress)="uploadProgress($event)" | (uploadProgress)="uploadProgress($event)" | ||||
| [showFileList]="false" | [showFileList]="false" | ||||
| [saveUrl]="uploadSaveUrl"> | [saveUrl]="uploadSaveUrl"> | ||||
| <!-- <ng-template kendoUploadFileInfoTemplate let-files>--> | |||||
| <!-- <div *ngIf="files!==undefined && files!== null && files[0] !== null">--> | |||||
| <!-- <div (click)="onClick(files)">Name: {{ files[0].name }}</div>--> | |||||
| <!-- <div *ngIf="files[0].validationErrors !== undefined"> Cannot upload this file {{files[0]}}</div>--> | |||||
| <!-- <div *ngIf="map.get(files[0].uid) !== undefined"> fuck all {{map.get(files[0].uid).response.body.Funder}} </div>--> | |||||
| <!-- </div>--> | |||||
| <!-- </ng-template>--> | |||||
| </kendo-upload> | </kendo-upload> | ||||
| </div> | </div> | ||||
| <div class="search-area"> | <div class="search-area"> |
| import {PayInModel} from './pay-in.model'; | |||||
| export class PayInAAARowModel { | export class PayInAAARowModel { | ||||
| private Lender = 'AAA'; | |||||
| public Period: Date; | public Period: Date; | ||||
| public LoanNumber: string; | public LoanNumber: string; | ||||
| public Settlement: Date; | public Settlement: Date; | ||||
| public Balance: number; | public Balance: number; | ||||
| public InTrail: number; | public InTrail: number; | ||||
| public matchedPayIn?: PayInModel | -1; | |||||
| constructor(payload: Partial<PayInAAARowModel>){ | constructor(payload: Partial<PayInAAARowModel>){ | ||||
| this.Period = new Date(payload.Period); | this.Period = new Date(payload.Period); | ||||
| this.LoanNumber = payload.LoanNumber || ''; | this.LoanNumber = payload.LoanNumber || ''; | ||||
| this.LoanAmount = payload.LoanAmount || 0; | this.LoanAmount = payload.LoanAmount || 0; | ||||
| this.Balance = payload.Balance || 0; | this.Balance = payload.Balance || 0; | ||||
| this.InTrail = payload.InTrail || 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; | |||||
| } | } | ||||
| } | } |
| } | } | ||||
| this.UploadId = payload.UploadId; | this.UploadId = payload.UploadId; | ||||
| } | } | ||||
| } | } | ||||
| export class UploadAnalysisModel { | export class UploadAnalysisModel { | ||||
| public Id: number; | public Id: number; | ||||
| public Funders: string[]; | |||||
| public Lender: string; | |||||
| public Mime: string; | public Mime: string; | ||||
| public PayIn: PayInModel[]; | public PayIn: PayInModel[]; | ||||
| constructor(payload: Partial<UploadAnalysisModel>){ | constructor(payload: Partial<UploadAnalysisModel>){ | ||||
| this.Id = payload.Id || 0 ; | this.Id = payload.Id || 0 ; | ||||
| this.Funders = payload.Funders || []; | |||||
| this.Lender = payload.Lender || ''; | |||||
| this.Mime = payload.Mime || ''; | this.Mime = payload.Mime || ''; | ||||
| if ( payload.PayIn && payload.PayIn.length > 0 ) { | if ( payload.PayIn && payload.PayIn.length > 0 ) { | ||||
| this.PayIn = []; | this.PayIn = []; |
| import {BehaviorSubject} from 'rxjs'; | |||||
| import {PayInModel} from '../models/pay-in.model'; | |||||
| export class PayInObservable extends BehaviorSubject<PayInModel[]> { | |||||
| constructor() { | |||||
| super(null); | |||||
| } | |||||
| Next(pis: PayInModel[]): void { | |||||
| super.next(pis); | |||||
| } | |||||
| } |
| <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css"> | |||||
| <kendo-grid [data]="data" (cellClick)="onCellClick($event)"> | |||||
| <ng-template kendoGridToolbarTemplate> | |||||
| AAA | |||||
| </ng-template> | |||||
| <kendo-grid-column field="Period" format='{0:yyyy MMMM}'> </kendo-grid-column> | |||||
| <kendo-grid-column field="LoanNumber"> </kendo-grid-column> | |||||
| <kendo-grid-column field="Settlement" format='{0:MM/dd/yyyy h:mm a}'> </kendo-grid-column> | |||||
| <kendo-grid-column field="LoanAmount" format='{0:c}' > </kendo-grid-column> | |||||
| <kendo-grid-column field="Balance" format='{0:c}' > </kendo-grid-column> | |||||
| <kendo-grid-column field="InTrail" format='{0:c}'> </kendo-grid-column> | |||||
| <kendo-grid-column field="matchedPayIn" title="Matched" format='{0:c}'> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | |||||
| <button kendoButton iconClass="fa fa-calendar fa-fw"></button> | |||||
| {{ dataItem.matchedPayIn === -1? 'Not matched': dataItem.matchedPayIn.Id}} | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| </kendo-grid> |
| import { ComponentFixture, TestBed } from '@angular/core/testing'; | |||||
| import { LenderAaaIncomeComponent } from './lender-aaa-income.component'; | |||||
| describe('LenderAaaIncomeComponent', () => { | |||||
| let component: LenderAaaIncomeComponent; | |||||
| let fixture: ComponentFixture<LenderAaaIncomeComponent>; | |||||
| beforeEach(async () => { | |||||
| await TestBed.configureTestingModule({ | |||||
| declarations: [ LenderAaaIncomeComponent ] | |||||
| }) | |||||
| .compileComponents(); | |||||
| }); | |||||
| beforeEach(() => { | |||||
| fixture = TestBed.createComponent(LenderAaaIncomeComponent); | |||||
| component = fixture.componentInstance; | |||||
| fixture.detectChanges(); | |||||
| }); | |||||
| it('should create', () => { | |||||
| expect(component).toBeTruthy(); | |||||
| }); | |||||
| }); |
| 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<PayInModel> = new EventEmitter<PayInModel>(); | |||||
| 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; | |||||
| } | |||||
| } |
| <ng-template kendoGridEditTemplate let-dataItem> | <ng-template kendoGridEditTemplate let-dataItem> | ||||
| <kendo-combobox | <kendo-combobox | ||||
| [formControl]="incomeFormGroup.get('Lender')" | [formControl]="incomeFormGroup.get('Lender')" | ||||
| [data]="funderListView | async" | |||||
| [loading]="funderListService.loading"> | |||||
| [data]="lenderListView | async" | |||||
| [loading]="lenderNameService.loading"> | |||||
| </kendo-combobox> | </kendo-combobox> | ||||
| </ng-template> | </ng-template> | ||||
| </kendo-grid-column> | </kendo-grid-column> |
| import {LoanSingleService} from '../service/loan.single.service'; | import {LoanSingleService} from '../service/loan.single.service'; | ||||
| import {PayInModelEx} from '../models/pay-in-ex.model'; | import {PayInModelEx} from '../models/pay-in-ex.model'; | ||||
| import {Observable} from 'rxjs'; | import {Observable} from 'rxjs'; | ||||
| import {FunderNameService} from '../service/funder.name.service'; | |||||
| import {LenderNameService} from '../service/lender-name.service'; | |||||
| public filterLoan = new LoanModel({}); | public filterLoan = new LoanModel({}); | ||||
| @Input() filter: PayInListFilterModel = new PayInListFilterModel({}); | @Input() filter: PayInListFilterModel = new PayInListFilterModel({}); | ||||
| @Output() errorOccurred = new EventEmitter<string>(); | @Output() errorOccurred = new EventEmitter<string>(); | ||||
| @Output() Updated = new EventEmitter<PayInModel>(); | |||||
| @ViewChild('filterDialog', {static: true}) filterDialog: PopupIncomeFilterComponent; | @ViewChild('filterDialog', {static: true}) filterDialog: PopupIncomeFilterComponent; | ||||
| @ViewChild('grid', {static: true}) grid: GridComponent; | @ViewChild('grid', {static: true}) grid: GridComponent; | ||||
| private privateLoadDataNow = false; | private privateLoadDataNow = false; | ||||
| }; | }; | ||||
| public loading = false; | public loading = false; | ||||
| public funderListView: Observable<string[]>; | |||||
| public lenderListView: Observable<string[]>; | |||||
| private debouncedLoadFilteredData = () => {}; | private debouncedLoadFilteredData = () => {}; | ||||
| constructor(private pis: PayInService, | constructor(private pis: PayInService, | ||||
| private lss: LoanSingleService, | private lss: LoanSingleService, | ||||
| private router: Router, | 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 { | ngOnInit(): void { | ||||
| const pi = this.buildPayInForSave(v, isNew); | const pi = this.buildPayInForSave(v, isNew); | ||||
| this.lss.savePayIn(pi, isNew).subscribe( | this.lss.savePayIn(pi, isNew).subscribe( | ||||
| (resp: PayInModelEx) => { | (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 => { | err => { | ||||
| // TODO: this.errorOccurred.emit('Error saving Income'); | // TODO: this.errorOccurred.emit('Error saving Income'); | ||||
| } | } | ||||
| } | } | ||||
| public ScrollTo(row: number): void { | |||||
| private ScrollTo(row: number): void { | |||||
| this.grid.scrollTo({ row}); | this.grid.scrollTo({ row}); | ||||
| this.grid.focusCell(row + 1, 1 ); | this.grid.focusCell(row + 1, 1 ); | ||||
| this.gridSelection = [row]; | 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); | |||||
| } | |||||
| } | |||||
| } | } |
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div *ngIf="scanDone" class="analysis-result"> | <div *ngIf="scanDone" class="analysis-result"> | ||||
| <div *ngIf="ua.Funders === undefined || ua.Funders.length == 0"> No result analyzed </div> | |||||
| <div *ngIf="ua.Lender === undefined || ua.Lender == ''"> AI has no results </div> | |||||
| <app-lender-aaa-income *ngIf="ua.Lender === 'AAA'" [analysis]="ua" | |||||
| [payIn]="payIn.gridData.data" | |||||
| [newPayInUpdate]="newPayInUpdateSubject | async" | |||||
| (Selected)="onSelected($event)"> | |||||
| </app-lender-aaa-income> | |||||
| </div> | </div> | ||||
| [showLoanColumn]="true" | [showLoanColumn]="true" | ||||
| [LoadDataNow] = "true" | [LoadDataNow] = "true" | ||||
| [pageable]="false" | [pageable]="false" | ||||
| (Updated)="onNewPayInUpdate($event)" | |||||
| > | > | ||||
| </app-pay-in> | </app-pay-in> | ||||
| </div> | </div> |
| import {UploadMetaModel} from '../models/uploadMetaModel'; | import {UploadMetaModel} from '../models/uploadMetaModel'; | ||||
| import {FloatingActionButtonComponent} from '@progress/kendo-angular-buttons'; | import {FloatingActionButtonComponent} from '@progress/kendo-angular-buttons'; | ||||
| import {DrawerSelectEvent, TabStripComponent} from '@progress/kendo-angular-layout'; | 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 {PayInComponent} from '../pay-in/pay-in.component'; | ||||
| import {PayInModel} from '../models/pay-in.model'; | |||||
| import {Subject} from 'rxjs'; | |||||
| @ViewChild('tabs', {static: true}) tab: TabStripComponent; | @ViewChild('tabs', {static: true}) tab: TabStripComponent; | ||||
| @ViewChild('PayIn', {static: false}) payIn: PayInComponent; | @ViewChild('PayIn', {static: false}) payIn: PayInComponent; | ||||
| // 'http://africau.edu/images/default/sample.pdf'; | |||||
| public uploadAsPicUrl = ''; | |||||
| public newPayInUpdateSubject = new Subject<PayInModel>(); | |||||
| public uploadAsPicUrl = ''; // 'http://africau.edu/images/default/sample.pdf'; | |||||
| public uploadAsPdfUrl = ''; | public uploadAsPdfUrl = ''; | ||||
| public initAnimation = false; | public initAnimation = false; | ||||
| public iframeLoaded = false; | public iframeLoaded = false; | ||||
| public tabText: string[] = ['Preview', 'Content', 'Analysis']; | public tabText: string[] = ['Preview', 'Content', 'Analysis']; | ||||
| public tabTitle: string[] = this.tabText; | public tabTitle: string[] = this.tabText; | ||||
| public analysisAAA: PayInAAARowModel[] = []; | |||||
| constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) { | constructor(private us: UploadAttachService, private actRoute: ActivatedRoute, private router: Router) { | ||||
| this.uploadAsPicUrl = location.origin + 'assets/img/no_preview.jpg'; | this.uploadAsPicUrl = location.origin + 'assets/img/no_preview.jpg'; | ||||
| this.us.getUploadAnalysis(this.uploadId).subscribe( | this.us.getUploadAnalysis(this.uploadId).subscribe( | ||||
| resp => { | resp => { | ||||
| this.ua = new UploadAnalysisModel(resp); | this.ua = new UploadAnalysisModel(resp); | ||||
| this.ua.AAA.forEach(v => { | |||||
| this.analysisAAA.push(new PayInAAARowModel(v)); | |||||
| }); | |||||
| this.uploadId = this.ua.Id; | this.uploadId = this.ua.Id; | ||||
| this.analysisIsDone = true; | this.analysisIsDone = true; | ||||
| }, err => { | }, err => { | ||||
| this.fabOffset = {x: '10px', y: s}; | 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); | |||||
| } | |||||
| } | } |