feat: downloadable tx summary and logs
This commit is contained in:
parent
bd9615c5ea
commit
92b6093a07
7 changed files with 311 additions and 37 deletions
|
|
@ -5,17 +5,17 @@ const transactions = require('../../services/transactions')
|
|||
const anonymous = require('../../../constants').anonymousCustomer
|
||||
|
||||
const transactionsLoader = new DataLoader(ids => transactions.getCustomerTransactionsBatch(ids))
|
||||
const tx_logFields = ["txClass", "id", "deviceId", "toAddress", "cryptoAtoms",
|
||||
"cryptoCode", "fiat", "fiatCode", "fee", "status",
|
||||
"dispense", "notified", "redeem", "phone", "error",
|
||||
"created", "confirmedAt", "hdIndex", "swept", "timedout",
|
||||
"dispenseConfirmed", "provisioned1", "provisioned2",
|
||||
"denomination1", "denomination2", "errorCode", "customerId",
|
||||
"txVersion", "publishedAt", "termsAccepted", "layer2Address",
|
||||
"commissionPercentage", "rawTickerPrice", "receivedCryptoAtoms",
|
||||
"discount", "txHash", "customerPhone", "customerIdCardDataNumber",
|
||||
"customerIdCardDataExpiration", "customerIdCardData", "customerName",
|
||||
"customerFrontCameraPath", "customerIdCardPhotoPath", "expired", "machineName"]
|
||||
const txLogFields = ['txClass', 'id', 'deviceId', 'toAddress', 'cryptoAtoms',
|
||||
'cryptoCode', 'fiat', 'fiatCode', 'fee', 'status',
|
||||
'dispense', 'notified', 'redeem', 'phone', 'error',
|
||||
'created', 'confirmedAt', 'hdIndex', 'swept', 'timedout',
|
||||
'dispenseConfirmed', 'provisioned1', 'provisioned2',
|
||||
'denomination1', 'denomination2', 'errorCode', 'customerId',
|
||||
'txVersion', 'publishedAt', 'termsAccepted', 'layer2Address',
|
||||
'commissionPercentage', 'rawTickerPrice', 'receivedCryptoAtoms',
|
||||
'discount', 'txHash', 'customerPhone', 'customerIdCardDataNumber',
|
||||
'customerIdCardDataExpiration', 'customerIdCardData', 'customerName',
|
||||
'customerFrontCameraPath', 'customerIdCardPhotoPath', 'expired', 'machineName']
|
||||
|
||||
const resolvers = {
|
||||
Customer: {
|
||||
|
|
@ -28,7 +28,11 @@ const resolvers = {
|
|||
transactions: (...[, { from, until, limit, offset, deviceId }]) =>
|
||||
transactions.batch(from, until, limit, offset, deviceId),
|
||||
transactionsCsv: (...[, { from, until, limit, offset }]) =>
|
||||
transactions.batch(from, until, limit, offset).then(data => parseAsync(data, {fields: tx_logFields}))
|
||||
transactions.batch(from, until, limit, offset).then(data => parseAsync(data, { fields: txLogFields })),
|
||||
transactionCsv: (...[, { id, txClass }]) =>
|
||||
transactions.getTx(id, txClass).then(parseAsync),
|
||||
txAssociatedDataCsv: (...[, { id, txClass }]) =>
|
||||
transactions.getTxAssociatedData(id, txClass).then(parseAsync)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -48,6 +48,8 @@ const typeDef = gql`
|
|||
type Query {
|
||||
transactions(from: Date, until: Date, limit: Int, offset: Int, deviceId: ID): [Transaction] @auth
|
||||
transactionsCsv(from: Date, until: Date, limit: Int, offset: Int): String @auth
|
||||
transactionCsv(id: ID, txClass: String): String @auth
|
||||
txAssociatedDataCsv(id: ID, txClass: String): String @auth
|
||||
}
|
||||
`
|
||||
|
||||
|
|
|
|||
|
|
@ -162,4 +162,33 @@ function cancel (txId) {
|
|||
.then(() => single(txId))
|
||||
}
|
||||
|
||||
module.exports = { batch, single, cancel, getCustomerTransactionsBatch }
|
||||
function getTx (txId, txClass) {
|
||||
const cashInSql = `select 'cashIn' as tx_class, txs.*,
|
||||
((not txs.send_confirmed) and (txs.created <= now() - interval $1)) as expired
|
||||
from cash_in_txs as txs
|
||||
where txs.id=$2`
|
||||
|
||||
const cashOutSql = `select 'cashOut' as tx_class,
|
||||
txs.*,
|
||||
(extract(epoch from (now() - greatest(txs.created, txs.confirmed_at))) * 1000) >= $2 as expired
|
||||
from cash_out_txs txs
|
||||
where txs.id=$1`
|
||||
|
||||
if (txClass === 'cashIn') {
|
||||
return db.oneOrNone(cashInSql, [cashInTx.PENDING_INTERVAL, txId])
|
||||
} else {
|
||||
return db.oneOrNone(cashOutSql, [txId, REDEEMABLE_AGE])
|
||||
}
|
||||
}
|
||||
|
||||
function getTxAssociatedData (txId, txClass) {
|
||||
const billsSql = `select 'bills' as bills, b.* from bills b where cash_in_txs_id = $1`
|
||||
const actionsSql = `select 'cash_out_actions' as cash_out_actions, actions.* from cash_out_actions actions where tx_id = $1`
|
||||
if (txClass === 'cashIn') {
|
||||
return db.manyOrNone(billsSql, [txId])
|
||||
} else {
|
||||
return db.manyOrNone(actionsSql, [txId])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { batch, single, cancel, getCustomerTransactionsBatch, getTx, getTxAssociatedData }
|
||||
|
|
|
|||
207
new-lamassu-admin/package-lock.json
generated
207
new-lamassu-admin/package-lock.json
generated
|
|
@ -9513,8 +9513,7 @@
|
|||
"core-util-is": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
|
||||
"dev": true
|
||||
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||
},
|
||||
"cosmiconfig": {
|
||||
"version": "6.0.0",
|
||||
|
|
@ -14315,6 +14314,11 @@
|
|||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"immediate": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz",
|
||||
"integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps="
|
||||
},
|
||||
"immer": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/immer/-/immer-1.10.0.tgz",
|
||||
|
|
@ -14420,13 +14424,12 @@
|
|||
"inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"ini": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"dev": true
|
||||
},
|
||||
"inline-style-prefixer": {
|
||||
|
|
@ -14437,6 +14440,133 @@
|
|||
"css-in-js-utils": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"inquirer": {
|
||||
"version": "7.3.3",
|
||||
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz",
|
||||
"integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-escapes": "^4.2.1",
|
||||
"chalk": "^4.1.0",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-width": "^3.0.0",
|
||||
"external-editor": "^3.0.3",
|
||||
"figures": "^3.0.0",
|
||||
"lodash": "^4.17.19",
|
||||
"mute-stream": "0.0.8",
|
||||
"run-async": "^2.4.0",
|
||||
"rxjs": "^6.6.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"through": "^2.3.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true
|
||||
},
|
||||
"eslint-scope": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz",
|
||||
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
|
||||
"requires": {
|
||||
"esrecurse": "^4.3.0",
|
||||
"estraverse": "^4.1.1"
|
||||
}
|
||||
},
|
||||
"eslint-utils": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz",
|
||||
"integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==",
|
||||
"requires": {
|
||||
"eslint-visitor-keys": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true
|
||||
},
|
||||
"string-width": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz",
|
||||
"integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"internal-ip": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
|
||||
|
|
@ -16848,6 +16978,17 @@
|
|||
"object.assign": "^4.1.2"
|
||||
}
|
||||
},
|
||||
"jszip": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/jszip/-/jszip-3.6.0.tgz",
|
||||
"integrity": "sha512-jgnQoG9LKnWO3mnVNBnfhkh0QknICd1FGSrXcgrl67zioyJ4wgx25o9ZqwNtrROSflGBCGYnJfjrIyRIby1OoQ==",
|
||||
"requires": {
|
||||
"lie": "~3.3.0",
|
||||
"pako": "~1.0.2",
|
||||
"readable-stream": "~2.3.6",
|
||||
"set-immediate-shim": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"killable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz",
|
||||
|
|
@ -16946,14 +17087,22 @@
|
|||
}
|
||||
},
|
||||
"libphonenumber-js": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.8.4.tgz",
|
||||
"integrity": "sha512-s0fTPZRB4hcsfDL9p6wUNOLngVh4y3fBPhH33dL7OfkHA2RirI8p3rlR+4f4SMxdcng9jPNOweS2Z47BivHMYw==",
|
||||
"version": "1.9.10",
|
||||
"resolved": "https://registry.npmjs.org/libphonenumber-js/-/libphonenumber-js-1.9.10.tgz",
|
||||
"integrity": "sha512-XyBYwt1dQCc9emeb78uCqJv9qy9tJQsg6vYDeJt37dwBYiZga8z0rHI5dcrn3aFKz9C5Nn9azaRBC+wmW91FfQ==",
|
||||
"requires": {
|
||||
"minimist": "^1.2.5",
|
||||
"xml2js": "^0.4.17"
|
||||
}
|
||||
},
|
||||
"lie": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz",
|
||||
"integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==",
|
||||
"requires": {
|
||||
"immediate": "~3.0.5"
|
||||
}
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
|
||||
|
|
@ -18717,8 +18866,7 @@
|
|||
"pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="
|
||||
},
|
||||
"parallel-transform": {
|
||||
"version": "1.2.0",
|
||||
|
|
@ -20369,8 +20517,7 @@
|
|||
"process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"dev": true
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||
},
|
||||
"progress": {
|
||||
"version": "2.0.3",
|
||||
|
|
@ -21102,9 +21249,9 @@
|
|||
}
|
||||
},
|
||||
"ignore": {
|
||||
"version": "3.3.10",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
|
||||
"integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
|
||||
"version": "5.1.8",
|
||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz",
|
||||
"integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==",
|
||||
"dev": true
|
||||
},
|
||||
"inquirer": {
|
||||
|
|
@ -23284,9 +23431,20 @@
|
|||
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||
}
|
||||
}
|
||||
},
|
||||
"readdirp": {
|
||||
|
|
@ -24632,6 +24790,11 @@
|
|||
"resolved": "https://registry.npmjs.org/set-harmonic-interval/-/set-harmonic-interval-1.0.1.tgz",
|
||||
"integrity": "sha512-AhICkFV84tBP1aWqPwLZqFvAwqEoVA9kxNMniGEUvzOlm4vLmOFLiTT3UZ6bziJTy4bOVpzWGTfSCbmaayGx8g=="
|
||||
},
|
||||
"set-immediate-shim": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
|
||||
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
|
||||
},
|
||||
"set-value": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
|
||||
|
|
@ -26850,8 +27013,8 @@
|
|||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"dev": true,
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"util.promisify": {
|
||||
"version": "1.0.1",
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"graphql": "^14.5.8",
|
||||
"graphql-tag": "^2.10.3",
|
||||
"jss-plugin-extend": "^10.0.0",
|
||||
"jszip": "^3.6.0",
|
||||
"libphonenumber-js": "^1.7.50",
|
||||
"match-sorter": "^4.2.0",
|
||||
"moment": "2.24.0",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,15 @@
|
|||
import { useLazyQuery } from '@apollo/react-hooks'
|
||||
import { makeStyles, Box } from '@material-ui/core'
|
||||
import BigNumber from 'bignumber.js'
|
||||
import FileSaver from 'file-saver'
|
||||
import gql from 'graphql-tag'
|
||||
import JSZip from 'jszip'
|
||||
import moment from 'moment'
|
||||
import * as R from 'ramda'
|
||||
import React, { memo } from 'react'
|
||||
|
||||
import { HoverableTooltip } from 'src/components/Tooltip'
|
||||
import { IDButton } from 'src/components/buttons'
|
||||
import { IDButton, ActionButton } from 'src/components/buttons'
|
||||
import { P, Label1 } from 'src/components/typography'
|
||||
import { ReactComponent as CardIdInverseIcon } from 'src/styling/icons/ID/card/white.svg'
|
||||
import { ReactComponent as CardIdIcon } from 'src/styling/icons/ID/card/zodiac.svg'
|
||||
|
|
@ -12,6 +17,7 @@ import { ReactComponent as PhoneIdInverseIcon } from 'src/styling/icons/ID/phone
|
|||
import { ReactComponent as PhoneIdIcon } from 'src/styling/icons/ID/phone/zodiac.svg'
|
||||
import { ReactComponent as CamIdInverseIcon } from 'src/styling/icons/ID/photo/white.svg'
|
||||
import { ReactComponent as CamIdIcon } from 'src/styling/icons/ID/photo/zodiac.svg'
|
||||
import { ReactComponent as Download } from 'src/styling/icons/button/download/zodiac.svg'
|
||||
import { ReactComponent as TxInIcon } from 'src/styling/icons/direction/cash-in.svg'
|
||||
import { ReactComponent as TxOutIcon } from 'src/styling/icons/direction/cash-out.svg'
|
||||
import { URI } from 'src/utils/apollo'
|
||||
|
|
@ -23,6 +29,27 @@ import styles from './DetailsCard.styles'
|
|||
import { getStatus, getStatusDetails } from './helper'
|
||||
|
||||
const useStyles = makeStyles(styles)
|
||||
const MINUTES_OFFSET = 3
|
||||
const TX_SUMMARY = gql`
|
||||
query txSummaryAndLogs(
|
||||
$txId: ID!
|
||||
$deviceId: ID!
|
||||
$limit: Int
|
||||
$from: Date
|
||||
$until: Date
|
||||
$txClass: String
|
||||
) {
|
||||
serverLogsCsv(limit: $limit, from: $from, until: $until)
|
||||
machineLogsCsv(
|
||||
deviceId: $deviceId
|
||||
limit: $limit
|
||||
from: $from
|
||||
until: $until
|
||||
)
|
||||
transactionCsv(id: $txId, txClass: $txClass)
|
||||
txAssociatedDataCsv(id: $txId, txClass: $txClass)
|
||||
}
|
||||
`
|
||||
|
||||
const formatAddress = (cryptoCode = '', address = '') =>
|
||||
formatCryptoAddress(cryptoCode, address).replace(/(.{5})/g, '$1 ')
|
||||
|
|
@ -35,6 +62,8 @@ const Label = ({ children }) => {
|
|||
const DetailsRow = ({ it: tx }) => {
|
||||
const classes = useStyles()
|
||||
|
||||
const zip = new JSZip()
|
||||
|
||||
const fiat = Number.parseFloat(tx.fiat)
|
||||
const crypto = toUnit(new BigNumber(tx.cryptoAtoms), tx.cryptoCode)
|
||||
const commissionPercentage = Number.parseFloat(tx.commissionPercentage, 2)
|
||||
|
|
@ -55,6 +84,30 @@ const DetailsRow = ({ it: tx }) => {
|
|||
)
|
||||
}
|
||||
|
||||
const from = moment(tx.created)
|
||||
.subtract(MINUTES_OFFSET, 'm')
|
||||
.format()
|
||||
const until = moment(tx.created)
|
||||
.add(MINUTES_OFFSET, 'm')
|
||||
.format()
|
||||
|
||||
const [fetchSummary] = useLazyQuery(TX_SUMMARY, {
|
||||
onCompleted: data => createCsv(data)
|
||||
})
|
||||
|
||||
const loadAndTxSummary = ({ id: txId, deviceId, txClass }) => {
|
||||
fetchSummary({ variables: { txId, from, until, deviceId, txClass } })
|
||||
}
|
||||
|
||||
const createCsv = logs => {
|
||||
const zipFilename = `tx_${tx.id}_summary.zip`
|
||||
const filesNames = R.keys(logs)
|
||||
R.map(name => zip.file(name + '.csv', logs[name]), filesNames)
|
||||
zip.generateAsync({ type: 'blob' }).then(function(content) {
|
||||
FileSaver.saveAs(content, zipFilename)
|
||||
})
|
||||
}
|
||||
|
||||
const errorElements = (
|
||||
<>
|
||||
<Label>Transaction status</Label>
|
||||
|
|
@ -197,7 +250,7 @@ const DetailsRow = ({ it: tx }) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className={classes.lastRow}>
|
||||
<div>
|
||||
<div className={classes.status}>
|
||||
{getStatusDetails(tx) ? (
|
||||
<HoverableTooltip parentElements={errorElements} width={200}>
|
||||
<P>{getStatusDetails(tx)}</P>
|
||||
|
|
@ -206,6 +259,22 @@ const DetailsRow = ({ it: tx }) => {
|
|||
errorElements
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
{
|
||||
<div
|
||||
onClick={() => {
|
||||
loadAndTxSummary(tx)
|
||||
}}>
|
||||
<Label>Other actions</Label>
|
||||
<ActionButton
|
||||
color="primary"
|
||||
Icon={Download}
|
||||
className={classes.downloadRawLogs}>
|
||||
{'Download raw logs'}
|
||||
</ActionButton>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -74,6 +74,12 @@ export default {
|
|||
address: {
|
||||
width: 280
|
||||
},
|
||||
downloadRawLogs: {
|
||||
width: 180
|
||||
},
|
||||
status: {
|
||||
width: 230
|
||||
},
|
||||
transactionId: {
|
||||
width: 280
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue