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-browser-dynamic": "15.0.3",
|
||||||
"@angular/platform-server": "15.0.3",
|
"@angular/platform-server": "15.0.3",
|
||||||
"@angular/router": "15.0.3",
|
"@angular/router": "15.0.3",
|
||||||
"@ng-matero/extensions": "15.4.2",
|
|
||||||
"@ngneat/input-mask": "6.0.0",
|
"@ngneat/input-mask": "6.0.0",
|
||||||
"@ngneat/until-destroy": "9.2.2",
|
"@ngneat/until-destroy": "9.2.2",
|
||||||
"@s-libs/js-core": "15.0.0",
|
"@s-libs/ng-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",
|
|
||||||
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
||||||
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
||||||
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
||||||
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
||||||
"@vality/magista-proto": "2.0.1-cf0eff8.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/payout-manager-proto": "2.0.1-b079679.0",
|
||||||
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
||||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||||
@ -42,6 +38,7 @@
|
|||||||
"angular2-prettyjson": "3.0.1",
|
"angular2-prettyjson": "3.0.1",
|
||||||
"coerce-property": "15.0.1",
|
"coerce-property": "15.0.1",
|
||||||
"css-element-queries": "1.2.3",
|
"css-element-queries": "1.2.3",
|
||||||
|
"date-fns": "2.30.0",
|
||||||
"element-resize-detector": "1.2.4",
|
"element-resize-detector": "1.2.4",
|
||||||
"humanize-duration": "3.21.0",
|
"humanize-duration": "3.21.0",
|
||||||
"inputmask": "5.0.7",
|
"inputmask": "5.0.7",
|
||||||
@ -51,7 +48,7 @@
|
|||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
"monaco-editor": "0.21.2",
|
"monaco-editor": "0.21.2",
|
||||||
"ngx-mat-select-search": "7.0.1",
|
"ngx-mat-select-search": "7.0.1",
|
||||||
"rxjs": "7.5.4",
|
"rxjs": "7.8.1",
|
||||||
"short-uuid": "4.1.0",
|
"short-uuid": "4.1.0",
|
||||||
"tslib": "2.3.1",
|
"tslib": "2.3.1",
|
||||||
"utility-types": "3.10.0",
|
"utility-types": "3.10.0",
|
||||||
@ -4664,6 +4661,7 @@
|
|||||||
"node_modules/@s-libs/js-core": {
|
"node_modules/@s-libs/js-core": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@ -4674,6 +4672,7 @@
|
|||||||
"node_modules/@s-libs/micro-dash": {
|
"node_modules/@s-libs/micro-dash": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
@ -4697,6 +4696,7 @@
|
|||||||
"node_modules/@s-libs/rxjs-core": {
|
"node_modules/@s-libs/rxjs-core": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@ -5639,29 +5639,30 @@
|
|||||||
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
||||||
},
|
},
|
||||||
"node_modules/@vality/ng-core": {
|
"node_modules/@vality/ng-core": {
|
||||||
"version": "0.7.1-pr-22-ac52e74.0",
|
"version": "0.7.1-pr-22-ff78425.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ac52e74.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ff78425.0.tgz",
|
||||||
"integrity": "sha512-9BstLrgeI9Q3IIGHF75o+b4MkcaZrw9B3odUbGKNr8FSWLCONcCApPFANeKBjg2/ytoe+iX4UfHukY+xt7/o2g==",
|
"integrity": "sha512-NzGQLu2tAZFim0apE4gItGrE9YbbzKYFDs3wBQovmUhFom7zglcG8O8ohtyHGmFZTGfPoHGKTMkjzjtpiZah5g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@ng-matero/extensions": "^15.0.0",
|
||||||
"@s-libs/js-core": "^15.2.0",
|
"@s-libs/js-core": "^15.2.0",
|
||||||
"@s-libs/micro-dash": "^15.2.0",
|
"@s-libs/micro-dash": "^15.2.0",
|
||||||
"@s-libs/ng-core": "^15.2.0",
|
"@s-libs/ng-core": "^15.2.0",
|
||||||
"@s-libs/rxjs-core": "^15.2.0",
|
"@s-libs/rxjs-core": "^15.2.0",
|
||||||
"dinero.js": "^2.0.0-alpha.14",
|
"dinero.js": "^2.0.0-alpha.14",
|
||||||
|
"ng-let": "^15.0.2",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@angular/cdk": ">=15.0.0",
|
"@angular/cdk": "^15.0.0",
|
||||||
"@angular/common": ">=15.0.0",
|
"@angular/common": "^15.0.0",
|
||||||
"@angular/core": ">=15.0.0",
|
"@angular/core": "^15.0.0",
|
||||||
"@angular/material": ">=15.0.0",
|
"@angular/material": "^15.0.0",
|
||||||
"@ng-matero/extensions": ">=15.0.0",
|
"@ngneat/until-destroy": "^9.0.0",
|
||||||
"@ngneat/until-destroy": ">=9.0.0",
|
|
||||||
"@types/lodash-es": "^4.0.0",
|
"@types/lodash-es": "^4.0.0",
|
||||||
"coerce-property": ">=15.0.0",
|
"coerce-property": "^15.0.0",
|
||||||
"lodash-es": "^4.0.0",
|
"lodash-es": "^4.0.0",
|
||||||
"rxjs": ">=7.0.0",
|
"rxjs": "^7.0.0",
|
||||||
"utility-types": ">=3.0.0"
|
"utility-types": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vality/ng-core/node_modules/@s-libs/js-core": {
|
"node_modules/@vality/ng-core/node_modules/@s-libs/js-core": {
|
||||||
@ -9851,6 +9852,37 @@
|
|||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/date-format": {
|
||||||
"version": "4.0.11",
|
"version": "4.0.11",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -13087,14 +13119,6 @@
|
|||||||
"node": ">=8"
|
"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": {
|
"node_modules/inquirer/node_modules/string-width": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -15287,6 +15311,18 @@
|
|||||||
"version": "2.6.2",
|
"version": "2.6.2",
|
||||||
"license": "MIT"
|
"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": {
|
"node_modules/ng-packagr": {
|
||||||
"version": "15.0.3",
|
"version": "15.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -15460,14 +15496,6 @@
|
|||||||
"node": ">=10"
|
"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": {
|
"node_modules/ngx-build-plus": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -17828,8 +17856,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rxjs": {
|
"node_modules/rxjs": {
|
||||||
"version": "7.5.4",
|
"version": "7.8.1",
|
||||||
"license": "Apache-2.0",
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz",
|
||||||
|
"integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
@ -23916,12 +23945,14 @@
|
|||||||
},
|
},
|
||||||
"@s-libs/js-core": {
|
"@s-libs/js-core": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@s-libs/micro-dash": {
|
"@s-libs/micro-dash": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.0",
|
"tslib": "^2.3.0",
|
||||||
"utility-types": "^3.10.0"
|
"utility-types": "^3.10.0"
|
||||||
@ -23937,6 +23968,7 @@
|
|||||||
},
|
},
|
||||||
"@s-libs/rxjs-core": {
|
"@s-libs/rxjs-core": {
|
||||||
"version": "15.0.0",
|
"version": "15.0.0",
|
||||||
|
"peer": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
}
|
}
|
||||||
@ -24530,15 +24562,17 @@
|
|||||||
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
"integrity": "sha512-59ncaJpt7tXFLOq9KrDu4OgrDQr9vTQ3j30T0hjN+ZIsPBsE+lld/pGKASWLLQfwvTtvp9laAuKgQGX9GuvIiQ=="
|
||||||
},
|
},
|
||||||
"@vality/ng-core": {
|
"@vality/ng-core": {
|
||||||
"version": "0.7.1-pr-22-ac52e74.0",
|
"version": "0.7.1-pr-22-ff78425.0",
|
||||||
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ac52e74.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vality/ng-core/-/ng-core-0.7.1-pr-22-ff78425.0.tgz",
|
||||||
"integrity": "sha512-9BstLrgeI9Q3IIGHF75o+b4MkcaZrw9B3odUbGKNr8FSWLCONcCApPFANeKBjg2/ytoe+iX4UfHukY+xt7/o2g==",
|
"integrity": "sha512-NzGQLu2tAZFim0apE4gItGrE9YbbzKYFDs3wBQovmUhFom7zglcG8O8ohtyHGmFZTGfPoHGKTMkjzjtpiZah5g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
|
"@ng-matero/extensions": "^15.0.0",
|
||||||
"@s-libs/js-core": "^15.2.0",
|
"@s-libs/js-core": "^15.2.0",
|
||||||
"@s-libs/micro-dash": "^15.2.0",
|
"@s-libs/micro-dash": "^15.2.0",
|
||||||
"@s-libs/ng-core": "^15.2.0",
|
"@s-libs/ng-core": "^15.2.0",
|
||||||
"@s-libs/rxjs-core": "^15.2.0",
|
"@s-libs/rxjs-core": "^15.2.0",
|
||||||
"dinero.js": "^2.0.0-alpha.14",
|
"dinero.js": "^2.0.0-alpha.14",
|
||||||
|
"ng-let": "^15.0.2",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -27508,6 +27542,29 @@
|
|||||||
"cyclist": {
|
"cyclist": {
|
||||||
"version": "1.0.1"
|
"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": {
|
"date-format": {
|
||||||
"version": "4.0.11",
|
"version": "4.0.11",
|
||||||
"dev": true
|
"dev": true
|
||||||
@ -29614,13 +29671,6 @@
|
|||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"rxjs": {
|
|
||||||
"version": "7.5.5",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.1.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"string-width": {
|
"string-width": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -31022,6 +31072,14 @@
|
|||||||
"neo-async": {
|
"neo-async": {
|
||||||
"version": "2.6.2"
|
"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": {
|
"ng-packagr": {
|
||||||
"version": "15.0.3",
|
"version": "15.0.3",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
@ -31135,13 +31193,6 @@
|
|||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^2.0.1"
|
"brace-expansion": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"rxjs": {
|
|
||||||
"version": "7.6.0",
|
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
|
||||||
"tslib": "^2.1.0"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -32642,7 +32693,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rxjs": {
|
"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": {
|
"requires": {
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
|
11
package.json
11
package.json
@ -31,19 +31,15 @@
|
|||||||
"@angular/platform-browser-dynamic": "15.0.3",
|
"@angular/platform-browser-dynamic": "15.0.3",
|
||||||
"@angular/platform-server": "15.0.3",
|
"@angular/platform-server": "15.0.3",
|
||||||
"@angular/router": "15.0.3",
|
"@angular/router": "15.0.3",
|
||||||
"@ng-matero/extensions": "15.4.2",
|
|
||||||
"@ngneat/input-mask": "6.0.0",
|
"@ngneat/input-mask": "6.0.0",
|
||||||
"@ngneat/until-destroy": "9.2.2",
|
"@ngneat/until-destroy": "9.2.2",
|
||||||
"@s-libs/js-core": "15.0.0",
|
"@s-libs/ng-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",
|
|
||||||
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
"@vality/deanonimus-proto": "2.0.1-2a3d5ad.0",
|
||||||
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
"@vality/domain-proto": "2.0.1-bfedcb9.0",
|
||||||
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
"@vality/dominant-cache-proto": "2.0.1-99f38c9.0",
|
||||||
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
"@vality/fistful-proto": "2.0.1-4ff4ea3.0",
|
||||||
"@vality/magista-proto": "2.0.1-cf0eff8.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/payout-manager-proto": "2.0.1-b079679.0",
|
||||||
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
"@vality/repairer-proto": "2.0.1-8f7973d.0",
|
||||||
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
"@vality/thrift-ts": "2.4.1-8ad5123.0",
|
||||||
@ -51,6 +47,7 @@
|
|||||||
"angular2-prettyjson": "3.0.1",
|
"angular2-prettyjson": "3.0.1",
|
||||||
"coerce-property": "15.0.1",
|
"coerce-property": "15.0.1",
|
||||||
"css-element-queries": "1.2.3",
|
"css-element-queries": "1.2.3",
|
||||||
|
"date-fns": "2.30.0",
|
||||||
"element-resize-detector": "1.2.4",
|
"element-resize-detector": "1.2.4",
|
||||||
"humanize-duration": "3.21.0",
|
"humanize-duration": "3.21.0",
|
||||||
"inputmask": "5.0.7",
|
"inputmask": "5.0.7",
|
||||||
@ -60,7 +57,7 @@
|
|||||||
"moment": "2.29.4",
|
"moment": "2.29.4",
|
||||||
"monaco-editor": "0.21.2",
|
"monaco-editor": "0.21.2",
|
||||||
"ngx-mat-select-search": "7.0.1",
|
"ngx-mat-select-search": "7.0.1",
|
||||||
"rxjs": "7.5.4",
|
"rxjs": "7.8.1",
|
||||||
"short-uuid": "4.1.0",
|
"short-uuid": "4.1.0",
|
||||||
"tslib": "2.3.1",
|
"tslib": "2.3.1",
|
||||||
"utility-types": "3.10.0",
|
"utility-types": "3.10.0",
|
||||||
|
@ -11,7 +11,7 @@ import { PartyManagementService } from '@cc/app/api/payment-processing';
|
|||||||
export class PartiesStoreService {
|
export class PartiesStoreService {
|
||||||
constructor(private partyManagementService: PartyManagementService) {}
|
constructor(private partyManagementService: PartyManagementService) {}
|
||||||
|
|
||||||
@MemoizeExpiring(30_000)
|
@MemoizeExpiring(5 * 60_000)
|
||||||
get(partyId: PartyID) {
|
get(partyId: PartyID) {
|
||||||
return this.partyManagementService
|
return this.partyManagementService
|
||||||
.Get(partyId)
|
.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 DEPOSITS_ROUTING_CONFIG } from './sections/deposits/routing-config';
|
||||||
import { ROUTING_CONFIG as DOMAIN_ROUTING_CONFIG } from './sections/domain/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 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 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 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 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 SOURCES_ROUTING_CONFIG } from './sections/sources/routing-config';
|
||||||
import { ROUTING_CONFIG as WALLETS_ROUTING_CONFIG } from './sections/wallets/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';
|
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 { LOCALE_ID, NgModule, Injector } from '@angular/core';
|
||||||
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
|
import { MAT_MOMENT_DATE_ADAPTER_OPTIONS } from '@angular/material-moment-adapter';
|
||||||
import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER } from '@angular/material/autocomplete';
|
import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY_FACTORY_PROVIDER } from '@angular/material/autocomplete';
|
||||||
@ -39,6 +41,8 @@ import {
|
|||||||
SMALL_SEARCH_LIMIT,
|
SMALL_SEARCH_LIMIT,
|
||||||
} from './tokens';
|
} from './tokens';
|
||||||
|
|
||||||
|
registerLocaleData(localeRu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For use in specific locations (for example, questionary PDF document)
|
* 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_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } },
|
||||||
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS },
|
{ provide: MAT_DATE_FORMATS, useValue: DEFAULT_MAT_DATE_FORMATS },
|
||||||
{ provide: DateAdapter, useClass: MomentUtcDateAdapter, deps: [MAT_DATE_LOCALE] },
|
{ provide: DateAdapter, useClass: MomentUtcDateAdapter, deps: [MAT_DATE_LOCALE] },
|
||||||
{ provide: MAT_DATE_LOCALE, useValue: 'ru' },
|
{ provide: MAT_DATE_LOCALE, useValue: 'en-GB' },
|
||||||
{ provide: LOCALE_ID, useValue: 'en' },
|
{ provide: LOCALE_ID, useValue: 'ru' },
|
||||||
{ provide: SEARCH_LIMIT, useValue: DEFAULT_SEARCH_LIMIT },
|
{ provide: SEARCH_LIMIT, useValue: DEFAULT_SEARCH_LIMIT },
|
||||||
{ provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT },
|
{ provide: SMALL_SEARCH_LIMIT, useValue: DEFAULT_SMALL_SEARCH_LIMIT },
|
||||||
{ provide: QUERY_PARAMS_SERIALIZERS, useValue: DEFAULT_QUERY_PARAMS_SERIALIZERS },
|
{ 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 { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { InvoicePaymentAdjustmentParams } from '@vality/domain-proto/payment_processing';
|
import { InvoicePaymentAdjustmentParams } from '@vality/domain-proto/payment_processing';
|
||||||
import { StatPayment } from '@vality/magista-proto/magista';
|
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 chunk from 'lodash-es/chunk';
|
||||||
import { BehaviorSubject, from, concatMap, of, forkJoin } from 'rxjs';
|
import { BehaviorSubject, from, concatMap, of, forkJoin } from 'rxjs';
|
||||||
import { catchError, finalize } from 'rxjs/operators';
|
import { catchError, finalize } from 'rxjs/operators';
|
||||||
@ -11,8 +11,6 @@ import { catchError, finalize } from 'rxjs/operators';
|
|||||||
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
import { DomainMetadataFormExtensionsService } from '@cc/app/shared/services';
|
||||||
|
|
||||||
import { InvoicingService } from '../../../../api/payment-processing';
|
import { InvoicingService } from '../../../../api/payment-processing';
|
||||||
import { NotificationService } from '../../../services/notification';
|
|
||||||
import { NotificationErrorService } from '../../../services/notification-error';
|
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
@ -33,9 +31,8 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
|||||||
constructor(
|
constructor(
|
||||||
injector: Injector,
|
injector: Injector,
|
||||||
private invoicingService: InvoicingService,
|
private invoicingService: InvoicingService,
|
||||||
private notificationService: NotificationService,
|
private log: NotifyLogService,
|
||||||
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService,
|
private domainMetadataFormExtensionsService: DomainMetadataFormExtensionsService
|
||||||
private notificationErrorService: NotificationErrorService
|
|
||||||
) {
|
) {
|
||||||
super(injector);
|
super(injector);
|
||||||
}
|
}
|
||||||
@ -71,7 +68,7 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
|||||||
.subscribe({
|
.subscribe({
|
||||||
complete: () => {
|
complete: () => {
|
||||||
if (!this.withError.length) {
|
if (!this.withError.length) {
|
||||||
this.notificationService.success(`${payments.length} created successfully`);
|
this.log.success(`${payments.length} created successfully`);
|
||||||
this.closeWithSuccess();
|
this.closeWithSuccess();
|
||||||
} else {
|
} else {
|
||||||
const errors = this.withError
|
const errors = this.withError
|
||||||
@ -82,7 +79,7 @@ export class CreatePaymentAdjustmentComponent extends DialogSuperclass<
|
|||||||
})
|
})
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join(', ');
|
.join(', ');
|
||||||
this.notificationErrorService.error(
|
this.log.error(
|
||||||
new Error(
|
new Error(
|
||||||
`${this.withError.length} out of ${payments.length} failed. Errors: ${errors}`
|
`${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 { AppAuthGuardService } from '@cc/app/shared/services';
|
||||||
|
|
||||||
|
import { PaymentsComponent } from './payments.component';
|
||||||
import { ROUTING_CONFIG } from './routing-config';
|
import { ROUTING_CONFIG } from './routing-config';
|
||||||
import { SearchPaymentsComponent } from './search-payments.component';
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{
|
{
|
||||||
path: '',
|
path: '',
|
||||||
component: SearchPaymentsComponent,
|
component: PaymentsComponent,
|
||||||
canActivate: [AppAuthGuardService],
|
canActivate: [AppAuthGuardService],
|
||||||
data: ROUTING_CONFIG,
|
data: ROUTING_CONFIG,
|
||||||
},
|
},
|
||||||
@ -19,4 +19,4 @@ import { SearchPaymentsComponent } from './search-payments.component';
|
|||||||
],
|
],
|
||||||
exports: [RouterModule],
|
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"
|
[rowSelected]="selected$ | async"
|
||||||
[trackBy]="trackById"
|
[trackBy]="trackById"
|
||||||
rowSelectable
|
rowSelectable
|
||||||
sizes
|
|
||||||
(more)="fetchMore()"
|
(more)="fetchMore()"
|
||||||
(rowSelectionChange)="selected$.next($event)"
|
(rowSelectionChange)="selected$.next($event)"
|
||||||
(sizeChange)="update($event)"
|
|
||||||
(update)="update($event.size)"
|
(update)="update($event.size)"
|
||||||
>
|
>
|
||||||
<v-table-actions>
|
<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',
|
path: 'payments',
|
||||||
loadChildren: () =>
|
loadChildren: () => import('./payments/payments.module').then((m) => m.PaymentsModule),
|
||||||
import('./search-payments/search-payments.module').then((m) => m.SearchPaymentsModule),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: 'deposits',
|
path: 'deposits',
|
||||||
|
@ -24,9 +24,7 @@
|
|||||||
[data]="wallets$ | async"
|
[data]="wallets$ | async"
|
||||||
[hasMore]="hasMore$ | async"
|
[hasMore]="hasMore$ | async"
|
||||||
[progress]="inProgress$ | async"
|
[progress]="inProgress$ | async"
|
||||||
sizes
|
|
||||||
(more)="fetchMore()"
|
(more)="fetchMore()"
|
||||||
(sizeChange)="search($event)"
|
|
||||||
(update)="search($event.size)"
|
(update)="search($event.size)"
|
||||||
>
|
>
|
||||||
<ng-template #balanceTpl let-col="colDef" let-index="index" let-row>
|
<ng-template #balanceTpl let-col="colDef" let-index="index" let-row>
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
export * from './claim-search-form';
|
export * from './claim-search-form';
|
||||||
export * from './party-modification-creator';
|
export * from './party-modification-creator';
|
||||||
export * from './party-modification-forms';
|
export * from './party-modification-forms';
|
||||||
export * from './payments-search-filters';
|
|
||||||
export * from './payments-table';
|
|
||||||
export * from './status';
|
export * from './status';
|
||||||
export * from './shop-field';
|
export * from './shop-field';
|
||||||
export * from './shop-details';
|
export * from './shop-details';
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
import { FormComponentSuperclass } from '@s-libs/ng-core';
|
||||||
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
import { MapType, SetType, ListType } from '@vality/thrift-ts';
|
||||||
|
import { merge } from 'rxjs';
|
||||||
|
|
||||||
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
import { MetadataFormExtension } from '@cc/app/shared/components/metadata-form';
|
||||||
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
import { createControlProviders, getErrorsTree } from '@cc/utils';
|
||||||
@ -23,6 +24,8 @@ function updateFormArray<V>(formArray: FormArray<AbstractControl<V>>, values: V[
|
|||||||
formArray.patchValue(values);
|
formArray.patchValue(values);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ComplexType<T, K = never> = T[] | Map<K, T> | Set<T>;
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'cc-complex-form',
|
selector: 'cc-complex-form',
|
||||||
@ -30,15 +33,15 @@ function updateFormArray<V>(formArray: FormArray<AbstractControl<V>>, values: V[
|
|||||||
styleUrls: ['complex-form.component.scss'],
|
styleUrls: ['complex-form.component.scss'],
|
||||||
providers: createControlProviders(() => ComplexFormComponent),
|
providers: createControlProviders(() => ComplexFormComponent),
|
||||||
})
|
})
|
||||||
export class ComplexFormComponent<T extends unknown[] | Map<unknown, unknown> | Set<unknown>>
|
export class ComplexFormComponent<V, K = never>
|
||||||
extends FormComponentSuperclass<T>
|
extends FormComponentSuperclass<ComplexType<V, K>>
|
||||||
implements OnInit, Validator
|
implements OnInit, Validator
|
||||||
{
|
{
|
||||||
@Input() data: MetadataFormData<SetType | MapType | ListType>;
|
@Input() data: MetadataFormData<SetType | MapType | ListType>;
|
||||||
@Input() extensions: MetadataFormExtension[];
|
@Input() extensions: MetadataFormExtension[];
|
||||||
|
|
||||||
valueControls = new FormArray([]);
|
valueControls = new FormArray<AbstractControl<V>>([]);
|
||||||
keyControls = new FormArray([]);
|
keyControls = new FormArray<AbstractControl<K>>([]);
|
||||||
|
|
||||||
get hasLabel() {
|
get hasLabel() {
|
||||||
return !!this.data.trueParent;
|
return !!this.data.trueParent;
|
||||||
@ -53,31 +56,34 @@ export class ComplexFormComponent<T extends unknown[] | Map<unknown, unknown> |
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.valueControls.valueChanges.pipe(untilDestroyed(this)).subscribe((value) => {
|
merge(this.valueControls.valueChanges, this.keyControls.valueChanges)
|
||||||
switch (this.data.type.name) {
|
.pipe(untilDestroyed(this))
|
||||||
case 'list':
|
.subscribe(() => {
|
||||||
this.emitOutgoingValue(value as never);
|
const values = this.valueControls.value;
|
||||||
break;
|
switch (this.data.type.name) {
|
||||||
case 'map':
|
case 'list':
|
||||||
this.emitOutgoingValue(
|
this.emitOutgoingValue(values);
|
||||||
new Map(value.map((v, idx) => [this.keyControls.value[idx], v])) as never
|
break;
|
||||||
);
|
case 'map': {
|
||||||
break;
|
const keys = this.keyControls.value;
|
||||||
case 'set':
|
this.emitOutgoingValue(new Map(values.map((v, idx) => [keys[idx], v])));
|
||||||
this.emitOutgoingValue(new Set(value) as never);
|
break;
|
||||||
break;
|
}
|
||||||
}
|
case 'set':
|
||||||
});
|
this.emitOutgoingValue(new Set(values));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIncomingValue(value: T) {
|
handleIncomingValue(value: ComplexType<V, K>) {
|
||||||
if (this.isKeyValue) {
|
if (this.isKeyValue) {
|
||||||
const keys = Array.from(value?.keys() || []);
|
const keys = Array.from((value as Map<K, V>)?.keys() || []);
|
||||||
updateFormArray(this.keyControls, keys);
|
updateFormArray(this.keyControls, keys);
|
||||||
}
|
}
|
||||||
const values = this.isKeyValue
|
const values = this.isKeyValue
|
||||||
? Array.from(value?.values() || [])
|
? Array.from(value?.values() || [])
|
||||||
: Array.from(value || []);
|
: Array.from((value as V[]) || []);
|
||||||
updateFormArray(this.valueControls, values);
|
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
|
<cc-extension-field
|
||||||
*ngIf="(extensionResult$ | async)?.type; else defaultFields"
|
*ngIf="(extensionResult$ | async)?.type; else defaultFields"
|
||||||
[data]="data"
|
[data]="data"
|
||||||
|
@ -21,6 +21,7 @@ export interface MetadataFormExtensionResult {
|
|||||||
label?: string;
|
label?: string;
|
||||||
type?: 'datetime' | 'cash';
|
type?: 'datetime' | 'cash';
|
||||||
converter?: Converter;
|
converter?: Converter;
|
||||||
|
hidden?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MetadataFormExtensionOption {
|
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-form-field>
|
||||||
<mat-label>{{ multiple ? 'Shops' : 'Shop' }}</mat-label>
|
<mat-label>{{ multiple ? 'Shops' : 'Shop' }}</mat-label>
|
||||||
<mat-select
|
<mat-select [formControl]="control" [multiple]="multiple" [required]="required">
|
||||||
[disabled]="!partyId"
|
|
||||||
[formControl]="control"
|
|
||||||
[multiple]="multiple"
|
|
||||||
[required]="required"
|
|
||||||
>
|
|
||||||
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
<mat-option *ngFor="let shop of shops$ | async" [value]="shop.id">
|
||||||
{{ shop.details.name }}
|
{{ shop.details.name }}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
:host {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
mat-form-field {
|
mat-form-field {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { FormControl } from '@angular/forms';
|
|
||||||
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
|
||||||
import { Shop } from '@vality/domain-proto/domain';
|
import { Shop } from '@vality/domain-proto/domain';
|
||||||
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
import { PartyID, ShopID } from '@vality/domain-proto/payment_processing';
|
||||||
|
import {
|
||||||
|
createControlProviders,
|
||||||
|
FormControlSuperclass,
|
||||||
|
setDisabled,
|
||||||
|
isEmpty,
|
||||||
|
} from '@vality/ng-core';
|
||||||
import { coerceBoolean } from 'coerce-property';
|
import { coerceBoolean } from 'coerce-property';
|
||||||
import { BehaviorSubject, defer, of } from 'rxjs';
|
import { BehaviorSubject, defer, of } from 'rxjs';
|
||||||
import { filter, map, share, switchMap } from 'rxjs/operators';
|
import { filter, map, share, switchMap } from 'rxjs/operators';
|
||||||
|
|
||||||
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
import { PartyManagementService } from '@cc/app/api/payment-processing';
|
||||||
import { ComponentChanges } from '@cc/app/shared/utils';
|
import { ComponentChanges } from '@cc/app/shared/utils';
|
||||||
import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/forms';
|
|
||||||
|
|
||||||
@UntilDestroy()
|
@UntilDestroy()
|
||||||
@Component({
|
@Component({
|
||||||
@ -20,7 +24,7 @@ import { createControlProviders, ValidatedControlSuperclass } from '@cc/utils/fo
|
|||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class ShopFieldComponent<M extends boolean = boolean>
|
export class ShopFieldComponent<M extends boolean = boolean>
|
||||||
extends ValidatedControlSuperclass<
|
extends FormControlSuperclass<
|
||||||
M extends true ? Shop[] : Shop,
|
M extends true ? Shop[] : Shop,
|
||||||
M extends true ? ShopID[] : ShopID
|
M extends true ? ShopID[] : ShopID
|
||||||
>
|
>
|
||||||
@ -30,7 +34,6 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
|||||||
@Input() @coerceBoolean multiple: M;
|
@Input() @coerceBoolean multiple: M;
|
||||||
@Input() @coerceBoolean required: boolean;
|
@Input() @coerceBoolean required: boolean;
|
||||||
|
|
||||||
control = new FormControl() as FormControl<M extends true ? ShopID[] : ShopID>;
|
|
||||||
shops$ = defer(() => this.partyId$).pipe(
|
shops$ = defer(() => this.partyId$).pipe(
|
||||||
switchMap((partyId) =>
|
switchMap((partyId) =>
|
||||||
partyId
|
partyId
|
||||||
@ -48,10 +51,15 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setDisabledState(isDisabled: boolean) {
|
||||||
|
super.setDisabledState(!this.partyId || isDisabled);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: ComponentChanges<ShopFieldComponent>): void {
|
ngOnChanges(changes: ComponentChanges<ShopFieldComponent>): void {
|
||||||
super.ngOnChanges(changes);
|
super.ngOnChanges(changes);
|
||||||
if (changes.partyId) {
|
if (changes.partyId && this.partyId !== this.partyId$.value) {
|
||||||
this.partyId$.next(changes.partyId.currentValue);
|
this.partyId$.next(changes.partyId.currentValue);
|
||||||
|
setDisabled(this.control, !this.partyId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,7 +67,11 @@ export class ShopFieldComponent<M extends boolean = boolean>
|
|||||||
this.shops$
|
this.shops$
|
||||||
.pipe(
|
.pipe(
|
||||||
filter(
|
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)
|
untilDestroyed(this)
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import { getCurrencySymbol } from '@angular/common';
|
import { getCurrencySymbol } from '@angular/common';
|
||||||
import { Pipe, PipeTransform } from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'ccCurrency',
|
name: 'ccCurrency',
|
||||||
})
|
})
|
||||||
|
@ -4,6 +4,9 @@ import round from 'lodash-es/round';
|
|||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'ccFormatAmount',
|
name: 'ccFormatAmount',
|
||||||
})
|
})
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
export class FormatAmountPipe implements PipeTransform {
|
export class FormatAmountPipe implements PipeTransform {
|
||||||
public transform(input: number): number {
|
public transform(input: number): number {
|
||||||
const value = round(input / 100, 2);
|
const value = round(input / 100, 2);
|
||||||
@ -11,6 +14,9 @@ export class FormatAmountPipe implements PipeTransform {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
function format(
|
function format(
|
||||||
value: any,
|
value: any,
|
||||||
decimalLength: number,
|
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 './moment-utc-date-adapter';
|
||||||
export * from './domain-metadata-form-extensions';
|
export * from './domain-metadata-form-extensions';
|
||||||
export * from './domain-secret-service';
|
export * from './domain-secret-service';
|
||||||
|
export * from './amount-currency.service';
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { InjectionToken } from '@angular/core';
|
import { InjectionToken } from '@angular/core';
|
||||||
import { MatDateFormats } from '@angular/material/core';
|
import { MatDateFormats } from '@angular/material/core';
|
||||||
import { DateRange } from '@angular/material/datepicker';
|
import { DateRange } from '@angular/material/datepicker';
|
||||||
|
import { DATE_QUERY_PARAMS_SERIALIZERS } from '@vality/ng-core';
|
||||||
import { Moment } from 'moment';
|
import { Moment } from 'moment';
|
||||||
import * as 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));
|
return (!start || moment.isMoment(start)) && (!end || moment.isMoment(end));
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...DATE_QUERY_PARAMS_SERIALIZERS,
|
||||||
];
|
];
|
||||||
|
|
||||||
export const DEFAULT_MAT_DATE_FORMATS: MatDateFormats = {
|
export const DEFAULT_MAT_DATE_FORMATS: MatDateFormats = {
|
||||||
|
Loading…
Reference in New Issue
Block a user