EPIC FE-954: CLAIM-MGT (#100)

* FE-954: claim management API integration

* FE-964: claim details added

* FE-972: timeline

* Merge with epic FE-958: claim mngt (#101) (#102)

* Merge with epic FE-958: claim mngt (#101)

* FE-954: claim management API integration

* FE-964: claim details added

* FE-972: timeline

* Thrift services added

* fix build

* clean up

* FileStorage service implemented

* build fix n clean up

* clean up

* FE-965: claim status changer (#107)

* Added claim status pipe and menu (#108)

* FE-976: comments (#104)

* FE-976: comments implemented, keycloaktokeninfo service added.

* update

* clean up

* build fix

* Comments added.

* clean up

* prettier

* import order

* build fix

* prettier

* PR fixes

* пеар фиксес

* build fix

* pr fix

* prettier

* FE-977: claim mngt files (#109)

* conversation filter

* file display

* file download

* file uploading

* filter removed, file upload transfered to send messages line

* prettier

* тп-сщтеуте куьщмувб штзкщпкуыы фввув

* angular-file rollback

* FE-993: party mods (#110)

* Add questionary (#111)

* add questionary service and component

* update ank service

* fox ank module

* fix ank get

* merge with master

* lgtm

* build fix

* prettier

* packages...

* package fix

* Dependencies fix (#113)

Co-authored-by: Ildar Galeev <KeinAsylum@gmail.com>
Co-authored-by: Rinat Arsaev <krickray@gmail.com>
This commit is contained in:
Aleksandra Usacheva 2020-01-31 21:00:10 +03:00 committed by GitHub
parent a252c12660
commit 9c7073e6a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
389 changed files with 5742 additions and 477 deletions

11
.gitignore vendored
View File

@ -37,11 +37,14 @@ testem.log
# System Files
.DS_Store
Thumbs.db
/src/assets/meta-damsel.json
/src/app/thrift/gen-nodejs/
/src/app/gen-damsel/
/src/app/machinegun/gen-*
/src/app/fistful/gen-*
/src/app/thrift-services/damsel/gen-*
/src/app/thrift-services/machinegun/gen-*
/src/app/thrift-services/fistful/gen-*
/src/app/thrift-services/messages/gen-*
/src/app/thrift-services/ank/gen-*
/src/app/thrift-services/file-storage/gen-*
# Sonar
.scannerwork

View File

@ -41,7 +41,7 @@ submodules: $(SUBTARGETS)
init:
npm install
compile: compile-damsel compile-machinegun compile-fistful
compile: compile-damsel compile-machinegun compile-fistful compile-messages compile-file-storage compile-ank
build: check lint compile
npm run build
@ -49,12 +49,12 @@ build: check lint compile
clean-compile: clean compile
clean:
rm -rf dist src/app/thrift/gen-* src/assets/meta-damsel.json src/app/gen-damsel src/app/machinegun/gen-* src/app/fistful/gen-*
rm -rf dist src/app/thrift/gen-* src/assets/meta-damsel.json src/app/gen-model src/app/machinegun/gen-* src/app/fistful/gen-* src/app/messages/gen-* src/app/file-storage/gen-* src/app/ank/gen-*
compile-damsel: damsel-client damsel-model damsel-meta
damsel-client:
@$(foreach file,domain_config payment_processing merch_stat,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift ./node_modules/damsel/proto/$(file).thrift;)
@$(foreach file,domain_config payment_processing merch_stat claim_management,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/damsel ./node_modules/damsel/proto/$(file).thrift;)
damsel-meta:
npm run damsel-meta
@ -65,7 +65,7 @@ damsel-model:
compile-machinegun: machinegun-model machinegun-client
machinegun-client:
@$(foreach file,state_processing,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/machinegun ./node_modules/machinegun_proto/proto/$(file).thrift;)
@$(foreach file,state_processing,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/machinegun ./node_modules/machinegun_proto/proto/$(file).thrift;)
machinegun-model:
npm run machinegun-model
@ -73,11 +73,35 @@ machinegun-model:
compile-fistful: fistful-model fistful-client
fistful-client:
@$(foreach file,withdrawal_session fistful_admin fistful_stat,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/fistful ./node_modules/fistful-proto/proto/$(file).thrift;)
@$(foreach file,withdrawal_session fistful_admin fistful_stat,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/fistful ./node_modules/fistful-proto/proto/$(file).thrift;)
fistful-model:
npm run fistful-model
compile-messages: messages-model messages-client
messages-client:
@$(foreach file,messages,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/messages ./node_modules/messages-proto/proto/$(file).thrift;)
messages-model:
npm run messages-model
compile-file-storage: file-storage-model file-storage-client
file-storage-client:
@$(foreach file,file_storage,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/file-storage ./node_modules/file-storage-proto/proto/$(file).thrift;)
file-storage-model:
npm run file-storage-model
compile-ank: ank-model ank-client
ank-client:
@$(foreach file,questionary_manager,echo $(file); thrift -r -gen js:node,runtime_package=woody_js/dist/thrift -o ./src/app/thrift-services/ank ./node_modules/ank-proto/proto/$(file).thrift;)
ank-model:
npm run ank-model
lint:
npm run lint

293
package-lock.json generated
View File

@ -1720,6 +1720,12 @@
"@types/node": "*"
}
},
"@types/humanize-duration": {
"version": "3.18.0",
"resolved": "https://registry.npmjs.org/@types/humanize-duration/-/humanize-duration-3.18.0.tgz",
"integrity": "sha512-11QHl+GvEQ5TlCjA9xqQKNv4S0P8XFq5uHeZe2UPjngESBl7tA1tai/60eEYwWMFWIyQOl7ybarYF0B33K3Qtg==",
"dev": true
},
"@types/jasmine": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.8.8.tgz",
@ -1735,6 +1741,12 @@
"@types/jasmine": "*"
}
},
"@types/jwt-decode": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/@types/jwt-decode/-/jwt-decode-2.2.1.tgz",
"integrity": "sha512-aWw2YTtAdT7CskFyxEX2K21/zSDStuf/ikI3yBqmwpwJF0pS+/IX5DWv+1UFffZIbruP6cnT9/LAJV1gFwAT1A==",
"dev": true
},
"@types/lodash": {
"version": "4.14.116",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.116.tgz",
@ -2207,6 +2219,11 @@
"integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=",
"dev": true
},
"angular-file": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/angular-file/-/angular-file-1.3.2.tgz",
"integrity": "sha512-k4HGJJ/JXGmNA8iV206I5WOHbufOy6L5f2MYHiUuGjlDiWjEJmjo8sxnNJsR79FzkjbL41TWRDAH2gi4VTUYKw=="
},
"angular2-prettyjson": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/angular2-prettyjson/-/angular2-prettyjson-3.0.1.tgz",
@ -2215,6 +2232,10 @@
"tslib": "^1.7.1"
}
},
"ank-proto": {
"version": "git+ssh://git@github.com/rbkmoney/ank-proto.git#9563a08d94c7691ec8f9166f78c05d68ae1e761d",
"from": "git+ssh://git@github.com/rbkmoney/ank-proto.git#9563a08d94c7691ec8f9166f78c05d68ae1e761d"
},
"ansi-colors": {
"version": "3.2.4",
"resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
@ -4580,8 +4601,8 @@
"dev": true
},
"damsel": {
"version": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c",
"from": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c"
"version": "git+ssh://git@github.com/rbkmoney/damsel.git#7dd9035d89e8dab01d28e25445796c60503363a2",
"from": "git+ssh://git@github.com/rbkmoney/damsel.git#7dd9035d89e8dab01d28e25445796c60503363a2"
},
"dashdash": {
"version": "1.14.1",
@ -4957,9 +4978,9 @@
"dev": true
},
"electron-to-chromium": {
"version": "1.3.273",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.273.tgz",
"integrity": "sha512-0kUppiHQvHEENHh+nTtvTt4eXMwcPyWmMaj73GPrSEm3ldKhmmHuOH6IjrmuW6YmyS/fpXcLvMQLNVpqRhpNWw=="
"version": "1.3.344",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.344.tgz",
"integrity": "sha512-tvbx2Wl8WBR+ym3u492D0L6/jH+8NoQXqe46+QhbWH3voVPauGuZYeb1QAXYoOAWuiP2dbSvlBx0kQ1F3hu/Mw=="
},
"elliptic": {
"version": "6.5.1",
@ -5530,6 +5551,10 @@
}
}
},
"file-storage-proto": {
"version": "git+ssh://git@github.com/rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b",
"from": "git+ssh://git@github.com/rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b"
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
@ -5665,8 +5690,8 @@
}
},
"fistful-proto": {
"version": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#6e653a244e7b2106908604c4692ee5ab4496af09",
"from": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#6e653a244e7b2106908604c4692ee5ab4496af09"
"version": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#c2113c853ed71a34bb6468b9a6cf9b468967af84",
"from": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#c2113c853ed71a34bb6468b9a6cf9b468967af84"
},
"flake-idgen": {
"version": "1.1.0",
@ -6812,6 +6837,11 @@
}
}
},
"humanize-duration": {
"version": "3.21.0",
"resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.21.0.tgz",
"integrity": "sha512-7BLsrQZ2nMGeakmGDUl1pDne6/7iAdvwf1RtDLCOPHNFIHjkOVW7lcu7xHkIM9HhZAlSSO5crhC1dHvtl4dIQw=="
},
"humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
@ -7935,8 +7965,8 @@
}
},
"machinegun_proto": {
"version": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#ebae56fe2b3e79e4eb34afc8cb55c9012ae989f8",
"from": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#ebae56fe2b3e79e4eb34afc8cb55c9012ae989f8"
"version": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#eac772bb8446fcd2f439232bf10fa086c336aca6",
"from": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#eac772bb8446fcd2f439232bf10fa086c336aca6"
},
"magic-string": {
"version": "0.25.6",
@ -8121,6 +8151,10 @@
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
"dev": true
},
"messages-proto": {
"version": "git+ssh://git@github.com/rbkmoney/messages-proto.git#a177efb574136961bcd0a8236b4bfc425264de29",
"from": "git+ssh://git@github.com/rbkmoney/messages-proto.git#a177efb574136961bcd0a8236b4bfc425264de29"
},
"methods": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
@ -11300,9 +11334,9 @@
}
},
"glob": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
"integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
"version": "7.1.6",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
@ -11572,6 +11606,27 @@
"integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==",
"dev": true
},
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
"integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
"requires": {
"commander": "~2.13.0",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"uglifyjs-webpack-plugin": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.3.0.tgz",
@ -11607,11 +11662,6 @@
"y18n": "^4.0.0"
}
},
"commander": {
"version": "2.13.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.13.0.tgz",
"integrity": "sha512-MVuS359B+YzaWqjCL/c+22gfryv+mCBPHAv3zyVI2GN8EY6IRP8VwtasXn8jyyhvvq84R4ImN1OKRtcbIasjYA=="
},
"find-cache-dir": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz",
@ -11728,15 +11778,6 @@
"requires": {
"safe-buffer": "^5.1.1"
}
},
"uglify-es": {
"version": "3.3.9",
"resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.3.9.tgz",
"integrity": "sha512-r+MU0rfv4L/0eeW3xZrd16t4NZfK8Ld4SWVglYBb7ez5uXFWHuVRs6xCTrf1yirs9a4j4Y27nn7SRfO6v67XsQ==",
"requires": {
"commander": "~2.13.0",
"source-map": "~0.6.1"
}
}
}
},
@ -12183,22 +12224,26 @@
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
"optional": true
},
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"optional": true
},
"aproba": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"optional": true
},
"are-we-there-yet": {
"version": "1.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"optional": true,
"requires": {
"delegates": "^1.0.0",
@ -12207,12 +12252,14 @@
},
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
@ -12221,32 +12268,38 @@
},
"chownr": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"optional": true
},
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"optional": true
},
"core-util-is": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
"optional": true
},
"debug": {
"version": "4.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
"optional": true,
"requires": {
"ms": "^2.1.1"
@ -12254,22 +12307,26 @@
},
"deep-extend": {
"version": "0.6.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
"optional": true
},
"delegates": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"optional": true
},
"detect-libc": {
"version": "1.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"optional": true
},
"fs-minipass": {
"version": "1.2.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"optional": true,
"requires": {
"minipass": "^2.2.1"
@ -12277,12 +12334,14 @@
},
"fs.realpath": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
"optional": true
},
"gauge": {
"version": "2.7.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"optional": true,
"requires": {
"aproba": "^1.0.3",
@ -12297,7 +12356,8 @@
},
"glob": {
"version": "7.1.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
"integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
"optional": true,
"requires": {
"fs.realpath": "^1.0.0",
@ -12310,12 +12370,14 @@
},
"has-unicode": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"optional": true
},
"iconv-lite": {
"version": "0.4.24",
"bundled": true,
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
"optional": true,
"requires": {
"safer-buffer": ">= 2.1.2 < 3"
@ -12323,7 +12385,8 @@
},
"ignore-walk": {
"version": "3.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"optional": true,
"requires": {
"minimatch": "^3.0.4"
@ -12331,7 +12394,8 @@
},
"inflight": {
"version": "1.0.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"optional": true,
"requires": {
"once": "^1.3.0",
@ -12340,17 +12404,20 @@
},
"inherits": {
"version": "2.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
"optional": true
},
"ini": {
"version": "1.3.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
@ -12358,12 +12425,14 @@
},
"isarray": {
"version": "1.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"optional": true
},
"minimatch": {
"version": "3.0.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
@ -12371,12 +12440,14 @@
},
"minimist": {
"version": "0.0.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
"integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
@ -12385,7 +12456,8 @@
},
"minizlib": {
"version": "1.2.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
"integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
"optional": true,
"requires": {
"minipass": "^2.2.1"
@ -12393,7 +12465,8 @@
},
"mkdirp": {
"version": "0.5.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"optional": true,
"requires": {
"minimist": "0.0.8"
@ -12401,12 +12474,14 @@
},
"ms": {
"version": "2.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
"integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
"optional": true
},
"needle": {
"version": "2.3.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz",
"integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
"optional": true,
"requires": {
"debug": "^4.1.0",
@ -12416,7 +12491,8 @@
},
"node-pre-gyp": {
"version": "0.12.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
"integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
@ -12433,7 +12509,8 @@
},
"nopt": {
"version": "4.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"optional": true,
"requires": {
"abbrev": "1",
@ -12442,12 +12519,14 @@
},
"npm-bundled": {
"version": "1.0.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
"integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
"optional": true
},
"npm-packlist": {
"version": "1.4.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
"integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
@ -12456,7 +12535,8 @@
},
"npmlog": {
"version": "4.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"optional": true,
"requires": {
"are-we-there-yet": "~1.1.2",
@ -12467,17 +12547,20 @@
},
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
"optional": true
},
"object-assign": {
"version": "4.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
"optional": true
},
"once": {
"version": "1.4.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"optional": true,
"requires": {
"wrappy": "1"
@ -12485,17 +12568,20 @@
},
"os-homedir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
"optional": true
},
"os-tmpdir": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
"optional": true
},
"osenv": {
"version": "0.1.5",
"bundled": true,
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"optional": true,
"requires": {
"os-homedir": "^1.0.0",
@ -12504,17 +12590,20 @@
},
"path-is-absolute": {
"version": "1.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
"optional": true
},
"process-nextick-args": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
"optional": true
},
"rc": {
"version": "1.2.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"optional": true,
"requires": {
"deep-extend": "^0.6.0",
@ -12525,14 +12614,16 @@
"dependencies": {
"minimist": {
"version": "1.2.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"optional": true
}
}
},
"readable-stream": {
"version": "2.3.6",
"bundled": true,
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"optional": true,
"requires": {
"core-util-is": "~1.0.0",
@ -12546,7 +12637,8 @@
},
"rimraf": {
"version": "2.6.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"optional": true,
"requires": {
"glob": "^7.1.3"
@ -12554,37 +12646,44 @@
},
"safe-buffer": {
"version": "5.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
"optional": true
},
"sax": {
"version": "1.2.4",
"bundled": true,
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"optional": true
},
"semver": {
"version": "5.7.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
"optional": true
},
"set-blocking": {
"version": "2.0.0",
"bundled": true,
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
"optional": true
},
"signal-exit": {
"version": "3.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"optional": true
},
"string-width": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
@ -12594,7 +12693,8 @@
},
"string_decoder": {
"version": "1.1.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"optional": true,
"requires": {
"safe-buffer": "~5.1.0"
@ -12602,7 +12702,8 @@
},
"strip-ansi": {
"version": "3.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
@ -12610,12 +12711,14 @@
},
"strip-json-comments": {
"version": "2.0.1",
"bundled": true,
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"optional": true
},
"tar": {
"version": "4.4.8",
"bundled": true,
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
"integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
"optional": true,
"requires": {
"chownr": "^1.1.1",
@ -12629,12 +12732,14 @@
},
"util-deprecate": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
"optional": true
},
"wide-align": {
"version": "1.1.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"optional": true,
"requires": {
"string-width": "^1.0.2 || 2"
@ -12642,12 +12747,14 @@
},
"wrappy": {
"version": "1.0.2",
"bundled": true,
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
"optional": true
},
"yallist": {
"version": "3.0.3",
"bundled": true,
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
"integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
"optional": true
}
}
@ -13359,7 +13466,7 @@
},
"stream-http": {
"version": "2.3.1",
"resolved": "http://registry.npmjs.org/stream-http/-/stream-http-2.3.1.tgz",
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.3.1.tgz",
"integrity": "sha1-fh3IcQLD4xsy5mDwTKMfI929HVI=",
"requires": {
"builtin-status-codes": "^2.0.0",

View File

@ -8,10 +8,13 @@
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
"damsel-model": "thrift-ts node_modules/damsel/proto -o src/app/gen-damsel -d false",
"damsel-model": "thrift-ts node_modules/damsel/proto -o src/app/thrift-services/damsel/gen-model -d false",
"damsel-meta": "thrift-ts node_modules/damsel/proto -o src/assets/meta-damsel.json --json --pack --prettify",
"machinegun-model": "thrift-ts node_modules/machinegun_proto/proto -o src/app/machinegun/gen-model -d false",
"fistful-model": "thrift-ts node_modules/fistful-proto/proto -o src/app/fistful/gen-model -d false",
"machinegun-model": "thrift-ts node_modules/machinegun_proto/proto -o src/app/thrift-services/machinegun/gen-model -d false",
"fistful-model": "thrift-ts node_modules/fistful-proto/proto -o src/app/thrift-services/fistful/gen-model -d false",
"messages-model": "thrift-ts node_modules/messages-proto/proto -o src/app/thrift-services/messages/gen-model -d false",
"file-storage-model": "thrift-ts node_modules/file-storage-proto/proto -o src/app/thrift-services/file-storage/gen-model -d false",
"ank-model": "thrift-ts node_modules/ank-proto/proto -o src/app/thrift-services/ank/gen-model -d false",
"prettier": "prettier \"**/*.{html,js,ts,css,md,json,prettierrc,svg}\" --write",
"check": "prettier \"**/*.{html,js,ts,css,md,json,prettierrc,svg}\" --list-different"
},
@ -31,19 +34,24 @@
"@angular/platform-server": "~8.2.14",
"@angular/router": "~8.2.14",
"@rbkmoney/partial-fetcher": "~1.0.4",
"angular-file": "1.3.2",
"angular2-prettyjson": "3.0.1",
"core-js": "~2.5.4",
"damsel": "git+ssh://git@github.com/rbkmoney/damsel.git#b563890354447a5e175a9a318b33233a926a5e9c",
"fistful-proto": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#6e653a244e7b2106908604c4692ee5ab4496af09",
"damsel": "git+ssh://git@github.com/rbkmoney/damsel.git#7dd9035d89e8dab01d28e25445796c60503363a2",
"ank-proto": "git+ssh://git@github.com:rbkmoney/ank-proto.git#9563a08d94c7691ec8f9166f78c05d68ae1e761d",
"file-storage-proto": "git+ssh://git@github.com:rbkmoney/file-storage-proto.git#281e1ca4cea9bf32229a6c389f0dcf5d49c05a0b",
"fistful-proto": "git+ssh://git@github.com/rbkmoney/fistful-proto.git#c2113c853ed71a34bb6468b9a6cf9b468967af84",
"hammerjs": "~2.0.8",
"humanize-duration": "~3.21.0",
"jsonc-parser": "~2.0.2",
"keycloak-angular": "6.0.0",
"keycloak-js": "4.5.0",
"lodash-es": "~4.17.10",
"machinegun_proto": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#ebae56fe2b3e79e4eb34afc8cb55c9012ae989f8",
"machinegun_proto": "git+ssh://git@github.com/rbkmoney/machinegun_proto.git#eac772bb8446fcd2f439232bf10fa086c336aca6",
"rxjs": "~6.5.4",
"messages-proto": "git+ssh://git@github.com:rbkmoney/messages-proto.git#a177efb574136961bcd0a8236b4bfc425264de29",
"moment": "~2.22.2",
"monaco-editor": "~0.15.6",
"rxjs": "~6.5.4",
"thrift-ts": "git+ssh://git@github.com/rbkmoney/thrift-ts.git#a5e3830ad30d5717e5e627ddcefa8f4d8918b174",
"uuid": "~3.3.2",
"woody_js": "git+ssh://git@github.com/rbkmoney/woody_js.git#bc2c9f86cae470a0fe99730ca4a30b204058214b",
@ -53,8 +61,10 @@
"@angular-devkit/build-angular": "~0.803.23",
"@angular/cli": "~8.3.23",
"@angular/compiler-cli": "~8.2.14",
"@types/humanize-duration": "~3.18.0",
"@types/jasmine": "~2.8.6",
"@types/jasminewd2": "~2.0.3",
"@types/jwt-decode": "~2.2.1",
"@types/lodash-es": "~4.17.1",
"@types/node": "~8.9.4",
"@types/uuid": "~3.4.3",

View File

@ -1,24 +1,30 @@
{
"/v1": {
"target": "http://iddqd.rbk.test:8080",
"target": "https://iddqd.rbk.money",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
"/stat": {
"target": "http://iddqd.rbk.test:8080",
"target": "https://iddqd.rbk.money",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
"/fistful/stat": {
"target": "http://iddqd.rbk.test:8080",
"target": "https://iddqd.rbk.money",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
"/papi/v1": {
"target": "http://iddqd.rbk.test:8080",
"target": "https://iddqd.rbk.money",
"secure": false,
"logLevel": "debug",
"changeOrigin": true
},
"/file_storage": {
"target": "https://iddqd.rbk.money",
"secure": false,
"logLevel": "debug",
"changeOrigin": true

View File

@ -27,6 +27,7 @@ export class AppComponent implements OnInit {
{ name: 'Domain config', route: '/domain', activateRole: 'dmt:checkout' },
{ name: 'Payouts', route: '/payouts', activateRole: 'payout:read' },
{ name: 'Claims', route: '/claims', activateRole: 'claim:get' },
{ name: 'Claim-MGT', route: '/claim-mgt', activateRole: 'claim:get' },
{
name: 'Payment adjustment',
route: '/payment-adjustment',

View File

@ -30,6 +30,7 @@ import { PartyModule } from './party/party.module';
import { DomainModule } from './domain';
import { RepairingModule } from './repairing/repairing.module';
import { DepositsModule } from './deposits/deposits.module';
import { ClaimMgtModule } from './claim-mgt/claim-mgt.module';
@NgModule({
declarations: [AppComponent],
@ -52,7 +53,8 @@ import { DepositsModule } from './deposits/deposits.module';
PartyModule,
DomainModule,
RepairingModule,
DepositsModule
DepositsModule,
ClaimMgtModule
],
providers: [
{ provide: MAT_MOMENT_DATE_ADAPTER_OPTIONS, useValue: { useUtc: true } },

View File

@ -0,0 +1,29 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppAuthGuardService } from '../app-auth-guard.service';
@NgModule({
imports: [
RouterModule.forChild([
{ path: 'claim-mgt', redirectTo: 'claim-mgt/claims', pathMatch: 'full' },
{
path: 'claim-mgt/claims',
loadChildren: () => import('./claims').then(m => m.ClaimsModule),
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
},
{
path: 'claim-mgt/party',
loadChildren: () => import('./claim').then(m => m.ClaimModule),
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
}
])
],
exports: [RouterModule]
})
export class ClaimMgtRouting {}

View File

@ -0,0 +1,8 @@
import { NgModule } from '@angular/core';
import { ClaimMgtRouting } from './claim-mgt-routing.module';
@NgModule({
imports: [ClaimMgtRouting]
})
export class ClaimMgtModule {}

View File

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule } from '@angular/router';
import { AppAuthGuardService } from '../../app-auth-guard.service';
import { ClaimComponent } from './claim.component';
@NgModule({
imports: [
RouterModule.forChild([
{
path: ':party_id/claim/:claim_id',
component: ClaimComponent,
canActivate: [AppAuthGuardService],
data: {
roles: ['claim:get']
}
}
])
],
exports: [RouterModule]
})
export class ClaimRoutingModule {}

View File

@ -0,0 +1,7 @@
export enum ClaimStatuses {
'pending_acceptance' = 'pending_acceptance',
'pending' = 'pending',
'revoked' = 'revoked',
'denied' = 'denied',
'review' = 'review'
}

View File

@ -0,0 +1,7 @@
<cc-card-container *ngIf="(claim$ | async) as claim">
<cc-claim-details [claim]="claim"></cc-claim-details>
<cc-claim-conversation
[claim]="claim"
(conversationChangedEvent)="conversationChanged()"
></cc-claim-conversation>
</cc-card-container>

View File

@ -0,0 +1,27 @@
import { Component } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import Int64 from 'thrift-ts/lib/int64';
import { ClaimService } from './claim.service';
@Component({
templateUrl: 'claim.component.html'
})
export class ClaimComponent {
claim$ = this.claimService.claim$;
constructor(private route: ActivatedRoute, private claimService: ClaimService) {
this.getClaim();
}
conversationChanged() {
this.getClaim();
}
private getClaim() {
this.route.params.subscribe(params => {
const { party_id, claim_id } = params;
this.claimService.getClaim(party_id, new Int64(Number(claim_id)));
});
}
}

View File

@ -0,0 +1,62 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexModule } from '@angular/flex-layout';
import {
MatCardModule,
MatSelectModule,
MatButtonModule,
MatDialogModule,
MatProgressBarModule,
MatInputModule
} from '@angular/material';
import { ReactiveFormsModule } from '@angular/forms';
import { MatListModule } from '@angular/material/list';
import { MatBottomSheetModule } from '@angular/material/bottom-sheet';
import { MatStepperModule } from '@angular/material/stepper';
import { ClaimComponent } from './claim.component';
import { ClaimRoutingModule } from './claim-routing.module';
import { SharedModule } from '../../shared/shared.module';
import { DetailsComponent } from './details/details.component';
import { ConversationModule } from './conversation/conversation.module';
import { StatusChangerComponent } from './status-changer/status-changer.component';
import { PartyModificationTargetModule } from '../../party-modification-target';
import { ClaimManagementService } from '../../thrift-services/damsel/claim-management.service';
import { UnitActionsComponent } from './party-modification-creator/unit-actions/unit-actions.component';
import { ContainerNamePipe } from './party-modification-creator/container-name.pipe';
import { PartyModificationCreationModule } from './party-modification-creator/creation';
import { CreateModificationComponent } from './party-modification-creator/create-modification.component';
import { ClaimService } from './claim.service';
@NgModule({
imports: [
ClaimRoutingModule,
SharedModule,
CommonModule,
MatCardModule,
FlexModule,
MatSelectModule,
ConversationModule,
MatButtonModule,
MatDialogModule,
MatProgressBarModule,
ReactiveFormsModule,
MatInputModule,
MatListModule,
MatBottomSheetModule,
MatStepperModule,
PartyModificationTargetModule,
PartyModificationCreationModule
],
declarations: [
ClaimComponent,
DetailsComponent,
StatusChangerComponent,
CreateModificationComponent,
ContainerNamePipe,
UnitActionsComponent
],
entryComponents: [StatusChangerComponent, CreateModificationComponent, UnitActionsComponent],
providers: [ClaimManagementService, ClaimService]
})
export class ClaimModule {}

View File

@ -0,0 +1,26 @@
import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';
import { MatSnackBar } from '@angular/material';
import { ClaimManagementService } from '../../thrift-services/damsel/claim-management.service';
import { Claim, ClaimID } from '../../thrift-services/damsel/gen-model/claim_management';
@Injectable()
export class ClaimService {
claim$: Subject<Claim> = new Subject();
constructor(
private claimManagementService: ClaimManagementService,
private snackBar: MatSnackBar
) {}
getClaim(partyID: string, claimID: ClaimID) {
this.claimManagementService.getClaim(partyID, claimID).subscribe(
claim => this.claim$.next(claim),
e => {
console.error(e);
this.snackBar.open('Error loading the claim', 'OK');
}
);
}
}

View File

@ -0,0 +1,21 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TimelineAction } from './to-timeline-info/model';
@Pipe({
name: 'actionIcon'
})
export class ActionIconPipe implements PipeTransform {
transform(action: TimelineAction): string {
return ({
[TimelineAction.statusPending]: 'visibility',
[TimelineAction.statusReview]: 'forward',
[TimelineAction.statusRevoked]: 'close',
[TimelineAction.statusDenied]: 'close',
[TimelineAction.statusAccepted]: 'done',
[TimelineAction.filesAdded]: 'attach_file',
[TimelineAction.commentAdded]: 'mode_comment',
[TimelineAction.changesAdded]: 'add'
} as const)[action];
}
}

View File

@ -0,0 +1,21 @@
import { Pipe, PipeTransform } from '@angular/core';
import { TimelineAction } from './to-timeline-info/model';
@Pipe({
name: 'actionName'
})
export class ActionNamePipe implements PipeTransform {
transform(action: TimelineAction): string {
return ({
[TimelineAction.statusPending]: 'Changed status to Pending',
[TimelineAction.statusReview]: 'Changed status to Review',
[TimelineAction.statusRevoked]: 'Changed status to Revoked',
[TimelineAction.statusDenied]: 'Changed status to Denied',
[TimelineAction.statusAccepted]: 'Changed status to Accepted',
[TimelineAction.filesAdded]: 'Files added',
[TimelineAction.commentAdded]: 'Comment added',
[TimelineAction.changesAdded]: 'Changes added'
} as const)[action];
}
}

View File

@ -0,0 +1,5 @@
<mat-card>
<mat-card-content>
{{ conversation ? conversation.messages[0].text : "Can't load conversation" }}
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,3 @@
mat-card-content {
word-break: break-all;
}

View File

@ -0,0 +1,12 @@
import { Component, Input } from '@angular/core';
import { Conversation } from '../../../../thrift-services/messages/gen-model/messages';
@Component({
selector: 'cc-conversation-comment',
templateUrl: 'comment.component.html',
styleUrls: ['comment.component.scss']
})
export class CommentComponent {
@Input() conversation: Conversation;
}

View File

@ -0,0 +1,74 @@
<div fxLayout="column" fxLayoutGap="20px">
<cc-timeline *ngIf="(timelineInfo$ | async) as timelineInfo">
<cc-timeline-item *ngFor="let item of timelineInfo">
<cc-timeline-item-title>
<span>
{{ item.action | actionName }} by {{ item.user_info.username }} at
{{ item.created_at | date: 'dd.MM.yyyy HH:mm:ss' }} ({{
item.created_at | humanizedDuration: { largest: 1, hasAgoEnding: true }
}})
</span>
</cc-timeline-item-title>
<cc-timeline-item-badge>
<mat-icon>{{ item.action | actionIcon }}</mat-icon>
</cc-timeline-item-badge>
<cc-timeline-item-content
*ngIf="item.modifications.length !== 0"
fxLayout="column"
fxLayoutGap="20px"
>
<ng-container *ngFor="let m of item.modifications">
<cc-file-container
*ngIf="item.action === timelineAction.filesAdded"
[fileID]="m.claim_modification.file_modification.id"
></cc-file-container>
<cc-conversation-comment
*ngIf="item.action === timelineAction.commentAdded"
[conversation]="item.data"
></cc-conversation-comment>
<cc-reason
*ngIf="
item.action === timelineAction.statusDenied ||
item.action === timelineAction.statusRevoked
"
[statusModificationUnit]="m.claim_modification.status_modification"
></cc-reason>
<cc-questionary
*ngIf="item.action === timelineAction.changesAdded"
[questionary]="questionary$ | async"
></cc-questionary>
</ng-container>
<ng-container
*ngIf="
item.action !== timelineAction.statusRevoked ||
item.action !== timelineAction.statusDenied
"
>
<mat-expansion-panel *ngFor="let modification of item.modifications">
<mat-expansion-panel-header>
<mat-panel-title> {{ getKey(modification) }} </mat-panel-title>
<mat-panel-description>
{{
modification.claim_modification
? getKey(modification.claim_modification)
: getKey(modification.party_modification)
}}
</mat-panel-description>
</mat-expansion-panel-header>
<cc-pretty-json [object]="modification"></cc-pretty-json>
</mat-expansion-panel>
</ng-container>
</cc-timeline-item-content>
</cc-timeline-item>
</cc-timeline>
<div fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="space-between center">
<cc-file-uploader
(filesUploaded)="updateConversation(timelineAction.filesAdded, $event)"
></cc-file-uploader>
<cc-send-comment
fxFlex="100"
*ngIf="claimStatus !== claimStatuses.denied && claimStatus !== claimStatuses.revoked"
(conversationSaved)="updateConversation(timelineAction.commentAdded, $event)"
></cc-send-comment>
</div>
</div>

View File

@ -0,0 +1,48 @@
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Modification, Claim } from '../../../thrift-services/damsel/gen-model/claim_management';
import { ConversationService } from './conversation.service';
import { extractClaimStatus } from '../../../shared/extract-claim-status';
import { ClaimStatus } from '../../../papi/model';
import { TimelineAction } from './to-timeline-info/model';
import { QuestionaryService } from './questionary.service';
import { getUnionKey } from '../../../shared/get-union-key';
@Component({
selector: 'cc-claim-conversation',
templateUrl: 'conversation.component.html',
providers: [ConversationService, QuestionaryService]
})
export class ConversationComponent implements OnChanges {
@Input() claim: Claim;
@Output() conversationChangedEvent = new EventEmitter();
timelineInfo$ = this.conversationService.timelineInfos$;
questionary$ = this.questionaryService.questionary$;
timelineAction = TimelineAction;
claimStatus: ClaimStatus;
claimStatuses = ClaimStatus;
constructor(
private conversationService: ConversationService,
private questionaryService: QuestionaryService
) {}
ngOnChanges(changes: SimpleChanges) {
const { currentValue } = changes.claim;
if (currentValue) {
this.claimStatus = extractClaimStatus(currentValue.status);
this.conversationService.enrichWithData(currentValue.changeset);
}
}
updateConversation(action: TimelineAction, modifications: Modification[]) {
this.conversationService
.updateConversation(this.claim.party_id, this.claim.id, action, modifications)
.subscribe(_ => this.conversationChangedEvent.emit());
}
getKey(modification: Modification) {
return getUnionKey(modification);
}
}

View File

@ -0,0 +1,67 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexLayoutModule } from '@angular/flex-layout';
import {
MatButtonModule,
MatExpansionModule,
MatFormFieldModule,
MatIconModule,
MatInputModule
} from '@angular/material';
import { MatSelectModule } from '@angular/material/select';
import { ReactiveFormsModule } from '@angular/forms';
import { LayoutModule } from '@angular/cdk/layout';
import { MatCardModule } from '@angular/material/card';
import { ConversationComponent } from './conversation.component';
import { ActionIconPipe } from './action-icon.pipe';
import { TimelineModule } from '../../../shared/components/timeline';
import { SharedModule } from '../../../shared/shared.module';
import { ActionNamePipe } from './action-name.pipe';
import { MonacoEditorModule } from '../../../monaco-editor';
import { HumanizeDurationModule } from '../../../shared/humanize-duration';
import { SendCommentComponent } from './send-comment';
import { MessagesModule } from '../../../thrift-services/messages';
import { CommentComponent } from './comment/comment.component';
import { ReasonComponent } from './reason/reason.component';
import { FileContainerModule } from './file-container';
import { FileUploaderModule } from './file-uploader/file-uploader.module';
import { QuestionaryComponent } from './questionary';
import { AnkModule } from '../../../thrift-services';
@NgModule({
imports: [
LayoutModule,
MatButtonModule,
FlexLayoutModule,
MatFormFieldModule,
MatInputModule,
TimelineModule,
MatIconModule,
SharedModule,
CommonModule,
ReactiveFormsModule,
SharedModule,
MatExpansionModule,
MonacoEditorModule,
HumanizeDurationModule,
MessagesModule,
MatCardModule,
HumanizeDurationModule,
MatSelectModule,
FileContainerModule,
FileUploaderModule,
AnkModule
],
declarations: [
ConversationComponent,
ReasonComponent,
SendCommentComponent,
ActionIconPipe,
ActionNamePipe,
CommentComponent,
QuestionaryComponent
],
exports: [ConversationComponent]
})
export class ConversationModule {}

View File

@ -0,0 +1,61 @@
import { Injectable } from '@angular/core';
import { from, Observable, Subject } from 'rxjs';
import { catchError, map } from 'rxjs/operators';
import flatten from 'lodash-es/flatten';
import { TimelineAction, TimelineItemInfo } from './to-timeline-info/model';
import {
ClaimChangeset,
ClaimID,
Modification
} from '../../../thrift-services/damsel/gen-model/claim_management';
import { ClaimManagementService } from '../../../thrift-services/damsel/claim-management.service';
import { toTimelineInfo } from './to-timeline-info';
import { MessagesService } from '../../../thrift-services/messages/messages.service';
import { ConversationId } from '../../../thrift-services/messages/gen-model/messages';
import { addCommentsToTimelineInfos } from './to-timeline-info';
@Injectable()
export class ConversationService {
timelineInfos$ = new Subject<TimelineItemInfo[]>();
constructor(
private claimManagementService: ClaimManagementService,
private messagesService: MessagesService
) {}
updateConversation(
party_id: string,
claim_id: ClaimID,
action: TimelineAction,
modifications: Modification[]
): Observable<void> {
return this.claimManagementService.updateClaim(party_id, claim_id, modifications);
}
enrichWithData(changeset: ClaimChangeset) {
from(this.addCommentsToInfo(toTimelineInfo(changeset))).subscribe(infos =>
this.timelineInfos$.next(infos)
);
}
private addCommentsToInfo(timelineInfos: TimelineItemInfo[]): Observable<TimelineItemInfo[]> {
const commentAddedIds: ConversationId[] = flatten(
timelineInfos
.filter(info => info.action === TimelineAction.commentAdded)
.map((commentInfo: TimelineItemInfo) =>
commentInfo.modifications.map(m => m.claim_modification.comment_modification.id)
)
);
return this.messagesService.getConversations(commentAddedIds, {}).pipe(
map(conversationsResponse =>
addCommentsToTimelineInfos(conversationsResponse.conversations, timelineInfos)
),
catchError(e => {
console.error(e);
return [timelineInfos];
})
);
}
}

View File

@ -0,0 +1,15 @@
/**
* https://github.com/sindresorhus/multi-download/blob/master/index.js
*/
export function download(url: string, name?: string): void {
const a = document.createElement('a');
a.download = name;
a.href = url;
a.style.display = 'none';
document.body.append(a);
a.click();
// Chrome requires the timeout
setTimeout(() => {
a.remove();
}, 100);
}

View File

@ -0,0 +1,7 @@
.download-icon {
color: rgba(0, 0, 0, 0.87);
}
.download-icon:hover {
cursor: pointer;
}

View File

@ -0,0 +1,6 @@
<mat-card *ngIf="(fileData$ | async) as fileData">
<mat-card-content fxLayout="row" fxLayoutAlign="space-between">
<div class="mat-body-1">{{ fileData.file_name }}</div>
<mat-icon class="download-icon" (click)="downloadFile()">cloud_download</mat-icon>
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,26 @@
import { Component, Input, OnInit } from '@angular/core';
import { FileContainerService } from './file-container.service';
@Component({
selector: 'cc-file-container',
templateUrl: 'file-container.component.html',
styleUrls: ['file-container.component.css'],
providers: [FileContainerService]
})
export class FileContainerComponent implements OnInit {
@Input()
fileID: string;
fileData$ = this.fileContainerService.fileData$;
constructor(private fileContainerService: FileContainerService) {}
ngOnInit() {
this.fileContainerService.getFileInfo(this.fileID);
}
downloadFile() {
this.fileContainerService.downloadFile(this.fileID);
}
}

View File

@ -0,0 +1,16 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexModule } from '@angular/flex-layout';
import { MatCardModule } from '@angular/material';
import { MatIconModule } from '@angular/material/icon';
import { FileContainerComponent } from './file-container.component';
import { FileStorageService } from '../../../../thrift-services/file-storage/file-storage.service';
@NgModule({
imports: [CommonModule, MatCardModule, FlexModule, MatIconModule],
exports: [FileContainerComponent],
declarations: [FileContainerComponent],
providers: [FileStorageService]
})
export class FileContainerModule {}

View File

@ -0,0 +1,56 @@
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Observable, Subject } from 'rxjs';
import { shareReplay, switchMap } from 'rxjs/operators';
import * as moment from 'moment';
import { FileStorageService } from '../../../../thrift-services/file-storage/file-storage.service';
import {
FileData,
FileNotFound
} from '../../../../thrift-services/file-storage/gen-model/file_storage';
import { booleanDelay } from '../../../../custom-operators';
import { download } from './download';
@Injectable()
export class FileContainerService {
private getFileInfo$ = new Subject<string>();
fileData$: Observable<FileData | FileNotFound> = this.getFileInfo$.pipe(
switchMap(fileID => this.fileStorageService.getFileData(fileID)),
shareReplay(1)
);
isLoading$ = this.fileData$.pipe(
booleanDelay(),
shareReplay(1)
);
constructor(private fileStorageService: FileStorageService, private snackBar: MatSnackBar) {
this.fileData$.subscribe();
}
getFileInfo(fileID: string) {
this.getFileInfo$.next(fileID);
}
downloadFile(fileID: string) {
this.fileStorageService
.generateDownloadUrl(
fileID,
moment()
.add(1, 'h')
.toISOString()
)
.subscribe(
url => {
if (typeof url === 'string') {
download(url);
} else {
this.snackBar.open('File not found', 'OK');
}
},
() => this.snackBar.open('Download error', 'OK')
);
}
}

View File

@ -0,0 +1,2 @@
export * from './file-container.module';
export * from './file-container.component';

View File

@ -0,0 +1,3 @@
.dsh-file-uploader:hover {
cursor: pointer;
}

View File

@ -0,0 +1,5 @@
<div ngfSelect class="dsh-file-uploader" (filesChange)="startUploading($event)">
<button mat-icon-button [disabled]="inProgress$ | async">
<mat-icon>attach_file</mat-icon>
</button>
</div>

View File

@ -0,0 +1,27 @@
import { Component, EventEmitter, Output } from '@angular/core';
import { FileUploaderService } from './file-uploader.service';
import { Modification } from '../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-file-uploader',
templateUrl: 'file-uploader.component.html',
styleUrls: ['file-uploader.component.css']
})
export class FileUploaderComponent {
@Output()
filesUploaded: EventEmitter<Modification[]> = new EventEmitter();
startUploading$ = this.fileUploaderService.startUploading$;
inProgress$ = this.fileUploaderService.inProgress$;
constructor(private fileUploaderService: FileUploaderService) {
this.fileUploaderService.filesUploaded$.subscribe(values =>
this.filesUploaded.emit(values.map(v => this.fileUploaderService.createModification(v)))
);
}
startUploading(files: File[]) {
this.startUploading$.next(files);
}
}

View File

@ -0,0 +1,17 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FlexModule } from '@angular/flex-layout';
import { ngfModule } from 'angular-file';
import { FileUploaderComponent } from './file-uploader.component';
import { FileUploaderService } from './file-uploader.service';
import { MatIconModule } from '@angular/material/icon';
import { MatButtonModule } from '@angular/material/button';
@NgModule({
imports: [FlexModule, ngfModule, CommonModule, MatIconModule, MatButtonModule],
exports: [FileUploaderComponent],
declarations: [FileUploaderComponent],
providers: [FileUploaderService]
})
export class FileUploaderModule {}

View File

@ -0,0 +1,92 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { MatSnackBar } from '@angular/material/snack-bar';
import { forkJoin, merge, Observable, of, Subject } from 'rxjs';
import { catchError, filter, map, shareReplay, switchMap } from 'rxjs/operators';
import * as moment from 'moment';
import { progress } from '@rbkmoney/partial-fetcher/dist/progress';
import { FileStorageService } from '../../../../thrift-services/file-storage/file-storage.service';
import { NewFileResult } from '../../../../thrift-services/file-storage/gen-model/file_storage';
import { Value } from '../../../../thrift-services/file-storage/gen-model/msgpack';
import { Modification } from '../../../../thrift-services/damsel/gen-model/claim_management';
@Injectable()
export class FileUploaderService {
startUploading$ = new Subject<File[]>();
filesUploadingError$ = new Subject<null>();
filesUploaded$: Observable<string[]> = this.startUploading$.pipe(
switchMap(files =>
this.uploadFiles(files).pipe(
catchError(() => {
this.filesUploadingError$.next(null);
return of([]);
})
)
),
filter(v => !!v.length),
shareReplay(1)
);
inProgress$: Observable<boolean> = progress(
this.startUploading$,
merge(this.filesUploaded$, this.filesUploadingError$)
);
constructor(
private fileStorageService: FileStorageService,
private snackBar: MatSnackBar,
private http: HttpClient
) {
this.filesUploadingError$.subscribe(() => this.snackBar.open('File uploading error', 'OK'));
}
uploadFiles(files: File[]): Observable<string[]> {
return forkJoin(
files.map(file =>
this.getUploadLink().pipe(
switchMap(uploadData =>
forkJoin(
of(uploadData.file_data_id),
this.uploadFileToUrl(file, uploadData.upload_url)
)
),
map(([fileId]) => fileId)
)
)
);
}
createModification(id: string): Modification {
return {
claim_modification: {
file_modification: {
id,
modification: {
creation: {}
}
}
}
};
}
private getUploadLink(): Observable<NewFileResult> {
return this.fileStorageService.createNewFile(
new Map<string, Value>(),
moment()
.add(1, 'h')
.toISOString()
);
}
private uploadFileToUrl(file: File, url: string): Observable<any> {
return this.http.put(url, file, {
headers: {
'Content-Disposition': `attachment;filename=${file.name}`,
'Content-Type': ''
}
});
}
}

View File

@ -0,0 +1,22 @@
import { Injectable } from '@angular/core';
import { ConversationService } from './conversation.service';
import { switchMap, pluck, map, publishReplay } from 'rxjs/operators';
import { AnkService } from '../../../thrift-services/ank/ank.service';
import { TimelineAction } from './to-timeline-info/model';
import { ConnectableObservable } from 'rxjs';
import { Questionary } from '../../../thrift-services/ank/gen-model/questionary_manager';
@Injectable()
export class QuestionaryService {
questionary$ = this.conversationService.timelineInfos$.pipe(
map(timelineInfos => timelineInfos.find(i => i.action === TimelineAction.changesAdded)),
pluck('modifications', 0, 'claim_modification', 'document_modification', 'id'),
switchMap(id => this.ankService.get(id)),
pluck('questionary'),
publishReplay(1)
) as ConnectableObservable<Questionary>;
constructor(private conversationService: ConversationService, private ankService: AnkService) {
this.questionary$.connect();
}
}

View File

@ -0,0 +1 @@
export * from './questionary.component';

View File

@ -0,0 +1 @@
<mat-card> <mat-card-content> Questionary </mat-card-content> </mat-card>

View File

@ -0,0 +1,3 @@
mat-card-content {
word-break: break-all;
}

View File

@ -0,0 +1,12 @@
import { Component, Input } from '@angular/core';
import { Questionary } from '../../../../thrift-services/ank/gen-model/questionary_manager';
@Component({
selector: 'cc-questionary',
templateUrl: 'questionary.component.html',
styleUrls: ['questionary.component.scss']
})
export class QuestionaryComponent {
@Input() questionary: Questionary;
}

View File

@ -0,0 +1,8 @@
<mat-card>
<mat-card-content>
{{
statusModificationUnit.status.denied?.reason ||
statusModificationUnit.status.revoked?.reason
}}
</mat-card-content>
</mat-card>

View File

@ -0,0 +1,10 @@
import { Component, Input } from '@angular/core';
import { StatusModificationUnit } from '../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-reason',
templateUrl: 'reason.component.html'
})
export class ReasonComponent {
@Input() statusModificationUnit: StatusModificationUnit;
}

View File

@ -0,0 +1 @@
export * from './send-comment.component';

View File

@ -0,0 +1,16 @@
<form [formGroup]="form" fxLayout="row" fxLayoutGap="10px" fxLayoutAlign="space-between end">
<mat-form-field fxFlex>
<mat-label>Write a comment...</mat-label>
<input formControlName="comment" matInput type="text" autocomplete="off" />
</mat-form-field>
<div class="send-comment-action">
<button
mat-icon-button
color="accent"
(click)="sendComment(form.value.comment)"
[disabled]="(inProgress$ | async) || !form.valid"
>
<mat-icon>send</mat-icon>
</button>
</div>
</form>

View File

@ -0,0 +1,9 @@
$cc-send-comment-action-padding: 10px 0 0 0;
.send-comment-action {
padding: $cc-send-comment-action-padding;
}
button {
margin-bottom: 1.25em;
}

View File

@ -0,0 +1,35 @@
import { Component, Output, EventEmitter } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { SendCommentService } from './send-comment.service';
import { Modification } from '../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-send-comment',
templateUrl: 'send-comment.component.html',
styleUrls: ['send-comment.component.scss'],
providers: [SendCommentService]
})
export class SendCommentComponent {
@Output() conversationSaved: EventEmitter<Modification[]> = new EventEmitter();
form: FormGroup = this.sendCommentService.form;
inProgress$ = this.sendCommentService.inProgress$;
constructor(private sendCommentService: SendCommentService) {
this.sendCommentService.conversationSaved$.subscribe(id =>
this.conversationSaved.next([sendCommentService.createModification(id)])
);
this.inProgress$.subscribe(inProgress => {
if (inProgress) {
this.form.controls.comment.disable();
} else {
this.form.controls.comment.enable();
}
});
}
sendComment(comment: string) {
this.sendCommentService.sendComment(comment);
}
}

View File

@ -0,0 +1,96 @@
import { Injectable } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Subject, of, forkJoin, BehaviorSubject, Observable, merge } from 'rxjs';
import { switchMap, filter, catchError, pluck, tap } from 'rxjs/operators';
import * as uuid from 'uuid/v4';
import get from 'lodash-es/get';
import { progress } from '@rbkmoney/partial-fetcher/dist/progress';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ConversationId, User } from '../../../../thrift-services/messages/gen-model/messages';
import { MessagesService } from '../../../../thrift-services/messages/messages.service';
import { createSingleMessageConversationParams } from '../../../../thrift-services/messages/utils';
import { KeycloakTokenInfoService } from '../../../../keycloak-token-info.service';
import { Modification } from '../../../../thrift-services/damsel/gen-model/claim_management';
@Injectable()
export class SendCommentService {
private conversationId$: BehaviorSubject<ConversationId | null> = new BehaviorSubject(null);
private error$: BehaviorSubject<any> = new BehaviorSubject({ hasError: false });
private sendComment$: Subject<string> = new Subject();
form: FormGroup;
conversationSaved$: Observable<ConversationId> = this.conversationId$.pipe(filter(id => !!id));
errorCode$: Observable<string> = this.error$.pipe(pluck('code'));
inProgress$: Observable<boolean> = progress(
this.sendComment$,
merge(this.conversationId$, this.error$)
);
constructor(
private fb: FormBuilder,
private messagesService: MessagesService,
private keycloakTokenInfoService: KeycloakTokenInfoService,
private snackBar: MatSnackBar
) {
this.form = this.fb.group({
comment: ['', [Validators.maxLength(1000)]]
});
this.sendComment$
.pipe(
tap(() => this.error$.next({ hasError: false })),
switchMap(text => {
const { name, email, sub } = this.keycloakTokenInfoService.decodedUserToken;
const user: User = { fullname: name, email, user_id: sub };
const conversation_id = uuid();
const conversation = createSingleMessageConversationParams(
conversation_id,
text,
sub
);
return forkJoin(
of(conversation_id),
this.messagesService.saveConversations([conversation], user).pipe(
catchError(ex => {
console.error(ex);
this.snackBar.open(
`There was an error sending a comment: ${ex}`,
'OK',
{ duration: 5000 }
);
const error = { hasError: true, code: 'saveConversationsFailed' };
this.error$.next(error);
return of(error);
})
)
);
}),
filter(([, res]) => get(res, ['hasError']) !== true)
)
.subscribe(([conversation_id]) => {
this.conversationId$.next(conversation_id);
this.form.reset();
});
}
sendComment(comment: string) {
if (comment.length === 0) {
return;
}
this.sendComment$.next(comment);
}
createModification(id: ConversationId): Modification {
return {
claim_modification: {
comment_modification: {
id,
modification: {
creation: {}
}
}
}
};
}
}

View File

@ -0,0 +1,25 @@
import { Conversation } from '../../../../thrift-services/messages/gen-model/messages';
import { TimelineAction, TimelineItemInfo } from './model';
export const addCommentsToTimelineInfos = (
conversations: Conversation[],
infos: TimelineItemInfo[]
): TimelineItemInfo[] =>
infos.map(info => {
if (info.action === TimelineAction.commentAdded) {
return {
...info,
data: conversations
? conversations.find(conversation => {
return !!info.modifications.find(
m =>
m.claim_modification.comment_modification.id ===
conversation.conversation_id
);
})
: null
};
} else {
return info;
}
});

View File

@ -0,0 +1,41 @@
import { TimelineAction } from './model';
import {
ClaimModification,
StatusModificationUnit
} from '../../../../thrift-services/damsel/gen-model/claim_management';
import { getUnionKey } from '../../../../shared/get-union-key';
import { ClaimStatus } from '../../../../papi/model/claim-statuses';
function getStatusModificationTimelineAction(unit: StatusModificationUnit): TimelineAction | null {
const Status = ClaimStatus;
switch (getUnionKey(unit.status)) {
case Status.accepted:
return TimelineAction.statusAccepted;
case Status.denied:
return TimelineAction.statusDenied;
case Status.pending:
return TimelineAction.statusPending;
case Status.review:
return TimelineAction.statusReview;
case Status.revoked:
return TimelineAction.statusRevoked;
case Status.pending_acceptance:
return null;
}
}
export function getClaimModificationTimelineAction(m: ClaimModification): TimelineAction | null {
switch (getUnionKey(m)) {
case 'document_modification':
return TimelineAction.changesAdded;
case 'status_modification':
return getStatusModificationTimelineAction(
m.status_modification as StatusModificationUnit
);
case 'file_modification':
return TimelineAction.filesAdded;
case 'comment_modification':
return TimelineAction.commentAdded;
}
throw new Error(`Unknown claimModification: ${m}`);
}

View File

@ -0,0 +1,2 @@
export * from './to-timeline-info';
export * from './add-comments-to-timeline-info';

View File

@ -0,0 +1,2 @@
export * from './timeline-item-info';
export * from './timeline-action';

View File

@ -0,0 +1,10 @@
export enum TimelineAction {
changesAdded = 'changesAdded',
filesAdded = 'filesAdded',
commentAdded = 'commentAdded',
statusReview = 'statusReview',
statusPending = 'statusPending',
statusDenied = 'statusDenied',
statusRevoked = 'statusRevoked',
statusAccepted = 'statusAccepted'
}

View File

@ -0,0 +1,14 @@
import { TimelineAction } from './timeline-action';
import {
Modification,
UserInfo
} from '../../../../../thrift-services/damsel/gen-model/claim_management';
import { Conversation } from '../../../../../thrift-services/messages/gen-model/messages';
export interface TimelineItemInfo {
action: TimelineAction;
user_info: UserInfo;
created_at: string;
modifications: Modification[];
data?: Conversation;
}

View File

@ -0,0 +1,68 @@
import {
ClaimModification,
Modification,
ModificationUnit
} from '../../../../thrift-services/damsel/gen-model/claim_management';
import { TimelineAction, TimelineItemInfo } from './model';
import { sortUnitsByCreatedAtAsc } from '../../../../shared/utils';
import { getUnionKey } from '../../../../shared/get-union-key';
import { getClaimModificationTimelineAction } from './get-claim-modification-timeline-action';
const isSame = (x: TimelineItemInfo, y: TimelineItemInfo): boolean =>
x.action === y.action && x.user_info.type === y.user_info.type;
const getUnitTimelineAction = (modification: Modification): TimelineAction | null => {
switch (getUnionKey(modification)) {
case 'claim_modification':
return getClaimModificationTimelineAction(
modification.claim_modification as ClaimModification
);
case 'party_modification':
return TimelineAction.changesAdded;
}
};
const concatLastItem = (
acc: TimelineItemInfo[],
updateItem: TimelineItemInfo
): TimelineItemInfo[] =>
acc.map((accItem, accItemIndex) =>
accItemIndex === acc.length - 1
? {
...updateItem,
modifications: accItem.modifications.concat(updateItem.modifications)
}
: accItem
);
const acceptTimelineItem = (
acc: TimelineItemInfo[],
{ created_at, modification, user_info }: ModificationUnit
): TimelineItemInfo[] => {
const action = getUnitTimelineAction(modification);
if (action === null) {
return acc;
}
const modifications = [modification];
const result = {
action,
user_info,
created_at: created_at as string,
modifications
};
if (acc.length !== 0 && modifications.length !== 0) {
const lastItem = acc[acc.length - 1];
if (isSame(result, lastItem)) {
return concatLastItem(acc, result);
}
}
return acc.concat(result);
};
export const toTimelineInfo = (units: ModificationUnit[]): TimelineItemInfo[] => {
if (!units || units.length === 0) {
return [];
}
const sortedUnits = sortUnitsByCreatedAtAsc(units);
return sortedUnits.reduce(acceptTimelineItem, []);
};

View File

@ -0,0 +1,56 @@
<mat-card *ngIf="claim">
<mat-card-subtitle>Claim details</mat-card-subtitle>
<mat-card-content>
<div fxFlex="50" fxLayout="column" fxLayoutGap="10px">
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Claim ID:</label>
<div>{{ claim.id }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Revision:</label>
<div>{{ claim.revision }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Status:</label>
<div>{{ claim.status | ccClaimStatus }}</div>
</div>
<div
fxLayout="row"
fxLayout.xs="column"
*ngIf="claim.status.denied || claim.status.revoked"
>
<label fxFlex="20">Reason:</label>
<div>{{ claim.status.revoked?.reason || claim.status.denied?.reason }}</div>
</div>
</div>
<div fxFlex="50" fxLayout="column" fxLayoutGap="10px">
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Party ID:</label>
<div>{{ claim.party_id }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Created At:</label>
<div>{{ claim.created_at | date: 'dd.MM.yyyy HH:mm:ss' }}</div>
</div>
<div fxLayout="row" fxLayout.xs="column">
<label fxFlex="20">Updated At:</label>
<div>{{ claim.updated_at | date: 'dd.MM.yyyy HH:mm:ss' }}</div>
</div>
</div>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayoutAlign="space-between stretch">
<div fxLayout="row" fxLayout.xs="column">
<button mat-button [disabled]="" (click)="addModification()">ADD MODIFICATION</button>
</div>
<div fxLayout="row" fxLayout.xs="column">
<button
mat-raised-button
color="primary"
(click)="editStatus()"
[disabled]="!canChangeStatus()"
>
CHANGE STATUS
</button>
</div>
</mat-card-actions>
</mat-card>

View File

@ -0,0 +1,56 @@
import { Component, Input } from '@angular/core';
import { MatDialog } from '@angular/material/dialog';
import { MatBottomSheet } from '@angular/material/bottom-sheet';
import { filter } from 'rxjs/operators';
import { Claim } from '../../../thrift-services/damsel/gen-model/claim_management';
import { StatusChangerComponent } from '../status-changer/status-changer.component';
import { getAvailableClaimStatuses } from '../status-changer/get-available-claim-statuses';
import { ClaimService } from '../claim.service';
import { UnitActionsComponent } from '../party-modification-creator/unit-actions/unit-actions.component';
@Component({
selector: 'cc-claim-details',
templateUrl: 'details.component.html'
})
export class DetailsComponent {
@Input() claim: Claim;
constructor(
private dialog: MatDialog,
private claimService: ClaimService,
private bottomSheet: MatBottomSheet
) {}
editStatus() {
this.dialog
.open(StatusChangerComponent, {
width: '500px',
disableClose: true,
data: {
partyID: this.claim.party_id,
claimID: this.claim.id,
claimStatus: this.claim.status
}
})
.afterClosed()
.pipe(filter(r => r))
.subscribe(_ => {
this.claimService.getClaim(this.claim.party_id, this.claim.id);
});
}
canChangeStatus(): boolean {
return getAvailableClaimStatuses(this.claim.status).length > 0;
}
addModification() {
this.bottomSheet.open(UnitActionsComponent, {
data: {
partyID: this.claim.party_id,
claimID: this.claim.id,
type: 'allActions'
}
});
}
}

View File

@ -0,0 +1 @@
export * from './claim.module';

View File

@ -0,0 +1,66 @@
import { Pipe, PipeTransform } from '@angular/core';
import { ShopModificationName } from './shop-modification-name';
import { ContractModificationName } from './contract-modification-name';
import { ModificationGroupType } from '../../../claim/model';
@Pipe({
name: 'ccContainerName'
})
export class ContainerNamePipe implements PipeTransform {
transform(value: any, ...args: any[]): any {
if (args.length < 1) {
return value;
}
const type = args[0] as ModificationGroupType;
switch (type) {
case ModificationGroupType.ShopUnitContainer:
return this.transformShopModification(value);
case ModificationGroupType.ContractUnitContainer:
return this.transformContractModificationName(value);
default:
return value;
}
}
private transformShopModification(value: ShopModificationName): string {
switch (value) {
case ShopModificationName.creation:
return 'Shop creation';
case ShopModificationName.categoryModification:
return 'Shop category modification';
case ShopModificationName.detailsModification:
return 'Shop details modification';
case ShopModificationName.contractModification:
return 'Shop contract modification';
case ShopModificationName.payoutToolModification:
return 'Shop payout tool modification';
case ShopModificationName.locationModification:
return 'Shop location modification';
case ShopModificationName.shopAccountCreation:
return 'Shop account creation';
case ShopModificationName.payoutScheduleModification:
return 'Shop schedule modification';
default:
return value;
}
}
private transformContractModificationName(value: ContractModificationName): string {
switch (value) {
case ContractModificationName.creation:
return 'Contract creation';
case ContractModificationName.termination:
return 'Contract termination';
case ContractModificationName.adjustmentModification:
return 'Contract adjustment modification';
case ContractModificationName.payoutToolModification:
return 'Contract payout tool modification';
case ContractModificationName.legalAgreementBinding:
return 'Contract legal agreement binding';
case ContractModificationName.reportPreferencesModification:
return 'Contract report preferences modification';
default:
return value;
}
}
}

View File

@ -0,0 +1,10 @@
export enum ContractModificationName {
creation = 'creation',
termination = 'termination',
adjustmentModification = 'adjustment_modification',
payoutToolModification = 'payout_tool_modification',
legalAgreementBinding = 'legal_agreement_binding',
reportPreferencesModification = 'report_preferences_modification',
contractorModification = 'contractor_modification',
unknown = 'unknown'
}

View File

@ -0,0 +1,18 @@
<div class="mat-dialog-title">
{{ action.name | ccContainerName: getContainerType(action.type) }}
</div>
<mat-dialog-content>
<cc-party-modification-creation
[action]="action"
(valueChanges)="valueChanges($event)"
(statusChanges)="statusChanges($event)"
>
</cc-party-modification-creation>
</mat-dialog-content>
<mat-dialog-actions *ngIf="initialized">
<button mat-button [disabled]="isLoading || !valid" color="primary" (click)="apply()">
APPLY
</button>
<button [disabled]="isLoading" mat-button [mat-dialog-close]="false">CANCEL</button>
<mat-progress-bar mode="indeterminate" *ngIf="isLoading"></mat-progress-bar>
</mat-dialog-actions>

View File

@ -0,0 +1,88 @@
import { Component, Inject, OnInit } from '@angular/core';
import { MAT_DIALOG_DATA } from '@angular/material';
import { MatDialogRef } from '@angular/material/dialog';
import { ActionType, ModificationAction } from './modification-action';
import {
ClaimID,
PartyModification
} from '../../../thrift-services/damsel/gen-model/claim_management';
import { ModificationGroupType } from '../../../claim/model';
import { ClaimManagementService } from '../../../thrift-services/damsel/claim-management.service';
import { ClaimService } from '../claim.service';
export interface CreateModificationData {
action: ModificationAction;
claimID: ClaimID;
partyID: string;
}
@Component({
templateUrl: 'create-modification.component.html'
})
export class CreateModificationComponent implements OnInit {
isLoading = false;
valid = false;
initialized = false;
values: PartyModification;
action: ModificationAction;
constructor(
private dialogRef: MatDialogRef<CreateModificationComponent>,
@Inject(MAT_DIALOG_DATA) public data: CreateModificationData,
private claimManagementService: ClaimManagementService,
private claimService: ClaimService
) {}
ngOnInit() {
this.action = this.data.action;
this.initialized = true;
}
valueChanges(e: any) {
this.values = e;
}
statusChanges(status: string) {
this.valid = status === 'VALID';
}
apply() {
switch (this.data.action.type) {
case ActionType.shopAction:
case ActionType.contractAction:
this.addChange();
break;
}
}
getContainerType(type: ActionType): string {
switch (type) {
case ActionType.shopAction:
return ModificationGroupType.ShopUnitContainer;
case ActionType.contractAction:
return ModificationGroupType.ContractUnitContainer;
}
}
private addChange() {
this.isLoading = true;
this.claimManagementService
.updateClaim(this.data.partyID, this.data.claimID, [
{ party_modification: this.values }
])
.subscribe(
_ => {
this.isLoading = false;
this.claimService.getClaim(this.data.partyID, this.data.claimID);
this.dialogRef.close(true);
},
e => {
this.isLoading = false;
console.error(e);
}
);
}
}

View File

@ -0,0 +1,6 @@
<form [formGroup]="form">
<cc-business-schedule-selector
(idChange)="scheduleIdChange($event)"
[initialValue]="initialValue?.id.valueOf()"
></cc-business-schedule-selector>
</form>

View File

@ -0,0 +1,28 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import get from 'lodash-es/get';
import { BusinessScheduleRef } from '../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-business-schedule-ref',
templateUrl: 'business-schedule-ref.component.html'
})
export class BusinessScheduleRefComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: BusinessScheduleRef;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const id = get(this, 'initialValue.id', '');
this.form.registerControl('id', this.fb.control(id, Validators.required));
this.form.updateValueAndValidity();
}
scheduleIdChange(id: number) {
this.form.controls.id.setValue(id);
}
}

View File

@ -0,0 +1,15 @@
<div fxLayout="column">
<mat-form-field>
<mat-select
placeholder="Select schedule"
[disabled]="isLoading || hasError"
(selectionChange)="selectionChange($event)"
[value]="initialValue"
>
<mat-option *ngFor="let schedule of (schedules$ | async)" [value]="schedule.ref.id">
{{ schedule.ref.id }} {{ schedule.data.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
</div>

View File

@ -0,0 +1,45 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { MatSelectChange, MatSnackBar } from '@angular/material';
import { tap } from 'rxjs/internal/operators';
import { Observable } from 'rxjs';
import { BusinessScheduleObject } from '../../../../../../thrift-services/damsel/gen-model/domain';
import { DomainTypedManager } from '../../../../../../thrift-services';
@Component({
selector: 'cc-business-schedule-selector',
templateUrl: 'business-schedule-selector.component.html'
})
export class BusinessScheduleSelectorComponent implements OnInit {
@Input()
initialValue: string;
@Output()
idChange = new EventEmitter<number>();
schedules$: Observable<BusinessScheduleObject[]>;
isLoading = true;
hasError = false;
constructor(private domainManager: DomainTypedManager, private snackBar: MatSnackBar) {}
selectionChange(change: MatSelectChange) {
this.idChange.emit(change.value);
}
ngOnInit() {
this.schedules$ = this.domainManager.getBusinessScheduleObjects().pipe(
tap(
() => {
this.isLoading = false;
},
() => {
this.isLoading = false;
this.hasError = true;
this.snackBar.open('An error occurred while business schedule receiving', 'OK');
}
)
);
}
}

View File

@ -0,0 +1,11 @@
<form [formGroup]="form" fxLayout="column" fxLayoutGap="15px">
<mat-form-field fxFlex>
<input matInput placeholder="Adjustment ID" formControlName="adjustment_id" required />
</mat-form-field>
<div><button (click)="generate()" mat-stroked-button>GENERATE NEW VALUE</button></div>
<cc-adjustment-modification
[form]="form.get('modification')"
[initialValue]="initialValue?.modification"
>
</cc-adjustment-modification>
</form>

View File

@ -0,0 +1,33 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import * as uuid from 'uuid/v4';
import get from 'lodash-es/get';
import { ContractAdjustmentModificationUnit } from '../../../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-adjustment-modification-unit',
templateUrl: 'adjustment-modification-unit.component.html'
})
export class AdjustmentModificationUnitComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: ContractAdjustmentModificationUnit;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const adjustmentId = get(this, 'initialValue.adjustment_id', '');
this.form.registerControl(
'adjustment_id',
this.fb.control(adjustmentId, Validators.required)
);
this.form.registerControl('modification', this.fb.group({}));
this.form.updateValueAndValidity();
}
generate() {
this.form.patchValue({ adjustment_id: uuid() });
}
}

