Browse Source

upload lender automatically if there is already a match.

tags/2.037
Patrick Sun 4 years ago
parent
commit
562b82658c
11 changed files with 172 additions and 38 deletions
  1. +53
    -0
      src/app/app.component.scss
  2. +12
    -2
      src/app/loan-select/loan-select.component.ts
  3. +14
    -4
      src/app/models/Pay.In.AAA.Row.model.ts
  4. +1
    -1
      src/app/models/pay-in-list.filter.model.ts
  5. +14
    -0
      src/app/models/pay-in.model.ts
  6. +0
    -13
      src/app/observable/pay.in.observable.ts
  7. +4
    -2
      src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html
  8. +9
    -8
      src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts
  9. +5
    -2
      src/app/pay-in/pay-in.component.html
  10. +14
    -0
      src/app/pay-in/pay-in.component.scss
  11. +46
    -6
      src/app/pay-in/pay-in.component.ts

+ 53
- 0
src/app/app.component.scss View File

@@ -43,3 +43,56 @@
.upload-details div[role="tabpanel"]{
padding:0px;
}

@keyframes flash-background {
from {background-color: white;}
to {background-color: lightgoldenrodyellow;}
}
kendo-grid.filterByUploadMeta {
.k-grid-add-row.k-grid-edit-row.ng-star-inserted {
animation: flash-background 1s infinite;
opacity: 1;
}

.k-state-selected {
animation: flash-background 1s 3;
opacity: 1;
}

tr {
position: relative;
}
@keyframes flash{
50% { opacity: 0.5 }
}

tr.dup {
td:first-child{
position: relative;
div {
display:unset;
transition: display 1s;
z-index:1;
}
}
}

tr.missingLoan {
td:last-child {
text-align: left;
&::before{
color: #020202;
background: #ffe172;
width: 110px;
content: "missing loan";
text-align: right;
position: absolute;
overflow:hidden;
right: 0;
border-radius: 10px 0 0 10px;
animation: flash 1s 3;
}
};
}
}


+ 12
- 2
src/app/loan-select/loan-select.component.ts View File

@@ -62,11 +62,21 @@ export class LoanSelectComponent implements OnInit, ControlValueAccessor {
}

onLoanSelected(loan: LoanModel): void {
if (loan !== undefined && this.Loan !== undefined && this.Loan.Id !== loan.Id){
let changed = false;
if ( loan === null || loan === undefined) {
if (this.Loan.Id !== '') {
changed = true;
}
}else{
changed = this.Loan.Id !== loan.Id;
}

if (changed ){
this.valueChange.emit(loan);
this.onChange(loan);
this.Loan = loan;
}

// update changes
if (loan === undefined || loan == null ){
this.Loan = new LoanModel({});
}else{

+ 14
- 4
src/app/models/Pay.In.AAA.Row.model.ts View File

@@ -6,7 +6,7 @@ export class PayInAAARowModel {
public Period: Date;
public LoanNumber: string;
public Settlement: Date;
public LoanAmount: number;
public LoanFacility: number;
public Balance: number;
public InTrail: number;

@@ -16,8 +16,8 @@ export class PayInAAARowModel {
this.Period = new Date(payload.Period);
this.LoanNumber = payload.LoanNumber || '';
this.Settlement = new Date(payload.Settlement);
this.LoanAmount = payload.LoanAmount || 0;
this.Balance = payload.Balance || 0;
this.LoanFacility = payload.LoanFacility || 0;
this.Balance = payload.Balance || -1;
this.InTrail = payload.InTrail || 0;
this.matchedPayIn = payload.matchedPayIn || -1;
}
@@ -29,12 +29,22 @@ export class PayInAAARowModel {
const pi = new PayInModel({});
pi.Lender = this.Lender;
pi.LoanNumber = this.LoanNumber;
pi.Amount = this.LoanAmount;
pi.Amount = this.LoanFacility;
pi.Settlement = this.Settlement;
pi.IncomeAmount = this.InTrail;
pi.IncomeType = 'Trail';
pi.Balance = this.Balance;
pi.OffsetBalance = -1;
pi.Ts = this.Period;

return pi;
}

public isMatch(pi: PayInModel): boolean {
return this.LoanNumber === pi.LoanNumber && this.LoanNumber !== '' &&
this.Lender === pi.Lender && this.Lender !== '' &&
this.InTrail === pi.IncomeAmount &&
this.Balance === pi.Balance &&
'Trail' === pi.IncomeType;
}
}

+ 1
- 1
src/app/models/pay-in-list.filter.model.ts View File

@@ -28,7 +28,7 @@ export class PayInListFilterModel {
}

const bigNumber = 9999999999;
this.Take = payload.Take || 10;
this.Take = payload.Take || 0;
this.Skip = payload.Skip || 0;
this.TsFrom = payload.TsFrom? new Date(payload.TsFrom) : new Date('1900-01-01');
this.TsTo = payload.TsTo? new Date(payload.TsTo) : new Date('2038-01-01');

+ 14
- 0
src/app/models/pay-in.model.ts View File

@@ -41,6 +41,20 @@ export class PayInModel {
this.UploadId = payload.UploadId;
}

public isEqual(pi: PayInModel): boolean {
return pi !== undefined && pi !== null &&
this.Amount === pi.Amount &&
this.Balance === pi.Balance &&
this.Lender === pi.Lender &&
this.LoanId === pi.LoanId &&
this.LoanNumber === pi.LoanNumber &&
this.OffsetBalance === pi.OffsetBalance &&
this.Settlement.getDate() === pi.Settlement.getDate() &&
this.IncomeAmount === pi.IncomeAmount &&
this.IncomeType === pi.IncomeType &&
this.Ts.getDate() === pi.Ts.getDate() &&
this.UploadId === pi.UploadId;
}
}



+ 0
- 13
src/app/observable/pay.in.observable.ts View File

@@ -1,13 +0,0 @@
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);
}
}

