| { | { | ||||
| "name": "broker", | "name": "broker", | ||||
| "version": "2.0.1", | |||||
| "version": "2.0.4", | |||||
| "lockfileVersion": 1, | "lockfileVersion": 1, | ||||
| "requires": true, | "requires": true, | ||||
| "dependencies": { | "dependencies": { |
| { | { | ||||
| "name": "broker", | "name": "broker", | ||||
| "version": "2.0.1", | |||||
| "version": "2.0.4", | |||||
| "scripts": { | "scripts": { | ||||
| "ng": "ng", | "ng": "ng", | ||||
| "start": "ng serve --proxy-config proxy.conf.json", | "start": "ng serve --proxy-config proxy.conf.json", | ||||
| "prebuild": "npm --no-git-tag-version version patch", | "prebuild": "npm --no-git-tag-version version patch", | ||||
| "build": "ng build ", | "build": "ng build ", | ||||
| "buildsfm": "ng build --prod --base-href=/broker/ --deploy-url=/broker/ ", | |||||
| "buildsfm": "npm --no-git-tag-version version patch && ng build --prod --base-href=/broker/ --deploy-url=/broker/ ", | |||||
| "test": "ng test", | "test": "ng test", | ||||
| "lint": "ng lint", | "lint": "ng lint", | ||||
| "e2e": "ng e2e" | "e2e": "ng e2e" |
| import {UploadDetailComponent} from './upload-detail/upload-detail.component'; | import {UploadDetailComponent} from './upload-detail/upload-detail.component'; | ||||
| import {LoansAllComponent} from './loans-all/loans-all.component'; | import {LoansAllComponent} from './loans-all/loans-all.component'; | ||||
| import {RewardsAllComponent} from './rewards-all/rewards-all.component'; | import {RewardsAllComponent} from './rewards-all/rewards-all.component'; | ||||
| import {PayOutDetailsComponent} from './pay-out-details/pay-out-details.component'; | |||||
| const routes: Routes = [ | const routes: Routes = [ | ||||
| {path : 'profile/:id', component: ProfileComponent, canActivate: [AuthGuard] }, | {path : 'profile/:id', component: ProfileComponent, canActivate: [AuthGuard] }, | ||||
| {path : 'upload-details/:id', component: UploadDetailComponent, canActivate: [AuthGuard] }, | {path : 'upload-details/:id', component: UploadDetailComponent, canActivate: [AuthGuard] }, | ||||
| {path : 'list-income', component: ListIncomeComponent, canActivate: [AuthGuard] }, | {path : 'list-income', component: ListIncomeComponent, canActivate: [AuthGuard] }, | ||||
| {path : 'payout-details/:id', component: PayOutDetailsComponent, canActivate: [AuthGuard] }, | |||||
| {path : 'reward-paid/:id', component: RewardPaidComponent, canActivate: [AuthGuard] }, | |||||
| {path : 'e403', component: E403Component }, | {path : 'e403', component: E403Component }, | ||||
| ]; | ]; | ||||
| //Angular | |||||
| // Angular | |||||
| import {APP_INITIALIZER, NgModule} from '@angular/core'; | import {APP_INITIALIZER, NgModule} from '@angular/core'; | ||||
| import { CommonModule } from '@angular/common'; | import { CommonModule } from '@angular/common'; | ||||
| import { BrowserModule } from '@angular/platform-browser'; | import { BrowserModule } from '@angular/platform-browser'; | ||||
| import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; | ||||
| import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; | ||||
| import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http'; | import {HTTP_INTERCEPTORS, HttpClientModule} from '@angular/common/http'; | ||||
| //Kendo | |||||
| // Kendo | |||||
| import { MenuModule, ContextMenuModule } from '@progress/kendo-angular-menu'; | import { MenuModule, ContextMenuModule } from '@progress/kendo-angular-menu'; | ||||
| import { IconsModule } from '@progress/kendo-angular-icons'; | import { IconsModule } from '@progress/kendo-angular-icons'; | ||||
| import { DialogsModule } from '@progress/kendo-angular-dialog'; | import { DialogsModule } from '@progress/kendo-angular-dialog'; | ||||
| import { GridModule, PDFModule, ExcelModule } from '@progress/kendo-angular-grid'; | import { GridModule, PDFModule, ExcelModule } from '@progress/kendo-angular-grid'; | ||||
| import { InputsModule } from '@progress/kendo-angular-inputs'; | import { InputsModule } from '@progress/kendo-angular-inputs'; | ||||
| //App | |||||
| // App | |||||
| import { AppComponent } from './app.component'; | import { AppComponent } from './app.component'; | ||||
| import { AppRoutingModule } from './app-routing.module'; | import { AppRoutingModule } from './app-routing.module'; | ||||
| import { DashboardComponent } from './dashboard/dashboard.component'; | import { DashboardComponent } from './dashboard/dashboard.component'; |
| [data]="gridView" | [data]="gridView" | ||||
| [loading]="loading" | [loading]="loading" | ||||
| [sortable]="true" | [sortable]="true" | ||||
| [pageable]="true" | |||||
| [pageable]="pageable" | |||||
| [filterable]="true" | [filterable]="true" | ||||
| [resizable]="true" | [resizable]="true" | ||||
| [selectable]="selectTableSettings" | [selectable]="selectTableSettings" | ||||
| kendoGridSelectBy="Id" | kendoGridSelectBy="Id" | ||||
| [selectedKeys]="selected" | [selectedKeys]="selected" | ||||
| (selectionChange)="onSelectionChange($event)" | |||||
| [pageSize]="state.take" | [pageSize]="state.take" | ||||
| [skip]="state.skip" | [skip]="state.skip" | ||||
| [sort]="state.sort" | [sort]="state.sort" | ||||
| [filter]="state.filter" | [filter]="state.filter" | ||||
| (dataStateChange)="dataStateChange($event)" | (dataStateChange)="dataStateChange($event)" | ||||
| class="fullheight_grid" | class="fullheight_grid" | ||||
| > | > | ||||
| <ng-template kendoGridToolbarTemplate [position]="'top'"> | <ng-template kendoGridToolbarTemplate [position]="'top'"> | ||||
| <button (click)="onSelectionEmit()" class="k-button">Make Payment</button> | |||||
| <div class="payment-toolbar"> | |||||
| <button *ngIf="showNonPaidOnly" (click)="onSelectionEmit()" class="k-button">Make Payment</button> | |||||
| <span *ngIf="!showNonPaidOnly"> Today: {{ today | date }}</span> | |||||
| </div> | |||||
| </ng-template> | </ng-template> | ||||
| <kendo-grid-checkbox-column *ngIf="EnableSelectButton" width="50" ></kendo-grid-checkbox-column> | <kendo-grid-checkbox-column *ngIf="EnableSelectButton" width="50" ></kendo-grid-checkbox-column> | ||||
| </kendo-grid-column> | </kendo-grid-column> | ||||
| <kendo-grid-column field="ToDisplay" title="Beneficiary" width="250"> | <kendo-grid-column field="ToDisplay" title="Beneficiary" width="250"> | ||||
| <ng-template kendoGridCellTemplate let-dataItem> | <ng-template kendoGridCellTemplate let-dataItem> | ||||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.To)}"></div> | |||||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.ToId)}"></div> | |||||
| <div class="customer-name"> {{ dataItem.ToDisplay }}</div> | <div class="customer-name"> {{ dataItem.ToDisplay }}</div> | ||||
| </ng-template> | </ng-template> | ||||
| <ng-template kendoGridFilterCellTemplate let-filter let-column="column"> | <ng-template kendoGridFilterCellTemplate let-filter let-column="column"> | ||||
| </kendo-grid-column> | </kendo-grid-column> | ||||
| <kendo-grid-column field="Paid" title="Paid"> | |||||
| <kendo-grid-column field="Paid" title="Invoice" [sortable]="false" [filterable]="false" width="100"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | |||||
| <button *ngIf="dataItem.Paid" kendoButton [icon]="'attachment'" | |||||
| (click)="onGoDetail(dataItem)"> {{dataItem.PayOutId}} </button> | |||||
| <kendo-chip *ngIf="! dataItem.Paid" [label]="'$'" (click)="onGoPayment(dataItem)" > | |||||
| </kendo-chip> | |||||
| </ng-template> | |||||
| <ng-template kendoGridFilterCellTemplate let-filter let-column="column"> | <ng-template kendoGridFilterCellTemplate let-filter let-column="column"> | ||||
| <kendo-grid-boolean-filter-cell | <kendo-grid-boolean-filter-cell | ||||
| [column]="column" | [column]="column" |
| kendo-grid.fullheight_grid{ | kendo-grid.fullheight_grid{ | ||||
| height: 100% !important; | height: 100% !important; | ||||
| div.payment-toolbar { | |||||
| width: 100%; | |||||
| text-align: right; | |||||
| display:block; | |||||
| } | |||||
| } | } | ||||
| .customer-photo{ | .customer-photo{ | ||||
| display: inline-block; | display: inline-block; | ||||
| width: 32px; | width: 32px; |
| import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; | ||||
| import {AuthService} from '../service/auth.service'; | import {AuthService} from '../service/auth.service'; | ||||
| import {HttpClient} from '@angular/common/http'; | |||||
| import {RewardByUserModel} from '../models/reward-by-user.model'; | |||||
| import {DataStateChangeEvent, GridDataResult, SelectableSettings,} from '@progress/kendo-angular-grid'; | |||||
| import {DataStateChangeEvent, GridDataResult, PagerSettings, SelectableSettings,} from '@progress/kendo-angular-grid'; | |||||
| import {State, process} from '@progress/kendo-data-query'; | import {State, process} from '@progress/kendo-data-query'; | ||||
| import {PayInModel} from '../models/pay-in.model'; | import {PayInModel} from '../models/pay-in.model'; | ||||
| import {RewardModel} from '../models/reward.model'; | |||||
| import {RewardExModel} from '../models/reward-ex.model'; | |||||
| import {SelectionEvent} from '@progress/kendo-angular-grid/dist/es2015/selection/types'; | |||||
| import {RewardService} from '../service/reward.service'; | |||||
| import {Router} from '@angular/router'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-list-all-rewards', | selector: 'app-list-all-rewards', | ||||
| styleUrls: ['./list-all-rewards.component.scss'] | styleUrls: ['./list-all-rewards.component.scss'] | ||||
| }) | }) | ||||
| export class ListAllRewardsComponent implements OnInit { | export class ListAllRewardsComponent implements OnInit { | ||||
| @Output() confirmSelection = new EventEmitter<RewardExModel[]>(); | |||||
| @Input() selectedRewards: RewardExModel[] = []; | |||||
| @Input() showNonPaidOnly: false; | |||||
| @Input() filterByPayOutId = 0; | |||||
| @Input() filterByUserId = ''; | |||||
| public today = new Date(); | |||||
| public selected: number[] = []; | |||||
| public gridData: RewardByUserModel[] = [] ; | |||||
| public gridData: RewardExModel[] = [] ; | |||||
| public gridView: GridDataResult; | public gridView: GridDataResult; | ||||
| public state: State = { | public state: State = { | ||||
| skip: 0, | skip: 0, | ||||
| }; | }; | ||||
| public loading = true; | public loading = true; | ||||
| @Input() public pageable: PagerSettings = { | |||||
| pageSizes: [2, 5, 10, 15, 20, 30], | |||||
| previousNext: true | |||||
| }; | |||||
| public selectTableSettings: SelectableSettings | boolean = true; | public selectTableSettings: SelectableSettings | boolean = true; | ||||
| // private multipleSelection: SelectableSettings = { | // private multipleSelection: SelectableSettings = { | ||||
| // checkboxOnly: false, | // checkboxOnly: false, | ||||
| // }; | // }; | ||||
| public EnableSelectButton = true; | public EnableSelectButton = true; | ||||
| @Input() selectedRewards: RewardModel[] = []; | |||||
| public selected: number[] = []; | |||||
| @Output() RewardsSelected: EventEmitter<PayInModel[]> = new EventEmitter<PayInModel[]>(); | @Output() RewardsSelected: EventEmitter<PayInModel[]> = new EventEmitter<PayInModel[]>(); | ||||
| constructor(private auth: AuthService, private http: HttpClient) { } | |||||
| constructor(private auth: AuthService, private rs: RewardService, private router: Router) { } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.loadInitRewardGrid(); | |||||
| this.EnableSelectButton = this.showNonPaidOnly; | |||||
| if ( this.showNonPaidOnly ){ | |||||
| this.state.filter.filters.push({ | |||||
| field: 'PayOutId', | |||||
| operator: 'isnull', | |||||
| value: '' | |||||
| }); | |||||
| } | |||||
| this.selectedRewards.forEach(v => this.selected.push(v.Id)); | |||||
| this.loadRewardGrid(); | |||||
| } | } | ||||
| public loadInitRewardGrid(): void { | |||||
| public loadRewardGrid(): void { | |||||
| this.loading = true; | this.loading = true; | ||||
| this.gridData = []; | |||||
| this.http.get<RewardByUserModel[]>(this.auth.getUrl('user-reward/')).subscribe( | |||||
| rsp => { | |||||
| this.gridView = {total: 0, data: []}; | |||||
| this.rs.getRewardExList(this.state).subscribe( | |||||
| resp => { | |||||
| this.gridView.total = resp.total; | |||||
| resp.data.forEach( v => this.gridView.data.push(new RewardExModel(v)) ); | |||||
| this.loading = false; | |||||
| }, error => { | |||||
| this.loading = false; | |||||
| }, () => { | |||||
| this.loading = false; | this.loading = false; | ||||
| rsp.forEach(v => { | |||||
| this.gridData.push(new RewardByUserModel(v)); | |||||
| }); | |||||
| this.loadRewards(); | |||||
| } | } | ||||
| ); | ); | ||||
| } | |||||
| private loadRewards(): void { | |||||
| this.gridView = process(this.gridData, this.state); | |||||
| } | } | ||||
| public dataStateChange(state: DataStateChangeEvent): void { | public dataStateChange(state: DataStateChangeEvent): void { | ||||
| this.state = state; | this.state = state; | ||||
| console.log(state); | |||||
| this.loadRewards(); | |||||
| this.loadRewardGrid(); | |||||
| } | } | ||||
| private photoURL(peopleId: any): string { | private photoURL(peopleId: any): string { | ||||
| } | } | ||||
| public onSelectionEmit(): void { | public onSelectionEmit(): void { | ||||
| console.log(this.selected); | |||||
| this.confirmSelection.emit(this.selectedRewards); | |||||
| } | |||||
| public onSelectionChange(e: SelectionEvent): void { | |||||
| this.selectedRewards = this.selectedRewards.filter( v => ! e.deselectedRows.find( deSel => v.Id === deSel.dataItem.Id ) ); | |||||
| e.selectedRows.forEach( v => { | |||||
| if (! this.selectedRewards.find(existing => existing.Id === v.dataItem.Id) ){ | |||||
| this.selectedRewards.push(v.dataItem); | |||||
| } | |||||
| }); | |||||
| return; | |||||
| } | |||||
| public onGoDetail(item: RewardExModel): void{ | |||||
| this.router.navigate(['reward-paid/', item.PayOutId]).then(); | |||||
| } | |||||
| public onGoPayment( item: RewardExModel): void{ | |||||
| this.router.navigate(['reward-paid/']).then(); | |||||
| } | } | ||||
| } | } |
| public action(status): void { | public action(status): void { | ||||
| this.dialogOpened = false; | this.dialogOpened = false; | ||||
| if ( this.navigateTo !== '' ) { | if ( this.navigateTo !== '' ) { | ||||
| this.router.navigate([this.navigateTo]); | |||||
| this.router.navigate([this.navigateTo]).then(); | |||||
| } | } | ||||
| } | } | ||||
| </ng-template> | </ng-template> | ||||
| </kendo-grid-command-column> | </kendo-grid-command-column> | ||||
| <kendo-grid-column field="To" title="Name" width="200"> | |||||
| <kendo-grid-column field="ToId" title="Name" width="200"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | <ng-template kendoGridCellTemplate let-dataItem> | ||||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.To) }"></div> | |||||
| <div class="customer-photo" [ngStyle]="{'background-image' : photoURL(dataItem.ToId) }"></div> | |||||
| <div class="customer-name"> {{ UserName(dataItem) }}</div> | <div class="customer-name"> {{ UserName(dataItem) }}</div> | ||||
| </ng-template> | </ng-template> | ||||
| <ng-template | |||||
| kendoGridEditTemplate let-fg="formGroup" let-column="column" let-dataItem="dataItem"> | |||||
| <ng-template kendoGridEditTemplate let-fg="formGroup" let-column="column" let-dataItem="dataItem"> | |||||
| <kendo-multicolumncombobox | <kendo-multicolumncombobox | ||||
| #selectRevelantPeople | #selectRevelantPeople |
| import {PeopleService} from '../../service/people.service'; | import {PeopleService} from '../../service/people.service'; | ||||
| import {Observable, of} from 'rxjs'; | import {Observable, of} from 'rxjs'; | ||||
| import {map} from 'rxjs/operators'; | import {map} from 'rxjs/operators'; | ||||
| import {RewardService} from '../../service/reward.service'; | |||||
| const createFormGroup = dataItem => new FormGroup({ | const createFormGroup = dataItem => new FormGroup({ | ||||
| Id: new FormControl(dataItem.Id), | Id: new FormControl(dataItem.Id), | ||||
| To: new FormControl(dataItem.To, [Validators.required, Validators.maxLength(128), Validators.minLength(1)]), | |||||
| From: new FormControl(dataItem.From), | |||||
| ToId: new FormControl(dataItem.ToId, [Validators.required, Validators.maxLength(128), Validators.minLength(1)]), | |||||
| FromId: new FormControl(dataItem.FromId), | |||||
| Role: new FormControl({value: dataItem.Role, disabled: true} , [Validators.required, Validators.minLength(2), Validators.maxLength(40)]), | Role: new FormControl({value: dataItem.Role, disabled: true} , [Validators.required, Validators.minLength(2), Validators.maxLength(40)]), | ||||
| Amount: new FormControl(dataItem.Amount, Validators.compose([Validators.required, Validators.min(0), Validators.max(1000000)])), | Amount: new FormControl(dataItem.Amount, Validators.compose([Validators.required, Validators.min(0), Validators.max(1000000)])), | ||||
| Description: new FormControl(dataItem.Description, [Validators.required, Validators.maxLength(128)]), | Description: new FormControl(dataItem.Description, [Validators.required, Validators.maxLength(128)]), | ||||
| this.closeEditor(sender); | this.closeEditor(sender); | ||||
| this.formGroup = createFormGroup({ | this.formGroup = createFormGroup({ | ||||
| Id: 0, | Id: 0, | ||||
| To: '', | |||||
| From: '', | |||||
| ToId: '', | |||||
| FromId: '', | |||||
| Role: 'Unknown', | Role: 'Unknown', | ||||
| Amount: 0, | Amount: 0, | ||||
| Description: '', | Description: '', | ||||
| } | } | ||||
| public saveHandler({ sender, rowIndex, formGroup, isNew }): void { | public saveHandler({ sender, rowIndex, formGroup, isNew }): void { | ||||
| const reward = formGroup.value; | |||||
| reward.From = '0'; // Admin | |||||
| const reward: RewardModel = formGroup.value; | |||||
| reward.FromId = '0'; // Admin | |||||
| // reward.Ts = new Date(); // Now | // reward.Ts = new Date(); // Now | ||||
| reward.LoanId = this.Loan.Id; // Enforce LoanId | reward.LoanId = this.Loan.Id; // Enforce LoanId | ||||
| this.ls.saveReward(reward, isNew).subscribe( | this.ls.saveReward(reward, isNew).subscribe( | ||||
| resp => { | resp => { | ||||
| if ( reward.Id === 0 ) { | if ( reward.Id === 0 ) { | ||||
| const r = this.Loan.addReward(resp.Amount, resp.Description, resp.Id, resp.LoanId, resp.PayOutId, resp.To, resp.From, resp.Ts); | |||||
| const r = this.Loan.addReward( | |||||
| resp.Amount, resp.Description, resp.Id, resp.LoanId, resp.PayOutId, resp.ToId, resp.FromId, resp.Ts); | |||||
| this.pendingReward.unshift(r); | this.pendingReward.unshift(r); | ||||
| }else{ | }else{ | ||||
| const idx = this.pendingReward.findIndex( v => v.Id === reward.Id); | const idx = this.pendingReward.findIndex( v => v.Id === reward.Id); | ||||
| // update | // update | ||||
| this.pendingReward[idx].To = reward.To; | |||||
| this.pendingReward[idx].ToId = reward.ToId; | |||||
| this.pendingReward[idx].Amount = reward.Amount; | this.pendingReward[idx].Amount = reward.Amount; | ||||
| this.pendingReward[idx].Description = reward.Description; | this.pendingReward[idx].Description = reward.Description; | ||||
| this.pendingReward[idx].Ts = reward.Ts; | this.pendingReward[idx].Ts = reward.Ts; | ||||
| // update Loan | // update Loan | ||||
| this.Loan.updateReward(resp.Amount, resp.Description, resp.Id, resp.LoanId, resp.PayOutId, resp.To, resp.From, resp.Ts); | |||||
| this.Loan.updateReward(resp.Amount, resp.Description, resp.Id, resp.LoanId, resp.PayOutId, resp.ToId, resp.FromId, resp.Ts); | |||||
| } | } | ||||
| } | } | ||||
| { text: '--', separator: 'true' }, | { text: '--', separator: 'true' }, | ||||
| { text: 'By Broker', icon: 'table', url: './#list-reward-by-broker' }, | { text: 'By Broker', icon: 'table', url: './#list-reward-by-broker' }, | ||||
| { text: '--', separator: 'true' }, | { text: '--', separator: 'true' }, | ||||
| { text: 'Not Paid', icon: 'attachment' , url: './#reward-unpaid'}, | |||||
| { text: 'Paid', icon: 'attachment' , url: './#reward-paid'}, | |||||
| { text: 'Invoice', icon: 'attachment' , url: './#reward-paid'}, | |||||
| ] | ] | ||||
| }, | }, | ||||
| { | { |
| reward.Id, | reward.Id, | ||||
| reward.LoanId, | reward.LoanId, | ||||
| reward.PayOutId, | reward.PayOutId, | ||||
| reward.To, | |||||
| reward.From, | |||||
| reward.ToId, | |||||
| reward.FromId, | |||||
| reward.Ts); | reward.Ts); | ||||
| }); | }); | ||||
| return; | return; | ||||
| }); | }); | ||||
| } | } | ||||
| public addReward(Amount: number, Description: string, Id: number, | public addReward(Amount: number, Description: string, Id: number, | ||||
| LoanId: string, PayOutId: number, To: string , From: string, Ts: Date): RewardModel { | |||||
| LoanId: string, PayOutId: number, ToId: string , FromId: string, Ts: Date): RewardModel { | |||||
| const r = new RewardModel( | const r = new RewardModel( | ||||
| Amount, | Amount, | ||||
| Description, | Description, | ||||
| Id, | Id, | ||||
| LoanId, | LoanId, | ||||
| PayOutId, | PayOutId, | ||||
| To, | |||||
| From, | |||||
| ToId, | |||||
| FromId, | |||||
| new Date(Ts), | new Date(Ts), | ||||
| this.callBacks() | this.callBacks() | ||||
| ); | ); | ||||
| } | } | ||||
| public updateReward(Amount: number, Description: string, Id: number, | public updateReward(Amount: number, Description: string, Id: number, | ||||
| LoanId: string, PayOutId: number, To: string , From: string, Ts: Date): RewardModel { | |||||
| LoanId: string, PayOutId: number, ToId: string , FromId: string, Ts: Date): RewardModel { | |||||
| const r = new RewardModel( | const r = new RewardModel( | ||||
| Amount, | Amount, | ||||
| Description, | Description, | ||||
| Id, | Id, | ||||
| LoanId, | LoanId, | ||||
| PayOutId, | PayOutId, | ||||
| To, | |||||
| From, | |||||
| ToId, | |||||
| FromId, | |||||
| new Date(Ts), | new Date(Ts), | ||||
| this.callBacks() | this.callBacks() | ||||
| ); | ); | ||||
| this.Reward[idx].Description = Description; | this.Reward[idx].Description = Description; | ||||
| this.Reward[idx].LoanId = r.LoanId; // Ensure Loan Id is correct | this.Reward[idx].LoanId = r.LoanId; // Ensure Loan Id is correct | ||||
| this.Reward[idx].PayOutId = PayOutId; | this.Reward[idx].PayOutId = PayOutId; | ||||
| this.Reward[idx].To = To; | |||||
| this.Reward[idx].From = From; | |||||
| this.Reward[idx].ToId = ToId; | |||||
| this.Reward[idx].FromId = FromId; | |||||
| this.Reward[idx].Ts = new Date(Ts); | this.Reward[idx].Ts = new Date(Ts); | ||||
| return r; | return r; | ||||
| const result: RelevantPeopleModel[] = []; | const result: RelevantPeopleModel[] = []; | ||||
| this.Client.forEach(( c => { | this.Client.forEach(( c => { | ||||
| result.push({Id: c.Id, Display: c.Display, Role: 'Client'} ) ; | |||||
| if ( !result.find( existing => existing.Id === c.Id ) ){ | |||||
| result.push({Id: c.Id, Display: c.Display, Role: 'Client'} ) ; | |||||
| } | |||||
| })); | })); | ||||
| this.Broker.forEach(( c => { | this.Broker.forEach(( c => { | ||||
| result.push({Id: c.Id, Display: c.Display, Role: 'Broker'}); | |||||
| if ( !result.find( existing => existing.Id === c.Id ) ) { | |||||
| result.push({Id: c.Id, Display: c.Display, Role: 'Broker'}); | |||||
| } | |||||
| })); | })); | ||||
| this.OtherRewarder.forEach(( c => { | this.OtherRewarder.forEach(( c => { | ||||
| result.push({Id: c.Id, Display: c.Display, Role: this.getRoleById(c.Id)}); | |||||
| if ( !result.find( existing => existing.Id === c.Id ) ) { | |||||
| result.push({Id: c.Id, Display: c.Display, Role: this.getRoleById(c.Id)}); | |||||
| } | |||||
| })); | })); | ||||
| this.RewardPeople.forEach( c => { | this.RewardPeople.forEach( c => { | ||||
| result.push({Id: c.Id, Display: c.Display, Role: 'none'}); | |||||
| if ( !result.find( existing => existing.Id === c.Id ) ) { | |||||
| result.push({Id: c.Id, Display: c.Display, Role: 'none'}); | |||||
| } | |||||
| }); | }); | ||||
| return [...new Set(result)]; // remove duplicates, if any | |||||
| return result ; // [...new Set(result)]; // remove duplicates, if any | |||||
| } | } | ||||
| public getRoleById(id: string): string { | public getRoleById(id: string): string { | ||||
| let role = ''; | let role = ''; | ||||
| this.PeopleMap.every(v => { | this.PeopleMap.every(v => { |
| import {LoanModel} from './loan.model'; | |||||
| import {UploadMetaModel} from './uploadMetaModel'; | |||||
| export class PayInModel { | export class PayInModel { | ||||
| public Id: number; | public Id: number; |
| export class PayoutAudit{ | |||||
| id: string; | |||||
| //parent | |||||
| payOut: string; | |||||
| //date | |||||
| when : Date; | |||||
| //by who, at least 2 | |||||
| who : string ; | |||||
| //for what? edit? paid? | |||||
| what: string; | |||||
| //ip | |||||
| ip: string; | |||||
| } |
| import {UserExModel} from './userExModel'; | import {UserExModel} from './userExModel'; | ||||
| import {PayoutModel} from './payout.model'; | |||||
| import {RewardExModel} from './reward-ex.model'; | |||||
| export class PayOutExModel{ | export class PayOutExModel{ | ||||
| Id: number; | Id: number; | ||||
| PayDate: Date; | PayDate: Date; | ||||
| PayAmount: number; | PayAmount: number; | ||||
| Status: string; | Status: string; | ||||
| constructor( payload: Partial<PayOutExModel>) { | |||||
| Rewards?: RewardExModel[]; | |||||
| constructor( payload?: Partial<PayOutExModel>) { | |||||
| if (! payload ) { payload = {}; } | |||||
| this.Id = payload.Id || 0; | this.Id = payload.Id || 0; | ||||
| if (payload.Ts){ | if (payload.Ts){ | ||||
| this.Ts = new Date( payload.Ts); | this.Ts = new Date( payload.Ts); | ||||
| }else{ | }else{ | ||||
| this.Ts = new Date('1800-01-01'); | |||||
| this.Ts = new Date(); | |||||
| } | } | ||||
| this.To = new UserExModel(payload.To); | this.To = new UserExModel(payload.To); | ||||
| } | } | ||||
| this.PayAmount = payload.PayAmount || 0; | this.PayAmount = payload.PayAmount || 0; | ||||
| this.Status = payload.Status || ''; | this.Status = payload.Status || ''; | ||||
| this.Rewards = []; | |||||
| if ( payload.Rewards && payload.Rewards.length){ | |||||
| payload.Rewards.forEach( v => this.Rewards.push( new RewardExModel(v) ) ); | |||||
| } | |||||
| } | |||||
| public toPayOutModel(): PayoutModel { | |||||
| const ret = new PayoutModel(); | |||||
| ret.Id = this.Id; | |||||
| ret.Ts = this.Ts; | |||||
| ret.To = this.To.Id; | |||||
| ret.Prepared = this.Prepared.Id; | |||||
| ret.Approved = this.Approved.Id; | |||||
| ret.Paid = this.Paid.Id; | |||||
| ret.PayDate = this.PayDate; | |||||
| ret.PayAmount = this.PayAmount; | |||||
| ret.Status = this.Status; | |||||
| ret.RewardIds = this.Rewards.map( v => v.Id); | |||||
| return ret; | |||||
| } | } | ||||
| } | } |
| import {UserExModel} from './userExModel'; | |||||
| export class PayoutModel { | |||||
| Id: number; | |||||
| Ts: Date; | |||||
| To: string; | |||||
| Prepared: string; | |||||
| Approved: string; | |||||
| Paid: string; | |||||
| PayDate: Date; | |||||
| PayAmount: number; | |||||
| Status: string; | |||||
| RewardIds?: number[]; | |||||
| constructor( payload?: Partial<PayoutModel>){ | |||||
| if (! payload ) { payload = {}; } | |||||
| this.Id = payload.Id || 0; | |||||
| if ( payload.Ts ){ | |||||
| this.Ts = new Date(payload.Ts); | |||||
| }else{ | |||||
| this.Ts = new Date('1900-01-01'); | |||||
| } | |||||
| this.To = payload.To || ''; | |||||
| this.Prepared = payload.Prepared || ''; | |||||
| this.Approved = payload.Approved || ''; | |||||
| this.Paid = payload.Paid || ''; | |||||
| if (payload.PayDate){ | |||||
| this.PayDate = new Date(payload.PayDate); | |||||
| }else{ | |||||
| this.PayDate = new Date('1900-01-01'); | |||||
| } | |||||
| this.PayAmount = payload.PayAmount || 0; | |||||
| this.Status = payload.Status || ''; | |||||
| this.RewardIds = []; | |||||
| if ( Array.isArray(payload) ) { | |||||
| this.RewardIds = payload.RewardIds; | |||||
| } | |||||
| } | |||||
| } |
| public Nick: string; | public Nick: string; | ||||
| public Enabled: boolean; | public Enabled: boolean; | ||||
| constructor(payload: Partial<PeopleModel>){ | |||||
| constructor(payload?: Partial<PeopleModel>){ | |||||
| if (! payload ) { payload = {} ; } | |||||
| this.Id = payload.Id || ''; | this.Id = payload.Id || ''; | ||||
| this.First = payload.First || ''; | this.First = payload.First || ''; | ||||
| this.Last = payload.Last || ''; | this.Last = payload.Last || ''; |
| import {GridDataResult} from '@progress/kendo-angular-grid'; | |||||
| import {RewardExModel} from './reward-ex.model'; | |||||
| export class RewardExListResultModel implements GridDataResult { | |||||
| public data: RewardExModel[]; | |||||
| public total: number; | |||||
| } |
| import {LoanModel} from './loan.model'; | import {LoanModel} from './loan.model'; | ||||
| import {PayOutModel} from './payout.ex.model'; | |||||
| import {PeopleModel} from './people.model'; | |||||
| import {PayOutExModel} from './payout.ex.model'; | |||||
| import {UserExModel} from './userExModel'; | import {UserExModel} from './userExModel'; | ||||
| export class RewardExModel { | export class RewardExModel { | ||||
| public FromId: string; | public FromId: string; | ||||
| public PayOutId: number; | public PayOutId: number; | ||||
| public To?: UserExModel; | |||||
| public Beneficiary?: UserExModel; | |||||
| public Loan?: LoanModel; | public Loan?: LoanModel; | ||||
| public From?: UserExModel; | public From?: UserExModel; | ||||
| public PayOut?: PayOutModel; | |||||
| constructor(payload: Partial<RewardExModel>) { | |||||
| // derived content, for compatible with reward-by-user purpose | |||||
| public ToFirst: string; | |||||
| public ToMiddle: string; | |||||
| public ToLast: string; | |||||
| public ToTitle: string; | |||||
| public ToDisplay: string; | |||||
| public ToNick: string; | |||||
| public FromFirst: string; | |||||
| public FromMiddle: string; | |||||
| public FromLast: string; | |||||
| public FromTitle: string; | |||||
| public FromDisplay: string; | |||||
| public FromNick: string; | |||||
| // Loan related derived property | |||||
| public Item: string; | |||||
| public Status: string; | |||||
| public Settlement: Date; | |||||
| constructor(payload?: Partial<RewardExModel>) { | |||||
| if ( !payload ) { payload = {}; } | |||||
| this.Id = payload.Id || 0; | this.Id = payload.Id || 0; | ||||
| if ( payload.Ts ) { | if ( payload.Ts ) { | ||||
| this.Ts = new Date(payload.Ts); | this.Ts = new Date(payload.Ts); | ||||
| this.FromId = payload.FromId || ''; | this.FromId = payload.FromId || ''; | ||||
| this.PayOutId = payload.PayOutId || 0; | this.PayOutId = payload.PayOutId || 0; | ||||
| if (payload.To) { | |||||
| this.To = new UserExModel(payload.To); | |||||
| // derived content | |||||
| // this.ToFirst = payload.ToFirst || ''; | |||||
| // this.ToMiddle = payload.ToMiddle || ''; | |||||
| // this.ToLast = payload.ToLast || ''; | |||||
| // this.ToTitle = payload.ToTitle || ''; | |||||
| // this.ToDisplay = payload.ToDisplay || ''; | |||||
| // this.ToNick = payload.ToNick || ''; | |||||
| // this.Item = payload.Item || ''; | |||||
| // this.Status = payload.Status || ''; | |||||
| // this.Settlement = new Date(payload.Settlement); | |||||
| if (payload.Beneficiary) { | |||||
| this.Beneficiary = new UserExModel(payload.Beneficiary); | |||||
| this.ToFirst = this.Beneficiary.First || ''; | |||||
| this.ToMiddle = this.Beneficiary.Middle || ''; | |||||
| this.ToLast = this.Beneficiary.Last || ''; | |||||
| this.ToTitle = this.Beneficiary.Title || ''; | |||||
| this.ToDisplay = this.Beneficiary.Display || ''; | |||||
| this.ToNick = this.Beneficiary.Nick || ''; | |||||
| } | } | ||||
| if (payload.Loan) { | if (payload.Loan) { | ||||
| this.Loan = new LoanModel(payload.Loan); | this.Loan = new LoanModel(payload.Loan); | ||||
| this.Item = this.Loan.Item || ''; | |||||
| this.Status = this.Loan.Status || ''; | |||||
| if ( this.Loan.Settlement ){ | |||||
| this.Settlement = new Date(payload.Settlement); | |||||
| }else{ | |||||
| this.Settlement = new Date('1900-01-01'); | |||||
| } | |||||
| } | } | ||||
| if ( payload.From) { | if ( payload.From) { | ||||
| this.From = new UserExModel(payload.From); | this.From = new UserExModel(payload.From); | ||||
| this.FromFirst = this.From.First || ''; | |||||
| this.FromMiddle = this.From.Middle || ''; | |||||
| this.FromLast = this.From.Last || ''; | |||||
| this.FromTitle = this.From.Title || ''; | |||||
| this.FromDisplay = this.From.Display || ''; | |||||
| this.FromNick = this.From.Nick || ''; | |||||
| } | } | ||||
| if ( payload. PayOut ) { | |||||
| this.PayOut = new PayOutModel(payload.PayOut); | |||||
| } | |||||
| } | |||||
| get Paid(): boolean{ | |||||
| return this.PayOutId > 0 ; | |||||
| } | |||||
| public Equal(v: RewardExModel): boolean{ | |||||
| if ( this.Id !== v.Id) { return false; } | |||||
| if ( this.Ts !== v.Ts ) { return false; } | |||||
| if ( this.ToId !== v.ToId) { return false; } | |||||
| if ( this.Amount !== v.Amount ) { return false; } | |||||
| if ( this.Description !== v.Description ) { return false; } | |||||
| if ( this.LoanId !== v.LoanId ) { return false; } | |||||
| if ( this.FromId !== v.FromId ) { return false; } | |||||
| if ( this.PayOutId !== v.PayOutId ) { return false; } | |||||
| return true; | |||||
| } | } | ||||
| } | } |
| public Id: number, | public Id: number, | ||||
| public LoanId: string, | public LoanId: string, | ||||
| public PayOutId: number, | public PayOutId: number, | ||||
| public To: string, | |||||
| public From: string, | |||||
| public ToId: string, | |||||
| public FromId: string, | |||||
| public Ts: Date, | public Ts: Date, | ||||
| private lc: LoanModelCallBacks | private lc: LoanModelCallBacks | ||||
| ){} | ){} | ||||
| public get Role(): string { | public get Role(): string { | ||||
| return this.lc.getUserRole(this.To); | |||||
| return this.lc.getUserRole(this.ToId); | |||||
| } | } | ||||
| public get UserId(): string { | |||||
| return this.To; | |||||
| } | |||||
| public set UserId(v) { | |||||
| this.To = v; | |||||
| } | |||||
| // public get UserId(): string { | |||||
| // return this.ToId; | |||||
| // } | |||||
| // | |||||
| // public set UserId(v) { | |||||
| // this.ToId = v; | |||||
| // } | |||||
| public get UserName(): string { | public get UserName(): string { | ||||
| return this.lc.getUserName(this.To); | |||||
| return this.lc.getUserName(this.ToId); | |||||
| } | } | ||||
| public get photoUrlTo(): string{ | public get photoUrlTo(): string{ | ||||
| return this.lc.getUserPhotoUrl(this.To); | |||||
| return this.lc.getUserPhotoUrl(this.ToId); | |||||
| } | } | ||||
| public get photoUrlFrom(): string{ | public get photoUrlFrom(): string{ | ||||
| return this.lc.getUserPhotoUrl(this.From); | |||||
| return this.lc.getUserPhotoUrl(this.FromId); | |||||
| } | } | ||||
| } | } | ||||
| Role: UserRoles; | Role: UserRoles; | ||||
| Broker?: BrokerModel; | Broker?: BrokerModel; | ||||
| Login: string; | Login: string; | ||||
| constructor(payload: Partial<UserExModel>) { | |||||
| constructor(payload?: Partial<UserExModel>) { | |||||
| super(payload); | super(payload); | ||||
| if ( ! payload ) { payload = {}; } | |||||
| this.Role = payload.Role || 'People' as UserRoles; | this.Role = payload.Role || 'People' as UserRoles; | ||||
| this.Login = payload.Login || ''; | this.Login = payload.Login || ''; | ||||
| this.Broker = new BrokerModel(payload); | this.Broker = new BrokerModel(payload); |
| private refreshFilterByUpload(): void{ | private refreshFilterByUpload(): void{ | ||||
| // make a copy of existing filters | // make a copy of existing filters | ||||
| const newFilter = { logic: 'and', filters: [], ...this.state.Filter.filters}; | |||||
| const newFilter = { logic: 'and', filters: []}; | |||||
| // remove any existing filters about UploadsId | // remove any existing filters about UploadsId | ||||
| newFilter.filters = newFilter.filters.filter(v => { | |||||
| if (!( 'field' in v) && v.operator === 'or') { // could be LoanId or UploadsIds | |||||
| const subFilters = v.filters; | |||||
| return ! subFilters.every( subf => subf.field === 'UploadIds' ); // if sub-filters are all about UploadsIds, we remove it | |||||
| this.state.Filter.filters.forEach(v => { | |||||
| if ('field' in v && 'operator' in v && 'value' in v) { | |||||
| if ( v.field !== 'UploadIds' ){ | |||||
| newFilter.filters.push (v); | |||||
| } | |||||
| }else{ | |||||
| newFilter.filters.push (v); | |||||
| } | } | ||||
| return true; | |||||
| }); | }); | ||||
| // build new filters | // build new filters | ||||
| }); | }); | ||||
| // add new filter | // add new filter | ||||
| newFilter.filters.push( uploadsFilter as CompositeFilterDescriptor ); | |||||
| if (uploadsFilter.filters.length > 0){ | |||||
| newFilter.filters.push( uploadsFilter as CompositeFilterDescriptor ); | |||||
| } | |||||
| this.state.Filter = newFilter as CompositeFilterDescriptor; | this.state.Filter = newFilter as CompositeFilterDescriptor; | ||||
| } | } |
| <div class="col-md-12"> | <div class="col-md-12"> | ||||
| <div class="card"> | <div class="card"> | ||||
| <div class="card-header bg-transparent header-elements-inline"> | <div class="card-header bg-transparent header-elements-inline"> | ||||
| <app-reward-select></app-reward-select> | |||||
| <div class="header-elements"> | <div class="header-elements"> | ||||
| <button> test </button> | |||||
| <kendo-chip | |||||
| [removable]="true" | |||||
| (remove)="onRemoveChip('somelabel', $event)" | |||||
| > | |||||
| <span class="k-avatar-image invoice-chip" [ngStyle]="{'background-image': background}"></span> | |||||
| <span> approved</span> | |||||
| <kendo-chip *ngIf="model.Prepared.Id !== '' " | |||||
| [removable]="model.Approved.Id === ''" | |||||
| (remove)="onCancelPrepared()" > | |||||
| <span class="k-avatar-image invoice-chip" | |||||
| [ngStyle]="{'background-image': photoBackground(model.Prepared.Id)}"></span> | |||||
| <span> prepared </span> by <span> {{model.Prepared.Display}}</span> | |||||
| </kendo-chip> | </kendo-chip> | ||||
| <kendo-chip | |||||
| [removable]="false" | |||||
| (remove)="onRemoveChip('somelabel', $event)" | |||||
| > | |||||
| <span class="k-avatar-image invoice-chip" [ngStyle]="{'background-image': background}"></span> | |||||
| <span> approved</span> | |||||
| <kendo-chip *ngIf="model.Approved.Id !== '' " [removable]="model.Paid.Id === ''" (remove)="onRevoke()" > | |||||
| <span class="k-avatar-image invoice-chip" | |||||
| [ngStyle]="{'background-image': photoBackground(model.Approved.Id)}"></span> | |||||
| <span> approved </span> by <span> {{model.Approved.Display}}</span> | |||||
| </kendo-chip> | </kendo-chip> | ||||
| <kendo-chip *ngIf="model.Paid.Id !== '' " [removable]="model.Paid.Id !== ''" (remove)="onUnPaid()" > | |||||
| <span class="k-avatar-image invoice-chip" | |||||
| [ngStyle]="{'background-image': photoBackground(model.Paid.Id)}"></span> | |||||
| <span> paid </span> by <span> {{model.Paid.Display}}</span> | |||||
| </kendo-chip> | |||||
| <button *ngIf="model.Prepared.Id !== '' && model.Approved.Id === ''" | |||||
| type="button" class="btn btn-primary" (click)="onApprove()"> | |||||
| <b><i class="fa fa-paper-plane-o mr-1"></i></b> Approve | |||||
| </button> | |||||
| <div class="select-beneficiary" *ngIf="model.Prepared.Id === ''"> | |||||
| <app-people-select #selectPeople [placeholder]= "'choose pay to'" | |||||
| [(ngModel)]="model.To" | |||||
| (ngModelChange)="onToChange($event)"> | |||||
| </app-people-select> | |||||
| </div> | |||||
| <button *ngIf="model.Prepared.Id === '' && model.Approved.Id === '' && model.Rewards.length > 1" | |||||
| type="button" class="btn btn-primary" (click)="onPrepared()"> | |||||
| <b><i class="fa fa-paper-plane-o mr-1"></i></b> Finish | |||||
| </button> | |||||
| <div class="make-payment" *ngIf="model.Prepared.Id !== '' && model.Approved.Id !== '' && model.Paid.Id === ''"> | |||||
| <kendo-numerictextbox [(ngModel)]="model.PayAmount"> </kendo-numerictextbox> | |||||
| <kendo-datepicker [(ngModel)]="model.PayDate"> </kendo-datepicker> | |||||
| <button type="button" class="btn btn-primary" (click)="onPaid()"> | |||||
| <b><i class="fa fa-paper-plane-o mr-1"></i></b> Paid | |||||
| </button> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <kendo-pdf-export #pdf paperSize="A4" margin="0.5cm"> | |||||
| <kendo-pdf-export #pdf paperSize="A4" [scale]="0.6" margin="0.2cm"> | |||||
| <div class="card-body"> | <div class="card-body"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="col-sm-6"> | <div class="col-sm-6"> | ||||
| <div class="col-sm-6"> | <div class="col-sm-6"> | ||||
| <div class="mb-4 "> | <div class="mb-4 "> | ||||
| <div class="text-sm-right"> | <div class="text-sm-right"> | ||||
| <h4 class="invoice-color mb-2 mt-md-2">Invoice #BBB1243</h4> | |||||
| <h4 class="invoice-color mb-2 mt-md-2">Invoice #{{model.Id }}</h4> | |||||
| <table class="invoice-to-details"> | <table class="invoice-to-details"> | ||||
| <tr (click)="onEditBeneficiary()"> | |||||
| <td class="left">To</td><td class="middle">:</td><td class="right"><h5 class="my-2"> | |||||
| {{ model.To.Display }}</h5></td> | |||||
| </tr> | |||||
| <tr> | <tr> | ||||
| <td class="left">To</td><td class="middle">:</td><td class="right"><h5 class="my-2">Tibco Turang</h5></td> | |||||
| <td class="left">email</td><td class="middle">:</td><td class="right"> | |||||
| {{ model.To.Login}} </td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td class="left">email</td><td class="middle">:</td><td class="right">abc@hotmail.com</td> | |||||
| <td class="left">Date</td><td class="middle">:</td><td class="right"> | |||||
| <span *ngIf="model.Ts.getFullYear() > 1900"> {{ model.Ts | date: "yyyy-MM-dd" }} </span> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td class="left">Date</td><td class="middle">:</td><td class="right">March 15, 2020</td> | |||||
| <td class="left">Pay Date</td><td class="middle">:</td><td class="right"> | |||||
| <span *ngIf="model.PayDate.getFullYear() > 1900"> {{model.PayDate | date: "yyyy-MM-dd" }} | |||||
| </span></td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td class="left">Pay Date</td><td class="middle">:</td><td class="right">March 15, 2020</td> | |||||
| <td class="left">Paid Amount</td><td class="middle">:</td> | |||||
| <td class="right"> {{model.PayAmount | currency}}</td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <td class="left">Paid To</td><td class="middle">:</td><td class="right">BSB/ACC</td> | |||||
| <td class="left">Status</td><td class="middle">:</td> | |||||
| <td class="right"> <h5 class="status"> {{model.Status | uppercase}} </h5> </td> | |||||
| </tr> | </tr> | ||||
| </table> | </table> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| <div #anchorSelectReward class="anchor"></div> | |||||
| <app-reward-select *ngIf="model.Prepared.Id === ''" | |||||
| [selectedRewards]="rewards" | |||||
| [showNonPaidOnly]="true" | |||||
| (valueChange)="onChangeRewardList($event)"> | |||||
| </app-reward-select> | |||||
| <kendo-popup class="hint" [anchor]="anchorSelectReward" *ngIf="hintSelectRewardsButton" | |||||
| [animate]="false" | |||||
| [margin]="{ horizontal: -20, vertical: -10 }"> | |||||
| <kendo-icon [name]="'cursor'" [size]="'large'" [themeColor]="'warning'"></kendo-icon> | |||||
| </kendo-popup> | |||||
| <div class="table-responsive"> | <div class="table-responsive"> | ||||
| <app-single-payout-rewards-list></app-single-payout-rewards-list> | |||||
| <app-single-payout-rewards-list [items]="rewards"> | |||||
| </app-single-payout-rewards-list> | |||||
| </div> | </div> | ||||
| <div class="card-body"> | <div class="card-body"> | ||||
| <div class="d-md-flex flex-md-wrap"> | <div class="d-md-flex flex-md-wrap"> | ||||
| <tbody> | <tbody> | ||||
| <tr> | <tr> | ||||
| <th class="text-left">Subtotal:</th> | <th class="text-left">Subtotal:</th> | ||||
| <td class="text-right">{{amount | currency}}</td> | |||||
| <td class="text-right">{{subTotal | currency}}</td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <th class="text-left">Tax: <span class="font-weight-normal">(25%)</span></th> | |||||
| <td class="text-right">$27</td> | |||||
| <th class="text-left">Tax: <span class="font-weight-normal">(10%)</span></th> | |||||
| <td class="text-right">{{tax | currency}}</td> | |||||
| </tr> | </tr> | ||||
| <tr> | <tr> | ||||
| <th class="text-left">Total:</th> | <th class="text-left">Total:</th> | ||||
| <td class="text-right text-primary"> | <td class="text-right text-primary"> | ||||
| <h5 class="font-weight-semibold">$1,160</h5> | |||||
| <h5 class="font-weight-semibold">{{Total | currency}}</h5> | |||||
| </td> | </td> | ||||
| </tr> | </tr> | ||||
| </tbody> | </tbody> | ||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </kendo-pdf-export> | </kendo-pdf-export> | ||||
| <div class="text-right mt-3"> <button type="button" class="btn btn-primary" (click)="pdf.saveAs('invoice.pdf')"><b><i class="fa fa-paper-plane-o mr-1"></i></b> Send invoice</button> </div> | |||||
| <div class="card-footer"> <span class="text-muted">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.Duis aute irure dolor in reprehenderit</span> </div> | |||||
| <div class="text-right mt-3"> | |||||
| <button type="button" class="btn btn-primary" (click)="pdf.saveAs('invoice.pdf')"> | |||||
| <b><i class="fa fa-paper-plane-o mr-1"></i></b> Download invoice</button> | |||||
| <button type="button" class="btn btn-primary" (click)="onGotoRewardList()"> | |||||
| <b><i class="fa fa-paper-plane-o mr-1"></i></b>Back to reward list</button> | |||||
| </div> | |||||
| <div class="card-footer"> | |||||
| <span class="text-muted"> | |||||
| While some lender can only provide residential home loans, At SuperCredit we have the experience and knoweldge in Residential, Commerical, Business & Development Finance. We will not only provide a lending solution for our customer but guide you through every single steps of the process. | |||||
| </span> | |||||
| </div> | |||||
| </div> | </div> | ||||
| </div> | </div> | ||||
| </div> | </div> |
| div.InvoiceBody { | div.InvoiceBody { | ||||
| margin: 0; | margin: 0; | ||||
| font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | font-family: Roboto, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; | ||||
| background-color: darkgrey; | background-color: darkgrey; | ||||
| padding-top:20px; | padding-top:20px; | ||||
| padding-bottom:20px; | padding-bottom:20px; | ||||
| height:100%; | |||||
| min-height:100%; | |||||
| .container{ | .container{ | ||||
| padding:0; | padding:0; | ||||
| kendo-chip { | kendo-chip { | ||||
| margin-left: 10px; | margin-left: 10px; | ||||
| } | } | ||||
| button { | |||||
| color: #fff; | |||||
| background-color: #ca974d; | |||||
| border-color: white; | |||||
| padding: 3px 11px 3px 3px; | |||||
| border-radius: 20px; | |||||
| margin-left: 10px; | |||||
| } | |||||
| div.select-beneficiary{ | |||||
| width: 200px; | |||||
| display: inline-block; | |||||
| margin: 1px 1px 1px 10px; | |||||
| border-left: 10px solid orange; | |||||
| } | |||||
| div.make-payment{ | |||||
| display: inline-block; | |||||
| vertical-align: bottom; | |||||
| margin-left:20px; | |||||
| button { | |||||
| margin-left: 15px; | |||||
| } | |||||
| } | |||||
| div.anchor{ | |||||
| float: right; | |||||
| background: yellow; | |||||
| height: 10px; | |||||
| right: 20px; | |||||
| } | |||||
| .hint { | |||||
| animation: blink normal 0.5s infinite; | |||||
| } | |||||
| @keyframes blink { 50%{opacity:0} } | |||||
| span.k-avatar-image.invoice-chip{ | span.k-avatar-image.invoice-chip{ | ||||
| display:inline-block; | display:inline-block; | ||||
| width:20px; | width:20px; | ||||
| @media (min-width: 768px) { | @media (min-width: 768px) { | ||||
| .wmin-md-400 { | .wmin-md-400 { | ||||
| min-width: 400px !important | |||||
| max-width: 400px !important | |||||
| } | } | ||||
| } | } | ||||
| import { Component, OnInit } from '@angular/core'; | |||||
| import {AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core'; | |||||
| import {ChipRemoveEvent} from '@progress/kendo-angular-buttons'; | import {ChipRemoveEvent} from '@progress/kendo-angular-buttons'; | ||||
| import {RewardService} from '../service/reward.service'; | |||||
| import {RewardExModel} from '../models/reward-ex.model'; | |||||
| import {PayOutExModel} from '../models/payout.ex.model'; | |||||
| import {PayOutService} from '../service/payout.service'; | |||||
| import {PeopleSelectComponent} from '../people-select/people-select.component'; | |||||
| import {AppConfig} from '../app.config'; | |||||
| import {UserExModel} from '../models/userExModel'; | |||||
| import {SessionService} from '../service/session.service'; | |||||
| import {Router} from '@angular/router'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-pay-out-details', | selector: 'app-pay-out-details', | ||||
| templateUrl: './pay-out-details.component.html', | templateUrl: './pay-out-details.component.html', | ||||
| styleUrls: ['./pay-out-details.component.scss'] | styleUrls: ['./pay-out-details.component.scss'] | ||||
| }) | }) | ||||
| export class PayOutDetailsComponent implements OnInit { | |||||
| sales = []; | |||||
| export class PayOutDetailsComponent implements OnInit , AfterViewInit{ | |||||
| @Input() Id = 0; | |||||
| @Input() public model: PayOutExModel = new PayOutExModel(); | |||||
| amount = 3218; | |||||
| background = 'url(\'https://svr2021.lawipac.com:8080/api/v1/avatar/0\')'; | |||||
| constructor() { } | |||||
| @ViewChild('selectPeople', {static: false}) sp: PeopleSelectComponent; | |||||
| subTotal = 0; | |||||
| tax = 0; | |||||
| Total = 0; | |||||
| hintSelectRewardsButton = false; | |||||
| hinted = false; | |||||
| rewards: RewardExModel[] = []; | |||||
| constructor(private rs: RewardService, private payOutService: PayOutService, | |||||
| private cfg: AppConfig, private ss: SessionService, private router: Router) { } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| setInterval(() => { | |||||
| this.amount += 1; | |||||
| }, 1000); | |||||
| if (this.Id > 0){ | |||||
| this.payOutService.getPayOutEx(this.Id).subscribe( | |||||
| resp => { | |||||
| this.model = new PayOutExModel(resp); | |||||
| this.rewards = this.model.Rewards; | |||||
| this.updateTotal(this.model.Rewards); | |||||
| }); | |||||
| } | |||||
| } | |||||
| ngAfterViewInit(): void { | |||||
| if ( this.Id === 0 ) { | |||||
| this.sp.showDropDown(); | |||||
| } | |||||
| } | |||||
| public photoBackground(id: string): string { | |||||
| return 'url(' + this.cfg.getUrl('avatar/' + id) + ')'; | |||||
| } | |||||
| public onChangeRewardList( list: RewardExModel[]): void { | |||||
| this.rewards = list; | |||||
| this.model.Rewards = this.rewards; | |||||
| this.payOutService.savePayOut(this.model.toPayOutModel()).subscribe( resp => { | |||||
| this.model = new PayOutExModel(resp); | |||||
| }); | |||||
| this.updateTotal(list); | |||||
| } | |||||
| private updateTotal(list: RewardExModel[]): void { | |||||
| this.Total = 0; | |||||
| list.forEach( v => { | |||||
| this.Total += v.Amount; | |||||
| }); | |||||
| this.subTotal = this.Total / 1.1; | |||||
| this.tax = this.Total - this.subTotal; | |||||
| } | |||||
| public onEditBeneficiary(): void{ | |||||
| this.sp.showDropDown(); | |||||
| } | |||||
| public onToChange(e: any): void { | |||||
| if ( this.model.Rewards.length === 0 && this.hinted === false ){ | |||||
| this.hintSelectRewardsButton = true; | |||||
| this.hinted = true; | |||||
| setTimeout( () => { | |||||
| this.hintSelectRewardsButton = false; | |||||
| }, 2000); | |||||
| } | |||||
| } | |||||
| public onPrepared(): void { | |||||
| this.model.Prepared.Id = this.ss.CurrentUser.Id; | |||||
| this.payOutService.setPayOutPrepared(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Prepared = new UserExModel(resp.Prepared); | |||||
| this.model.Status = resp.Status; | |||||
| } | |||||
| ); | |||||
| } | |||||
| public onCancelPrepared(): void { | |||||
| this.model.Prepared.Id = ''; | |||||
| this.payOutService.setPayOutUnPrepared(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Prepared = new UserExModel(resp.Prepared); | |||||
| this.model.Status = resp.Status; | |||||
| } | |||||
| ); | |||||
| } | |||||
| public onApprove(): void{ | |||||
| this.model.Approved.Id = this.ss.CurrentUser.Id; | |||||
| this.payOutService.setPayOutApproved(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Approved = new UserExModel(resp.Approved); | |||||
| this.model.Status = resp.Status; | |||||
| // prepare payment | |||||
| if ( this.model.PayDate.getFullYear() <= 1900 ){ | |||||
| this.model.PayDate = new Date(); | |||||
| } | |||||
| if (this.model.PayAmount === 0 && this.Total !== 0){ | |||||
| this.model.PayAmount = this.subTotal; | |||||
| } | |||||
| } | |||||
| ); | |||||
| } | |||||
| public onRevoke(): void { | |||||
| this.payOutService.setPayOutUnapproved(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Approved = new UserExModel(resp.Approved); | |||||
| this.model.Status = resp.Status; | |||||
| this.model.Paid.Id = ''; | |||||
| this.model.PayDate = new Date('1900-01-01'); | |||||
| this.model.PayAmount = 0; | |||||
| } | |||||
| ); | |||||
| } | |||||
| public onPaid(): void { | |||||
| this.model.Paid.Id = this.ss.CurrentUser.Id; | |||||
| this.payOutService.setPayOutPaid(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Paid = new UserExModel(resp.Paid); | |||||
| this.model.Status = resp.Status; | |||||
| this.model.PayDate = new Date(resp.PayDate); | |||||
| this.model.PayAmount = resp.PayAmount; | |||||
| } | |||||
| ); | |||||
| } | } | ||||
| range(start: number, end: number): number[] { | |||||
| if (start === end) { return [start]; } | |||||
| return [start, ...this.range(start + 1, end)]; | |||||
| public onUnPaid(): void{ | |||||
| this.payOutService.setPayOutUnpaid(this.model.toPayOutModel()).subscribe( | |||||
| resp => { | |||||
| this.model.Paid = new UserExModel(resp.Paid); | |||||
| this.model.Status = resp.Status; | |||||
| this.model.PayDate = new Date(resp.PayDate); | |||||
| this.model.PayAmount = resp.PayAmount; | |||||
| } | |||||
| ); | |||||
| } | } | ||||
| onRemoveChip(s: string, e: ChipRemoveEvent): void { | |||||
| console.log(s, e); | |||||
| public onGotoRewardList(): void{ | |||||
| this.router.navigate(['/list-all-rewards']).then(); | |||||
| } | } | ||||
| } | } | ||||
| #list | #list | ||||
| [data]="searchResult" | [data]="searchResult" | ||||
| [textField]="'Display'" | [textField]="'Display'" | ||||
| [valueField]="getEffectiveField()" | |||||
| [valueField]="'Id'" | |||||
| [valuePrimitive]="true" | [valuePrimitive]="true" | ||||
| [listHeight]="300" | [listHeight]="300" | ||||
| placeholder="Type here to search" | |||||
| [placeholder]="placeholder" | |||||
| [suggest]="true" | [suggest]="true" | ||||
| [filterable]="true" | [filterable]="true" | ||||
| [clearButton]="true" | [clearButton]="true" | ||||
| [allowCustom]="false" | [allowCustom]="false" | ||||
| [virtual]="{itemHeight: 36}" | |||||
| [formControl]="formControl" | [formControl]="formControl" | ||||
| (filterChange)="filterChange($event)" | (filterChange)="filterChange($event)" | ||||
| (valueChange)="valueChange($event)" | |||||
| (valueChange)="onSelectionChange($event)" | |||||
| > | > | ||||
| <kendo-combobox-column | <kendo-combobox-column | ||||
| [field]="'Display'" | [field]="'Display'" | ||||
| [title]="'Contact Name'" | [title]="'Contact Name'" | ||||
| [width]="width" | |||||
| > | > | ||||
| <ng-template | <ng-template | ||||
| kendoMultiColumnComboBoxColumnCellTemplate | kendoMultiColumnComboBoxColumnCellTemplate |
| import {Component, forwardRef, Input, OnInit, ViewChild} from '@angular/core'; | |||||
| import {Component, EventEmitter, forwardRef, Input, OnInit, Output, ViewChild} from '@angular/core'; | |||||
| import {AuthService} from '../service/auth.service'; | import {AuthService} from '../service/auth.service'; | ||||
| import { debounce } from 'ts-debounce'; | |||||
| import {PeopleModel} from '../models/people.model'; | |||||
| import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms'; | import {ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR} from '@angular/forms'; | ||||
| import {MultiColumnComboBoxComponent} from '@progress/kendo-angular-dropdowns'; | import {MultiColumnComboBoxComponent} from '@progress/kendo-angular-dropdowns'; | ||||
| import {Observable} from 'rxjs'; | |||||
| import {PeopleService} from '../service/people.service'; | import {PeopleService} from '../service/people.service'; | ||||
| import {UserExModel} from '../models/userExModel'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-people-select', | selector: 'app-people-select', | ||||
| export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | export class PeopleSelectComponent implements OnInit, ControlValueAccessor { | ||||
| @Input() disabled = false; | @Input() disabled = false; | ||||
| @Input() translateId: true; // always tralsnate user Id, because name is not unique | |||||
| @Input() width: number; | |||||
| @Input() initSearch: PeopleModel[]; | |||||
| @Input() placeholder: string; | |||||
| @Input() searchWithin: UserExModel[] = []; | |||||
| @Input() formControl: FormControl = new FormControl(); // this is a dummy place holder | @Input() formControl: FormControl = new FormControl(); // this is a dummy place holder | ||||
| @Output() valueChange: EventEmitter<UserExModel> = new EventEmitter<UserExModel>(); | |||||
| @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; | @ViewChild('list', {static: true}) public text: MultiColumnComboBoxComponent; | ||||
| public searchResult: PeopleModel[] = []; | |||||
| public searchResult: UserExModel[] = []; | |||||
| public value = ''; // selecting the default and only empty contact element // TODO: remove ngModel | public value = ''; // selecting the default and only empty contact element // TODO: remove ngModel | ||||
| public total = 0; | public total = 0; | ||||
| private debounceFilter: any ; | |||||
| // Function to call when the rating changes. | // Function to call when the rating changes. | ||||
| private onChange = ( nameOrId: string) => {}; | |||||
| private onChange = ( nameOrId: UserExModel) => {}; | |||||
| // Function to call when the input is touched (when a star is clicked). | // Function to call when the input is touched (when a star is clicked). | ||||
| private onTouched = () => {}; | private onTouched = () => {}; | ||||
| constructor(private auth: AuthService, private ps: PeopleService) { } | constructor(private auth: AuthService, private ps: PeopleService) { } | ||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.prepareSearchPeople(); | |||||
| this.initSearchResult(); | |||||
| } | |||||
| private initSearchResult(): void { | |||||
| this.initSearch.forEach( v => { | |||||
| this.searchResult.push(v); | |||||
| }); | |||||
| this.total = this.initSearch.length; | |||||
| } | |||||
| private prepareSearchPeople(): void{ | |||||
| this.debounceFilter = debounce( (filter: string): void => { | |||||
| this.ps.getPeopleList(filter).subscribe( | |||||
| resp => { | |||||
| this.text.loading = false; | |||||
| this.searchResult = resp.List; | |||||
| this.total = resp.Count; | |||||
| }, | |||||
| error => { this.text.loading = false; }, | |||||
| () => { this.text.loading = false; } | |||||
| ); | |||||
| }, 500) ; | |||||
| this.loadFilteredPeopleList(''); // load every one | |||||
| } | } | ||||
| getEffectiveField(): string { | |||||
| return this.translateId ? 'Id' : 'Display'; | |||||
| private loadFilteredPeopleList( filter: string): void { | |||||
| this.text.loading = true; | |||||
| this.ps.getUserExList(filter).subscribe( | |||||
| resp => { | |||||
| this.text.loading = false; | |||||
| this.searchWithin = resp.List; | |||||
| this.total = resp.Count; | |||||
| this.searchResult = this.searchWithin; | |||||
| }, | |||||
| error => { this.text.loading = false; }, | |||||
| () => { this.text.loading = false; } | |||||
| ); | |||||
| } | } | ||||
| filterChange(filter: string): void { | filterChange(filter: string): void { | ||||
| if ( filter.length > 0 ) { | |||||
| this.text.loading = true; | |||||
| this.debounceFilter(filter); // conduct search even if filter is empty | |||||
| } | |||||
| this.searchResult = []; | |||||
| this.searchWithin.forEach( v => { | |||||
| if ( filter === '' ){ | |||||
| this.searchResult.push(v); | |||||
| } else if ( v.Id === filter) { | |||||
| this.searchResult.push (v); | |||||
| } else if ( v.Display.includes( filter ) ){ | |||||
| this.searchResult.push(v); | |||||
| } | |||||
| }); | |||||
| } | } | ||||
| public getContactImageUrl(contactId: string): string { | public getContactImageUrl(contactId: string): string { | ||||
| } | } | ||||
| // ComboBox emit event on value change | // ComboBox emit event on value change | ||||
| public valueChange(str: string): void { | |||||
| return; | |||||
| console.log('value change', str); | |||||
| this.onChange(this.value); | |||||
| } | |||||
| // public selectionChange(value: PeopleModel): void { | |||||
| // this.onTouched(); | |||||
| // console.log('selectionChange', value); | |||||
| // this.value = this.translateId ? value.Id : value.FullName; | |||||
| // this.onChange(this.value); | |||||
| // } | |||||
| // public open(): void { | |||||
| // this.onTouched(); | |||||
| // // console.log('open', this.text); | |||||
| // } | |||||
| // | |||||
| // public close(): void { | |||||
| // this.onTouched(); | |||||
| // // console.log('close', this.text); | |||||
| // } | |||||
| // | |||||
| // public focus(): void { | |||||
| // this.onTouched(); | |||||
| // // console.log('focus', this.text); | |||||
| // } | |||||
| // | |||||
| // public blur(): void { | |||||
| // // console.log('blur', this.text); | |||||
| // } | |||||
| // Allows Angular to update the model (name or ID). | |||||
| // Update the model and changes needed for the view here. | |||||
| writeValue(nameOrId: string): void { | |||||
| if ( nameOrId === undefined ){ | |||||
| console.log('who called me for write', this); | |||||
| return; | |||||
| } | |||||
| const changed = nameOrId !== this.value; | |||||
| if (this.needSearch(nameOrId) ){ | |||||
| this.text.loading = true; | |||||
| console.log('searching ... ', nameOrId, this.translateId ? 'by id' : 'by name'); | |||||
| this.searchUser(nameOrId, this.translateId).subscribe( | |||||
| ppl => { | |||||
| const person = new PeopleModel(ppl); | |||||
| console.log('got search result ', person); | |||||
| this.searchResult.push(person); // make sure it's available for selection, thus proper display | |||||
| this.value = this.translateId ? person.Id : person.FullName; | |||||
| console.log('before update', this.text.value); | |||||
| this.text.value = this.value; | |||||
| console.log('after update', this.text.value); | |||||
| }, error => { console.error(error); this.text.loading = false; }, | |||||
| () => {this.text.loading = false; } | |||||
| ); | |||||
| if ( changed ) { | |||||
| this.onChange(nameOrId); | |||||
| } | |||||
| } | |||||
| } | |||||
| needSearch(incoming: string ): boolean { | |||||
| if ( incoming === undefined || incoming === '' || incoming === this.value ) { | |||||
| return false; | |||||
| public onSelectionChange(str: string): void { | |||||
| const p = this.searchWithin.find( v => v.Id === str); | |||||
| if ( p ){ | |||||
| this.onChange(p); | |||||
| } | } | ||||
| const idx = this.searchResult.findIndex( person => { | |||||
| if ( this.translateId) { | |||||
| return person.Id === incoming; | |||||
| }else{ | |||||
| return person.FullName.includes(incoming); | |||||
| } | |||||
| }); | |||||
| return idx === -1; // not found need search | |||||
| } | } | ||||
| // Search a user either based on partial name or a complete ID | |||||
| searchUser(nameOrId: string, translateId: boolean): Observable<PeopleModel>{ | |||||
| if ( translateId ) { | |||||
| return this.ps.getPeopleById(nameOrId); | |||||
| // return this.searchPersonById( nameOrId) ; | |||||
| writeValue(inV: UserExModel): void { | |||||
| console.log( ' value in', inV); | |||||
| if (inV){ | |||||
| this.value = inV.Id; | |||||
| }else{ | }else{ | ||||
| // return this.ps.searchById(nameOrId); | |||||
| // return this.searchPersonByName(nameOrId) ; | |||||
| this.value = null; | |||||
| } | } | ||||
| } | } | ||||
| // searchPersonByName(name: string): Observable<PeopleModel>{ | |||||
| // return new Observable ( observer => { | |||||
| // const dummy: PeopleModel = new PeopleModel( | |||||
| // 'dummy-id', | |||||
| // 'FSearch', | |||||
| // 'LResult', | |||||
| // '', | |||||
| // 'Mr.', | |||||
| // 'Display Name', | |||||
| // 'Nick Name' | |||||
| // ); | |||||
| // setTimeout(() => { | |||||
| // observer.next(dummy); | |||||
| // observer.complete(); | |||||
| // }, 1000); | |||||
| // }); | |||||
| // } | |||||
| // | |||||
| // searchPersonById( id: string): Observable<PeopleModel> { | |||||
| // return new Observable ( observer => { | |||||
| // const dummy: PeopleModel = new PeopleModel( | |||||
| // id, | |||||
| // 'FSearch', | |||||
| // 'LResult', | |||||
| // '', | |||||
| // 'Mr.', | |||||
| // 'P:' + id, | |||||
| // 'Nick Name' | |||||
| // ); | |||||
| // setTimeout(() => { | |||||
| // observer.next(dummy); | |||||
| // observer.complete(); | |||||
| // }, 1000); | |||||
| // }); | |||||
| // } | |||||
| // Allows Angular to register a function to call when the model (rating) changes. | // Allows Angular to register a function to call when the model (rating) changes. | ||||
| // Save the function as a property to call later here. | // Save the function as a property to call later here. | ||||
| registerOnChange(fn: (nameOrId: string) => void): void { | |||||
| registerOnChange(fn: (nameOrId: UserExModel) => void): void { | |||||
| this.onChange = fn; | this.onChange = fn; | ||||
| } | } | ||||
| // Allows Angular to register a function to call when the input has been touched. | // Allows Angular to register a function to call when the input has been touched. | ||||
| this.disabled = isDisabled; | this.disabled = isDisabled; | ||||
| } | } | ||||
| public showDropDown(): void{ | |||||
| this.text.toggle(true); | |||||
| } | |||||
| } | } |
| <div class="box"> | <div class="box"> | ||||
| <app-pay-out-details></app-pay-out-details> | |||||
| <app-pay-out-details [Id]="Id"></app-pay-out-details> | |||||
| </div> | </div> | ||||
| import { Component, OnInit } from '@angular/core'; | import { Component, OnInit } from '@angular/core'; | ||||
| import {ActivatedRoute, Router} from '@angular/router'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-reward-paid', | selector: 'app-reward-paid', | ||||
| styleUrls: ['./reward-paid.component.scss'] | styleUrls: ['./reward-paid.component.scss'] | ||||
| }) | }) | ||||
| export class RewardPaidComponent implements OnInit { | export class RewardPaidComponent implements OnInit { | ||||
| constructor() { } | |||||
| Id = 0; | |||||
| constructor(private actRoute: ActivatedRoute) { } | |||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| this.Id = this.actRoute.snapshot.params.id; | |||||
| } | } | ||||
| } | } |
| (click)="onToggle()" | (click)="onToggle()" | ||||
| ></button> | ></button> | ||||
| <div class='popup-content'> | <div class='popup-content'> | ||||
| <app-list-all-rewards></app-list-all-rewards> | |||||
| <app-list-all-rewards (confirmSelection)="onConfirmSelection($event)" | |||||
| [selectedRewards]="selectedRewards" | |||||
| [showNonPaidOnly]="showNonPaidOnly" | |||||
| > | |||||
| </app-list-all-rewards> | |||||
| </div> | </div> | ||||
| </kendo-popup> | </kendo-popup> |
| import {ListAllLoansComponent} from '../list-all-loans/list-all-loans.component'; | import {ListAllLoansComponent} from '../list-all-loans/list-all-loans.component'; | ||||
| import {LoanModel} from '../models/loan.model'; | import {LoanModel} from '../models/loan.model'; | ||||
| import {RewardModel} from '../models/reward.model'; | import {RewardModel} from '../models/reward.model'; | ||||
| import {RewardExModel} from '../models/reward-ex.model'; | |||||
| @Component({ | @Component({ | ||||
| selector: 'app-reward-select', | selector: 'app-reward-select', | ||||
| // @ViewChild('list', {static: false} ) list: list-all; | // @ViewChild('list', {static: false} ) list: list-all; | ||||
| @Input() Max = 1; // we do not support multiple loan selection at the moment | @Input() Max = 1; // we do not support multiple loan selection at the moment | ||||
| @Input() readOnly = false; | @Input() readOnly = false; | ||||
| @Output() valueChange: EventEmitter<RewardModel[]> = new EventEmitter<RewardModel[]>(); | |||||
| public Rewards: RewardModel[]; | |||||
| @Input() showNonPaidOnly = false; | |||||
| @Output() valueChange: EventEmitter<RewardExModel[]> = new EventEmitter<RewardExModel[]>(); | |||||
| @Input() public selectedRewards: RewardExModel[] = []; | |||||
| // popup | // popup | ||||
| public showPopup = false; | public showPopup = false; | ||||
| public onToggle(): void { | public onToggle(): void { | ||||
| this.showPopup = !this.showPopup; | this.showPopup = !this.showPopup; | ||||
| } | } | ||||
| public onConfirmSelection(sel: RewardExModel[]): void { | |||||
| if (this.isDiff(this.selectedRewards, sel)) { | |||||
| this.valueChange.emit (sel); | |||||
| this.selectedRewards = sel; | |||||
| console.log('reward-select', this.selectedRewards); | |||||
| } | |||||
| this.showPopup = !this.showPopup; | |||||
| } | |||||
| private isDiff(a: RewardExModel[], b: RewardExModel[]): boolean { | |||||
| if ( !a || !b ) { return a !== b; } | |||||
| if ( a.length !== b.length) { return true; } | |||||
| for ( let i = 0; i < a.length; i++ ){ | |||||
| if ( ! a[i].Equal(b[i]) ){ | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| } | } |
| import {Observable} from 'rxjs'; | import {Observable} from 'rxjs'; | ||||
| import {PayOutExModel} from '../models/payout.ex.model'; | import {PayOutExModel} from '../models/payout.ex.model'; | ||||
| import {CompositeFilterDescriptor} from '@progress/kendo-data-query'; | import {CompositeFilterDescriptor} from '@progress/kendo-data-query'; | ||||
| import {PayoutModel} from '../models/payout.model'; | |||||
| @Injectable({providedIn: 'root'}) | @Injectable({providedIn: 'root'}) | ||||
| export class PayOutService { | export class PayOutService { | ||||
| constructor(private http: HttpClient, private auth: AuthService ){ } | constructor(private http: HttpClient, private auth: AuthService ){ } | ||||
| public getPayOutEx(id: string): Observable<PayOutExModel> { | |||||
| public getPayOutEx(id: number): Observable<PayOutExModel> { | |||||
| return this.http.get<PayOutExModel>(this.auth.getUrl('payout-ex/' + id)); | return this.http.get<PayOutExModel>(this.auth.getUrl('payout-ex/' + id)); | ||||
| } | } | ||||
| public getPayOutList(filter: CompositeFilterDescriptor): Observable<PayOutExModel[]> { | public getPayOutList(filter: CompositeFilterDescriptor): Observable<PayOutExModel[]> { | ||||
| return this.http.post<PayOutExModel[]>(this.auth.getUrl('payout-ex-list/'), filter); | return this.http.post<PayOutExModel[]>(this.auth.getUrl('payout-ex-list/'), filter); | ||||
| } | } | ||||
| public savePayOut(po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout/'), po); | |||||
| } | |||||
| public setPayOutPrepared(po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-prepared/'), po); | |||||
| } | |||||
| public setPayOutUnPrepared( po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-unprepared/'), po); | |||||
| } | |||||
| public setPayOutApproved(po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-approved/' ), po); | |||||
| } | |||||
| public setPayOutUnapproved(po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-unapproved/'), po); | |||||
| } | |||||
| public setPayOutPaid( po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-paid/' ), po); | |||||
| } | |||||
| public setPayOutUnpaid(po: PayoutModel): Observable<PayOutExModel>{ | |||||
| return this.http.post<PayOutExModel>(this.auth.getUrl('payout-unpaid/'), po); | |||||
| } | |||||
| } | } |
| import {LoanModel} from '../models/loan.model'; | import {LoanModel} from '../models/loan.model'; | ||||
| import {ChangePassword} from '../models/change-password.model'; | import {ChangePassword} from '../models/change-password.model'; | ||||
| import {UserExtraModel} from '../models/user-extra.model'; | import {UserExtraModel} from '../models/user-extra.model'; | ||||
| import {UserExModel} from '../models/userExModel'; | |||||
| @Injectable({providedIn: 'root'}) | @Injectable({providedIn: 'root'}) | ||||
| export class PeopleService { | export class PeopleService { | ||||
| return this.http.get<{Count: number, List: PeopleModel[]}>(this.auth.getUrl( 'people-list/'), { params}); | return this.http.get<{Count: number, List: PeopleModel[]}>(this.auth.getUrl( 'people-list/'), { params}); | ||||
| } | } | ||||
| public getUserExList(filter: string): Observable<{Count: number, List: UserExModel[]}> { | |||||
| const params = new HttpParams().set('filter', filter); | |||||
| return this.http.get<{Count: number, List: UserExModel[]}>(this.auth.getUrl( 'user-ex-list/'), { params}); | |||||
| } | |||||
| public getBrokerList(filter: string): Observable<{Count: number, List: BrokerModel[]}> { | public getBrokerList(filter: string): Observable<{Count: number, List: BrokerModel[]}> { | ||||
| const params = new HttpParams().set('filter', filter); | const params = new HttpParams().set('filter', filter); | ||||
| return this.http.get<{Count: number, List: BrokerModel[]}>(this.auth.getUrl( 'broker-list/'), { params}); | return this.http.get<{Count: number, List: BrokerModel[]}>(this.auth.getUrl( 'broker-list/'), { params}); |
| import {Injectable} from '@angular/core'; | |||||
| import {RewardExModel} from '../models/reward-ex.model'; | |||||
| import {Observable} from 'rxjs'; | |||||
| import {HttpClient} from '@angular/common/http'; | |||||
| import {AppConfig} from '../app.config'; | |||||
| import {DataStateChangeEvent} from '@progress/kendo-angular-grid'; | |||||
| import {RewardExListResultModel} from '../models/reward-ex-list-result.model'; | |||||
| import {State} from '@progress/kendo-data-query'; | |||||
| @Injectable({providedIn: 'root'}) | |||||
| export class RewardService { | |||||
| constructor(private http: HttpClient, private cfg: AppConfig) { | |||||
| } | |||||
| public getRewardExListByPayoutId(payOutId: number): Observable<RewardExListResultModel>{ | |||||
| const state = { | |||||
| skip: 0, take: 0, filter: { | |||||
| logic: 'and', | |||||
| filters: [ | |||||
| {field: 'PayOutId', operator: 'eq', value: payOutId} | |||||
| ] | |||||
| } | |||||
| }; | |||||
| return this.getRewardExList(state as State); | |||||
| } | |||||
| public getUserReward(userid?: string): Observable<RewardExModel[]>{ | |||||
| if (! userid ) { userid = ''; } | |||||
| return this.http.get<RewardExModel[]>(this.cfg.getUrl('user-reward/' + userid)); | |||||
| } | |||||
| public getRewardExList(state: State): Observable<RewardExListResultModel> { | |||||
| return this.http.post<RewardExListResultModel>(this.cfg.getUrl('reward-ex-list/'), state); | |||||
| } | |||||
| } |
| <kendo-grid [scrollable]="false"> | |||||
| <kendo-grid [resizable]="true" | |||||
| [scrollable]="'none'" | |||||
| [data]="items"> | |||||
| <kendo-grid-column field="ToDisplay" title="Beneficiary" width="100"> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Description"> | |||||
| <ng-template kendoGridCellTemplate let-dataItem> | |||||
| <div class="invoice-item-description"> | |||||
| <span class="label"> For: </span> <span class="beneficiary"> {{dataItem.Description }} </span> | |||||
| <p class="description" *ngIf="dataItem.LoanId !== '' "> | |||||
| <span class="label"> Regarding Loan: </span> | |||||
| <span class="regarding"> {{dataItem.Item}}, </span> | |||||
| </p> | |||||
| <span class="label"> Issued on : </span> | |||||
| <span class="issued-on-date">{{dataItem.Ts | date:"yyyy-MMMM-dd" }} </span> | |||||
| <span *ngIf="dataItem.FromId !== '0' && dataItem.FromId !== '' " class="money-giver"> | |||||
| From: {{dataItem.From.Display}} | |||||
| </span> | |||||
| <sub > * SFM Reference: {{ dataItem.Id}} *</sub> | |||||
| </div> | |||||
| </ng-template> | |||||
| </kendo-grid-column> | |||||
| <kendo-grid-column field="Amount" format="{0:c}" width="200"></kendo-grid-column> | |||||
| </kendo-grid> | </kendo-grid> | ||||
| div.invoice-item-description{ | |||||
| width: 100%; | |||||
| p.description{ | |||||
| margin-bottom: 1px; | |||||
| } | |||||
| span.label { | |||||
| font-family: "Courier New"; | |||||
| color: #ab2828 | |||||
| } | |||||
| span.beneficiary{ | |||||
| font-weight: bold; | |||||
| color: black; | |||||
| } | |||||
| span.regarding{ | |||||
| font-family: "Courier New"; | |||||
| } | |||||
| span.issued-on-date { | |||||
| font-family: "Courier New"; | |||||
| color: darkgrey; | |||||
| } | |||||
| } |
| import {Component, Input, OnInit} from '@angular/core'; | |||||
| import {Component, Input, OnChanges, OnInit} from '@angular/core'; | |||||
| import {RewardModel} from '../models/reward.model'; | import {RewardModel} from '../models/reward.model'; | ||||
| @Component({ | @Component({ | ||||
| templateUrl: './single-payout-rewards-list.component.html', | templateUrl: './single-payout-rewards-list.component.html', | ||||
| styleUrls: ['./single-payout-rewards-list.component.scss'] | styleUrls: ['./single-payout-rewards-list.component.scss'] | ||||
| }) | }) | ||||
| export class SinglePayoutRewardsListComponent implements OnInit { | |||||
| export class SinglePayoutRewardsListComponent implements OnInit, OnChanges { | |||||
| @Input() items: RewardModel[] = []; | @Input() items: RewardModel[] = []; | ||||
| constructor() { } | constructor() { } | ||||
| ngOnInit(): void { | ngOnInit(): void { | ||||
| // this.items.push(new RewardModel({})); | // this.items.push(new RewardModel({})); | ||||
| } | } | ||||
| ngOnChanges(changes): void { | |||||
| // console.log(changes, this.items); | |||||
| } | |||||
| } | } |