1 import {Component, Input, ViewChild, OnInit, AfterViewInit} from '@angular/core';
2 import {Location} from '@angular/common';
3 import {FormatService} from '@eg/core/format.service';
4 import {GridDataSource, GridCellTextGenerator} from '@eg/share/grid/grid';
5 import {GridComponent} from '@eg/share/grid/grid.component';
6 import {AdminPageComponent} from '@eg/staff/share/admin-page/admin-page.component';
7 import {Pager} from '@eg/share/util/pager';
8 import {ActivatedRoute} from '@angular/router';
9 import {IdlService, IdlObject} from '@eg/core/idl.service';
10 import {ToastService} from '@eg/share/toast/toast.service';
11 import {PcrudService} from '@eg/core/pcrud.service';
12 import {FmRecordEditorComponent} from '@eg/share/fm-editor/fm-editor.component';
13 import {OrgService} from '@eg/core/org.service';
14 import {PermService} from '@eg/core/perm.service';
15 import {AuthService} from '@eg/core/auth.service';
16 import {NetService} from '@eg/core/net.service';
17 import {map, mergeMap} from 'rxjs/operators';
18 import {StringComponent} from '@eg/share/string/string.component';
19 import {Observable, forkJoin, of} from 'rxjs';
20 import {AlertDialogComponent} from '@eg/share/dialog/alert.component';
21 import {ConfirmDialogComponent} from '@eg/share/dialog/confirm.component';
22 import {FundingSourceTransactionsDialogComponent} from './funding-source-transactions-dialog.component';
25 selector: 'eg-funding-sources',
26 templateUrl: './funding-sources.component.html'
29 export class FundingSourcesComponent extends AdminPageComponent implements OnInit, AfterViewInit {
33 @Input() startId: number;
35 @ViewChild('grid', { static: true }) grid: GridComponent;
36 @ViewChild('fundingSourceTransactionsDialog', { static: false })
37 fundingSourceTransactionsDialog: FundingSourceTransactionsDialogComponent;
38 @ViewChild('applyCreditDialog', { static: true }) applyCreditDialog: FmRecordEditorComponent;
39 @ViewChild('allocateToFundDialog', { static: true }) allocateToFundDialog: FmRecordEditorComponent;
40 @ViewChild('alertDialog', {static: false}) private alertDialog: AlertDialogComponent;
41 @ViewChild('confirmDel', { static: true }) confirmDel: ConfirmDialogComponent;
43 cellTextGenerator: GridCellTextGenerator;
44 notOneSelectedRow: (rows: IdlObject[]) => boolean;
47 route: ActivatedRoute,
49 format: FormatService,
56 private net: NetService
58 super(route, ngLocation, format, idl, org, auth, pcrud, perm, toast);
59 this.dataSource = new GridDataSource();
63 this.cellTextGenerator = {
64 name: row => row.name()
66 this.notOneSelectedRow = (rows: IdlObject[]) => (rows.length !== 1);
67 this.fieldOrder = 'name,code,year,org,active,currency_type,balance_stop_percentage,balance_warning_percentage,propagate,rollover';
68 this.defaultNewRecord = this.idl.create('acqfs');
69 this.defaultNewRecord.owner(this.auth.user().ws_ou());
71 this.dataSource.getRows = (pager: Pager, sort: any[]) => {
72 const orderBy: any = {};
74 // Sort specified from grid
75 orderBy[this.idlClass] = sort[0].name + ' ' + sort[0].dir;
76 } else if (this.sortField) {
78 orderBy[this.idlClass] = this.sortField;
87 acqfs: ['credits', 'allocations']
94 if (!this.contextOrg && !Object.keys(this.dataSource.filters).length) {
95 // No org filter -- fetch all rows
96 return this.pcrud.retrieveAll(
97 this.idlClass, searchOps, reqOps)
98 .pipe(mergeMap((row) => this.calculateSummary(row)));
101 const search: any = new Array();
102 const orgFilter: any = {};
104 if (this.orgField && (this.searchOrgs || this.contextOrg)) {
105 orgFilter[this.orgField] =
106 this.searchOrgs.orgIds || [this.contextOrg.id()];
107 search.push(orgFilter);
110 Object.keys(this.dataSource.filters).forEach(key => {
111 Object.keys(this.dataSource.filters[key]).forEach(key2 => {
112 search.push(this.dataSource.filters[key][key2]);
116 return this.pcrud.search(
117 this.idlClass, search, searchOps, reqOps)
118 .pipe(mergeMap((row) => this.calculateSummary(row)));
123 this.classLabel = this.idlClassDef.label;
124 this.includeOrgDescendants = true;
129 this.pcrud.retrieve('acqfs', this.startId).subscribe(
130 acqfs => this.openTransactionsDialog([acqfs], 'allocations'),
132 () => this.startId = null
137 calculateSummary(row: IdlObject): Observable<IdlObject> {
139 row['total_credits'] = 0;
140 row['total_allocations'] = 0;
142 row.credits().forEach((c) => row['total_credits'] += Number(c.amount()));
143 row.allocations().forEach((a) => row['total_allocations'] += Number(a.amount()));
144 row['balance'] = row['total_credits'] - row['total_allocations'];
148 deleteSelected(rows: IdlObject[]) {
149 if (rows.length > 0) {
150 const id = rows[0].id();
153 this.pcrud.search('acqfa', { funding_source: id }, { limit: 1 }, { atomic: true }),
154 this.pcrud.search('acqfscred', { funding_source: id }, { limit: 1 }, { atomic: true }),
157 results.forEach((res) => {
158 if (res.length > 0) {
166 this.confirmDel.open().subscribe(confirmed => {
167 if (!confirmed) { return; }
168 super.deleteSelected([ rows[0] ]);
171 this.alertDialog.open();
178 openTransactionsDialog(rows: IdlObject[], tab: string) {
179 if (rows.length !== 1) { return; }
180 this.fundingSourceTransactionsDialog.fundingSourceId = rows[0].id();
181 this.fundingSourceTransactionsDialog.activeTab = tab;
182 this.fundingSourceTransactionsDialog.open({size: 'xl'}).subscribe(
185 () => this.grid.reload()
189 createCredit(rows: IdlObject[]) {
190 if (rows.length !== 1) { return; }
191 const fundingSourceId = rows[0].id();
192 const credit = this.idl.create('acqfscred');
193 credit.funding_source(fundingSourceId);
194 this.applyCreditDialog.defaultNewRecord = credit;
195 this.applyCreditDialog.mode = 'create';
196 this.applyCreditDialog.hiddenFieldsList = ['id', 'funding_source'];
197 this.applyCreditDialog.fieldOrder = 'amount,note,effective_date,deadline_date';
198 this.applyCreditDialog.open().subscribe(
200 this.successString.current()
201 .then(str => this.toast.success(str));
205 this.updateFailedString.current()
206 .then(str => this.toast.danger(str));
211 allocateToFund(rows: IdlObject[]) {
212 if (rows.length !== 1) { return; }
213 const fundingSourceId = rows[0].id();
214 const allocation = this.idl.create('acqfa');
215 allocation.funding_source(fundingSourceId);
216 allocation.allocator(this.auth.user().id());
217 this.allocateToFundDialog.defaultNewRecord = allocation;
218 this.allocateToFundDialog.mode = 'create';
220 this.allocateToFundDialog.hiddenFieldsList = ['id', 'funding_source', 'allocator', 'create_time'];
221 this.allocateToFundDialog.fieldOrder = 'fund,amount,note';
222 this.allocateToFundDialog.open().subscribe(
224 this.successString.current()
225 .then(str => this.toast.success(str));
229 this.updateFailedString.current()
230 .then(str => this.toast.danger(str));