+ 4
- 2
src/app/pay-in/lender-aaa-income/lender-aaa-income.component.html View File

@@ -6,12 +6,14 @@
<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="LoanFacility" 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>

<kendo-icon *ngIf="dataItem.matchedPayIn === -1" [name]="'close-circle'" [size]="'small'" [themeColor]="'warning'"></kendo-icon>
<kendo-icon *ngIf="dataItem.matchedPayIn !== -1" [name]="'tick'" [size]="'small'" [themeColor]="'success'"></kendo-icon>
{{ dataItem.matchedPayIn === -1? 'Not matched': dataItem.matchedPayIn.Id}}
</ng-template>
</kendo-grid-column>

+ 9
- 8
src/app/pay-in/lender-aaa-income/lender-aaa-income.component.ts View File

@@ -24,15 +24,19 @@ export class LenderAaaIncomeComponent implements OnInit, OnChanges {
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){
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;
}
@@ -54,12 +58,10 @@ export class LenderAaaIncomeComponent implements OnInit, OnChanges {
if ( v === null || pi === null ){
return false;
}
return v.LoanNumber === pi.LoanNumber &&
this.Lender === pi.Lender &&
v.InTrail === pi.IncomeAmount &&
'Trail' === pi.IncomeType;
return v.isMatch(pi);
}


@Input() set payIn(pis: PayInModel[]) {
this.payInCandidates = [];
pis.forEach( v => this.payInCandidates.push(new PayInModel(v)));
@@ -68,7 +70,6 @@ export class LenderAaaIncomeComponent implements OnInit, OnChanges {
v.matchedPayIn = this.matchPayIn(v);
});

console.log ('new payin comes in');
}

get PayIn(): PayInModel[] {

+ 5
- 2
src/app/pay-in/pay-in.component.html View File

@@ -13,6 +13,7 @@
kendoGridSelectBy
[selectedKeys]="gridSelection"

[rowClass]="rowClassCallbackBind"

(add)="addHandler($event)"
(cancel)="cancelHandler($event)"
@@ -22,6 +23,7 @@

(pageChange)="pageChange($event)"
(sortChange)="sortChange($event)"
[ngClass]="{ 'filterByUploadMeta': uploadMeta.Id > 0 }"
>
<ng-template kendoGridToolbarTemplate>
<div style="width:100%; margin:0px; display:block">
@@ -39,6 +41,7 @@

<kendo-grid-command-column *ngIf="allowEdit" title="command" width="100">
<ng-template kendoGridCellTemplate let-isNew="isNew" let-dataItem>
<div class="duplicate">dup</div>
<button kendoGridEditCommand *ngIf="!dataItem.Uploads !== 0" icon="edit"></button>
<button kendoGridRemoveCommand *ngIf="!dataItem.Uploads !== 0" icon="delete"></button>
<button kendoGridSaveCommand [disabled]="incomeFormGroup?.invalid" icon="save"></button>
@@ -55,9 +58,9 @@
</kendo-grid-column>

<kendo-grid-column field="Lender" title="Lender" width="150" >
<ng-template kendoGridEditTemplate let-dataItem>
<ng-template kendoGridEditTemplate let-dataItem let-formGroup>
<kendo-combobox
[formControl]="incomeFormGroup.get('Lender')"
[formControl]="formGroup.get('Lender')"
[data]="lenderListView | async"
[loading]="lenderNameService.loading">
</kendo-combobox>

+ 14
- 0
src/app/pay-in/pay-in.component.scss View File

@@ -14,6 +14,20 @@ kendo-grid {
margin-right: 10px;
}
}

div.duplicate {
background: darkgrey;
position: absolute;
top: 0px;
transform: rotate(
-45deg
);
display: none;
width: 50px;
left: -15px;
text-align: center;
color: white;
}
}