View File

@ -0,0 +1,7 @@
<div fxLayout="column">
<cc-contract-adjustment-params
[form]="form.get('creation')"
[initialValue]="initialValue?.creation"
>
</cc-contract-adjustment-params>
</div>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ContractAdjustmentModification } from '../../../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-adjustment-modification',
templateUrl: 'adjustment-modification.component.html'
})
export class AdjustmentModificationComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: ContractAdjustmentModification;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('creation', this.fb.group({}));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,8 @@
<form [formGroup]="form" fxLayout="column" fxLayoutGap="5px">
<cc-contract-template-ref
[form]="form.get('template')"
[required]="true"
[initialValue]="initialValue?.template"
>
</cc-contract-template-ref>
</form>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { ContractAdjustmentParams } from '../../../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-contract-adjustment-params',
templateUrl: 'adjustment-params.component.html'
})
export class AdjustmentParamsComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: ContractAdjustmentParams;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('template', this.fb.group({}));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,36 @@
<form *ngIf="form" [formGroup]="form" fxLayout="column" fxLayoutGap="5px">
<!--<mat-form-field fxFlex>-->
<!--<input matInput-->
<!--placeholder="Contractor ID"-->
<!--formControlName="contractorId"-->
<!--required>-->
<!--</mat-form-field>-->
<mat-checkbox [checked]="showTemplate" (change)="toggleCheckbox($event.checked, 'template')"
>Template</mat-checkbox
>
<cc-contract-template-ref
*ngIf="form.get('template')"
[form]="form.get('template')"
[initialValue]="initialValue?.template"
>
</cc-contract-template-ref>
<mat-checkbox
[checked]="showPaymentInstitution"
(change)="toggleCheckbox($event.checked, 'payment_institution')"
>Payment institution</mat-checkbox
>
<cc-payment-institution-ref
*ngIf="form.get('payment_institution')"
[form]="form.get('payment_institution')"
[initialValue]="initialValue?.payment_institution"
>
</cc-payment-institution-ref>
<!-- <cc-nested-form-wrapper caption="contractor">-->
<!-- <cc-contractor-->
<!-- fxFlex-->
<!-- [form]="form.get('contractor')"-->
<!-- [initialValue]="initialValue?.contractor"-->
<!-- >-->
<!-- </cc-contractor>-->
<!-- </cc-nested-form-wrapper>-->
</form>

