@mojaloop/sdk-scheme-adapter 11.18.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (277) hide show
  1. package/.env.example +140 -0
  2. package/.eslintignore +2 -0
  3. package/.eslintrc.json +30 -0
  4. package/.nvmrc +1 -0
  5. package/.versionrc +15 -0
  6. package/CHANGELOG.md +118 -0
  7. package/InboundServer/api.yaml +3594 -0
  8. package/InboundServer/api_template.yaml +69 -0
  9. package/InboundServer/handlers.js +940 -0
  10. package/InboundServer/index.js +205 -0
  11. package/InboundServer/middlewares.js +426 -0
  12. package/OAuthTestServer/index.js +66 -0
  13. package/OAuthTestServer/model.js +70 -0
  14. package/OutboundServer/api.yaml +2732 -0
  15. package/OutboundServer/api_interfaces/index.d.ts +117 -0
  16. package/OutboundServer/api_interfaces/openapi.d.ts +1475 -0
  17. package/OutboundServer/api_template/components/parameters/bulkQuoteId.yaml +9 -0
  18. package/OutboundServer/api_template/components/parameters/bulkTransferId.yaml +9 -0
  19. package/OutboundServer/api_template/components/parameters/requestToPayTransactionId.yaml +9 -0
  20. package/OutboundServer/api_template/components/parameters/transferId.yaml +9 -0
  21. package/OutboundServer/api_template/components/responses/accountsCreationCompleted.yaml +5 -0
  22. package/OutboundServer/api_template/components/responses/accountsCreationError.yaml +5 -0
  23. package/OutboundServer/api_template/components/responses/accountsCreationTimeout.yaml +5 -0
  24. package/OutboundServer/api_template/components/responses/authorizationPostSuccess.yaml +5 -0
  25. package/OutboundServer/api_template/components/responses/authorizationsServerError.yaml +5 -0
  26. package/OutboundServer/api_template/components/responses/bulkQuoteBadRequest.yaml +5 -0
  27. package/OutboundServer/api_template/components/responses/bulkQuoteServerError.yaml +5 -0
  28. package/OutboundServer/api_template/components/responses/bulkQuoteSuccess.yaml +5 -0
  29. package/OutboundServer/api_template/components/responses/bulkQuoteTimeout.yaml +5 -0
  30. package/OutboundServer/api_template/components/responses/bulkTransferBadRequest.yaml +5 -0
  31. package/OutboundServer/api_template/components/responses/bulkTransferServerError.yaml +5 -0
  32. package/OutboundServer/api_template/components/responses/bulkTransferSuccess.yaml +5 -0
  33. package/OutboundServer/api_template/components/responses/bulkTransferTimeout.yaml +5 -0
  34. package/OutboundServer/api_template/components/responses/partiesByIdError404.yaml +9 -0
  35. package/OutboundServer/api_template/components/responses/partiesByIdSuccess.yaml +5 -0
  36. package/OutboundServer/api_template/components/responses/quotesPostSuccess.yaml +5 -0
  37. package/OutboundServer/api_template/components/responses/quotesServerError.yaml +5 -0
  38. package/OutboundServer/api_template/components/responses/requestToPaySuccess.yaml +5 -0
  39. package/OutboundServer/api_template/components/responses/requestToPayTransferBadRequest.yaml +5 -0
  40. package/OutboundServer/api_template/components/responses/requestToPayTransferSuccess.yaml +5 -0
  41. package/OutboundServer/api_template/components/responses/simpleTransfersPostSuccess.yaml +5 -0
  42. package/OutboundServer/api_template/components/responses/simpleTransfersServerError.yaml +5 -0
  43. package/OutboundServer/api_template/components/responses/transferBadRequest.yaml +5 -0
  44. package/OutboundServer/api_template/components/responses/transferServerError.yaml +5 -0
  45. package/OutboundServer/api_template/components/responses/transferSuccess.yaml +5 -0
  46. package/OutboundServer/api_template/components/responses/transferTimeout.yaml +5 -0
  47. package/OutboundServer/api_template/components/schemas/accountCreationStatus.yaml +18 -0
  48. package/OutboundServer/api_template/components/schemas/accountsCreationState.yaml +4 -0
  49. package/OutboundServer/api_template/components/schemas/accountsRequest.yaml +20 -0
  50. package/OutboundServer/api_template/components/schemas/accountsResponse.yaml +15 -0
  51. package/OutboundServer/api_template/components/schemas/async2SyncCurrentState.yaml +5 -0
  52. package/OutboundServer/api_template/components/schemas/authorizationsPostRequest.yaml +15 -0
  53. package/OutboundServer/api_template/components/schemas/authorizationsPostResponse.yaml +19 -0
  54. package/OutboundServer/api_template/components/schemas/bulkQuoteErrorResponse.yaml +8 -0
  55. package/OutboundServer/api_template/components/schemas/bulkQuoteRequest.yaml +26 -0
  56. package/OutboundServer/api_template/components/schemas/bulkQuoteResponse.yaml +21 -0
  57. package/OutboundServer/api_template/components/schemas/bulkQuoteStatus.yaml +4 -0
  58. package/OutboundServer/api_template/components/schemas/bulkQuoteStatusResponse.yaml +17 -0
  59. package/OutboundServer/api_template/components/schemas/bulkTransferErrorResponse.yaml +8 -0
  60. package/OutboundServer/api_template/components/schemas/bulkTransferRequest.yaml +26 -0
  61. package/OutboundServer/api_template/components/schemas/bulkTransferResponse.yaml +16 -0
  62. package/OutboundServer/api_template/components/schemas/bulkTransferStatus.yaml +4 -0
  63. package/OutboundServer/api_template/components/schemas/bulkTransferStatusResponse.yaml +17 -0
  64. package/OutboundServer/api_template/components/schemas/errorAccountsResponse.yaml +8 -0
  65. package/OutboundServer/api_template/components/schemas/errorAuthorizationsResponse.yaml +3 -0
  66. package/OutboundServer/api_template/components/schemas/errorQuotesResponse.yaml +9 -0
  67. package/OutboundServer/api_template/components/schemas/errorResponse.yaml +8 -0
  68. package/OutboundServer/api_template/components/schemas/errorSimpleTransfersResponse.yaml +3 -0
  69. package/OutboundServer/api_template/components/schemas/errorTransferResponse.yaml +8 -0
  70. package/OutboundServer/api_template/components/schemas/extensionListEmptiable.yaml +6 -0
  71. package/OutboundServer/api_template/components/schemas/individualQuote.yaml +32 -0
  72. package/OutboundServer/api_template/components/schemas/individualQuoteResult.yaml +28 -0
  73. package/OutboundServer/api_template/components/schemas/individualTransfer.yaml +32 -0
  74. package/OutboundServer/api_template/components/schemas/individualTransferFulfilment.yaml +13 -0
  75. package/OutboundServer/api_template/components/schemas/individualTransferResult.yaml +41 -0
  76. package/OutboundServer/api_template/components/schemas/mojaloopError.yaml +5 -0
  77. package/OutboundServer/api_template/components/schemas/mojaloopTransactionRequestState.yaml +2 -0
  78. package/OutboundServer/api_template/components/schemas/partiesByIdResponse.yaml +13 -0
  79. package/OutboundServer/api_template/components/schemas/quote.yaml +3 -0
  80. package/OutboundServer/api_template/components/schemas/quoteError.yaml +16 -0
  81. package/OutboundServer/api_template/components/schemas/quotesPostRequest.yaml +13 -0
  82. package/OutboundServer/api_template/components/schemas/quotesPostResponse.yaml +48 -0
  83. package/OutboundServer/api_template/components/schemas/requestToPayRequest.yaml +39 -0
  84. package/OutboundServer/api_template/components/schemas/requestToPayResponse.yaml +41 -0
  85. package/OutboundServer/api_template/components/schemas/requestToPayTransferRequest.yaml +42 -0
  86. package/OutboundServer/api_template/components/schemas/requestToPayTransferResponse.yaml +58 -0
  87. package/OutboundServer/api_template/components/schemas/simpleTransferServerError.yaml +5 -0
  88. package/OutboundServer/api_template/components/schemas/simpleTransfersPostRequest.yaml +12 -0
  89. package/OutboundServer/api_template/components/schemas/simpleTransfersPostResponse.yaml +11 -0
  90. package/OutboundServer/api_template/components/schemas/transactionType.yaml +4 -0
  91. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptOTP.yaml +9 -0
  92. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptParty.yaml +8 -0
  93. package/OutboundServer/api_template/components/schemas/transferContinuationAcceptQuote.yaml +9 -0
  94. package/OutboundServer/api_template/components/schemas/transferError.yaml +16 -0
  95. package/OutboundServer/api_template/components/schemas/transferFulfilment.yaml +3 -0
  96. package/OutboundServer/api_template/components/schemas/transferParty.yaml +40 -0
  97. package/OutboundServer/api_template/components/schemas/transferRequest.yaml +37 -0
  98. package/OutboundServer/api_template/components/schemas/transferResponse.yaml +58 -0
  99. package/OutboundServer/api_template/components/schemas/transferStatus.yaml +6 -0
  100. package/OutboundServer/api_template/components/schemas/transferStatusResponse.yaml +13 -0
  101. package/OutboundServer/api_template/health.yaml +12 -0
  102. package/OutboundServer/api_template/openapi.yaml +55 -0
  103. package/OutboundServer/api_template/paths/accounts.yaml +26 -0
  104. package/OutboundServer/api_template/paths/authorizations.yaml +19 -0
  105. package/OutboundServer/api_template/paths/bulkQuotes.yaml +23 -0
  106. package/OutboundServer/api_template/paths/bulkQuotes_bulkQuoteId.yaml +24 -0
  107. package/OutboundServer/api_template/paths/bulkTransfers.yaml +23 -0
  108. package/OutboundServer/api_template/paths/bulkTransfers_bulkTransferId.yaml +24 -0
  109. package/OutboundServer/api_template/paths/parties_Type_ID.yaml +20 -0
  110. package/OutboundServer/api_template/paths/parties_Type_ID_SubId.yaml +22 -0
  111. package/OutboundServer/api_template/paths/quotes.yaml +20 -0
  112. package/OutboundServer/api_template/paths/requestToPay.yaml +22 -0
  113. package/OutboundServer/api_template/paths/requestToPayTransfer.yaml +57 -0
  114. package/OutboundServer/api_template/paths/requestToPayTransfer_requestToPayTransactionId.yaml +34 -0
  115. package/OutboundServer/api_template/paths/simpleTransfers.yaml +19 -0
  116. package/OutboundServer/api_template/paths/transfers.yaml +55 -0
  117. package/OutboundServer/api_template/paths/transfers_transferId.yaml +58 -0
  118. package/OutboundServer/handlers.js +622 -0
  119. package/OutboundServer/index.js +137 -0
  120. package/OutboundServer/middlewares.js +67 -0
  121. package/TestServer/api.yaml +62 -0
  122. package/TestServer/handlers.js +63 -0
  123. package/TestServer/index.js +215 -0
  124. package/audit-resolve.json +65 -0
  125. package/babel.config.js +3 -0
  126. package/config.js +158 -0
  127. package/index.d.ts +1 -0
  128. package/index.js +149 -0
  129. package/jest.config.js +15 -0
  130. package/lib/api/index.js +12 -0
  131. package/lib/cache.js +352 -0
  132. package/lib/check.js +25 -0
  133. package/lib/model/AccountsModel.js +396 -0
  134. package/lib/model/Async2SyncModel.js +283 -0
  135. package/lib/model/AuthorizationsModel.js +86 -0
  136. package/lib/model/InboundTransfersModel.js +730 -0
  137. package/lib/model/OutboundBulkQuotesModel.js +485 -0
  138. package/lib/model/OutboundBulkTransfersModel.js +479 -0
  139. package/lib/model/OutboundRequestToPayModel.js +517 -0
  140. package/lib/model/OutboundRequestToPayTransferModel.js +893 -0
  141. package/lib/model/OutboundTransfersModel.js +823 -0
  142. package/lib/model/PartiesModel.js +70 -0
  143. package/lib/model/ProxyModel/MatchRules/Expression.js +48 -0
  144. package/lib/model/ProxyModel/MatchRules/Headers.js +65 -0
  145. package/lib/model/ProxyModel/MatchRules/MatchRule.js +27 -0
  146. package/lib/model/ProxyModel/MatchRules/Path.js +36 -0
  147. package/lib/model/ProxyModel/MatchRules/Query.js +65 -0
  148. package/lib/model/ProxyModel/MatchRules/index.js +19 -0
  149. package/lib/model/ProxyModel/Route.js +82 -0
  150. package/lib/model/ProxyModel/configSchema.json +118 -0
  151. package/lib/model/ProxyModel/index.js +138 -0
  152. package/lib/model/QuotesModel.js +94 -0
  153. package/lib/model/TransfersModel.js +81 -0
  154. package/lib/model/common/BackendError.js +26 -0
  155. package/lib/model/common/PersistentStateMachine.js +93 -0
  156. package/lib/model/common/index.js +18 -0
  157. package/lib/model/index.js +43 -0
  158. package/lib/model/lib/deferredJob.js +113 -0
  159. package/lib/model/lib/index.js +9 -0
  160. package/lib/model/lib/requests/backendRequests.js +227 -0
  161. package/lib/model/lib/requests/common.js +76 -0
  162. package/lib/model/lib/requests/index.js +19 -0
  163. package/lib/model/lib/shared.js +468 -0
  164. package/lib/randomphrase/index.js +21 -0
  165. package/lib/randomphrase/words.json +3397 -0
  166. package/lib/router.js +28 -0
  167. package/lib/validate.js +205 -0
  168. package/package.json +102 -0
  169. package/test/__mocks__/@mojaloop/sdk-standard-components.js +152 -0
  170. package/test/__mocks__/javascript-state-machine.js +21 -0
  171. package/test/__mocks__/redis.js +49 -0
  172. package/test/__mocks__/uuidv4.js +16 -0
  173. package/test/config/integration.env +136 -0
  174. package/test/integration/lib/Outbound/authorizations.test.js +58 -0
  175. package/test/integration/lib/Outbound/data/authorizationsPostRequest.json +43 -0
  176. package/test/integration/lib/Outbound/data/quotesPostRequest.json +52 -0
  177. package/test/integration/lib/Outbound/data/transfersPostRequest.json +24 -0
  178. package/test/integration/lib/Outbound/parties.test.js +28 -0
  179. package/test/integration/lib/Outbound/quotes.test.js +58 -0
  180. package/test/integration/lib/Outbound/simpleTransfers.test.js +67 -0
  181. package/test/integration/lib/cache.test.js +80 -0
  182. package/test/integration/testEnv.js +7 -0
  183. package/test/unit/InboundServer.test.js +443 -0
  184. package/test/unit/TestServer.test.js +394 -0
  185. package/test/unit/api/accounts/accounts.test.js +128 -0
  186. package/test/unit/api/accounts/data/postAccountsBody.json +7 -0
  187. package/test/unit/api/accounts/data/postAccountsErrorMojaloopResponse.json +25 -0
  188. package/test/unit/api/accounts/data/postAccountsErrorTimeoutResponse.json +19 -0
  189. package/test/unit/api/accounts/data/postAccountsSuccessResponse.json +17 -0
  190. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError1.json +21 -0
  191. package/test/unit/api/accounts/data/postAccountsSuccessResponseWithError2.json +21 -0
  192. package/test/unit/api/accounts/utils.js +65 -0
  193. package/test/unit/api/proxy/data/proxyConfig.yaml +82 -0
  194. package/test/unit/api/proxy/data/requestBody.json +22 -0
  195. package/test/unit/api/proxy/data/requestHeaders.json +5 -0
  196. package/test/unit/api/proxy/data/requestQuery.json +6 -0
  197. package/test/unit/api/proxy/data/responseBody.json +21 -0
  198. package/test/unit/api/proxy/data/responseHeaders.json +5 -0
  199. package/test/unit/api/proxy/proxy.test.js +220 -0
  200. package/test/unit/api/proxy/utils.js +79 -0
  201. package/test/unit/api/transfers/data/getTransfersCommittedResponse.json +21 -0
  202. package/test/unit/api/transfers/data/getTransfersErrorNotFound.json +17 -0
  203. package/test/unit/api/transfers/data/postQuotesBody.json +52 -0
  204. package/test/unit/api/transfers/data/postTransfersBadBody.json +17 -0
  205. package/test/unit/api/transfers/data/postTransfersBody.json +24 -0
  206. package/test/unit/api/transfers/data/postTransfersErrorMojaloopResponse.json +53 -0
  207. package/test/unit/api/transfers/data/postTransfersErrorTimeoutResponse.json +47 -0
  208. package/test/unit/api/transfers/data/postTransfersSimpleBody.json +26 -0
  209. package/test/unit/api/transfers/data/postTransfersSuccessResponse.json +101 -0
  210. package/test/unit/api/transfers/data/putPartiesBody.json +20 -0
  211. package/test/unit/api/transfers/data/putQuotesBody.json +37 -0
  212. package/test/unit/api/transfers/data/putTransfersBody.json +17 -0
  213. package/test/unit/api/transfers/transfers.test.js +191 -0
  214. package/test/unit/api/transfers/utils.js +183 -0
  215. package/test/unit/api/utils.js +75 -0
  216. package/test/unit/config.test.js +119 -0
  217. package/test/unit/data/commonHttpHeaders.json +6 -0
  218. package/test/unit/data/defaultConfig.json +58 -0
  219. package/test/unit/data/postQuotesBody.json +52 -0
  220. package/test/unit/data/putParticipantsBody.json +12 -0
  221. package/test/unit/data/putPartiesBody.json +20 -0
  222. package/test/unit/data/testFile.json +29 -0
  223. package/test/unit/data/testFile.yaml +14 -0
  224. package/test/unit/inboundApi/data/mockArguments.json +117 -0
  225. package/test/unit/inboundApi/data/mockTransactionRequest.json +42 -0
  226. package/test/unit/inboundApi/handlers.test.js +799 -0
  227. package/test/unit/index.test.js +55 -0
  228. package/test/unit/lib/cache.test.js +146 -0
  229. package/test/unit/lib/model/AccountsModel.test.js +121 -0
  230. package/test/unit/lib/model/AuthorizationsModel.test.js +460 -0
  231. package/test/unit/lib/model/InboundTransfersModel.test.js +628 -0
  232. package/test/unit/lib/model/OutboundBulkQuotesModel.test.js +249 -0
  233. package/test/unit/lib/model/OutboundBulkTransfersModel.test.js +244 -0
  234. package/test/unit/lib/model/OutboundRequestToPayModel.test.js +166 -0
  235. package/test/unit/lib/model/OutboundRequestToPayTransferModel.test.js +245 -0
  236. package/test/unit/lib/model/OutboundTransfersModel.test.js +836 -0
  237. package/test/unit/lib/model/PartiesModel.test.js +468 -0
  238. package/test/unit/lib/model/QuotesModel.test.js +470 -0
  239. package/test/unit/lib/model/TransfersModel.test.js +474 -0
  240. package/test/unit/lib/model/common/PersistentStateMachine.test.js +179 -0
  241. package/test/unit/lib/model/data/authorizationsResponse.json +13 -0
  242. package/test/unit/lib/model/data/bulkQuoteRequest.json +27 -0
  243. package/test/unit/lib/model/data/bulkQuoteResponse.json +35 -0
  244. package/test/unit/lib/model/data/bulkTransferFulfil.json +13 -0
  245. package/test/unit/lib/model/data/bulkTransferRequest.json +29 -0
  246. package/test/unit/lib/model/data/defaultConfig.json +47 -0
  247. package/test/unit/lib/model/data/getBulkTransfersBackendResponse.json +42 -0
  248. package/test/unit/lib/model/data/getBulkTransfersMojaloopResponse.json +22 -0
  249. package/test/unit/lib/model/data/getTransfersBackendResponse.json +34 -0
  250. package/test/unit/lib/model/data/getTransfersMojaloopResponse.json +17 -0
  251. package/test/unit/lib/model/data/mockArguments.json +131 -0
  252. package/test/unit/lib/model/data/mockTxnRequestsArguments.json +63 -0
  253. package/test/unit/lib/model/data/notificationToPayee.json +10 -0
  254. package/test/unit/lib/model/data/payeeParty.json +16 -0
  255. package/test/unit/lib/model/data/putAuthorizationsResponse.json +10 -0
  256. package/test/unit/lib/model/data/putQuotesResponse.json +33 -0
  257. package/test/unit/lib/model/data/putTransfersResponse.json +5 -0
  258. package/test/unit/lib/model/data/quoteResponse.json +31 -0
  259. package/test/unit/lib/model/data/requestToPayRequest.json +20 -0
  260. package/test/unit/lib/model/data/requestToPayTransferRequest.json +27 -0
  261. package/test/unit/lib/model/data/transactionRequestResponse.json +18 -0
  262. package/test/unit/lib/model/data/transferFulfil.json +8 -0
  263. package/test/unit/lib/model/data/transferRequest.json +26 -0
  264. package/test/unit/lib/model/mockedLibRequests.js +74 -0
  265. package/test/unit/mockLogger.js +39 -0
  266. package/test/unit/outboundApi/data/bulkQuoteRequest.json +28 -0
  267. package/test/unit/outboundApi/data/bulkTransferRequest.json +28 -0
  268. package/test/unit/outboundApi/data/mockBulkQuoteError.json +45 -0
  269. package/test/unit/outboundApi/data/mockBulkTransferError.json +48 -0
  270. package/test/unit/outboundApi/data/mockError.json +41 -0
  271. package/test/unit/outboundApi/data/mockGetPartiesError.json +4 -0
  272. package/test/unit/outboundApi/data/mockRequestToPayError.json +32 -0
  273. package/test/unit/outboundApi/data/mockRequestToPayTransferError.json +39 -0
  274. package/test/unit/outboundApi/data/requestToPay.json +21 -0
  275. package/test/unit/outboundApi/data/requestToPayTransferRequest.json +20 -0
  276. package/test/unit/outboundApi/data/transferRequest.json +21 -0
  277. package/test/unit/outboundApi/handlers.test.js +986 -0