.balance {

+ 46
- 6
src/app/pay-in/pay-in.component.ts View File

@@ -6,7 +6,7 @@ import {PayInService} from '../service/pay-in.service';
import {PayInListResult} from '../models/pay-in-list-result.model';
import {Router} from '@angular/router';
import {PopupIncomeFilterComponent} from '../popup-income-filter/popup-income-filter.component';
import {GridComponent, PageChangeEvent, SortSettings} from '@progress/kendo-angular-grid';
import {GridComponent, PageChangeEvent, RowClassArgs, SortSettings} from '@progress/kendo-angular-grid';
import {SortDescriptor} from '@progress/kendo-data-query';
import {UploadMetaModel} from '../models/uploadMetaModel';
import {debounce} from 'ts-debounce';
@@ -47,6 +47,7 @@ export class PayInComponent implements OnInit {
public showOffsetBalance = true;

@Input() public pageable = true;
@Input() public pageSize = 15;

public gridSelection: number[] = [];
public sortable: SortSettings = {
@@ -55,15 +56,21 @@ export class PayInComponent implements OnInit {

public loading = false;
public lenderListView: Observable<string[]>;
public rowClassCallbackBind: any;
private debouncedLoadFilteredData = () => {};



constructor(private pis: PayInService,
private lss: LoanSingleService,
private router: Router,
private lenderNameService: LenderNameService) {
this.lenderListView = this.lenderNameService;
this.lenderNameService.query();
if ( this.pageable ) {
this.filter.Take = this.pageSize;
}
this.rowClassCallbackBind = this.rowClassCallback.bind(this);
}

ngOnInit(): void {
@@ -100,7 +107,7 @@ export class PayInComponent implements OnInit {
this.filter.UploadIds = [ value.Id.toString() ];
}
this.debouncedLoadFilteredData();
//console.log('upload filter changed', value, this.filter);
// console.log('upload filter changed', value, this.filter);
}

get uploadMeta(): UploadMetaModel {
@@ -143,10 +150,13 @@ export class PayInComponent implements OnInit {
this.showOffsetBalance = offsetBalance >= 0 ;
this.incomeFormGroup = this.createFormGroup(new PayInModelEx({}));



// console.log(this.incomeFormGroup);
sender.addRow(this.incomeFormGroup);
}


private createFormGroup(dataItem: PayInModelEx): FormGroup {
const Loan = this.filterLoan.Id !== '' ? this.filterLoan : dataItem.Loan;
const UploadMeta = this.filterUploadMeta.Id !== 0 ? this.filterUploadMeta : dataItem.UploadMeta ;
@@ -178,7 +188,6 @@ export class PayInComponent implements OnInit {
}

public cancelHandler({ sender, rowIndex }): void {
// console.log(sender);
this.closeEditor(sender, rowIndex);
}

@@ -195,6 +204,7 @@ export class PayInComponent implements OnInit {
this.Loan.cuPayIn( model);
this.updatePiInGrid(model);
this.Updated.emit(model);
console.log(this);
},
err => {
// TODO: this.errorOccurred.emit('Error saving Income');
@@ -253,7 +263,9 @@ export class PayInComponent implements OnInit {
}

private closeEditor(grid, rowIndex = this.editedRowIndex): void{
grid.closeRow(rowIndex);
if ( rowIndex !== undefined ){
grid.closeRow(rowIndex);
}
this.editedRowIndex = undefined;
this.incomeFormGroup = undefined;
}
@@ -310,12 +322,15 @@ export class PayInComponent implements OnInit {
}

public onLoanChange(loan: LoanModel): void {
if ( loan.Id !== '' ) {
if ( loan !== undefined && loan.Id !== '' ) {
this.incomeFormGroup.get('Lender').setValue(loan.Lender);
this.incomeFormGroup.get('Lender').disable({onlySelf: true, emitEvent: false});

this.incomeFormGroup.get('LoanNumber').setValue(loan.LenderLoanNumber);
this.incomeFormGroup.get('LoanNumber').disable({onlySelf: true, emitEvent: false});
}else{
this.incomeFormGroup.get('Lender').enable({onlySelf: true, emitEvent: false});
this.incomeFormGroup.get('LoanNumber').enable({onlySelf: true, emitEvent: false});
}
}

@@ -326,6 +341,7 @@ export class PayInComponent implements OnInit {
}

public selectOrAddPayIn(pi: PayInModel): void{

const row = this.gridData.data.findIndex( v => {
return v.LoanNumber === pi.LoanNumber &&
v.Lender === pi.Lender &&
@@ -336,9 +352,33 @@ export class PayInComponent implements OnInit {
if ( row >= 0 ) { // we found it
this.ScrollTo(row);
} else{
this.gridSelection = []; // select none
this.incomeFormGroup = this.createFormGroup(new PayInModelEx(pi));
// this.closeEditor(this.grid);
this.grid.addRow(this.incomeFormGroup);
}
}

public rowClassCallback( context: RowClassArgs): any {
const pi = context.dataItem as PayInModel;
const rowIndex = context.index;

const duplicate = this.checkDup(pi, rowIndex);

return {
dup: duplicate,
missingLoan: pi.LoanId === ''
};
}
private checkDup(pi: PayInModel, rowIndex: number): boolean {
let found = false;
if (this.uploadMeta.Id <= 0 ) {
return false; // dup check is only available for upload filtered situation.
}
this.gridData.data.forEach( (v, index) => {
if ( v.isEqual(pi) && index !== rowIndex ){
found = true;
}
});
return found;
}
}

Loading…
Cancel
Save