View File

@ -0,0 +1,49 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { get } from 'lodash-es';
import { ContractParams } from '../../../../../../thrift-services/damsel/gen-model/claim_management';
@Component({
selector: 'cc-contract-params',
templateUrl: 'contract-params.component.html'
})
export class ContractParamsComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: ContractParams;
showTemplate = false;
showPaymentInstitution = false;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('contractor', this.fb.group({}));
this.toggleTemplate();
this.togglePaymentInstitution();
this.form.updateValueAndValidity();
}
toggleCheckbox(show: boolean, controlName: string, data: object = {}) {
if (show) {
this.form.registerControl(controlName, this.fb.group(data || {}));
} else {
this.form.removeControl(controlName);
}
}
toggleTemplate() {
const template = get(this, 'initialValue.template', null);
this.showTemplate = template !== null;
this.toggleCheckbox(this.showTemplate, 'template', template);
}
togglePaymentInstitution() {
const paymentInstitution = get(this, 'initialValue.payment_institution', null);
this.showPaymentInstitution = paymentInstitution !== null;
this.toggleCheckbox(this.showPaymentInstitution, 'payment_institution', paymentInstitution);
}
}

View File

@ -0,0 +1,14 @@
<form [formGroup]="form" fxLayout="column">
<mat-form-field fxFlex>
<mat-select placeholder="Select contract template" formControlName="id" required>
<mat-option
*ngFor="let contract of (contracts$ | async)"
[value]="contract.id"
required
>
{{ contract.id }} {{ contract.name }}
</mat-option>
</mat-select>
</mat-form-field>
<mat-progress-bar *ngIf="isLoading" mode="indeterminate"></mat-progress-bar>
</form>

