mirror of
https://github.com/valitydev/control-center.git
synced 2024-11-06 02:25:17 +00:00
IMP-63: New payments table, fix metadata form Map (#228)
This commit is contained in:
parent
5993f71141
commit
817b58149a
163
package-lock.json
generated
163
package-lock.json
generated
@ -22,19 +22,15 @@
|
||||
"@angular/platform-browser-dynamic": "15.0.3",
|
||||
"@angular/platform-server": "15.0.3",
|
||||
"@angular/router": "15.0.3",
|
||||
"@ng-matero/extensions": "15.4.2",
|
||||
"@ngneat/input-mask": "6.0.0",
|
||||
"@ngneat/until-destroy": "9.2.2",
|
||||
"@s-libs/js-core": "15.0.0",
|
||||
"@s-libs/micro-dash": "15.0.0",
|
||||
"@s-libs/ng-core": "15.0.0",
|
||||
"@s-libs/rxjs-core": "15.0.0",
|
||||
"@s-libs/ng-core": "^15.0.0",
|
||||
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
||||
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
||||
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
||||
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
||||
"@vality/magista-proto": "2.0.1-cf0eff8.0",
|
||||
"@vality/ng-core": "0.7.1-pr-22-ac52e74.0",
|
||||
"@vality/ng-core": "0.7.1-pr-22-ff78425.0",
|
||||
"@vality/payout-manager-proto": "2.0.1-b079679.0",
|
||||
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||
@ -42,6 +38,7 @@
|
||||
"angular2-prettyjson": "3.0.1",
|
||||
"coerce-property": "15.0.1",
|
||||
"css-element-queries": "1.2.3",
|
||||
"date-fns": "2.30.0",
|
||||
"element-resize-detector": "1.2.4",
|
||||
"humanize-duration": "3.21.0",
|
||||
"inputmask": "5.0.7",
|
||||
@ -51,7 +48,7 @@
|
||||
"moment": "2.29.4",
|
||||
"monaco-editor": "0.21.2",
|
||||
"ngx-mat-select-search": "7.0.1",
|
||||
"rxjs": "7.5.4",
|
||||
"rxjs": "7.8.1",
|
||||
"short-uuid": "4.1.0",
|
||||
"tslib": "2.3.1",
|
||||
"utility-types": "3.10.0",
|
||||
@ -4664,6 +4661,7 @@
|
||||
"node_modules/@s-libs/js-core": {
|
||||
"version": "15.0.0",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
@ -4674,6 +4672,7 @@
|
||||
"node_modules/@s-libs/micro-dash": {
|
||||
"version": "15.0.0",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0",
|
||||
"utility-types": "^3.10.0"
|
||||
@ -4697,6 +4696,7 @@
|
||||
"node_modules/@s-libs/rxjs-core": {
|
||||
"version": "15.0.0",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
@ -5639,29 +5639,30 @@
|
||||
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
||||
},
|
||||
"node_modules/@vality/ng-core": {
|
||||
"version": "0.7.1-pr-22-ac52e74.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ac52e74.0.tgz",
|
||||
"integrity": "sha512-9BstLrgeI9Q3IIGHF75o+b4MkcaZrw9B3odUbGKNr8FSWLCONcCApPFANeKBjg2/ytoe+iX4UfHukY+xt7/o2g==",
|
||||
"version": "0.7.1-pr-22-ff78425.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ff78425.0.tgz",
|
||||
"integrity": "sha512-NzGQLu2tAZFim0apE4gItGrE9YbbzKYFDs3wBQovmUhFom7zglcG8O8ohtyHGmFZTGfPoHGKTMkjzjtpiZah5g==",
|
||||
"dependencies": {
|
||||
"@ng-matero/extensions": "^15.0.0",
|
||||
"@s-libs/js-core": "^15.2.0",
|
||||
"@s-libs/micro-dash": "^15.2.0",
|
||||
"@s-libs/ng-core": "^15.2.0",
|
||||
"@s-libs/rxjs-core": "^15.2.0",
|
||||
"dinero.js": "^2.0.0-alpha.14",
|
||||
"ng-let": "^15.0.2",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/cdk": ">=15.0.0",
|
||||
"@angular/common": ">=15.0.0",
|
||||
"@angular/core": ">=15.0.0",
|
||||
"@angular/material": ">=15.0.0",
|
||||
"@ng-matero/extensions": ">=15.0.0",
|
||||
"@ngneat/until-destroy": ">=9.0.0",
|
||||
"@angular/cdk": "^15.0.0",
|
||||
"@angular/common": "^15.0.0",
|
||||
"@angular/core": "^15.0.0",
|
||||
"@angular/material": "^15.0.0",
|
||||
"@ngneat/until-destroy": "^9.0.0",
|
||||
"@types/lodash-es": "^4.0.0",
|
||||
"coerce-property": ">=15.0.0",
|
||||
"coerce-property": "^15.0.0",
|
||||
"lodash-es": "^4.0.0",
|
||||
"rxjs": ">=7.0.0",
|
||||
"utility-types": ">=3.0.0"
|
||||
"rxjs": "^7.0.0",
|
||||
"utility-types": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@vality/ng-core/node_modules/@s-libs/js-core": {
|
||||
@ -9851,6 +9852,37 @@
|
||||
"version": "1.0.1",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.11"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/date-fns"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns/node_modules/@babel/runtime": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz",
|
||||
"integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/date-fns/node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/date-format": {
|
||||
"version": "4.0.11",
|
||||
"dev": true,
|
||||
@ -13087,14 +13119,6 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/inquirer/node_modules/rxjs": {
|
||||
"version": "7.5.5",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/inquirer/node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"dev": true,
|
||||
@ -15287,6 +15311,18 @@
|
||||
"version": "2.6.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ng-let": {
|
||||
"version": "15.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ng-let/-/ng-let-15.0.2.tgz",
|
||||
"integrity": "sha512-bOt8GOMCRtMPbJEgNrK2YLr8uEkhfQdw41UJziOQp2fCLxdmEP42ppUzr17Wcv0emsOo2bJ01Y7xfos7uJWczA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.3.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^15.0.0",
|
||||
"@angular/core": "^15.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ng-packagr": {
|
||||
"version": "15.0.3",
|
||||
"dev": true,
|
||||
@ -15460,14 +15496,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/ng-packagr/node_modules/rxjs": {
|
||||
"version": "7.6.0",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ngx-build-plus": {
|
||||
"version": "15.0.0",
|
||||
"dev": true,
|
||||
@ -17828,8 +17856,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.5.4",
|
||||
"license": "Apache-2.0",
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
||||
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
@ -23916,12 +23945,14 @@
|
||||
},
|
||||
"@s-libs/js-core": {
|
||||
"version": "15.0.0",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
},
|
||||
"@s-libs/micro-dash": {
|
||||
"version": "15.0.0",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"tslib": "^2.3.0",
|
||||
"utility-types": "^3.10.0"
|
||||
@ -23937,6 +23968,7 @@
|
||||
},
|
||||
"@s-libs/rxjs-core": {
|
||||
"version": "15.0.0",
|
||||
"peer": true,
|
||||
"requires": {
|
||||
"tslib": "^2.3.0"
|
||||
}
|
||||
@ -24530,15 +24562,17 @@
|
||||
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
||||
},
|
||||
"@vality/ng-core": {
|
||||
"version": "0.7.1-pr-22-ac52e74.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ac52e74.0.tgz",
|
||||
"integrity": "sha512-9BstLrgeI9Q3IIGHF75o+b4MkcaZrw9B3odUbGKNr8FSWLCONcCApPFANeKBjg2/ytoe+iX4UfHukY+xt7/o2g==",
|
||||
"version": "0.7.1-pr-22-ff78425.0",
|
||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ff78425.0.tgz",
|
||||
"integrity": "sha512-NzGQLu2tAZFim0apE4gItGrE9YbbzKYFDs3wBQovmUhFom7zglcG8O8ohtyHGmFZTGfPoHGKTMkjzjtpiZah5g==",
|
||||
"requires": {
|
||||
"@ng-matero/extensions": "^15.0.0",
|
||||
"@s-libs/js-core": "^15.2.0",
|
||||
"@s-libs/micro-dash": "^15.2.0",
|
||||
"@s-libs/ng-core": "^15.2.0",
|
||||
"@s-libs/rxjs-core": "^15.2.0",
|
||||
"dinero.js": "^2.0.0-alpha.14",
|
||||
"ng-let": "^15.0.2",
|
||||
"tslib": "^2.3.0"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -27508,6 +27542,29 @@
|
||||
"cyclist": {
|
||||
"version": "1.0.1"
|
||||
},
|
||||
"date-fns": {
|
||||
"version": "2.30.0",
|
||||
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz",
|
||||
"integrity": "sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.21.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": {
|
||||
"version": "7.22.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.3.tgz",
|
||||
"integrity": "sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==",
|
||||
"requires": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
}
|
||||
},
|
||||
"regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"date-format": {
|
||||
"version": "4.0.11",
|
||||
"dev": true
|
||||
@ -29614,13 +29671,6 @@
|
||||
"version": "3.0.0",
|
||||
"dev": true
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "7.5.5",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.3",
|
||||
"dev": true,
|
||||
@ -31022,6 +31072,14 @@
|
||||
"neo-async": {
|
||||
"version": "2.6.2"
|
||||
},
|
||||
"ng-let": {
|
||||
"version": "15.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ng-let/-/ng-let-15.0.2.tgz",
|
||||
"integrity": "sha512-bOt8GOMCRtMPbJEgNrK2YLr8uEkhfQdw41UJziOQp2fCLxdmEP42ppUzr17Wcv0emsOo2bJ01Y7xfos7uJWczA==",
|
||||
"requires": {
|
||||
"tslib": "^2.3.1"
|
||||
}
|
||||
},
|
||||
"ng-packagr": {
|
||||
"version": "15.0.3",
|
||||
"dev": true,
|
||||
@ -31135,13 +31193,6 @@
|
||||
"requires": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "7.6.0",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -32642,7 +32693,9 @@
|
||||
}
|
||||
},
|
||||
"rxjs": {
|
||||
"version": "7.5.4",
|
||||
"version": "7.8.1",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
||||
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
|
11
package.json
11
package.json
@ -31,19 +31,15 @@
|
||||
"@angular/platform-browser-dynamic": "15.0.3",
|
||||
"@angular/platform-server": "15.0.3",
|
||||
"@angular/router": "15.0.3",
|
||||
"@ng-matero/extensions": "15.4.2",
|
||||
"@ngneat/input-mask": "6.0.0",
|
||||
"@ngneat/until-destroy": "9.2.2",
|
||||
"@s-libs/js-core": "15.0.0",
|
||||
"@s-libs/micro-dash": "15.0.0",
|
||||
"@s-libs/ng-core": "15.0.0",
|
||||
"@s-libs/rxjs-core": "15.0.0",
|
||||
"@s-libs/ng-core": "^15.0.0",
|
||||
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
||||
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
||||
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
||||
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
||||
"@vality/magista-proto": "2.0.1-cf0eff8.0",
|
||||
"@vality/ng-core": "0.7.1-pr-22-ac52e74.0",
|
||||
"@vality/ng-core": "0.7.1-pr-22-ff78425.0",
|
||||
"@vality/payout-manager-proto": "2.0.1-b079679.0",
|
||||
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||
@ -51,6 +47,7 @@
|
||||
"angular2-prettyjson": "3.0.1",
|
||||
"coerce-property": "15.0.1",
|
||||
"css-element-queries": "1.2.3",
|
||||
"date-fns": "2.30.0",
|
||||
"element-resize-detector": "1.2.4",
|
||||
"humanize-duration": "3.21.0",
|
||||
"inputmask": "5.0.7",
|
||||
@ -60,7 +57,7 @@
|
||||
"moment": "2.29.4",
|
||||
"monaco-editor": "0.21.2",
|
||||
"ngx-mat-select-search": "7.0.1",
|
||||
"rxjs": "7.5.4",
|
||||
"rxjs": "7.8.1",
|
||||
"short-uuid": "4.1.0",
|
||||
"tslib": "2.3.1",
|
||||
"utility-types": "3.10.0",
|
||||
|
@ -11,7 +11,7 @@ import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
export class PartiesStoreService {
|
||||
constructor(private partyManagementService: PartyManagementService) {}
|
||||
|
||||
@MemoizeExpiring(30_000)
|
||||
@MemoizeExpiring(5 * 60_000)
|
||||
get(partyId: PartyID) {
|
||||
return this.partyManagementService
|
||||
.Get(partyId)
|
||||
|
@ -5,11 +5,11 @@ import { AppAuthGuardService } from '@cc/app/shared/services';
|
||||
|
||||
import { ROUTING_CONFIG as DEPOSITS_ROUTING_CONFIG } from './sections/deposits/routing-config';
|
||||
import { ROUTING_CONFIG as DOMAIN_ROUTING_CONFIG } from './sections/domain/routing-config';
|
||||
import { ROUTING_CONFIG as PAYMENTS_ROUTING_CONFIG } from './sections/payments/routing-config';
|
||||
import { ROUTING_CONFIG as PAYOUTS_ROUTING_CONFIG } from './sections/payouts/payouts/routing-config';
|
||||
import { ROUTING_CONFIG as REPAIRING_ROUTING_CONFIG } from './sections/repairing/routing-config';
|
||||
import { ROUTING_CONFIG as CLAIMS_ROUTING_CONFIG } from './sections/search-claims/routing-config';
|
||||
import { ROUTING_CONFIG as PARTIES_ROUTING_CONFIG } from './sections/search-parties/routing-config';
|
||||
import { ROUTING_CONFIG as PAYMENTS_ROUTING_CONFIG } from './sections/search-payments/routing-config';
|
||||
import { ROUTING_CONFIG as SOURCES_ROUTING_CONFIG } from './sections/sources/routing-config';
|
||||
import { ROUTING_CONFIG as WALLETS_ROUTING_CONFIG } from './sections/wallets/routing-config';
|
||||
import { ROUTING_CONFIG as WITHDRAWALS_ROUTING_CONFIG } from './sections/withdrawals/routing-config';
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { registerLocaleData } from '@angular/common';
|
||||
import localeRu from '@angular/common/locales/ru';
|
||||
import { LOCALE_ID, NgModule, Injector } from '@angular/core';
|
||||
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
|
||||
import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER } from '@angular/material/autocomplete';
|
||||
@ -39,6 +41,8 @@ import {
|
||||
SMALL_SEARCH_LIMIT,
|
||||
} from './tokens';
|
||||
|
||||
registerLocaleData(localeRu);
|
||||
|
||||
/**
|
||||
* For use in specific locations (for example, questionary PDF document)
|
||||
*/
|
||||
@ -77,8 +81,8 @@ export let AppInjector: Injector;
|
||||
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } },
|
||||
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS },
|
||||
{ provide: DateAdapter, useClass: MomentUtcDateAdapter, deps: [MAT_DATE_LOCALE] },
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'ru' },
|
||||
{ provide: LOCALE_ID, useValue: 'en' },
|
||||
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
|
||||
{ provide: LOCALE_ID, useValue: 'ru' },
|
||||
{ provide: SEARCH_LIMIT, useValue: DEFAULT_SEARCH_LIMIT },
|
||||
{ provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT },
|
||||
{ provide: QUERY_PARAMS_SERIALIZERS, useValue: DEFAULT_QUERY_PARAMS_SERIALIZERS },
|
||||
|
@ -3,7 +3,7 @@ import { FormControl } from '@angular/forms';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { InvoicePaymentAdjustmentParams } from '@vality/domain-proto/payment_processing';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
import { DialogSuperclass, NotifyLogService } from '@vality/ng-core';
|
||||
import chunk from 'lodash-es/chunk';
|
||||
import { BehaviorSubject, from, concatMap, of, forkJoin } from 'rxjs';
|
||||
import { catchError, finalize } from 'rxjs/operators';
|
||||
@ -11,8 +11,6 @@ import { catchError, finalize } from 'rxjs/operators';
|
||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||
|
||||
import { InvoicingService } from '../../../../api/payment-processing';
|
||||
import { NotificationService } from '../../../services/notification';
|
||||
import { NotificationErrorService } from '../../../services/notification-error';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
@ -33,9 +31,8 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
||||
constructor(
|
||||
injector: Injector,
|
||||
private invoicingService: InvoicingService,
|
||||
private notificationService: NotificationService,
|
||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
||||
private notificationErrorService: NotificationErrorService
|
||||
private log: NotifyLogService,
|
||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService
|
||||
) {
|
||||
super(injector);
|
||||
}
|
||||
@ -71,7 +68,7 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
||||
.subscribe({
|
||||
complete: () => {
|
||||
if (!this.withError.length) {
|
||||
this.notificationService.success(`${payments.length} created successfully`);
|
||||
this.log.success(`${payments.length} created successfully`);
|
||||
this.closeWithSuccess();
|
||||
} else {
|
||||
const errors = this.withError
|
||||
@ -82,7 +79,7 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
||||
})
|
||||
.filter(Boolean)
|
||||
.join(', ');
|
||||
this.notificationErrorService.error(
|
||||
this.log.error(
|
||||
new Error(
|
||||
`${this.withError.length} out of ${payments.length} failed. Errors: ${errors}`
|
||||
)
|
@ -0,0 +1,15 @@
|
||||
<v-table
|
||||
[columns]="columns"
|
||||
[data]="data"
|
||||
[hasMore]="hasMore"
|
||||
[progress]="isLoading"
|
||||
[rowSelected]="selected"
|
||||
rowSelectable
|
||||
(more)="more.emit()"
|
||||
(rowSelectionChange)="selectedChange.emit($event)"
|
||||
(update)="update.emit($event)"
|
||||
>
|
||||
<v-table-actions>
|
||||
<ng-content></ng-content>
|
||||
</v-table-actions>
|
||||
</v-table>
|
@ -0,0 +1,90 @@
|
||||
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { InvoicePaymentStatus } from '@vality/domain-proto/domain';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import { Column, TagColumn, LoadOptions } from '@vality/ng-core';
|
||||
import startCase from 'lodash-es/startCase';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { PartiesStoreService } from '@cc/app/api/payment-processing';
|
||||
import { AmountCurrencyService } from '@cc/app/shared/services';
|
||||
import { getUnionKey } from '@cc/utils';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payments-table',
|
||||
templateUrl: './payments-table.component.html',
|
||||
})
|
||||
export class PaymentsTableComponent {
|
||||
@Input() data!: StatPayment[];
|
||||
@Input() isLoading?: boolean | null;
|
||||
@Input() hasMore?: boolean | null;
|
||||
@Input() selected?: StatPayment[];
|
||||
|
||||
@Output() selectedChange = new EventEmitter<StatPayment[]>();
|
||||
@Output() update = new EventEmitter<LoadOptions>();
|
||||
@Output() more = new EventEmitter<void>();
|
||||
|
||||
columns: Column<StatPayment>[] = [
|
||||
{ field: 'id', hide: true },
|
||||
'invoice_id',
|
||||
{
|
||||
field: 'amount',
|
||||
type: 'currency',
|
||||
formatter: (data) =>
|
||||
this.amountCurrencyService.toMajor(data.amount, data.currency_symbolic_code),
|
||||
typeParameters: {
|
||||
currencyCode: 'currency_symbolic_code',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'fee',
|
||||
type: 'currency',
|
||||
formatter: (data) =>
|
||||
this.amountCurrencyService.toMajor(data.fee, data.currency_symbolic_code),
|
||||
typeParameters: {
|
||||
currencyCode: 'currency_symbolic_code',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'status',
|
||||
type: 'tag',
|
||||
formatter: (data) => startCase(getUnionKey(data.status)),
|
||||
typeParameters: {
|
||||
value: (data) => getUnionKey(data.status),
|
||||
tags: {
|
||||
pending: { color: 'pending' },
|
||||
processed: { color: 'pending' },
|
||||
captured: { color: 'success' },
|
||||
cancelled: {},
|
||||
refunded: { color: 'success' },
|
||||
failed: { color: 'warn' },
|
||||
charged_back: { color: 'success' },
|
||||
},
|
||||
},
|
||||
} as TagColumn<StatPayment, keyof InvoicePaymentStatus>,
|
||||
{ field: 'created_at', type: 'datetime' },
|
||||
{
|
||||
field: 'owner_id',
|
||||
header: 'Party',
|
||||
formatter: (data) =>
|
||||
this.partiesStoreService.get(data.owner_id).pipe(map((p) => p.contact_info.email)),
|
||||
description: 'owner_id',
|
||||
},
|
||||
{
|
||||
field: 'shop',
|
||||
formatter: (data) =>
|
||||
this.partiesStoreService
|
||||
.get(data.owner_id)
|
||||
.pipe(map((p) => p.shops.get(data.shop_id).details.name)),
|
||||
description: 'shop_id',
|
||||
header: 'Shop',
|
||||
},
|
||||
'domain_revision',
|
||||
{ field: 'terminal_id.id', header: 'Terminal' },
|
||||
{ field: 'provider_id.id', header: 'Provider' },
|
||||
];
|
||||
|
||||
constructor(
|
||||
private amountCurrencyService: AmountCurrencyService,
|
||||
private partiesStoreService: PartiesStoreService
|
||||
) {}
|
||||
}
|
1
src/app/sections/payments/index.ts
Normal file
1
src/app/sections/payments/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './payments.module';
|
@ -3,15 +3,15 @@ import { RouterModule } from '@angular/router';
|
||||
|
||||
import { AppAuthGuardService } from '@cc/app/shared/services';
|
||||
|
||||
import { PaymentsComponent } from './payments.component';
|
||||
import { ROUTING_CONFIG } from './routing-config';
|
||||
import { SearchPaymentsComponent } from './search-payments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
RouterModule.forChild([
|
||||
{
|
||||
path: '',
|
||||
component: SearchPaymentsComponent,
|
||||
component: PaymentsComponent,
|
||||
canActivate: [AppAuthGuardService],
|
||||
data: ROUTING_CONFIG,
|
||||
},
|
||||
@ -19,4 +19,4 @@ import { SearchPaymentsComponent } from './search-payments.component';
|
||||
],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class SearchPaymentsRoutingModule {}
|
||||
export class PaymentsRoutingModule {}
|
53
src/app/sections/payments/payments.component.html
Normal file
53
src/app/sections/payments/payments.component.html
Normal file
@ -0,0 +1,53 @@
|
||||
<cc-page-layout title="Payments">
|
||||
<cc-page-layout-actions>
|
||||
<v-more-filters-button [filters]="filters"></v-more-filters-button>
|
||||
</cc-page-layout-actions>
|
||||
<v-filters
|
||||
#filters
|
||||
[active]="active"
|
||||
merge
|
||||
(clear)="filtersForm.reset(); otherFiltersControl.reset()"
|
||||
>
|
||||
<ng-template [formGroup]="filtersForm" vMainFilters>
|
||||
<v-date-range-field formControlName="dateRange"></v-date-range-field>
|
||||
<v-list-field formControlName="invoice_ids" label="Invoice Ids"></v-list-field>
|
||||
<cc-merchant-field formControlName="party_id"></cc-merchant-field>
|
||||
<cc-shop-field
|
||||
[partyId]="filtersForm.value.party_id"
|
||||
formControlName="shop_ids"
|
||||
multiple
|
||||
></cc-shop-field>
|
||||
<v-input-field formControlName="payment_first6" label="Card BIN"></v-input-field>
|
||||
<v-input-field formControlName="payment_last4" label="Card PAN"></v-input-field>
|
||||
<v-input-field formControlName="payment_rrn" label="Payment RRN"></v-input-field>
|
||||
<v-input-field formControlName="payment_email" label="Payer email"></v-input-field>
|
||||
</ng-template>
|
||||
<ng-template vOtherFilters>
|
||||
<cc-metadata-form
|
||||
[extensions]="extensions"
|
||||
[formControl]="otherFiltersControl"
|
||||
[metadata]="metadata$ | async"
|
||||
namespace="magista"
|
||||
type="PaymentSearchQuery"
|
||||
></cc-metadata-form>
|
||||
</ng-template>
|
||||
</v-filters>
|
||||
<cc-payments-table
|
||||
[data]="(payments$ | async) || []"
|
||||
[hasMore]="hasMore$ | async"
|
||||
[isLoading]="isLoading$ | async"
|
||||
[selected]="selected$ | async"
|
||||
(more)="more()"
|
||||
(selectedChange)="selected$.next($event)"
|
||||
(update)="load($event ?? {})"
|
||||
>
|
||||
<button
|
||||
[disabled]="!(selected$ | async)?.length"
|
||||
color="primary"
|
||||
mat-button
|
||||
(click)="createPaymentAdjustment()"
|
||||
>
|
||||
Create payment adjustment
|
||||
</button>
|
||||
</cc-payments-table>
|
||||
</cc-page-layout>
|
149
src/app/sections/payments/payments.component.ts
Normal file
149
src/app/sections/payments/payments.component.ts
Normal file
@ -0,0 +1,149 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { NonNullableFormBuilder } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { ThriftAstMetadata } from '@vality/fistful-proto';
|
||||
import { PaymentSearchQuery, StatPayment } from '@vality/magista-proto/magista';
|
||||
import {
|
||||
DialogService,
|
||||
DialogResponseStatus,
|
||||
LoadOptions,
|
||||
getNoTimeZoneIsoString,
|
||||
clean,
|
||||
DateRange,
|
||||
} from '@vality/ng-core';
|
||||
import { endOfDay, startOfDay, subDays } from 'date-fns';
|
||||
import lodashMerge from 'lodash-es/merge';
|
||||
import { BehaviorSubject, debounceTime, from, of, merge } from 'rxjs';
|
||||
import { startWith } from 'rxjs/operators';
|
||||
|
||||
import { MetadataFormExtension, isTypeWithAliases } from '../../shared/components/metadata-form';
|
||||
import { QueryParamsService } from '../../shared/services';
|
||||
import { CreatePaymentAdjustmentComponent } from './components/create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { FetchPaymentsService } from './services/fetch-payments.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
templateUrl: 'payments.component.html',
|
||||
})
|
||||
export class PaymentsComponent implements OnInit {
|
||||
isLoading$ = this.fetchPaymentsService.isLoading$;
|
||||
payments$ = this.fetchPaymentsService.result$;
|
||||
hasMore$ = this.fetchPaymentsService.hasMore$;
|
||||
selected$ = new BehaviorSubject<StatPayment[]>([]);
|
||||
filtersForm = this.fb.group({
|
||||
dateRange: {
|
||||
start: subDays(startOfDay(new Date()), 1),
|
||||
end: endOfDay(new Date()),
|
||||
} as DateRange,
|
||||
invoice_ids: [undefined as string[]],
|
||||
party_id: undefined as string,
|
||||
shop_ids: [undefined as string[]],
|
||||
payment_first6: undefined as string,
|
||||
payment_last4: undefined as string,
|
||||
payment_rrn: undefined as string,
|
||||
payment_email: undefined as string,
|
||||
});
|
||||
otherFiltersControl = this.fb.control({
|
||||
common_search_query_params: {},
|
||||
payment_params: {},
|
||||
});
|
||||
metadata$ = from(
|
||||
import('@vality/magista-proto/metadata.json').then((m) => m.default as ThriftAstMetadata[])
|
||||
);
|
||||
extensions: MetadataFormExtension[] = [
|
||||
{
|
||||
determinant: (data) =>
|
||||
of(
|
||||
isTypeWithAliases(data, 'CommonSearchQueryParams', 'magista') ||
|
||||
[
|
||||
'invoice_ids',
|
||||
'payment_email',
|
||||
'payment_first6',
|
||||
'payment_last4',
|
||||
'payment_rrn',
|
||||
].includes(data?.field?.name)
|
||||
),
|
||||
extension: () => of({ hidden: true }),
|
||||
},
|
||||
];
|
||||
active = 0;
|
||||
|
||||
constructor(
|
||||
private router: Router,
|
||||
private qp: QueryParamsService<{
|
||||
filters: object;
|
||||
otherFilters: object;
|
||||
dateRange: DateRange;
|
||||
}>,
|
||||
private fetchPaymentsService: FetchPaymentsService,
|
||||
private dialogService: DialogService,
|
||||
private fb: NonNullableFormBuilder
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.filtersForm.patchValue(
|
||||
lodashMerge({}, this.qp.params.filters, clean({ dateRange: this.qp.params.dateRange }))
|
||||
);
|
||||
const otherFilters = this.otherFiltersControl.value;
|
||||
const otherFiltersParams: Partial<PaymentSearchQuery> = this.qp.params.otherFilters || {};
|
||||
this.otherFiltersControl.patchValue(lodashMerge({}, otherFilters, otherFiltersParams));
|
||||
merge(this.filtersForm.valueChanges, this.otherFiltersControl.valueChanges)
|
||||
.pipe(startWith(null), debounceTime(500), untilDestroyed(this))
|
||||
.subscribe(() => {
|
||||
this.load();
|
||||
});
|
||||
}
|
||||
|
||||
more() {
|
||||
this.fetchPaymentsService.more();
|
||||
}
|
||||
|
||||
load(options?: LoadOptions) {
|
||||
const { dateRange, ...filters } = clean(this.filtersForm.value);
|
||||
const otherFilters = clean(this.otherFiltersControl.value);
|
||||
void this.qp.set({ filters, otherFilters, dateRange });
|
||||
this.fetchPaymentsService.load(
|
||||
clean({
|
||||
...otherFilters,
|
||||
common_search_query_params: {
|
||||
...(otherFilters.common_search_query_params || {}),
|
||||
party_id: filters.party_id,
|
||||
shop_ids: filters.shop_ids,
|
||||
from_time: getNoTimeZoneIsoString(dateRange.start),
|
||||
to_time: getNoTimeZoneIsoString(dateRange.end),
|
||||
},
|
||||
payment_params: {
|
||||
...(otherFilters.payment_params || {}),
|
||||
payment_email: filters.payment_email,
|
||||
payment_first6: filters.payment_first6,
|
||||
payment_last4: filters.payment_last4,
|
||||
payment_rrn: filters.payment_rrn,
|
||||
},
|
||||
invoice_ids: filters.invoice_ids,
|
||||
}),
|
||||
options
|
||||
);
|
||||
this.active =
|
||||
Object.keys(dateRange).length +
|
||||
Object.keys(filters).length +
|
||||
Object.keys(otherFilters.payment_params || {}).length +
|
||||
Object.keys(otherFilters.common_search_query_params || {}).length;
|
||||
}
|
||||
|
||||
createPaymentAdjustment() {
|
||||
this.dialogService
|
||||
.open(CreatePaymentAdjustmentComponent, {
|
||||
payments: this.selected$.value,
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((res) => {
|
||||
if (res.status === DialogResponseStatus.Success) {
|
||||
this.load();
|
||||
this.selected$.next([]);
|
||||
} else if (res.data?.withError?.length) {
|
||||
this.selected$.next(res.data.withError.map((w) => w.payment));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
43
src/app/sections/payments/payments.module.ts
Normal file
43
src/app/sections/payments/payments.module.ts
Normal file
@ -0,0 +1,43 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { ReactiveFormsModule, FormsModule } from '@angular/forms';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import {
|
||||
FiltersModule,
|
||||
DateRangeFieldModule,
|
||||
ListFieldModule,
|
||||
TableModule,
|
||||
DialogModule,
|
||||
InputFieldModule,
|
||||
} from '@vality/ng-core';
|
||||
|
||||
import { PageLayoutModule, ShopFieldModule } from '@cc/app/shared';
|
||||
import { MerchantFieldModule } from '@cc/app/shared/components/merchant-field';
|
||||
import { MetadataFormModule } from '@cc/app/shared/components/metadata-form';
|
||||
|
||||
import { CreatePaymentAdjustmentComponent } from './components/create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { PaymentsTableComponent } from './components/payments-table/payments-table.component';
|
||||
import { PaymentsRoutingModule } from './payments-routing.module';
|
||||
import { PaymentsComponent } from './payments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
PaymentsRoutingModule,
|
||||
PageLayoutModule,
|
||||
FiltersModule,
|
||||
DateRangeFieldModule,
|
||||
ListFieldModule,
|
||||
MerchantFieldModule,
|
||||
ReactiveFormsModule,
|
||||
TableModule,
|
||||
DialogModule,
|
||||
MetadataFormModule,
|
||||
MatButtonModule,
|
||||
ShopFieldModule,
|
||||
InputFieldModule,
|
||||
FormsModule,
|
||||
],
|
||||
declarations: [PaymentsComponent, CreatePaymentAdjustmentComponent, PaymentsTableComponent],
|
||||
})
|
||||
export class PaymentsModule {}
|
44
src/app/sections/payments/services/fetch-payments.service.ts
Normal file
44
src/app/sections/payments/services/fetch-payments.service.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatPayment, PaymentSearchQuery } from '@vality/magista-proto/magista';
|
||||
import { FetchSuperclass, FetchOptions, FetchResult, NotifyLogService } from '@vality/ng-core';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { map, catchError } from 'rxjs/operators';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FetchPaymentsService extends FetchSuperclass<StatPayment, PaymentSearchQuery> {
|
||||
constructor(
|
||||
private merchantStatisticsService: MerchantStatisticsService,
|
||||
private log: NotifyLogService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(
|
||||
params: PaymentSearchQuery,
|
||||
{ size, continuationToken }: FetchOptions
|
||||
): Observable<FetchResult<StatPayment>> {
|
||||
return this.merchantStatisticsService
|
||||
.SearchPayments({
|
||||
payment_params: {},
|
||||
...params,
|
||||
common_search_query_params: Object.assign({}, params.common_search_query_params, {
|
||||
continuation_token: continuationToken,
|
||||
limit: size,
|
||||
}),
|
||||
})
|
||||
.pipe(
|
||||
map(({ payments, continuation_token }) => ({
|
||||
result: payments,
|
||||
continuationToken: continuation_token,
|
||||
})),
|
||||
catchError((err) => {
|
||||
this.log.errorOperation(err, 'receive', 'payments');
|
||||
return of({ result: [] });
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
@ -43,10 +43,8 @@
|
||||
[rowSelected]="selected$ | async"
|
||||
[trackBy]="trackById"
|
||||
rowSelectable
|
||||
sizes
|
||||
(more)="fetchMore()"
|
||||
(rowSelectionChange)="selected$.next($event)"
|
||||
(sizeChange)="update($event)"
|
||||
(update)="update($event.size)"
|
||||
>
|
||||
<v-table-actions>
|
||||
|
@ -1 +0,0 @@
|
||||
export * from './search-payments.module';
|
@ -1,7 +0,0 @@
|
||||
<cc-page-layout title="Payments">
|
||||
<cc-payments-searcher
|
||||
[initSearchParams]="qp.params || {}"
|
||||
(paymentEventFired)="paymentEventFired($event)"
|
||||
(searchParamsChanged)="searchParamsUpdated($event)"
|
||||
></cc-payments-searcher>
|
||||
</cc-page-layout>
|
@ -1,32 +0,0 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { clean } from '@vality/ng-core';
|
||||
|
||||
import {
|
||||
PaymentActions,
|
||||
PaymentMenuItemEvent,
|
||||
SearchFiltersParams,
|
||||
} from '@cc/app/shared/components';
|
||||
|
||||
import { QueryParamsService } from '../../shared/services';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'search-payments.component.html',
|
||||
})
|
||||
export class SearchPaymentsComponent {
|
||||
constructor(private router: Router, public qp: QueryParamsService<SearchFiltersParams>) {}
|
||||
|
||||
searchParamsUpdated(params: SearchFiltersParams) {
|
||||
void this.qp.set(clean(params));
|
||||
}
|
||||
|
||||
paymentEventFired($event: PaymentMenuItemEvent) {
|
||||
const { partyID, invoiceID, paymentID } = $event;
|
||||
switch ($event.action) {
|
||||
case PaymentActions.NavigateToPayment:
|
||||
void this.router.navigate([
|
||||
`/party/${partyID}/invoice/${invoiceID}/payment/${paymentID}`,
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexModule } from '@angular/flex-layout';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
|
||||
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
|
||||
|
||||
import { PageLayoutModule } from '../../shared';
|
||||
import { PaymentsSearcherModule } from '../../shared/components/payments-searcher';
|
||||
import { SearchPaymentsRoutingModule } from './search-payments-routing.module';
|
||||
import { SearchPaymentsComponent } from './search-payments.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
SearchPaymentsRoutingModule,
|
||||
MatCardModule,
|
||||
FlexModule,
|
||||
MatProgressBarModule,
|
||||
CommonModule,
|
||||
EmptySearchResultModule,
|
||||
MatButtonModule,
|
||||
PaymentsSearcherModule,
|
||||
PageLayoutModule,
|
||||
],
|
||||
declarations: [SearchPaymentsComponent],
|
||||
})
|
||||
export class SearchPaymentsModule {}
|
@ -38,8 +38,7 @@ const ROUTES: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'payments',
|
||||
loadChildren: () =>
|
||||
import('./search-payments/search-payments.module').then((m) => m.SearchPaymentsModule),
|
||||
loadChildren: () => import('./payments/payments.module').then((m) => m.PaymentsModule),
|
||||
},
|
||||
{
|
||||
path: 'deposits',
|
||||
|
@ -24,9 +24,7 @@
|
||||
[data]="wallets$ | async"
|
||||
[hasMore]="hasMore$ | async"
|
||||
[progress]="inProgress$ | async"
|
||||
sizes
|
||||
(more)="fetchMore()"
|
||||
(sizeChange)="search($event)"
|
||||
(update)="search($event.size)"
|
||||
>
|
||||
<ng-template #balanceTpl let-col="colDef" let-index="index" let-row>
|
||||
|
@ -1,8 +1,6 @@
|
||||
export * from './claim-search-form';
|
||||
export * from './party-modification-creator';
|
||||
export * from './party-modification-forms';
|
||||
export * from './payments-search-filters';
|
||||
export * from './payments-table';
|
||||
export * from './status';
|
||||
export * from './shop-field';
|
||||
export * from './shop-details';
|
||||
|
@ -9,6 +9,7 @@ import {
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
||||
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
||||
import { merge } from 'rxjs';
|
||||
|
||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||
@ -23,6 +24,8 @@ function updateFormArray<V>(formArray: FormArray<AbstractControl<V>>, values: V[
|
||||
formArray.patchValue(values);
|
||||
}
|
||||
|
||||
type ComplexType<T, K = never> = T[] | Map<K, T> | Set<T>;
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'cc-complex-form',
|
||||
@ -30,15 +33,15 @@ function updateFormArray<V>(formArray: FormArray<AbstractControl<V>>, values: V[
|
||||
styleUrls: ['complex-form.component.scss'],
|
||||
providers: createControlProviders(() => ComplexFormComponent),
|
||||
})
|
||||
export class ComplexFormComponent<T extends unknown[] | Map<unknown, unknown> | Set<unknown>>
|
||||
extends FormComponentSuperclass<T>
|
||||
export class ComplexFormComponent<V, K = never>
|
||||
extends FormComponentSuperclass<ComplexType<V, K>>
|
||||
implements OnInit, Validator
|
||||
{
|
||||
@Input() data: MetadataFormData<SetType | MapType | ListType>;
|
||||
@Input() extensions: MetadataFormExtension[];
|
||||
|
||||
valueControls = new FormArray([]);
|
||||
keyControls = new FormArray([]);
|
||||
valueControls = new FormArray<AbstractControl<V>>([]);
|
||||
keyControls = new FormArray<AbstractControl<K>>([]);
|
||||
|
||||
get hasLabel() {
|
||||
return !!this.data.trueParent;
|
||||
@ -53,31 +56,34 @@ export class ComplexFormComponent<T extends unknown[] | Map<unknown, unknown> |
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.valueControls.valueChanges.pipe(untilDestroyed(this)).subscribe((value) => {
|
||||
switch (this.data.type.name) {
|
||||
case 'list':
|
||||
this.emitOutgoingValue(value as never);
|
||||
break;
|
||||
case 'map':
|
||||
this.emitOutgoingValue(
|
||||
new Map(value.map((v, idx) => [this.keyControls.value[idx], v])) as never
|
||||
);
|
||||
break;
|
||||
case 'set':
|
||||
this.emitOutgoingValue(new Set(value) as never);
|
||||
break;
|
||||
}
|
||||
});
|
||||
merge(this.valueControls.valueChanges, this.keyControls.valueChanges)
|
||||
.pipe(untilDestroyed(this))
|
||||
.subscribe(() => {
|
||||
const values = this.valueControls.value;
|
||||
switch (this.data.type.name) {
|
||||
case 'list':
|
||||
this.emitOutgoingValue(values);
|
||||
break;
|
||||
case 'map': {
|
||||
const keys = this.keyControls.value;
|
||||
this.emitOutgoingValue(new Map(values.map((v, idx) => [keys[idx], v])));
|
||||
break;
|
||||
}
|
||||
case 'set':
|
||||
this.emitOutgoingValue(new Set(values));
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
handleIncomingValue(value: T) {
|
||||
handleIncomingValue(value: ComplexType<V, K>) {
|
||||
if (this.isKeyValue) {
|
||||
const keys = Array.from(value?.keys() || []);
|
||||
const keys = Array.from((value as Map<K, V>)?.keys() || []);
|
||||
updateFormArray(this.keyControls, keys);
|
||||
}
|
||||
const values = this.isKeyValue
|
||||
? Array.from(value?.values() || [])
|
||||
: Array.from(value || []);
|
||||
: Array.from((value as V[]) || []);
|
||||
updateFormArray(this.valueControls, values);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<div *ngIf="data" [ngSwitch]="data?.typeGroup">
|
||||
<div *ngIf="!(extensionResult$ | async)?.hidden" [ngSwitch]="data?.typeGroup">
|
||||
<cc-extension-field
|
||||
*ngIf="(extensionResult$ | async)?.type; else defaultFields"
|
||||
[data]="data"
|
||||
|
@ -21,6 +21,7 @@ export interface MetadataFormExtensionResult {
|
||||
label?: string;
|
||||
type?: 'datetime' | 'cash';
|
||||
converter?: Converter;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
export interface MetadataFormExtensionOption {
|
||||
|
@ -1,3 +0,0 @@
|
||||
export * from './payments-main-search-filters';
|
||||
export * from './payments-other-search-filters';
|
||||
export * from './search-filters-params';
|
@ -1,11 +0,0 @@
|
||||
import { Moment } from 'moment';
|
||||
|
||||
export interface FormValue {
|
||||
fromTime: Moment;
|
||||
toTime: Moment;
|
||||
invoiceIDs?: string;
|
||||
shopIDs?: string[];
|
||||
bin?: string;
|
||||
pan?: string;
|
||||
rrn?: string;
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export * from './payments-main-search-filters.module';
|
||||
export * from './payments-main-search-filters.component';
|
@ -1,71 +0,0 @@
|
||||
<div
|
||||
[formGroup]="form"
|
||||
gdColumns="1fr 1fr 1fr 1fr"
|
||||
gdColumns.lt-lg="1fr 1fr 1fr"
|
||||
gdColumns.lt-md="1fr 1fr"
|
||||
gdColumns.lt-sm="1fr"
|
||||
gdGap="16px"
|
||||
>
|
||||
<mat-form-field>
|
||||
<mat-label>Date Range</mat-label>
|
||||
<mat-date-range-input [rangePicker]="picker">
|
||||
<input formControlName="fromTime" matInput matStartDate placeholder="Start Date" />
|
||||
<input formControlName="toTime" matEndDate matInput placeholder="End Date" />
|
||||
</mat-date-range-input>
|
||||
<mat-datepicker-toggle [for]="picker" matSuffix>
|
||||
<mat-icon matDatepickerToggleIcon>keyboard_arrow_down</mat-icon>
|
||||
</mat-datepicker-toggle>
|
||||
<mat-date-range-picker #picker></mat-date-range-picker>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="invoiceIDs"
|
||||
matInput
|
||||
placeholder="Invoice IDs"
|
||||
type="string"
|
||||
/>
|
||||
<mat-hint>id0,id1</mat-hint>
|
||||
</mat-form-field>
|
||||
<cc-merchant-field formControlName="partyID"></cc-merchant-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Shops</mat-label>
|
||||
<mat-select
|
||||
[disabled]="!form.value['partyID']"
|
||||
class="select"
|
||||
formControlName="shopIDs"
|
||||
multiple
|
||||
>
|
||||
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
||||
{{ shop.details.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="bin"
|
||||
matInput
|
||||
placeholder="Card Bin"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="pan"
|
||||
matInput
|
||||
placeholder="Card Pan"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<input
|
||||
autocomplete="false"
|
||||
formControlName="rrn"
|
||||
matInput
|
||||
placeholder="Payment RRN"
|
||||
type="string"
|
||||
/>
|
||||
</mat-form-field>
|
||||
</div>
|
@ -1,42 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { filter } from 'rxjs/operators';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { PaymentsMainSearchFiltersService } from './payments-main-search-filters.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'cc-payments-main-search-filters',
|
||||
templateUrl: 'payments-main-search-filters.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [PaymentsMainSearchFiltersService],
|
||||
})
|
||||
export class PaymentsMainSearchFiltersComponent implements OnInit {
|
||||
@Input() initParams: SearchFiltersParams;
|
||||
@Output() valueChanges = new EventEmitter<SearchFiltersParams>();
|
||||
|
||||
shops$ = this.paymentsMainSearchFiltersService.shops$;
|
||||
form = this.paymentsMainSearchFiltersService.form;
|
||||
|
||||
constructor(private paymentsMainSearchFiltersService: PaymentsMainSearchFiltersService) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.paymentsMainSearchFiltersService.searchParamsChanges$
|
||||
.pipe(untilDestroyed(this))
|
||||
.subscribe((params) => this.valueChanges.emit(params));
|
||||
this.paymentsMainSearchFiltersService.init(this.initParams);
|
||||
this.form.controls.partyID.valueChanges
|
||||
.pipe(filter(Boolean), untilDestroyed(this))
|
||||
.subscribe((partyID: string) => {
|
||||
this.paymentsMainSearchFiltersService.getShops(partyID);
|
||||
});
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
|
||||
import { MerchantFieldModule } from '../../merchant-field';
|
||||
import { PaymentsMainSearchFiltersComponent } from './payments-main-search-filters.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatDatepickerModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatBadgeModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
FlexLayoutModule,
|
||||
MatSelectModule,
|
||||
MerchantFieldModule,
|
||||
],
|
||||
declarations: [PaymentsMainSearchFiltersComponent],
|
||||
exports: [PaymentsMainSearchFiltersComponent],
|
||||
})
|
||||
export class PaymentsMainSearchFiltersModule {}
|
@ -1,52 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
import { PartyID } from '@vality/domain-proto/payment_processing';
|
||||
import * as moment from 'moment';
|
||||
import { ReplaySubject, defer } from 'rxjs';
|
||||
import { debounceTime, filter, map, shareReplay, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { searchParamsToFormParams } from './search-params-to-form-params';
|
||||
|
||||
@Injectable()
|
||||
export class PaymentsMainSearchFiltersService {
|
||||
form = this.fb.group({
|
||||
fromTime: [moment().subtract(1, 'year').startOf('d'), Validators.required],
|
||||
toTime: [moment().endOf('d'), Validators.required],
|
||||
invoiceIDs: '',
|
||||
partyID: '',
|
||||
shopIDs: [],
|
||||
bin: ['', [Validators.pattern(/\d{6}$/), Validators.maxLength(6)]],
|
||||
pan: ['', [Validators.pattern(/\d{4}$/), Validators.maxLength(4)]],
|
||||
rrn: '',
|
||||
});
|
||||
|
||||
searchParamsChanges$ = this.form.valueChanges.pipe(
|
||||
debounceTime(600),
|
||||
filter(() => this.form.valid),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
shops$ = defer(() => this.getShops$).pipe(
|
||||
switchMap((partyID) => this.partyManagementService.Get(partyID)),
|
||||
map(({ shops }) => Array.from(shops.values())),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
private getShops$ = new ReplaySubject<string>();
|
||||
|
||||
constructor(
|
||||
private partyManagementService: PartyManagementService,
|
||||
private fb: UntypedFormBuilder
|
||||
) {}
|
||||
|
||||
getShops(partyID: PartyID) {
|
||||
this.getShops$.next(partyID);
|
||||
}
|
||||
|
||||
init(params: SearchFiltersParams) {
|
||||
this.form.patchValue(searchParamsToFormParams(params));
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import moment from 'moment';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { FormValue } from './form-value';
|
||||
|
||||
export const searchParamsToFormParams = (value: SearchFiltersParams): FormValue =>
|
||||
({
|
||||
...value,
|
||||
...(value.fromTime ? { fromTime: moment(value.fromTime) } : {}),
|
||||
...(value.toTime ? { toTime: moment(value.toTime) } : {}),
|
||||
} as any);
|
@ -1,6 +0,0 @@
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const countActiveFilters = (filters: SearchFiltersParams, formFields: string[]): number => {
|
||||
const paramsFields = Object.keys(filters);
|
||||
return paramsFields.reduce((acc, curr) => (formFields.includes(curr) ? ++acc : acc), 0) || null;
|
||||
};
|
@ -1,9 +0,0 @@
|
||||
import { toMinor } from '@cc/utils/to-minor';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const formParamsToSearchParams = (params: SearchFiltersParams): SearchFiltersParams => ({
|
||||
...params,
|
||||
...(params.paymentAmountFrom ? { paymentAmountFrom: toMinor(params.paymentAmountFrom) } : {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: toMinor(params.paymentAmountTo) } : {}),
|
||||
});
|
@ -1,2 +0,0 @@
|
||||
export * from './payments-other-search-filters.module';
|
||||
export * from './payments-other-search-filters.component';
|
@ -1,2 +0,0 @@
|
||||
export * from './other-filters-dialog.module';
|
||||
export * from './other-filters-dialog.component';
|
@ -1,78 +0,0 @@
|
||||
<v-dialog title="Other filters">
|
||||
<div [formGroup]="form" fxLayout="column" fxLayoutGap="24px">
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="payerEmail" matInput placeholder="Payer email" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="terminalID" matInput placeholder="Terminal ID" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="providerID" matInput placeholder="Provider ID" />
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentStatus" placeholder="Payment Status">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let s of paymentStatuses" [value]="s.value">
|
||||
{{ s.key }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentMethod" placeholder="Payment Method">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let pm of paymentMethods" [value]="pm.value">
|
||||
{{ pm.key }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="tokenProvider" placeholder="Token Provider">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let p of tokenProviders$ | async" [value]="p.ref.id">
|
||||
{{ p.data.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-form-field>
|
||||
<mat-select formControlName="paymentSystem" placeholder="Payment System">
|
||||
<mat-option [value]="null">any</mat-option>
|
||||
<mat-option *ngFor="let ps of paymentSystems$ | async" [value]="ps.ref.id">
|
||||
{{ ps.data.name }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Domain Revision</h2>
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="domainRevisionFrom" matInput placeholder="From" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="domainRevisionTo" matInput placeholder="To" />
|
||||
<mat-hint *ngIf="currentDomainVersion$ | async as version"
|
||||
>Latest: {{ version }}</mat-hint
|
||||
>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<mat-divider></mat-divider>
|
||||
<h2 class="mat-title">Payment Amount</h2>
|
||||
<div fxLayout fxLayoutGap="16px">
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="paymentAmountFrom" matInput placeholder="From" />
|
||||
</mat-form-field>
|
||||
<mat-form-field fxFlex>
|
||||
<input formControlName="paymentAmountTo" matInput placeholder="To" />
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
||||
<v-dialog-actions>
|
||||
<button [disabled]="form.invalid" color="primary" mat-button (click)="save()">Save</button>
|
||||
</v-dialog-actions>
|
||||
</v-dialog>
|
@ -1,43 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, OnInit, Injector } from '@angular/core';
|
||||
import { magista } from '@vality/magista-proto';
|
||||
import { DialogSuperclass } from '@vality/ng-core';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/deprecated-damsel';
|
||||
|
||||
import { getEnumKeyValues } from '../../../../../../utils';
|
||||
import { SearchFiltersParams } from '../../search-filters-params';
|
||||
import { OtherFiltersDialogService } from './other-filters-dialog.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: 'other-filters-dialog.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [OtherFiltersDialogService],
|
||||
})
|
||||
export class OtherFiltersDialogComponent
|
||||
extends DialogSuperclass<OtherFiltersDialogComponent, SearchFiltersParams, SearchFiltersParams>
|
||||
implements OnInit
|
||||
{
|
||||
paymentStatuses = getEnumKeyValues(magista.InvoicePaymentStatus);
|
||||
paymentMethods = getEnumKeyValues(magista.PaymentToolType);
|
||||
tokenProviders$ = this.domainStoreService.getObjects('payment_token');
|
||||
paymentSystems$ = this.domainStoreService.getObjects('payment_system');
|
||||
|
||||
currentDomainVersion$ = this.paymentsOtherSearchFiltersService.currentDomainVersion$;
|
||||
form = this.paymentsOtherSearchFiltersService.form;
|
||||
|
||||
constructor(
|
||||
injector: Injector,
|
||||
private paymentsOtherSearchFiltersService: OtherFiltersDialogService,
|
||||
private domainStoreService: DomainStoreService
|
||||
) {
|
||||
super(injector);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.form.patchValue(this.dialogData);
|
||||
}
|
||||
|
||||
save() {
|
||||
this.closeWithSuccess(this.form.value);
|
||||
}
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { DialogModule } from '@vality/ng-core';
|
||||
|
||||
import { OtherFiltersDialogComponent } from './other-filters-dialog.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatDatepickerModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatBadgeModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
FlexLayoutModule,
|
||||
MatSelectModule,
|
||||
DialogModule,
|
||||
],
|
||||
declarations: [OtherFiltersDialogComponent],
|
||||
exports: [OtherFiltersDialogComponent],
|
||||
})
|
||||
export class OtherFiltersDialogModule {}
|
@ -1,25 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UntypedFormBuilder, Validators } from '@angular/forms';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/deprecated-damsel';
|
||||
|
||||
@Injectable()
|
||||
export class OtherFiltersDialogService {
|
||||
currentDomainVersion$ = this.domainStoreService.version$;
|
||||
|
||||
form = this.fb.group({
|
||||
payerEmail: ['', [Validators.email]],
|
||||
terminalID: '',
|
||||
providerID: '',
|
||||
paymentStatus: null,
|
||||
domainRevisionFrom: '',
|
||||
domainRevisionTo: '',
|
||||
paymentAmountFrom: '',
|
||||
paymentAmountTo: '',
|
||||
paymentMethod: null,
|
||||
tokenProvider: null,
|
||||
paymentSystem: null,
|
||||
});
|
||||
|
||||
constructor(private fb: UntypedFormBuilder, private domainStoreService: DomainStoreService) {}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<button
|
||||
[matBadge]="count$ | async"
|
||||
class="other-filters-button"
|
||||
mat-button
|
||||
matBadgeColor="accent"
|
||||
matBadgePosition="after"
|
||||
(click)="openOtherFiltersDialog()"
|
||||
>
|
||||
Other filters
|
||||
</button>
|
@ -1,38 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
Output,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { PaymentsOtherSearchFiltersService } from './payments-other-search-filters.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payments-other-search-filters',
|
||||
templateUrl: 'payments-other-search-filters.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
providers: [PaymentsOtherSearchFiltersService],
|
||||
})
|
||||
export class PaymentsOtherSearchFiltersComponent implements OnInit {
|
||||
@Input() initParams: SearchFiltersParams;
|
||||
@Output() valueChanges = new EventEmitter<SearchFiltersParams>();
|
||||
|
||||
count$ = this.paymentsOtherSearchFiltersService.filtersCount$;
|
||||
|
||||
private searchParamsChanges$ = this.paymentsOtherSearchFiltersService.searchParamsChanges$;
|
||||
|
||||
constructor(private paymentsOtherSearchFiltersService: PaymentsOtherSearchFiltersService) {
|
||||
this.searchParamsChanges$.subscribe((params) => this.valueChanges.emit(params));
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.paymentsOtherSearchFiltersService.init(this.initParams);
|
||||
}
|
||||
|
||||
openOtherFiltersDialog() {
|
||||
this.paymentsOtherSearchFiltersService.openOtherFiltersDialog();
|
||||
}
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatDatepickerModule } from '@angular/material/datepicker';
|
||||
import { MatDialogModule } from '@angular/material/dialog';
|
||||
import { MatDividerModule } from '@angular/material/divider';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
|
||||
import { OtherFiltersDialogModule } from './other-filters-dialog';
|
||||
import { PaymentsOtherSearchFiltersComponent } from './payments-other-search-filters.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatDatepickerModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatButtonModule,
|
||||
MatBadgeModule,
|
||||
MatDialogModule,
|
||||
MatDividerModule,
|
||||
FlexLayoutModule,
|
||||
OtherFiltersDialogModule,
|
||||
],
|
||||
declarations: [PaymentsOtherSearchFiltersComponent],
|
||||
exports: [PaymentsOtherSearchFiltersComponent],
|
||||
})
|
||||
export class PaymentsOtherSearchFiltersModule {}
|
@ -1,62 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { DialogService, DialogResponseStatus } from '@vality/ng-core';
|
||||
import { ReplaySubject } from 'rxjs';
|
||||
import { filter, map, shareReplay, switchMap, first } from 'rxjs/operators';
|
||||
|
||||
import { removeEmptyProperties } from '@cc/utils/remove-empty-properties';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
import { formParamsToSearchParams } from './form-params-to-search-params';
|
||||
import { OtherFiltersDialogComponent } from './other-filters-dialog';
|
||||
import { searchParamsToFormParams } from './search-params-to-form-params';
|
||||
import { toFiltersCount } from './to-filters-count';
|
||||
|
||||
@UntilDestroy()
|
||||
@Injectable()
|
||||
export class PaymentsOtherSearchFiltersService {
|
||||
private formParams = new ReplaySubject<SearchFiltersParams>(1);
|
||||
|
||||
private countableKeys = [
|
||||
'payerEmail',
|
||||
'terminalID',
|
||||
'providerID',
|
||||
'paymentStatus',
|
||||
'domainRevisionFrom',
|
||||
'domainRevisionTo',
|
||||
'paymentAmountFrom',
|
||||
'paymentAmountTo',
|
||||
'paymentMethod',
|
||||
'tokenProvider',
|
||||
'paymentSystem',
|
||||
];
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
searchParamsChanges$ = this.formParams.pipe(map(formParamsToSearchParams), shareReplay(1));
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/member-ordering
|
||||
filtersCount$ = this.searchParamsChanges$.pipe(
|
||||
map(removeEmptyProperties),
|
||||
map(toFiltersCount(this.countableKeys)),
|
||||
shareReplay(1)
|
||||
);
|
||||
|
||||
constructor(private dialogService: DialogService) {}
|
||||
|
||||
init(params: SearchFiltersParams) {
|
||||
this.formParams.next(searchParamsToFormParams(params));
|
||||
}
|
||||
|
||||
openOtherFiltersDialog() {
|
||||
this.formParams
|
||||
.pipe(
|
||||
first(),
|
||||
switchMap((data) =>
|
||||
this.dialogService.open(OtherFiltersDialogComponent, data).afterClosed()
|
||||
),
|
||||
filter(({ status }) => status === DialogResponseStatus.Success),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
.subscribe(({ data }) => this.formParams.next(data));
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
import { toMajor } from '@cc/utils/to-major';
|
||||
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const searchParamsToFormParams = (params: SearchFiltersParams): SearchFiltersParams => ({
|
||||
...params,
|
||||
...(params.paymentAmountFrom ? { paymentAmountFrom: toMajor(params.paymentAmountFrom) } : {}),
|
||||
...(params.paymentAmountTo ? { paymentAmountTo: toMajor(params.paymentAmountTo) } : {}),
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
import { SearchFiltersParams } from '../search-filters-params';
|
||||
|
||||
export const toFiltersCount =
|
||||
(keys: string[]) =>
|
||||
(p: Partial<SearchFiltersParams>): number =>
|
||||
Object.keys(p).filter((k) => keys.includes(k)).length || null;
|
@ -1,23 +0,0 @@
|
||||
import { InvoicePaymentStatus, PaymentToolType } from '@vality/magista-proto/magista';
|
||||
|
||||
export interface SearchFiltersParams {
|
||||
partyID?: string;
|
||||
fromTime?: string;
|
||||
toTime?: string;
|
||||
invoiceIDs?: string;
|
||||
shopIDs?: string[];
|
||||
payerEmail?: string;
|
||||
terminalID?: string;
|
||||
providerID?: string;
|
||||
rrn?: string;
|
||||
paymentMethod?: PaymentToolType;
|
||||
paymentSystem?: string;
|
||||
tokenProvider?: string;
|
||||
bin?: string;
|
||||
pan?: string;
|
||||
domainRevisionFrom?: number;
|
||||
domainRevisionTo?: number;
|
||||
paymentAmountFrom?: number;
|
||||
paymentAmountTo?: number;
|
||||
paymentStatus?: InvoicePaymentStatus;
|
||||
}
|
@ -1,83 +0,0 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import { cleanPrimitiveProps, clean, splitBySeparators } from '@vality/ng-core';
|
||||
import * as moment from 'moment';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
import { MerchantStatisticsService } from '@cc/app/api/magista';
|
||||
import { FetchResult, PartialFetcher } from '@cc/app/shared/services';
|
||||
|
||||
import { SearchFiltersParams } from '../payments-search-filters';
|
||||
|
||||
const SEARCH_LIMIT = 1000;
|
||||
|
||||
@Injectable()
|
||||
export class FetchPaymentsService extends PartialFetcher<StatPayment, SearchFiltersParams> {
|
||||
constructor(private merchantStatisticsService: MerchantStatisticsService) {
|
||||
super();
|
||||
}
|
||||
|
||||
protected fetch(
|
||||
params: SearchFiltersParams,
|
||||
continuationToken: string
|
||||
): Observable<FetchResult<StatPayment>> {
|
||||
const {
|
||||
partyID,
|
||||
fromTime,
|
||||
toTime,
|
||||
invoiceIDs,
|
||||
shopIDs,
|
||||
payerEmail,
|
||||
terminalID,
|
||||
providerID,
|
||||
rrn,
|
||||
paymentMethod,
|
||||
paymentSystem,
|
||||
tokenProvider,
|
||||
bin,
|
||||
pan,
|
||||
domainRevisionFrom,
|
||||
domainRevisionTo,
|
||||
paymentAmountFrom,
|
||||
paymentAmountTo,
|
||||
paymentStatus,
|
||||
} = params;
|
||||
return this.merchantStatisticsService
|
||||
.SearchPayments(
|
||||
cleanPrimitiveProps({
|
||||
common_search_query_params: clean({
|
||||
from_time: moment(fromTime).utc().format(),
|
||||
to_time: moment(toTime).utc().format(),
|
||||
limit: SEARCH_LIMIT,
|
||||
continuation_token: continuationToken,
|
||||
party_id: partyID,
|
||||
shop_ids: shopIDs,
|
||||
}),
|
||||
invoice_ids: clean(splitBySeparators(invoiceIDs), true),
|
||||
payment_params: clean({
|
||||
payment_status: paymentStatus,
|
||||
payment_tool: paymentMethod,
|
||||
payment_email: payerEmail,
|
||||
payment_first6: bin,
|
||||
payment_system: { id: paymentSystem },
|
||||
payment_last4: pan,
|
||||
payment_provider_id: providerID,
|
||||
payment_terminal_id: terminalID,
|
||||
from_payment_domain_revision: domainRevisionFrom,
|
||||
to_payment_domain_revision: domainRevisionTo,
|
||||
payment_rrn: rrn,
|
||||
payment_amount_from: paymentAmountFrom,
|
||||
payment_amount_to: paymentAmountTo,
|
||||
payment_token_provider: { id: tokenProvider },
|
||||
}),
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
map(({ payments, continuation_token }) => ({
|
||||
result: payments,
|
||||
continuationToken: continuation_token,
|
||||
}))
|
||||
);
|
||||
}
|
||||
}
|
@ -1 +0,0 @@
|
||||
export * from './payments-searcher.module';
|
@ -1,51 +0,0 @@
|
||||
<div fxLayout="column" fxLayoutGap="24px">
|
||||
<mat-card>
|
||||
<mat-card-content>
|
||||
<cc-payments-main-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-main-search-filters>
|
||||
</mat-card-content>
|
||||
<mat-card-footer *ngIf="doAction$ | async">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</mat-card-footer>
|
||||
</mat-card>
|
||||
<v-actions>
|
||||
<button mat-button (click)="searchParamsChanges()">Update</button>
|
||||
<cc-payments-other-search-filters
|
||||
[initParams]="initSearchParams"
|
||||
(valueChanges)="searchParamsChanges($event)"
|
||||
></cc-payments-other-search-filters>
|
||||
<button
|
||||
[disabled]="!selectedPayments?.length"
|
||||
color="primary"
|
||||
mat-button
|
||||
(click)="createPaymentAdjustment()"
|
||||
>
|
||||
Create payment adjustment{{
|
||||
selectedPayments?.length ? ' (' + selectedPayments?.length + ')' : ''
|
||||
}}
|
||||
</button>
|
||||
</v-actions>
|
||||
<cc-empty-search-result
|
||||
*ngIf="!(doAction$ | async) && !(payments$ | async)?.length"
|
||||
label="Payments not found"
|
||||
></cc-empty-search-result>
|
||||
<mat-card *ngIf="(payments$ | async)?.length > 0" fxLayout="column" fxLayoutGap="16px">
|
||||
<cc-payments-table
|
||||
[payments]="payments$ | async"
|
||||
[selected]="selectedPayments"
|
||||
(menuItemSelected$)="paymentMenuItemSelected($event)"
|
||||
(selected$)="selectedPayments = $event.selected"
|
||||
></cc-payments-table>
|
||||
<button
|
||||
*ngIf="hasMore$ | async"
|
||||
[disabled]="doAction$ | async"
|
||||
fxFlex="100"
|
||||
mat-button
|
||||
(click)="fetchMore()"
|
||||
>
|
||||
{{ (doAction$ | async) ? 'Loading...' : 'Show more' }}
|
||||
</button>
|
||||
</mat-card>
|
||||
</div>
|
@ -1,85 +0,0 @@
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
} from '@angular/core';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { untilDestroyed, UntilDestroy } from '@ngneat/until-destroy';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
import { DialogService, DialogResponseStatus } from '@vality/ng-core';
|
||||
import { BehaviorSubject, skip } from 'rxjs';
|
||||
|
||||
import { SearchFiltersParams } from '../payments-search-filters';
|
||||
import { PaymentActions, PaymentMenuItemEvent } from '../payments-table';
|
||||
import { CreatePaymentAdjustmentComponent } from './create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { FetchPaymentsService } from './fetch-payments.service';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
selector: 'cc-payments-searcher',
|
||||
templateUrl: 'payments-searcher.component.html',
|
||||
providers: [FetchPaymentsService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentsSearcherComponent implements OnInit {
|
||||
@Input() initSearchParams: SearchFiltersParams;
|
||||
@Output() searchParamsChanged: EventEmitter<SearchFiltersParams> = new EventEmitter();
|
||||
@Output() paymentEventFired: EventEmitter<PaymentMenuItemEvent> = new EventEmitter();
|
||||
|
||||
doAction$ = this.fetchPaymentsService.doAction$;
|
||||
payments$ = this.fetchPaymentsService.searchResult$;
|
||||
hasMore$ = this.fetchPaymentsService.hasMore$;
|
||||
searchParamsChange$ = new BehaviorSubject<SearchFiltersParams>({});
|
||||
selectedPayments: StatPayment[];
|
||||
|
||||
constructor(
|
||||
private fetchPaymentsService: FetchPaymentsService,
|
||||
private snackBar: MatSnackBar,
|
||||
private dialogService: DialogService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.searchParamsChange$.pipe(skip(1), untilDestroyed(this)).subscribe((params) => {
|
||||
this.fetchPaymentsService.search(params);
|
||||
this.searchParamsChanged.emit(params);
|
||||
});
|
||||
this.fetchPaymentsService.errors$.subscribe((e) =>
|
||||
this.snackBar.open(`An error occurred while search payments (${String(e)})`, 'OK')
|
||||
);
|
||||
}
|
||||
|
||||
fetchMore() {
|
||||
this.fetchPaymentsService.fetchMore();
|
||||
}
|
||||
|
||||
searchParamsChanges(params: SearchFiltersParams = {}) {
|
||||
this.searchParamsChange$.next({ ...this.searchParamsChange$.value, ...params });
|
||||
}
|
||||
|
||||
paymentMenuItemSelected(paymentMenuItemEvent: PaymentMenuItemEvent) {
|
||||
switch (paymentMenuItemEvent.action) {
|
||||
case PaymentActions.NavigateToPayment:
|
||||
this.paymentEventFired.emit(paymentMenuItemEvent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
createPaymentAdjustment() {
|
||||
this.dialogService
|
||||
.open(CreatePaymentAdjustmentComponent, {
|
||||
payments: this.selectedPayments,
|
||||
})
|
||||
.afterClosed()
|
||||
.subscribe((res) => {
|
||||
if (res.status === DialogResponseStatus.Success) {
|
||||
this.searchParamsChanges();
|
||||
this.selectedPayments = [];
|
||||
} else if (res.data?.withError?.length) {
|
||||
this.selectedPayments = res.data.withError.map((w) => w.payment);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexModule } from '@angular/flex-layout';
|
||||
import { ReactiveFormsModule } from '@angular/forms';
|
||||
import { MatBadgeModule } from '@angular/material/badge';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatCardModule } from '@angular/material/card';
|
||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatInputModule } from '@angular/material/input';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { ActionsModule, DialogModule } from '@vality/ng-core';
|
||||
|
||||
import { EmptySearchResultModule } from '@cc/components/empty-search-result';
|
||||
|
||||
import { MetadataFormModule } from '../metadata-form';
|
||||
import {
|
||||
PaymentsMainSearchFiltersModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
} from '../payments-search-filters';
|
||||
import { PaymentsTableModule } from '../payments-table';
|
||||
import { StatusModule } from '../status';
|
||||
import { CreatePaymentAdjustmentComponent } from './create-payment-adjustment/create-payment-adjustment.component';
|
||||
import { PaymentsSearcherComponent } from './payments-searcher.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
FlexModule,
|
||||
MatCardModule,
|
||||
MatProgressBarModule,
|
||||
CommonModule,
|
||||
MatButtonModule,
|
||||
ReactiveFormsModule,
|
||||
MatFormFieldModule,
|
||||
MatInputModule,
|
||||
MatTableModule,
|
||||
MatMenuModule,
|
||||
MatIconModule,
|
||||
PaymentsMainSearchFiltersModule,
|
||||
StatusModule,
|
||||
PaymentsTableModule,
|
||||
MatBadgeModule,
|
||||
PaymentsOtherSearchFiltersModule,
|
||||
EmptySearchResultModule,
|
||||
ActionsModule,
|
||||
DialogModule,
|
||||
MetadataFormModule,
|
||||
],
|
||||
declarations: [PaymentsSearcherComponent, CreatePaymentAdjustmentComponent],
|
||||
exports: [PaymentsSearcherComponent],
|
||||
})
|
||||
export class PaymentsSearcherModule {}
|
@ -1,3 +0,0 @@
|
||||
export * from './payments-table.module';
|
||||
export * from './payment-actions';
|
||||
export * from './payment-menu-item-event';
|
@ -1,16 +0,0 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
import { PaymentActions } from './payment-actions';
|
||||
|
||||
const PAYMENT_ACTION_NAMES: { [N in PaymentActions]: string } = {
|
||||
[PaymentActions.NavigateToPayment]: 'Details',
|
||||
};
|
||||
|
||||
@Pipe({
|
||||
name: 'ccPaymentActions',
|
||||
})
|
||||
export class PaymentActionsPipe implements PipeTransform {
|
||||
transform(action: string): string {
|
||||
return PAYMENT_ACTION_NAMES[action] || action;
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export enum PaymentActions {
|
||||
NavigateToPayment = 'NavigateToPayment',
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
import { InvoiceID, InvoicePaymentID, PartyID } from '@vality/domain-proto/domain';
|
||||
|
||||
import { PaymentActions } from './payment-actions';
|
||||
|
||||
export interface PaymentMenuItemEvent {
|
||||
action: PaymentActions;
|
||||
paymentID: InvoicePaymentID;
|
||||
invoiceID: InvoiceID;
|
||||
partyID: PartyID;
|
||||
}
|
@ -1,90 +0,0 @@
|
||||
<table *ngIf="cols" [dataSource]="payments" mat-table>
|
||||
<cc-select-column
|
||||
[dataSource]="payments"
|
||||
sticky
|
||||
(changed)="selection = $event; selected$.emit($event)"
|
||||
></cc-select-column>
|
||||
|
||||
<ng-container matColumnDef="revision">
|
||||
<th *matHeaderCellDef mat-header-cell>Revision</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.domain_revision }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th *matHeaderCellDef mat-header-cell>Amount</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.amount | ccFormatAmount }}
|
||||
{{ payment.currency_symbolic_code | ccCurrency }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th *matHeaderCellDef mat-header-cell>Status</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
<cc-status [color]="payment.status | toStatus | toPaymentColor">{{
|
||||
payment.status | toStatus
|
||||
}}</cc-status>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="createdAt">
|
||||
<th *matHeaderCellDef mat-header-cell>Created At</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.created_at | date : 'dd.MM.yyyy HH:mm:ss' }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="shop">
|
||||
<th *matHeaderCellDef mat-header-cell>Shop</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
<div>{{ payment.shop_id | shopName : payment.owner_id }}</div>
|
||||
<div class="mat-caption mat-secondary-text">{{ payment.shop_id }}</div>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="party">
|
||||
<th *matHeaderCellDef mat-header-cell>Party</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.owner_id }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="invoice">
|
||||
<th *matHeaderCellDef mat-header-cell>Invoice</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.invoice_id }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="terminal_id">
|
||||
<th *matHeaderCellDef mat-header-cell>Terminal</th>
|
||||
<td *matCellDef="let payment" mat-cell>
|
||||
{{ payment.terminal_id.id }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="actions" stickyEnd>
|
||||
<th *matHeaderCellDef class="action-cell" mat-header-cell></th>
|
||||
<td *matCellDef="let payment" class="action-cell" mat-cell>
|
||||
<button [matMenuTriggerFor]="menu" mat-icon-button>
|
||||
<mat-icon>more_vert</mat-icon>
|
||||
</button>
|
||||
<mat-menu #menu="matMenu">
|
||||
<button
|
||||
*ngFor="let action of paymentActions"
|
||||
mat-menu-item
|
||||
(click)="
|
||||
menuItemSelected(action, payment.id, payment.invoice_id, payment.owner_id)
|
||||
"
|
||||
>
|
||||
{{ action | ccPaymentActions }}
|
||||
</button>
|
||||
</mat-menu>
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr *matHeaderRowDef="cols.list; sticky: true" mat-header-row></tr>
|
||||
<tr *matRowDef="let row; columns: cols.list" mat-row></tr>
|
||||
</table>
|
@ -1,17 +0,0 @@
|
||||
:host {
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
|
||||
td,
|
||||
th {
|
||||
white-space: nowrap;
|
||||
padding: 0 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.action-cell {
|
||||
width: 8px;
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { InvoiceID, InvoicePaymentID, PartyID } from '@vality/domain-proto/domain';
|
||||
import { StatPayment } from '@vality/magista-proto/magista';
|
||||
|
||||
import { Columns, SELECT_COLUMN_NAME } from '../../../../components/table';
|
||||
import { PaymentActions } from './payment-actions';
|
||||
import { PaymentMenuItemEvent } from './payment-menu-item-event';
|
||||
|
||||
@Component({
|
||||
selector: 'cc-payments-table',
|
||||
templateUrl: 'payments-table.component.html',
|
||||
styleUrls: ['payments-table.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PaymentsTableComponent {
|
||||
@Input() payments: StatPayment[];
|
||||
@Input() set selected(selected: StatPayment[]) {
|
||||
this.selection.clear();
|
||||
if (selected?.length) this.selection.select(...selected);
|
||||
}
|
||||
@Output() menuItemSelected$ = new EventEmitter<PaymentMenuItemEvent>();
|
||||
@Output() selected$ = new EventEmitter<SelectionModel<StatPayment>>();
|
||||
|
||||
paymentActions = Object.keys(PaymentActions);
|
||||
cols = new Columns(
|
||||
SELECT_COLUMN_NAME,
|
||||
'amount',
|
||||
'status',
|
||||
'createdAt',
|
||||
'shop',
|
||||
'revision',
|
||||
'invoice',
|
||||
'party',
|
||||
'terminal_id',
|
||||
'actions'
|
||||
);
|
||||
selection = new SelectionModel<StatPayment>();
|
||||
|
||||
menuItemSelected(
|
||||
action: string,
|
||||
paymentID: InvoicePaymentID,
|
||||
invoiceID: InvoiceID,
|
||||
partyID: PartyID
|
||||
) {
|
||||
switch (action) {
|
||||
case PaymentActions.NavigateToPayment:
|
||||
this.menuItemSelected$.emit({ action, paymentID, invoiceID, partyID });
|
||||
break;
|
||||
default:
|
||||
console.error('Wrong payment action type.');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FlexModule } from '@angular/flex-layout';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatMenuModule } from '@angular/material/menu';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
|
||||
import { TableModule } from '../../../../components/table';
|
||||
import { ApiModelPipesModule, CommonPipesModule } from '../../pipes';
|
||||
import { StatusModule } from '../status';
|
||||
import { PaymentActionsPipe } from './payment-actions.pipe';
|
||||
import { PaymentsTableComponent } from './payments-table.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatTableModule,
|
||||
FlexModule,
|
||||
StatusModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatMenuModule,
|
||||
CommonPipesModule,
|
||||
ApiModelPipesModule,
|
||||
TableModule,
|
||||
],
|
||||
declarations: [PaymentsTableComponent, PaymentActionsPipe],
|
||||
exports: [PaymentsTableComponent],
|
||||
})
|
||||
export class PaymentsTableModule {}
|
@ -1,11 +1,6 @@
|
||||
<mat-form-field>
|
||||
<mat-label>{{ multiple ? 'Shops' : 'Shop' }}</mat-label>
|
||||
<mat-select
|
||||
[disabled]="!partyId"
|
||||
[formControl]="control"
|
||||
[multiple]="multiple"
|
||||
[required]="required"
|
||||
>
|
||||
<mat-select [formControl]="control" [multiple]="multiple" [required]="required">
|
||||
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
||||
{{ shop.details.name }}
|
||||
</mat-option>
|
||||
|
@ -1,3 +1,8 @@
|
||||
:host {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
mat-form-field {
|
||||
width: 100%;
|
||||
}
|
||||
|
@ -1,15 +1,19 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||
import { FormControl } from '@angular/forms';
|
||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||
import { Shop } from '@vality/domain-proto/domain';
|
||||
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
||||
import {
|
||||
createControlProviders,
|
||||
FormControlSuperclass,
|
||||
setDisabled,
|
||||
isEmpty,
|
||||
} from '@vality/ng-core';
|
||||
import { coerceBoolean } from 'coerce-property';
|
||||
import { BehaviorSubject, defer, of } from 'rxjs';
|
||||
import { filter, map, share, switchMap } from 'rxjs/operators';
|
||||
|
||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||
import { ComponentChanges } from '@cc/app/shared/utils';
|
||||
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/forms';
|
||||
|
||||
@UntilDestroy()
|
||||
@Component({
|
||||
@ -20,7 +24,7 @@ import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/fo
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ShopFieldComponent<M extends boolean = boolean>
|
||||
extends ValidatedControlSuperclass<
|
||||
extends FormControlSuperclass<
|
||||
M extends true ? Shop[] : Shop,
|
||||
M extends true ? ShopID[] : ShopID
|
||||
>
|
||||
@ -30,7 +34,6 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
||||
@Input() @coerceBoolean multiple: M;
|
||||
@Input() @coerceBoolean required: boolean;
|
||||
|
||||
control = new FormControl() as FormControl<M extends true ? ShopID[] : ShopID>;
|
||||
shops$ = defer(() => this.partyId$).pipe(
|
||||
switchMap((partyId) =>
|
||||
partyId
|
||||
@ -48,10 +51,15 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
||||
super();
|
||||
}
|
||||
|
||||
setDisabledState(isDisabled: boolean) {
|
||||
super.setDisabledState(!this.partyId || isDisabled);
|
||||
}
|
||||
|
||||
ngOnChanges(changes: ComponentChanges<ShopFieldComponent>): void {
|
||||
super.ngOnChanges(changes);
|
||||
if (changes.partyId) {
|
||||
if (changes.partyId && this.partyId !== this.partyId$.value) {
|
||||
this.partyId$.next(changes.partyId.currentValue);
|
||||
setDisabled(this.control, !this.partyId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,7 +67,11 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
||||
this.shops$
|
||||
.pipe(
|
||||
filter(
|
||||
(shops) => this.control.value && !shops.find((s) => s.id === this.control.value)
|
||||
(shops) =>
|
||||
!isEmpty(this.control.value) &&
|
||||
(Array.isArray(this.control.value)
|
||||
? !this.control.value.every((v) => shops.some((s) => s.id === v))
|
||||
: !shops.some((s) => s.id === this.control.value))
|
||||
),
|
||||
untilDestroyed(this)
|
||||
)
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { getCurrencySymbol } from '@angular/common';
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Pipe({
|
||||
name: 'ccCurrency',
|
||||
})
|
||||
|
@ -4,6 +4,9 @@ import round from 'lodash-es/round';
|
||||
@Pipe({
|
||||
name: 'ccFormatAmount',
|
||||
})
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
export class FormatAmountPipe implements PipeTransform {
|
||||
public transform(input: number): number {
|
||||
const value = round(input / 100, 2);
|
||||
@ -11,6 +14,9 @@ export class FormatAmountPipe implements PipeTransform {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
function format(
|
||||
value: any,
|
||||
decimalLength: number,
|
||||
|
27
src/app/shared/services/amount-currency.service.ts
Normal file
27
src/app/shared/services/amount-currency.service.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { toMajorByExponent } from '@vality/ng-core';
|
||||
import { map, first } from 'rxjs/operators';
|
||||
|
||||
import { DomainStoreService } from '@cc/app/api/deprecated-damsel';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class AmountCurrencyService {
|
||||
constructor(private domainStoreService: DomainStoreService) {}
|
||||
|
||||
toMajor(amount: number, symbolicCode: string) {
|
||||
return this.getCurrency(symbolicCode).pipe(
|
||||
first(),
|
||||
map((currency) => toMajorByExponent(amount, currency.data.exponent))
|
||||
);
|
||||
}
|
||||
|
||||
getCurrency(symbolicCode: string) {
|
||||
return this.domainStoreService
|
||||
.getObjects('currency')
|
||||
.pipe(
|
||||
map((currencies) => currencies.find((c) => c.ref.symbolic_code === symbolicCode))
|
||||
);
|
||||
}
|
||||
}
|
@ -8,3 +8,4 @@ export * from './query-params';
|
||||
export * from './moment-utc-date-adapter';
|
||||
export * from './domain-metadata-form-extensions';
|
||||
export * from './domain-secret-service';
|
||||
export * from './amount-currency.service';
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { InjectionToken } from '@angular/core';
|
||||
import { MatDateFormats } from '@angular/material/core';
|
||||
import { DateRange } from '@angular/material/datepicker';
|
||||
import { DATE_QUERY_PARAMS_SERIALIZERS } from '@vality/ng-core';
|
||||
import { Moment } from 'moment';
|
||||
import * as moment from 'moment';
|
||||
|
||||
@ -34,6 +35,7 @@ export const DEFAULT_QUERY_PARAMS_SERIALIZERS: Serializer[] = [
|
||||
return (!start || moment.isMoment(start)) && (!end || moment.isMoment(end));
|
||||
},
|
||||
},
|
||||
...DATE_QUERY_PARAMS_SERIALIZERS,
|
||||
];
|
||||
|
||||
export const DEFAULT_MAT_DATE_FORMATS: MatDateFormats = {
|
||||
|
Loading…
Reference in New Issue
Block a user