| import {Directive, EventEmitter, Injectable, Input, OnChanges, Output} from '@angular/core'; | |||||
| import {UploadAnalysisModel} from '../models/upload.analysis.model'; | |||||
| import {PayInModel} from '../models/pay-in.model'; | |||||
| import {PayInAAARowModel} from '../models/Pay.In.AAA.Row.model'; | |||||
| import {PayInLenderIncomeModel} from './pay-in-lender.income.model'; | |||||
| import {CellCloseEvent} from '@progress/kendo-angular-grid'; | |||||
| @Directive() | |||||
| export class LenderIncomeAbstractDirective { | |||||
| @Input() public analysis = new UploadAnalysisModel({}); | |||||
| @Input() newPayInUpdate: PayInModel; | |||||
| @Output() Selected: EventEmitter<PayInModel> = new EventEmitter<PayInModel>(); | |||||
| public data: PayInLenderIncomeModel[] = []; | |||||
| @Input() payIn: PayInModel[] = []; | |||||
| constructor(protected AgencyName: string) { | |||||
| } | |||||
| OnChanges(changes): void { | |||||
| if (changes.newPayInUpdate) { | |||||
| const piNew = changes.newPayInUpdate.currentValue as PayInModel; | |||||
| this.onNewPayInUpdate(piNew); | |||||
| } | |||||
| if (changes.payIn){ | |||||
| this.data.forEach( v => { | |||||
| v.matchedPayIn = this.matchPayIn(v); | |||||
| }); | |||||
| } | |||||
| } | |||||
| private onNewPayInUpdate(piNew: PayInModel): void { | |||||
| this.data.forEach(value => { | |||||
| const v = value as PayInLenderIncomeModel; | |||||
| // remove old matches | |||||
| if (v.matchedPayIn !== -1 && v.matchedPayIn.Id === piNew.Id) { | |||||
| v.matchedPayIn = -1; | |||||
| } | |||||
| // add new matches | |||||
| if (this.isMatch(v, piNew)) { | |||||
| v.matchedPayIn = piNew; | |||||
| } | |||||
| }); | |||||
| } | |||||
| public onCellClick(event: CellCloseEvent): void{ | |||||
| this.Selected.emit(event.dataItem.asPayIn()); | |||||
| } | |||||
| protected matchPayIn(v: PayInLenderIncomeModel): PayInModel | -1 { | |||||
| const idx = this.payIn.findIndex( pi => this.isMatch(v, pi) ); | |||||
| if ( idx === -1 ) { return -1; } | |||||
| return this.payIn[idx]; | |||||
| } | |||||
| protected isMatch( v: PayInLenderIncomeModel, pi: PayInModel): boolean { | |||||
| if ( v === null || pi === null ){ | |||||
| return false; | |||||
| } | |||||
| return v.isMatch(pi); | |||||
| } | |||||
| } |
| import {PayInModel} from '../models/pay-in.model'; | |||||
| export abstract class PayInLenderIncomeModel { | |||||
| public matchedPayIn?: PayInModel | -1; | |||||
| abstract convertToPayIn(): PayInModel; | |||||
| abstract isMatch(pi: PayInModel): boolean; | |||||
| protected constructor(protected AgencyName: string, payload: Partial<PayInLenderIncomeModel>){ | |||||
| this.matchedPayIn = payload.matchedPayIn || -1; | |||||
| } | |||||
| public asPayIn(): PayInModel { | |||||
| if (this.matchedPayIn !== undefined && this.matchedPayIn !== -1) { | |||||
| return this.matchedPayIn; | |||||
| } | |||||
| return this.convertToPayIn(); | |||||
| } | |||||
| } |
| import {PayInModel} from './pay-in.model'; | import {PayInModel} from './pay-in.model'; | ||||
| import {PayInLenderIncomeModel} from '../abstract/pay-in-lender.income.model'; | |||||
| export class PayInAAARowModel { | |||||
| private Lender = 'AAA'; | |||||
| export class PayInAAARowModel extends PayInLenderIncomeModel { | |||||
| 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>){ | ||||
| super('AAA', payload); | |||||
| this.Period = new Date(payload.Period); | this.Period = new Date(payload.Period); | ||||
| this.LoanNumber = payload.LoanNumber || ''; | this.LoanNumber = payload.LoanNumber || ''; | ||||
| this.Settlement = new Date(payload.Settlement); | this.Settlement = new Date(payload.Settlement); | ||||
| this.LoanFacility = payload.LoanFacility || 0; | this.LoanFacility = payload.LoanFacility || 0; | ||||
| this.Balance = payload.Balance || -1; | this.Balance = payload.Balance || -1; | ||||
| 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; | |||||
| } | |||||
| public convertToPayIn(): PayInModel { | |||||
| const pi = new PayInModel({}); | const pi = new PayInModel({}); | ||||
| pi.Lender = this.Lender; | |||||
| pi.Lender = this.AgencyName; | |||||
| pi.LoanNumber = this.LoanNumber; | pi.LoanNumber = this.LoanNumber; | ||||
| pi.Amount = this.LoanFacility; | pi.Amount = this.LoanFacility; | ||||
| pi.Settlement = this.Settlement; | pi.Settlement = this.Settlement; | ||||
| pi.Balance = this.Balance; | pi.Balance = this.Balance; | ||||
| pi.OffsetBalance = -1; | pi.OffsetBalance = -1; | ||||
| pi.Ts = this.Period; | pi.Ts = this.Period; | ||||
| return pi; | return pi; | ||||
| } | } | ||||
| public isMatch(pi: PayInModel): boolean { | public isMatch(pi: PayInModel): boolean { | ||||
| return this.LoanNumber === pi.LoanNumber && this.LoanNumber !== '' && | return this.LoanNumber === pi.LoanNumber && this.LoanNumber !== '' && | ||||
| this.Lender === pi.Lender && this.Lender !== '' && | |||||
| this.AgencyName === pi.Lender && this.AgencyName !== '' && | |||||
| this.InTrail === pi.IncomeAmount && | this.InTrail === pi.IncomeAmount && | ||||
| this.Balance === pi.Balance && | this.Balance === pi.Balance && | ||||
| 'Trail' === pi.IncomeType; | 'Trail' === pi.IncomeType; |
| import {PayInModel} from './pay-in.model'; | import {PayInModel} from './pay-in.model'; | ||||
| import {PayInLenderIncomeModel} from '../abstract/pay-in-lender.income.model'; | |||||
| export class PayInConnectiveModel { | |||||
| private AgencyName = 'Connective'; | |||||
| export class PayInConnectiveModel extends PayInLenderIncomeModel { | |||||
| public Period: Date; | |||||
| public LoanAccount: string; | public LoanAccount: string; | ||||
| public Name: string; | public Name: string; | ||||
| public Settled: Date; | public Settled: Date; | ||||
| public GST: number; | public GST: number; | ||||
| public Total: number; | public Total: number; | ||||
| public Period: Date; | |||||
| public matchedPayIn?: PayInModel | -1; | |||||
| constructor(payload: Partial<PayInConnectiveModel>){ | constructor(payload: Partial<PayInConnectiveModel>){ | ||||
| super('Connective', payload); | |||||
| this.Period = new Date(payload.Period); | this.Period = new Date(payload.Period); | ||||
| this.LoanAccount = payload.LoanAccount || ''; | this.LoanAccount = payload.LoanAccount || ''; | ||||
| this.Name = payload.Name || ''; | this.Name = payload.Name || ''; | ||||
| this.Settled = new Date(payload.Settled); | this.Settled = new Date(payload.Settled); | ||||
| this.Lender = payload.Lender || ''; | this.Lender = payload.Lender || ''; | ||||
| if ( this.Lender.indexOf(this.AgencyName) === -1 ){ | |||||
| this.Lender += '_' + this.AgencyName; | |||||
| } | |||||
| this.ensureLenderHasAgencyNameAppended(); | |||||
| this.LoanAmount = payload.LoanAmount || 0; | this.LoanAmount = payload.LoanAmount || 0; | ||||
| this.Balance = payload.Balance || 0; | this.Balance = payload.Balance || 0; | ||||
| this.Associate = payload.Associate || ''; | this.Associate = payload.Associate || ''; | ||||
| this.matchedPayIn = payload.matchedPayIn || -1; | this.matchedPayIn = payload.matchedPayIn || -1; | ||||
| } | } | ||||
| public asPayIn(): PayInModel { | |||||
| if ( this.matchedPayIn !== undefined && this.matchedPayIn !== -1 ) { | |||||
| return this.matchedPayIn; | |||||
| private ensureLenderHasAgencyNameAppended(): void { | |||||
| if ( this.Lender.indexOf(this.AgencyName) === -1 ){ | |||||
| this.Lender += '_' + this.AgencyName; | |||||
| } | } | ||||
| } | |||||
| public convertToPayIn(): PayInModel { | |||||
| const pi = new PayInModel({}); | const pi = new PayInModel({}); | ||||
| pi.Lender = this.Lender; | pi.Lender = this.Lender; | ||||
| pi.LoanNumber = this.LoanAccount; | pi.LoanNumber = this.LoanAccount; |
| import {PayInAAARowModel} from '../../models/Pay.In.AAA.Row.model'; | import {PayInAAARowModel} from '../../models/Pay.In.AAA.Row.model'; | ||||
| import {PayInModel} from '../../models/pay-in.model'; | import {PayInModel} from '../../models/pay-in.model'; | ||||
| import {Subject} from 'rxjs'; | import {Subject} from 'rxjs'; | ||||
| import {PayInLenderIncomeModel} from '../../abstract/pay-in-lender.income.model'; | |||||
| import {LenderIncomeAbstractDirective} from '../../abstract/lender-income-abstract.directive'; | |||||
| import {PayInConnectiveModel} from '../../models/pay-in-connective.model'; | |||||
| @Component({ | @Component({ | ||||
| templateUrl: './lender-aaa-income.component.html', | templateUrl: './lender-aaa-income.component.html', | ||||
| styleUrls: ['./lender-aaa-income.component.scss'] | 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() { } | |||||
| export class LenderAaaIncomeComponent extends LenderIncomeAbstractDirective implements OnInit, OnChanges { | |||||
| constructor() { super('AAA'); } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.analysis.AAA.forEach(v => { | |||||
| this.analysis[this.AgencyName].forEach(v => { | |||||
| v.matchedPayIn = this.matchPayIn(v); | v.matchedPayIn = this.matchPayIn(v); | ||||
| this.data.push(new PayInAAARowModel(v)); | this.data.push(new PayInAAARowModel(v)); | ||||
| }); | }); | ||||
| } | } | ||||
| ngOnChanges(changes): void { | ngOnChanges(changes): void { | ||||
| if (changes.newPayInUpdate){ | |||||
| const piNew = changes.newPayInUpdate.currentValue as PayInModel; | |||||
| this.data.forEach(v => { | |||||
| // remove old matches | |||||
| if (v.matchedPayIn !== -1 && v.matchedPayIn.Id === piNew.Id){ | |||||
| v.matchedPayIn = -1; | |||||
| } | |||||
| // add new matches | |||||
| 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.isMatch(pi); | |||||
| super.OnChanges(changes); | |||||
| } | } | ||||
| @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); | |||||
| }); | |||||
| } | |||||
| get PayIn(): PayInModel[] { | |||||
| return this.payInCandidates; | |||||
| } | |||||
| } | } |
| <ng-template kendoGridToolbarTemplate> | <ng-template kendoGridToolbarTemplate> | ||||
| Connective | Connective | ||||
| </ng-template> | </ng-template> | ||||
| <kendo-grid-column field="Period" format='{0:yyyy MMMM}' width="200"> </kendo-grid-column> | |||||
| <kendo-grid-column field="Period" format='{0:yyyy MMMM}' width="110"> </kendo-grid-column> | |||||
| <kendo-grid-column field="LoanAccount" width="150"> </kendo-grid-column> | <kendo-grid-column field="LoanAccount" width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="Name" width="150"> </kendo-grid-column> | <kendo-grid-column field="Name" width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="Settled" format='{0:MM/dd/yyyy}' width="150"> </kendo-grid-column> | <kendo-grid-column field="Settled" format='{0:MM/dd/yyyy}' width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="Paid" format='{0:c}' width="150"> </kendo-grid-column> | <kendo-grid-column field="Paid" format='{0:c}' width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="GST" format='{0:c}' width="150"> </kendo-grid-column> | <kendo-grid-column field="GST" format='{0:c}' width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="Total" format='{0:c}' width="150"> </kendo-grid-column> | <kendo-grid-column field="Total" format='{0:c}' width="150"> </kendo-grid-column> | ||||
| <kendo-grid-column field="matchedPayIn" title="Matched" format='{0:c}'> | |||||
| <kendo-grid-column field="matchedPayIn" title="Matched" format='{0:c}' width="180"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | <ng-template kendoGridCellTemplate let-dataItem> | ||||
| <kendo-icon *ngIf="dataItem.matchedPayIn === -1" [name]="'close-circle'" [size]="'small'" [themeColor]="'warning'"></kendo-icon> | <kendo-icon *ngIf="dataItem.matchedPayIn === -1" [name]="'close-circle'" [size]="'small'" [themeColor]="'warning'"></kendo-icon> |
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | |||||
| import {UploadAnalysisModel} from '../../models/upload.analysis.model'; | |||||
| import {PayInModel} from '../../models/pay-in.model'; | |||||
| import {CellCloseEvent} from '@progress/kendo-angular-grid'; | |||||
| import {PayInConnectiveModel} from '../../models/pay-in-connective.model'; | |||||
| import {Component, EventEmitter, Input, OnChanges, OnInit, Output} from '@angular/core'; | |||||
| import {DataResult, GroupDescriptor, process} from '@progress/kendo-data-query'; | import {DataResult, GroupDescriptor, process} from '@progress/kendo-data-query'; | ||||
| import {LenderIncomeAbstractDirective} from '../../abstract/lender-income-abstract.directive'; | |||||
| import {PayInAAARowModel} from '../../models/Pay.In.AAA.Row.model'; | |||||
| import {PayInConnectiveModel} from '../../models/pay-in-connective.model'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-lender-connective-income', | selector: 'app-lender-connective-income', | ||||
| templateUrl: './lender-connective-income.component.html', | templateUrl: './lender-connective-income.component.html', | ||||
| styleUrls: ['./lender-connective-income.component.scss'] | styleUrls: ['./lender-connective-income.component.scss'] | ||||
| }) | }) | ||||
| export class LenderConnectiveIncomeComponent implements OnInit { | |||||
| private Lender = 'Connective'; | |||||
| @Input() public analysis = new UploadAnalysisModel({}); | |||||
| @Input() newPayInUpdate: PayInModel; | |||||
| @Output() Selected: EventEmitter<PayInModel> = new EventEmitter<PayInModel>(); | |||||
| public data: PayInConnectiveModel[] = []; | |||||
| private payInCandidates: PayInModel[] = []; | |||||
| export class LenderConnectiveIncomeComponent extends LenderIncomeAbstractDirective | |||||
| implements OnInit, OnChanges { | |||||
| public groups: GroupDescriptor[] = [{ field: 'Lender' }]; | public groups: GroupDescriptor[] = [{ field: 'Lender' }]; | ||||
| public gridView: DataResult; | public gridView: DataResult; | ||||
| constructor() { } | |||||
| constructor() { super('Connective'); } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.analysis.Connective.forEach(v => { | |||||
| this.analysis[this.AgencyName].forEach(v => { | |||||
| v.matchedPayIn = this.matchPayIn(v); | v.matchedPayIn = this.matchPayIn(v); | ||||
| this.data.push(new PayInConnectiveModel(v)); | this.data.push(new PayInConnectiveModel(v)); | ||||
| }); | }); | ||||
| this.gridView = process(this.data, { group: this.groups }); | this.gridView = process(this.data, { group: this.groups }); | ||||
| } | } | ||||
| ngOnChanges(changes): void { // Todo: build super class for common features | |||||
| if (changes.newPayInUpdate){ | |||||
| const piNew = changes.newPayInUpdate.currentValue as PayInModel; | |||||
| this.data.forEach(v => { | |||||
| // remove old matches | |||||
| if (v.matchedPayIn !== -1 && v.matchedPayIn.Id === piNew.Id){ | |||||
| v.matchedPayIn = -1; | |||||
| } | |||||
| // add new matches | |||||
| 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: PayInConnectiveModel): PayInModel | -1 { | |||||
| const idx = this.payInCandidates.findIndex( pi => this.isMatch(v, pi) ); | |||||
| if ( idx === -1 ) { return -1; } | |||||
| return this.payInCandidates[idx]; | |||||
| } | |||||
| private isMatch( v: PayInConnectiveModel, pi: PayInModel): boolean { | |||||
| if ( v === null || pi === null ){ | |||||
| return false; | |||||
| } | |||||
| return v.isMatch(pi); | |||||
| ngOnChanges(changes): void { | |||||
| super.OnChanges(changes); | |||||
| } | } | ||||
| @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); | |||||
| }); | |||||
| } | |||||
| get PayIn(): PayInModel[] { | |||||
| return this.payInCandidates; | |||||
| } | |||||
| } | } |