View File

@ -0,0 +1,66 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material';
import { Observable } from 'rxjs';
import { tap, map } from 'rxjs/internal/operators';
import sortBy from 'lodash-es/sortBy';
import get from 'lodash-es/get';
import {
ContractTemplate,
ContractTemplateRef
} from '../../../../../../thrift-services/damsel/gen-model/domain';
import { ContractService } from './contract.service';
@Component({
selector: 'cc-contract-template-ref',
templateUrl: 'contract-template-ref.component.html',
providers: [ContractService]
})
export class ContractTemplateRefComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
required: boolean;
@Input()
initialValue: ContractTemplateRef;
contracts$: Observable<ContractTemplate[]>;
isLoading = true;
constructor(
private fb: FormBuilder,
private contractService: ContractService,
private snackBar: MatSnackBar
) {}
ngOnInit() {
const templateId = get(this, 'initialValue.id', '');
this.form.registerControl(
'id',
this.fb.control(
{
value: templateId,
disabled: templateId.length === 0
},
this.required ? Validators.required : null
)
);
this.form.updateValueAndValidity();
this.contracts$ = this.contractService.getContractTemplates().pipe(
map(contracts => sortBy(contracts, 'id')),
tap(
() => {
this.form.controls.id.enable();
this.isLoading = false;
},
() => {
this.isLoading = false;
this.snackBar.open('An error occurred while contract template receiving', 'OK');
}
)
);
}
}