@@ -0,0 +1,517 @@
1
+ /**************************************************************************
2
+ * (C) Copyright ModusBox Inc. 2019 - All rights reserved. *
3
+ * *
4
+ * This file is made available under the terms of the license agreement *
5
+ * specified in the corresponding source code repository. *
6
+ * *
7
+ * ORIGINAL AUTHOR: *
8
+ * Murthy Kakarlamudi - murthy@modusbox.com *
9
+ **************************************************************************/
10
+
11
+ 'use strict';
12
+
13
+ const util = require('util');
14
+ const { uuid } = require('uuidv4');
15
+ const StateMachine = require('javascript-state-machine');
16
+ const { MojaloopRequests } = require('@mojaloop/sdk-standard-components');
17
+ const { BackendError } = require('./common');
18
+ const PartiesModel = require('./PartiesModel');
19
+
20
+ const transferStateEnum = {
21
+ 'WAITING_FOR_PARTY_ACCEPTANCE': 'WAITING_FOR_PARTY_ACCEPTANCE',
22
+ 'WAITING_FOR_QUOTE_ACCEPTANCE': 'WAITING_FOR_QUOTE_ACCEPTANCE',
23
+ 'ERROR_OCCURRED': 'ERROR_OCCURRED',
24
+ 'COMPLETED': 'COMPLETED',
25
+ };
26
+
27
+ class OutboundRequestToPayModel {
28
+
29
+ constructor(config) {
30
+ this._cache = config.cache;
31
+ this._logger = config.logger;
32
+ this._requestProcessingTimeoutSeconds = config.requestProcessingTimeoutSeconds;
33
+ this._dfspId = config.dfspId;
34
+ this._expirySeconds = config.expirySeconds;
35
+ this._autoAcceptParty = config.autoAcceptParty;
36
+
37
+ this._requests = new MojaloopRequests({
38
+ logger: this._logger,
39
+ peerEndpoint: config.peerEndpoint,
40
+ alsEndpoint: config.alsEndpoint,
41
+ dfspId: config.dfspId,
42
+ tls: config.tls,
43
+ jwsSign: config.jwsSign,
44
+ jwsSignPutParties: config.jwsSignPutParties,
45
+ jwsSigningKey: config.jwsSigningKey,
46
+ wso2: config.wso2,
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Initializes the request to pay model
52
+ *
53
+ * @param data {object} - The inbound API POST /requestToPay request body
54
+ */
55
+ async initialize(data) {
56
+ this.data = data;
57
+
58
+ // add a transactionRequestId if one is not present e.g. on first submission
59
+ if(!this.data.hasOwnProperty('transactionRequestId')) {
60
+ this.data.transactionRequestId = uuid();
61
+ }
62
+
63
+ // initialize the transfer state machine to its starting state
64
+ if(!this.data.hasOwnProperty('currentState')) {
65
+ this.data.currentState = 'start';
66
+ }
67
+
68
+ //Set fsp id in the from section of the request that gets sent back in the response
69
+ this.data.from.fspId = this._dfspId;
70
+
71
+ this._initStateMachine(this.data.currentState);
72
+ }
73
+
74
+ /**
75
+ * Initializes the internal state machine object
76
+ */
77
+ _initStateMachine (initState) {
78
+ this.stateMachine = new StateMachine({
79
+ init: initState,
80
+ transitions: [
81
+ { name: 'resolvePayee', from: 'start', to: 'payeeResolved' },
82
+ { name: 'executeTransactionRequest', from: 'payeeResolved', to: 'succeeded' },
83
+ { name: 'error', from: '*', to: 'errored' },
84
+ ],
85
+ methods: {
86
+ onTransition: this._handleTransition.bind(this),
87
+ onAfterTransition: this._afterTransition.bind(this),
88
+ onPendingTransition: (transition, from, to) => {
89
+ // allow transitions to 'error' state while other transitions are in progress
90
+ if(transition !== 'error') {
91
+ throw new Error(`Transition requested while another transition is in progress: ${transition} from: ${from} to: ${to}`);
92
+ }
93
+ }
94
+ }
95
+ });
96
+
97
+ return this.stateMachine[initState];
98
+ }
99
+
100
+ /**
101
+ * Handles state machine transitions
102
+ */
103
+ async _handleTransition(lifecycle, ...args) {
104
+ this._logger.log(`Request To Pay ${this.data.transactionRequestId} is transitioning from ${lifecycle.from} to ${lifecycle.to} in response to ${lifecycle.transition}`);
105
+
106
+ switch(lifecycle.transition) {
107
+ case 'init':
108
+ // init, just allow the fsm to start
109
+ return;
110
+
111
+ case 'resolvePayee':
112
+ // resolve the payee
113
+ return this._resolvePayee();
114
+
115
+ case 'executeTransactionRequest':
116
+ // call request to pay
117
+ return this._executeTransactionRequest();
118
+
119
+ case 'error':
120
+ this._logger.log(`State machine is erroring with error: ${util.inspect(args)}`);
121
+ this.data.lastError = args[0] || new Error('unspecified error');
122
+ break;
123
+
124
+ default:
125
+ throw new Error(`Unhandled state transition for transfer ${this.data.transferId}: ${util.inspect(args)}`);
126
+ }
127
+ }
128
+
129
+ /**
130
+ * Updates the internal state representation to reflect that of the state machine itself
131
+ */
132
+ _afterTransition() {
133
+ this._logger.log(`State machine transitioned: ${this.data.currentState} -> ${this.stateMachine.state}`);
134
+ this.data.currentState = this.stateMachine.state;
135
+ }
136
+
137
+ /**
138
+ * Resolves the payee.
139
+ * Starts the payee resolution process by sending a GET /parties request to the switch;
140
+ * then waits for a notification from the cache that the payee has been resolved.
141
+ */
142
+ async _resolvePayee() {
143
+ // eslint-disable-next-line no-async-promise-executor
144
+ return new Promise(async (resolve, reject) => {
145
+ // listen for resolution events on the payee idType and idValue
146
+ const payeeKey = PartiesModel.channelName({
147
+ type: this.data.to.idType,
148
+ id: this.data.to.idValue,
149
+ subId: this.data.to.idSubValue
150
+ });
151
+
152
+ // hook up a subscriber to handle response messages
153
+ const subId = await this._cache.subscribe(payeeKey, (cn, msg, subId) => {
154
+ try {
155
+ let payee = JSON.parse(msg);
156
+
157
+ if(payee.errorInformation) {
158
+ // this is an error response to our GET /parties request
159
+ const err = new BackendError(`Got an error response resolving party: ${util.inspect(payee)}`, 500);
160
+ err.mojaloopError = payee;
161
+
162
+ // cancel the timeout handler
163
+ clearTimeout(timeout);
164
+ return reject(err);
165
+ }
166
+
167
+ if(!payee.party) {
168
+ // we should never get a non-error response without a party, but just in case...
169
+ // cancel the timeout handler
170
+ clearTimeout(timeout);
171
+ return reject(new Error(`Resolved payee has no party object: ${util.inspect(payee)}`));
172
+ }
173
+
174
+ payee = payee.party;
175
+
176
+ // cancel the timeout handler
177
+ clearTimeout(timeout);
178
+
179
+ this._logger.push({ payee }).log('Payee resolved');
180
+
181
+ // stop listening for payee resolution messages
182
+ // no need to await for the unsubscribe to complete.
183
+ // we dont really care if the unsubscribe fails but we should log it regardless
184
+ this._cache.unsubscribe(payeeKey, subId).catch(e => {
185
+ this._logger.log(`Error unsubscribing (in callback) ${payeeKey} ${subId}: ${e.stack || util.inspect(e)}`);
186
+ });
187
+
188
+ // check we got the right payee and info we need
189
+ if(payee.partyIdInfo.partyIdType !== this.data.to.idType) {
190
+ const err = new Error(`Expecting resolved payee party IdType to be ${this.data.to.idType} but got ${payee.partyIdInfo.partyIdType}`);
191
+ return reject(err);
192
+ }
193
+
194
+ if(payee.partyIdInfo.partyIdentifier !== this.data.to.idValue) {
195
+ const err = new Error(`Expecting resolved payee party identifier to be ${this.data.to.idValue} but got ${payee.partyIdInfo.partyIdentifier}`);
196
+ return reject(err);
197
+ }
198
+
199
+ if(payee.partyIdInfo.partySubIdOrType !== this.data.to.idSubValue) {
200
+ const err = new Error(`Expecting resolved payee party subTypeId to be ${this.data.to.idSubValue} but got ${payee.partyIdInfo.partySubIdOrType}`);
201
+ return reject(err);
202
+ }
203
+
204
+ if(!payee.partyIdInfo.fspId) {
205
+ const err = new Error(`Expecting resolved payee party to have an FSPID: ${util.inspect(payee.partyIdInfo)}`);
206
+ return reject(err);
207
+ }
208
+
209
+ // now we got the payee, add the details to our data so we can use it
210
+ // in the quote request
211
+ this.data.to.fspId = payee.partyIdInfo.fspId;
212
+
213
+ if(payee.personalInfo) {
214
+ if(payee.personalInfo.complexName) {
215
+ this.data.to.firstName = payee.personalInfo.complexName.firstName || this.data.to.firstName;
216
+ this.data.to.middleName = payee.personalInfo.complexName.middleName || this.data.to.middleName;
217
+ this.data.to.lastName = payee.personalInfo.complexName.lastName || this.data.to.lastName;
218
+ }
219
+ this.data.to.dateOfBirth = payee.personalInfo.dateOfBirth;
220
+ }
221
+
222
+ return resolve(payee);
223
+ }
224
+ catch(err) {
225
+ return reject(err);
226
+ }
227
+ });
228
+
229
+ // set up a timeout for the resolution
230
+ const timeout = setTimeout(() => {
231
+ const err = new BackendError(`Timeout resolving payee for transfer ${this.data.transferId}`, 504);
232
+
233
+ // we dont really care if the unsubscribe fails but we should log it regardless
234
+ this._cache.unsubscribe(payeeKey, subId).catch(e => {
235
+ this._logger.log(`Error unsubscribing (in timeout handler) ${payeeKey} ${subId}: ${e.stack || util.inspect(e)}`);
236
+ });
237
+
238
+ return reject(err);
239
+ }, this._requestProcessingTimeoutSeconds * 1000);
240
+
241
+ // now we have a timeout handler and a cache subscriber hooked up we can fire off
242
+ // a GET /parties request to the switch
243
+ try {
244
+ const res = await this._requests.getParties(this.data.to.idType, this.data.to.idValue,
245
+ this.data.to.idSubValue);
246
+ this._logger.push({ peer: res }).log('Party lookup sent to peer');
247
+ }
248
+ catch(err) {
249
+ // cancel the timout and unsubscribe before rejecting the promise
250
+ clearTimeout(timeout);
251
+
252
+ // we dont really care if the unsubscribe fails but we should log it regardless
253
+ this._cache.unsubscribe(payeeKey, subId).catch(e => {
254
+ this._logger.log(`Error unsubscribing ${payeeKey} ${subId}: ${e.stack || util.inspect(e)}`);
255
+ });
256
+
257
+ return reject(err);
258
+ }
259
+ });
260
+ }
261
+
262
+ async _executeTransactionRequest() {
263
+ // eslint-disable-next-line no-async-promise-executor
264
+ return new Promise(async (resolve, reject) => {
265
+ // create a transfer prepare request
266
+ const transactionRequest = this._buildTransactionRequest();
267
+
268
+ // listen for events on the transactionRequestId
269
+ const transactionRequestKey = `txnreq_${this.data.transactionRequestId}`;
270
+
271
+ const subId = await this._cache.subscribe(transactionRequestKey, async (cn, msg, subId) => {
272
+ try {
273
+ let error;
274
+ let message = JSON.parse(msg);
275
+
276
+ // if (message.type === 'transactionRequestFail') {
277
+ // error = new BackendError(`Got an error response processing transaction request: ${util.inspect(message.data)}`, 500);
278
+ // error.mojaloopError = message.data;
279
+ // } else {
280
+ // this._logger.push({ message }).log(`Ignoring cache notification for transfer ${transactionRequestKey}. Uknokwn message type ${message.type}.`);
281
+ // return;
282
+ // }
283
+
284
+ // cancel the timeout handler
285
+ clearTimeout(timeout);
286
+
287
+ // stop listening for transfer fulfil messages
288
+ this._cache.unsubscribe(transactionRequestKey, subId).catch(e => {
289
+ this._logger.log(`Error unsubscribing (in callback) ${transactionRequestKey} ${subId}: ${e.stack || util.inspect(e)}`);
290
+ });
291
+
292
+ if (error) {
293
+ return reject(error);
294
+ }
295
+
296
+ const transactionRequestResponse = message.data;
297
+ this._logger.push({ transactionRequestResponse }).log('Transaction Request Response received');
298
+ this.data.requestToPayState = transactionRequestResponse.transactionRequestState;
299
+
300
+
301
+ return resolve(transactionRequestResponse);
302
+ }
303
+ catch(err) {
304
+ return reject(err);
305
+ }
306
+ });
307
+
308
+ // set up a timeout for the request
309
+ const timeout = setTimeout(() => {
310
+ const err = new BackendError(`Timeout waiting for fulfil for transfer ${this.data.transferId}`, 504);
311
+
312
+ // we dont really care if the unsubscribe fails but we should log it regardless
313
+ this._cache.unsubscribe(transactionRequestKey, subId).catch(e => {
314
+ this._logger.log(`Error unsubscribing (in timeout handler) ${transactionRequestKey} ${subId}: ${e.stack || util.inspect(e)}`);
315
+ });
316
+
317
+ return reject(err);
318
+ }, this._requestProcessingTimeoutSeconds * 1000);
319
+
320
+ // now we have a timeout handler and a cache subscriber hooked up we can fire off
321
+ // a POST /transfers request to the switch
322
+ try {
323
+ const res = await this._requests.postTransactionRequests(transactionRequest, this.data.to.fspId);
324
+ this._logger.push({ res }).log('Transfer prepare sent to peer');
325
+ }
326
+ catch(err) {
327
+ // cancel the timout and unsubscribe before rejecting the promise
328
+ clearTimeout(timeout);
329
+
330
+ // we dont really care if the unsubscribe fails but we should log it regardless
331
+ this._cache.unsubscribe(transactionRequestKey, subId).catch(e => {
332
+ this._logger.log(`Error unsubscribing (in error handler) ${transactionRequestKey} ${subId}: ${e.stack || util.inspect(e)}`);
333
+ });
334
+
335
+ return reject(err);
336
+ }
337
+ });
338
+ }
339
+
340
+ /**
341
+ * Builds a transaction request payload from current state
342
+ *
343
+ * @returns {object} - the transaction request payload
344
+ */
345
+ _buildTransactionRequest() {
346
+ let transactionRequest = {
347
+ transactionRequestId: this.data.transactionRequestId,
348
+ payer: {
349
+ partyIdType: this.data.from.idType,
350
+ partyIdentifier: this.data.from.idValue,
351
+ fspId: this._dfspId
352
+ },
353
+ payee: {
354
+ partyIdInfo: {
355
+ partyIdType: this.data.to.idType,
356
+ partyIdentifier: this.data.to.idValue,
357
+ fspId: this.data.to.fspId,
358
+ },
359
+ personalInfo: {
360
+ complexName: {
361
+ firstName: this.data.to.firstName,
362
+ middleName: this.data.to.middleName,
363
+ lastName: this.data.to.lastName
364
+ },
365
+ dateOfBirth: this.data.to.dateOfBirth
366
+ }
367
+ },
368
+ amount: {
369
+ currency: this.data.currency,
370
+ amount: this.data.amount
371
+ },
372
+ transactionType: {
373
+ scenario: this.data.scenario,
374
+ initiator: this.data.initiator,
375
+ initiatorType: this.data.initiatorType
376
+ }
377
+ };
378
+
379
+ // add extensions list if provided
380
+ // if(this.data.transferRequestExtensions && this.data.transferRequestExtensions.length > 0) {
381
+ // prepare.extensionList = {
382
+ // extension: this.data.transferRequestExtensions
383
+ // };
384
+ // }
385
+
386
+ return transactionRequest;
387
+ }
388
+
389
+ /**
390
+ * Loads a transfer model from cache for resumption of the transfer process
391
+ *
392
+ * @param transferId {string} - UUID transferId of the model to load from cache
393
+ */
394
+ async load(transactionRequestId) {
395
+ try {
396
+ const data = await this._cache.get(`txnReqModel_${transactionRequestId}`);
397
+ if(!data) {
398
+ throw new Error(`No cached data found for transactionRequestId: ${transactionRequestId}`);
399
+ }
400
+ await this.initialize(data);
401
+ this._logger.push({ cache: this.data }).log('TransactionRequest model loaded from cached state');
402
+ }
403
+ catch(err) {
404
+ this._logger.push({ err }).log('Error loading transfer model');
405
+ throw err;
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Returns a promise that resolves when the state machine has reached a terminal state
411
+ */
412
+ async run() {
413
+ try {
414
+ // run transitions based on incoming state
415
+ switch(this.data.currentState) {
416
+ case 'start':
417
+ // next transition is to resolvePayee
418
+ await this.stateMachine.resolvePayee();
419
+ this._logger.log(`Payee resolved for transfer ${this.data.transferId}`);
420
+ if(this.stateMachine.state === 'payeeResolved' && !this._autoAcceptParty) {
421
+ //we break execution here and return the resolved party details to allow asynchronous accept or reject
422
+ //of the resolved party
423
+ await this._save();
424
+ return this.getResponse();
425
+ }
426
+ break;
427
+
428
+ case 'payeeResolved':
429
+ // next transition is to requestQuote
430
+ await this.stateMachine.executeTransactionRequest();
431
+ this._logger.log(`Transaction Request for ${this.data.transactionRequestId} has been completed`);
432
+ break;
433
+
434
+ case 'succeeded':
435
+ // all steps complete so return
436
+ this._logger.log('Transaction Request completed successfully');
437
+ await this._save();
438
+ return this.getResponse();
439
+
440
+ case 'errored':
441
+ // stopped in errored state
442
+ this._logger.log('State machine in errored state');
443
+ return;
444
+ }
445
+
446
+ // now call ourslves recursively to deal with the next transition
447
+ this._logger.log(`Transfer model state machine transition completed in state: ${this.stateMachine.state}. Recusring to handle next transition.`);
448
+ return this.run();
449
+ }
450
+ catch(err) {
451
+ this._logger.log(`Error running transfer model: ${util.inspect(err)}`);
452
+
453
+ // as this function is recursive, we dont want to error the state machine multiple times
454
+ if(this.data.currentState !== 'errored') {
455
+ // err should not have a transferState property here!
456
+ if(err.transferState) {
457
+ this._logger.log(`State machine is broken: ${util.inspect(err)}`);
458
+ }
459
+ // transition to errored state
460
+ await this.stateMachine.error(err);
461
+
462
+ // avoid circular ref between transferState.lastError and err
463
+ err.transferState = JSON.parse(JSON.stringify(this.getResponse()));
464
+ }
465
+ throw err;
466
+ }
467
+ }
468
+
469
+ /**
470
+ * Returns an object representing the final state of the transfer suitable for the outbound API
471
+ *
472
+ * @returns {object} - Response representing the result of the transfer process
473
+ */
474
+ getResponse() {
475
+ // we want to project some of our internal state into a more useful
476
+ // representation to return to the SDK API consumer
477
+ let resp = { ...this.data };
478
+
479
+ switch(this.data.currentState) {
480
+ case 'payeeResolved':
481
+ resp.currentState = transferStateEnum.WAITING_FOR_PARTY_ACCEPTANCE;
482
+ break;
483
+
484
+ case 'succeeded':
485
+ resp.currentState = transferStateEnum.COMPLETED;
486
+ break;
487
+
488
+ case 'errored':
489
+ resp.currentState = transferStateEnum.ERROR_OCCURRED;
490
+ break;
491
+
492
+ default:
493
+ this._logger.log(`Transaction Request model response being returned from an unexpected state: ${this.data.currentState}. Returning ERROR_OCCURRED state`);
494
+ resp.currentState = transferStateEnum.ERROR_OCCURRED;
495
+ break;
496
+ }
497
+
498
+ return resp;
499
+ }
500
+
501
+ /**
502
+ * Persists the model state to cache for reinstantiation at a later point
503
+ */
504
+ async _save() {
505
+ try {
506
+ this.data.currentState = this.stateMachine.state;
507
+ const res = await this._cache.set(`txnReqModel_${this.data.transactionRequestId}`, this.data);
508
+ this._logger.push({ res }).log('Persisted transaction request model in cache');
509
+ }
510
+ catch(err) {
511
+ this._logger.push({ err }).log('Error saving transfer model');
512
+ throw err;
513
+ }
514
+ }
515
+ }
516
+
517
+ module.exports = OutboundRequestToPayModel;