View File

@ -0,0 +1,16 @@
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ConfigService } from '../../../../../../core/config.service';
import { ContractTemplate } from '../../../../../../thrift-services/damsel/gen-model/domain';
@Injectable()
export class ContractService {
private readonly papiEndpoint = this.configService.config.papiEndpoint;
constructor(private http: HttpClient, private configService: ConfigService) {}
getContractTemplates(): Observable<ContractTemplate[]> {
return this.http.get<ContractTemplate[]>(`${this.papiEndpoint}/dmt/contract/templates`);
}
}

View File

@ -0,0 +1,5 @@
<form [formGroup]="form" fxLayout="column" fxLayoutGap="5px">
<mat-form-field fxFlex>
<input matInput placeholder="Contractor ID" formControlName="modification" required />
</mat-form-field>
</form>

View File

@ -0,0 +1,18 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
@Component({
selector: 'cc-contractor-id',
templateUrl: 'contractor-id.component.html'
})
export class ContractorIdComponent implements OnInit {
@Input()
form: FormGroup;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('modification', this.fb.control('', Validators.required));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,4 @@
<form *ngIf="form" [formGroup]="form" fxLayout="column" fxLayoutGap="5px">
<cc-legal-entity [form]="form.get('legal_entity')" [initialValue]="initialValue?.legal_entity">
</cc-legal-entity>
</form>

View File

@ -0,0 +1,22 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { Contractor } from '../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-contractor',
templateUrl: 'contractor.component.html'
})
export class ContractorComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: Contractor;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('legal_entity', this.fb.group({}));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,31 @@
<form [formGroup]="form" fxLayout="column" fxLayoutGap="5px">
<mat-form-field fxFlex="50">
<input
matInput
placeholder="Legal agreement ID"
formControlName="legal_agreement_id"
required
/>
</mat-form-field>
<mat-form-field fxFlex="50">
<input
matInput
[matDatepicker]="signedAtDatepicker"
placeholder="Signed at"
formControlName="signed_at"
required
/>
<mat-datepicker-toggle matSuffix [for]="signedAtDatepicker"></mat-datepicker-toggle>
<mat-datepicker #signedAtDatepicker></mat-datepicker>
</mat-form-field>
<mat-form-field fxFlex="50">
<input
matInput
[matDatepicker]="validUntilDatepicker"
placeholder="Valid until"
formControlName="valid_until"
/>
<mat-datepicker-toggle matSuffix [for]="validUntilDatepicker"></mat-datepicker-toggle>
<mat-datepicker #validUntilDatepicker></mat-datepicker>
</mat-form-field>
</form>

View File

@ -0,0 +1,31 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import get from 'lodash-es/get';
import { LegalAgreement } from '../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-legal-agreement-binding',
templateUrl: 'legal-agreement-binding.component.html'
})
export class LegalAgreementBindingComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: LegalAgreement;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const legalAgreementId = get(this, 'initialValue.legal_agreement_id', '');
const signedAt = get(this, 'initialValue.signed_at', '');
const validUntil = get(this, 'initialValue.valid_until', '');
this.form.registerControl(
'legal_agreement_id',
this.fb.control(legalAgreementId, Validators.required)
);
this.form.registerControl('signed_at', this.fb.control(signedAt, Validators.required));
this.form.registerControl('valid_until', this.fb.control(validUntil));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,24 @@
<form [formGroup]="form">
<div fxLayout="column">
<mat-form-field fxFlex>
<input matInput placeholder="Legal name" formControlName="legal_name" required />
</mat-form-field>
<mat-form-field fxFlex>
<input matInput placeholder="Trading name" formControlName="trading_name" />
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Registered address"
formControlName="registered_address"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input matInput placeholder="Actual address" formControlName="actual_address" />
</mat-form-field>
<mat-form-field fxFlex>
<input matInput placeholder="Registered number" formControlName="registered_number" />
</mat-form-field>
</div>
</form>

View File

@ -0,0 +1,27 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { InternationalLegalEntity } from '../../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-international-legal-entity',
templateUrl: 'international-legal-entity.component.html'
})
export class InternationalLegalEntityComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: InternationalLegalEntity;
constructor(private fb: FormBuilder) {}
ngOnInit() {
this.form.registerControl('legal_name', this.fb.control('', Validators.required));
this.form.registerControl('registered_address', this.fb.control('', Validators.required));
this.form.registerControl('trading_name', this.fb.control(''));
this.form.registerControl('actual_address', this.fb.control(''));
this.form.registerControl('registered_number', this.fb.control(''));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,25 @@
<cc-form-wrapper name="Legal entity">
<div fxLayout="column">
<mat-form-field>
<mat-select
placeholder="Legal entity type"
[(value)]="selected"
(selectionChange)="select()"
>
<mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option>
</mat-select>
</mat-form-field>
<cc-russian-legal-entity
*ngIf="selected === t.russian_legal_entity"
[form]="form.get(t.russian_legal_entity)"
[initialValue]="initialValue?.russian_legal_entity"
>
</cc-russian-legal-entity>
<cc-international-legal-entity
*ngIf="selected === t.international_legal_entity"
[form]="form.get(t.international_legal_entity)"
[initialValue]="initialValue?.international_legal_entity"
>
</cc-international-legal-entity>
</div>
</cc-form-wrapper>

View File

@ -0,0 +1,56 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import get from 'lodash-es/get';
import { LegalEntity } from '../../../../../../thrift-services/damsel/gen-model/domain';
enum Type {
russian_legal_entity = 'russian_legal_entity',
international_legal_entity = 'international_legal_entity'
}
@Component({
selector: 'cc-legal-entity',
templateUrl: 'legal-entity.component.html'
})
export class LegalEntityComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: LegalEntity;
types = [Type.russian_legal_entity, Type.international_legal_entity];
selected: Type;
t = Type;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const russianLegalEntity = get(this, 'initialValue.russian_legal_entity', null);
const internationalLegalEntity = get(this, 'initialValue.international_legal_entity', null);
if (russianLegalEntity) {
this.selected = Type.russian_legal_entity;
this.select();
}
if (internationalLegalEntity) {
this.selected = Type.international_legal_entity;
this.select();
}
}
select() {
switch (this.selected) {
case Type.russian_legal_entity:
this.form.removeControl(Type.international_legal_entity);
this.form.registerControl(Type.russian_legal_entity, this.fb.group({}));
break;
case Type.international_legal_entity:
this.form.removeControl(Type.russian_legal_entity);
this.form.registerControl(Type.international_legal_entity, this.fb.group({}));
break;
}
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,69 @@
<cc-form-wrapper name="Russian legal entity">
<form [formGroup]="form">
<div fxLayout="column">
<mat-form-field fxFlex>
<input
matInput
placeholder="Registered name"
formControlName="registered_name"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Registered number"
formControlName="registered_number"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input matInput placeholder="INN" formControlName="inn" required />
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Actual address"
formControlName="actual_address"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Post address"
formControlName="post_address"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Representative position"
formControlName="representative_position"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Representative full name"
formControlName="representative_full_name"
required
/>
</mat-form-field>
<mat-form-field fxFlex>
<input
matInput
placeholder="Representative document"
formControlName="representative_document"
required
/>
</mat-form-field>
<cc-nested-form-wrapper caption="russian_bank_account">
<cc-russian-bank-account fxFlex [form]="form.get('russian_bank_account')">
</cc-russian-bank-account>
</cc-nested-form-wrapper>
</div>
</form>
</cc-form-wrapper>

View File

@ -0,0 +1,40 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import get from 'lodash-es/get';
import { RussianLegalEntity } from '../../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-russian-legal-entity',
templateUrl: 'russian-legal-entity.component.html'
})
export class RussianLegalEntityComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: RussianLegalEntity;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const control = value => this.fb.control(value, Validators.required);
const registeredName = get(this, 'initialValue.registered_name', '');
const registeredNumber = get(this, 'initialValue.registered_number', '');
const inn = get(this, 'initialValue.inn', '');
const actualAddress = get(this, 'initialValue.actual_address', '');
const postAddress = get(this, 'initialValue.post_address', '');
const representativePosition = get(this, 'initialValue.representative_position', '');
const representativeFullName = get(this, 'initialValue.representative_full_name', '');
const representativeDocument = get(this, 'initialValue.representative_document', '');
this.form.registerControl('registered_name', control(registeredName));
this.form.registerControl('registered_number', control(registeredNumber));
this.form.registerControl('inn', control(inn));
this.form.registerControl('actual_address', control(actualAddress));
this.form.registerControl('post_address', control(postAddress));
this.form.registerControl('representative_position', control(representativePosition));
this.form.registerControl('representative_full_name', control(representativeFullName));
this.form.registerControl('representative_document', control(representativeDocument));
this.form.registerControl('russian_bank_account', this.fb.group({}));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,13 @@
<form [formGroup]="form">
<mat-form-field fxFlex>
<mat-select placeholder="Select payment institution" formControlName="id">
<mat-option
*ngFor="let paymentInstitution of (paymentInstitutions$ | async)"
[value]="paymentInstitution.ref.id"
required
>
{{ paymentInstitution.ref.id }} {{ paymentInstitution.data.name }}
</mat-option>
</mat-select>
</mat-form-field>
</form>

View File

@ -0,0 +1,46 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { map } from 'rxjs/operators';
import sortBy from 'lodash-es/sortBy';
import { Observable } from 'rxjs';
import get from 'lodash-es/get';
import {
PaymentInstitutionObject,
PaymentInstitutionRef
} from '../../../../../../thrift-services/damsel/gen-model/domain';
import { DomainTypedManager } from '../../../../../../thrift-services';
@Component({
selector: 'cc-payment-institution-ref',
templateUrl: 'payment-institution-ref.component.html'
})
export class PaymentInstitutionRefComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
required: boolean;
@Input()
initialValue: PaymentInstitutionRef;
paymentInstitutions$: Observable<PaymentInstitutionObject[]>;
constructor(private fb: FormBuilder, private dtm: DomainTypedManager) {}
ngOnInit() {
this.paymentInstitutions$ = this.dtm
.getPaymentInstitutions()
.pipe(
map(paymentInstitutions =>
sortBy(paymentInstitutions, paymentInstitution => paymentInstitution.ref.id)
)
);
const paymentInstitutionId = get(this, 'initialValue.id', '');
this.form.registerControl(
'id',
this.fb.control(paymentInstitutionId, this.required ? Validators.required : null)
);
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,40 @@
<cc-form-wrapper name="International bank account">
<form [formGroup]="form" fxLayout="column">
<mat-form-field>
<input matInput placeholder="Number" formControlName="number" />
</mat-form-field>
<mat-form-field>
<input matInput placeholder="IBAN" formControlName="iban" />
</mat-form-field>
<div fxLayout="column" fxLayoutGap="15px">
<section>
<mat-checkbox [checked]="isBankDetails" (change)="detailsChange($event.checked)"
>International bank details</mat-checkbox
>
</section>
<cc-international-bank-details
*ngIf="isBankDetails"
[form]="form.get('bank')"
[initialValue]="initialValue?.bank"
>
</cc-international-bank-details>
<section>
<mat-checkbox
[checked]="isCorrespondentAccount"
(change)="accountChange($event.checked)"
>Correspondent account</mat-checkbox
>
</section>
<div fxLayout>
<div fxFlex="10"></div>
<cc-international-bank-account
fxFlex="90"
*ngIf="isCorrespondentAccount"
[form]="form.get('correspondent_account')"
[initialValue]="initialValue?.correspondent_account"
>
</cc-international-bank-account>
</div>
</div>
</form>
</cc-form-wrapper>

View File

@ -0,0 +1,52 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import get from 'lodash-es/get';
import { InternationalBankAccount } from '../../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-international-bank-account',
templateUrl: 'international-bank-account.component.html'
})
export class InternationalBankAccountComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: InternationalBankAccount;
isBankDetails = false;
isCorrespondentAccount = false;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const number = get(this, 'initialValue.number', '');
const iban = get(this, 'initialValue.iban', '');
this.form.registerControl('number', this.fb.control(number));
this.form.registerControl('iban', this.fb.control(iban));
const bank = get(this, 'initialValue.bank', null);
if (bank) {
this.detailsChange(true);
}
const account = get(this, 'initialValue.correspondent_account', null);
if (account) {
this.accountChange(true);
}
this.form.updateValueAndValidity();
}
detailsChange(showDetails: boolean) {
this.isBankDetails = showDetails;
this.isBankDetails
? this.form.registerControl('bank', this.fb.group({}))
: this.form.removeControl('bank');
}
accountChange(showCorrespondentAccount: boolean) {
this.isCorrespondentAccount = showCorrespondentAccount;
this.isCorrespondentAccount
? this.form.registerControl('correspondent_account', this.fb.group({}))
: this.form.removeControl('correspondent_account');
}
}

View File

@ -0,0 +1,13 @@
<form [formGroup]="form" fxLayout="column">
<mat-form-field> <input matInput placeholder="BIC" formControlName="bic" /> </mat-form-field>
<mat-form-field> <input matInput placeholder="Name" formControlName="name" /> </mat-form-field>
<mat-form-field>
<input matInput placeholder="Address" formControlName="address" />
</mat-form-field>
<mat-form-field>
<input matInput placeholder="ABA routing transit number" formControlName="aba_rtn" />
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Country code" formControlName="country" />
</mat-form-field>
</form>

View File

@ -0,0 +1,33 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import get from 'lodash-es/get';
import { InternationalBankDetails } from '../../../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-international-bank-details',
templateUrl: 'international-bank-details.component.html'
})
export class InternationalBankDetailsComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: InternationalBankDetails;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const control = (data = '') => this.fb.control(data);
const bic = get(this, 'initialValue.bic', '');
const country = get(this, 'initialValue.country', '');
const name = get(this, 'initialValue.name', '');
const address = get(this, 'initialValue.address', '');
const abaRtn = get(this, 'initialValue.aba_rtn', '');
this.form.registerControl('bic', control(bic));
this.form.registerControl('country', control(country)); // Residence enum
this.form.registerControl('name', control(name));
this.form.registerControl('address', control(address));
this.form.registerControl('aba_rtn', control(abaRtn));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,25 @@
<div fxLayout="column">
<mat-form-field>
<mat-select
placeholder="Payout tool info"
[(value)]="selected"
(selectionChange)="select()"
>
<mat-option *ngFor="let type of types" [value]="type">{{ type }}</mat-option>
</mat-select>
</mat-form-field>
<cc-russian-bank-account
*ngIf="selected === t.russian_bank_account"
[form]="form.get(t.russian_bank_account)"
[initialValue]="initialValue?.russian_bank_account"
>
</cc-russian-bank-account>
<cc-international-bank-account
*ngIf="selected === t.international_bank_account"
[form]="form.get(t.international_bank_account)"
[initialValue]="initialValue?.international_bank_account"
>
</cc-international-bank-account>
<cc-wallet-info *ngIf="selected === t.wallet_info" [form]="form.get(t.wallet_info)">
</cc-wallet-info>
</div>

View File

@ -0,0 +1,71 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import get from 'lodash-es/get';
import { PayoutToolInfo } from '../../../../../../thrift-services/damsel/gen-model/domain';
enum Type {
russian_bank_account = 'russian_bank_account',
international_bank_account = 'international_bank_account',
wallet_info = 'wallet_info'
}
@Component({
selector: 'cc-payout-tool-info',
templateUrl: 'payout-tool-info.component.html'
})
export class PayoutToolInfoComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: PayoutToolInfo;
selected: Type;
types = [Type.russian_bank_account, Type.international_bank_account, Type.wallet_info];
t = Type;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const russianBankAccount = get(this, 'initialValue.russian_bank_account', null);
const internationalBankAccount = get(this, 'initialValue.international_bank_account', null);
const walletInfo = get(this, 'initialValue.wallet_info', null);
if (russianBankAccount) {
this.selected = Type.russian_bank_account;
}
if (internationalBankAccount) {
this.selected = Type.international_bank_account;
}
if (walletInfo) {
this.selected = Type.wallet_info;
}
this.select();
this.form.updateValueAndValidity();
}
select() {
switch (this.selected) {
case Type.russian_bank_account:
this.clearControl();
this.form.registerControl(Type.russian_bank_account, this.fb.group({}));
break;
case Type.international_bank_account:
this.clearControl();
this.form.registerControl(Type.international_bank_account, this.fb.group({}));
break;
case Type.wallet_info:
this.clearControl();
const walletInfo = get(this, 'initialValue.wallet_info', {});
this.form.registerControl(Type.wallet_info, this.fb.group(walletInfo));
break;
}
}
private clearControl() {
this.types.forEach(type => {
this.form.removeControl(type);
});
}
}

View File

@ -0,0 +1,21 @@
<cc-form-wrapper name="Russian bank account">
<form [formGroup]="form" fxLayout="column">
<mat-form-field>
<input matInput placeholder="Account" formControlName="account" required />
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Bank name" formControlName="bank_name" required />
</mat-form-field>
<mat-form-field>
<input
matInput
placeholder="Bank post account"
formControlName="bank_post_account"
required
/>
</mat-form-field>
<mat-form-field>
<input matInput placeholder="Bank bik" formControlName="bank_bik" required />
</mat-form-field>
</form>
</cc-form-wrapper>

View File

@ -0,0 +1,31 @@
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import get from 'lodash-es/get';
import { RussianBankAccount } from '../../../../../../../thrift-services/damsel/gen-model/domain';
@Component({
selector: 'cc-russian-bank-account',
templateUrl: 'russian-bank-account.component.html'
})
export class RussianBankAccountComponent implements OnInit {
@Input()
form: FormGroup;
@Input()
initialValue: RussianBankAccount;
constructor(private fb: FormBuilder) {}
ngOnInit() {
const control = value => this.fb.control(value, Validators.required);
const account = get(this, 'initialValue.account', '');
const bankName = get(this, 'initialValue.bank_name', '');
const bankPostAccount = get(this, 'initialValue.bank_post_account', '');
const bankBik = get(this, 'initialValue.bank_bik', '');
this.form.registerControl('account', control(account));
this.form.registerControl('bank_name', control(bankName));
this.form.registerControl('bank_post_account', control(bankPostAccount));
this.form.registerControl('bank_bik', control(bankBik));
this.form.updateValueAndValidity();
}
}

View File

@ -0,0 +1,7 @@
<cc-form-wrapper name="Wallet Info">
<form [formGroup]="form" fxLayout="column">
<mat-form-field>
<input matInput placeholder="Wallet ID" formControlName="wallet_id" required />
</mat-form-field>
</form>
</cc-form-wrapper>

Some files were not shown because too many files have changed in this diff Show More