account-lookup-service 17.6.0 → 17.7.0-snapshot.0

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.
@@ -25,185 +25,170 @@
25
25
  --------------
26
26
  ******/
27
27
 
28
- const ErrorHandler = require('@mojaloop/central-services-error-handling')
29
28
  const { ERROR_MESSAGES } = require('../../../constants')
30
- const { createCallbackHeaders } = require('../../../lib/headers')
31
29
  const BasePartiesService = require('./BasePartiesService')
32
30
 
33
- const {
34
- FspEndpointTypes, FspEndpointTemplates,
35
- Headers, RestMethods
36
- } = BasePartiesService.enums()
37
-
31
+ const { FspEndpointTypes, RestMethods } = BasePartiesService.enums()
38
32
  const proxyCacheTtlSec = 40 // todo: make configurable
39
33
 
40
34
  class GetPartiesService extends BasePartiesService {
41
- async handleRequest ({ headers, params, query, results }) {
42
- const source = headers[Headers.FSPIOP.SOURCE]
43
- const proxy = headers[Headers.FSPIOP.PROXY]
44
- const destination = headers[Headers.FSPIOP.DESTINATION]
35
+ async handleRequest () {
36
+ const { destination, source, proxy } = this.state
45
37
  // see https://github.com/mojaloop/design-authority/issues/79
46
38
  // the requester has specified a destination routing header. We should respect that and forward the request directly to the destination
47
39
  // without consulting any oracles.
48
- this.log.info('handling getParties request', { source, destination, proxy })
49
-
50
- const requester = await this.validateRequester({ source, proxy })
51
- results.requester = requester
40
+ this.log.info('handling getParties request...', { source, destination, proxy })
41
+ this.state.requester = await this.validateRequester()
42
+ // dfsp in scheme OR proxy
52
43
 
53
44
  if (destination) {
54
- await this.forwardRequestToDestination({ destination, headers, params })
45
+ await this.forwardRequestToDestination()
55
46
  return
56
47
  }
57
- const response = await this.sendOracleDiscoveryRequest({ headers, params, query })
58
48
 
49
+ const response = await this.sendOracleDiscoveryRequest()
59
50
  if (Array.isArray(response?.data?.partyList) && response.data.partyList.length > 0) {
60
- const partyList = this.filterOraclePartyList({ response, params })
61
- await this.processOraclePartyList({ partyList, headers, params, destination })
51
+ const partyList = this.filterOraclePartyList(response)
52
+ await this.processOraclePartyList(partyList)
62
53
  return
63
54
  }
64
55
 
65
- this.log.info('empty partyList form oracle, getting proxyList...', { params })
66
- const proxyNames = await this.getFilteredProxyList(proxy)
67
-
68
- if (proxyNames.length) {
69
- await this.triggerSendToProxiesFlow({ proxyNames, headers, params, source })
70
- return
56
+ this.log.info('empty partyList form oracle, checking inter-scheme discovery flow...')
57
+ const fspiopError = await this.triggerInterSchemeDiscoveryFlow(this.inputs.headers)
58
+ if (fspiopError) {
59
+ this.state.fspiopError = fspiopError // todo: think, if we need this
71
60
  }
72
-
73
- results.fspiopError = await this.sendPartyNotFoundErrorCallback({ requester, headers, params })
74
61
  }
75
62
 
76
- async validateRequester ({ source, proxy }) {
77
- this.deps.stepState.inProgress('validateRequester-0')
63
+ async validateRequester () {
64
+ const { source, proxy, proxyEnabled } = this.state
78
65
  const log = this.log.child({ source, proxy, method: 'validateRequester' })
66
+ this.stepInProgress('validateRequester-0')
79
67
 
80
- const sourceParticipant = await this.validateParticipant(source)
81
- if (sourceParticipant) {
82
- log.debug('source is in scheme')
68
+ const schemeSource = await this.validateParticipant(source)
69
+ if (schemeSource) {
70
+ log.debug('source participant is in scheme')
83
71
  return source
84
72
  }
85
73
 
86
- if (!this.proxyEnabled || !proxy) {
87
- const errMessage = ERROR_MESSAGES.sourceFspNotFound
88
- log.warn(errMessage)
89
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
74
+ if (!proxyEnabled || !proxy) {
75
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.sourceFspNotFound, log)
90
76
  }
91
77
 
92
- const proxyParticipant = await this.validateParticipant(proxy)
93
- if (!proxyParticipant) {
94
- const errMessage = ERROR_MESSAGES.partyProxyNotFound
95
- log.warn(errMessage)
96
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
78
+ const schemeProxy = await this.validateParticipant(proxy)
79
+ if (!schemeProxy) {
80
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.partyProxyNotFound, log)
97
81
  }
98
82
 
99
83
  const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
100
84
  if (!isCached) {
101
- const errMessage = 'failed to addDfspIdToProxyMapping'
102
- log.warn(errMessage)
103
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
85
+ throw super.createFspiopIdNotFoundError('failed to addDfspIdToProxyMapping', log)
104
86
  }
105
87
 
106
88
  log.info('source is added to proxyMapping cache:', { proxy, isCached })
107
89
  return proxy
108
90
  }
109
91
 
110
- async forwardRequestToDestination ({ destination, headers, params }) {
111
- this.deps.stepState.inProgress('validateDestination-1')
92
+ async forwardRequestToDestination () {
93
+ const { headers, params } = this.inputs
94
+ const { destination } = this.state
112
95
  const log = this.log.child({ method: 'forwardRequestToDestination' })
113
96
  let sendTo = destination
114
97
 
115
- const destParticipantModel = await this.validateParticipant(destination)
116
- if (!destParticipantModel) {
117
- this.deps.stepState.inProgress('lookupProxyDestination-2')
118
- const proxyId = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
98
+ const schemeParticipant = await this.validateParticipant(destination)
99
+ if (!schemeParticipant) {
100
+ this.stepInProgress('lookupProxyDestination-2')
101
+ const proxyId = this.state.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
119
102
 
120
103
  if (!proxyId) {
121
- log.warn('no destination participant, and no dfsp-to-proxy mapping', { destination })
122
- const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
123
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
104
+ log.warn('destination participant is not in scheme, and no dfsp-to-proxy mapping', { destination })
105
+ await super.sendDeleteOracleRequest(headers, params)
106
+ await this.triggerInterSchemeDiscoveryFlow(GetPartiesService.headersWithoutDestination(headers))
107
+ return
124
108
  }
125
109
  sendTo = proxyId
126
110
  }
127
- // all ok, go ahead and forward the request
111
+
128
112
  await this.#forwardGetPartiesRequest({ sendTo, headers, params })
129
113
  log.info('discovery getPartiesByTypeAndID request was sent', { sendTo })
130
114
  }
131
115
 
132
- filterOraclePartyList ({ response, params }) {
133
- // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records. We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
134
- this.deps.stepState.inProgress('filterOraclePartyList-5')
116
+ filterOraclePartyList (response) {
117
+ // Oracle's API is a standard rest-style end-point Thus a GET /party on the oracle will return all participant-party records.
118
+ // We must filter the results based on the callbackEndpointType to make sure we remove records containing partySubIdOrType when we are in FSPIOP_CALLBACK_URL_PARTIES_GET mode:
119
+ this.stepInProgress('filterOraclePartyList-5')
120
+ const { params } = this.inputs
135
121
  const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
136
- let filteredResponsePartyList
122
+ let filteredPartyList
137
123
 
138
124
  switch (callbackEndpointType) {
139
125
  case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_GET:
140
- filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
126
+ filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType == null) // Filter records that DON'T contain a partySubIdOrType
141
127
  break
142
128
  case FspEndpointTypes.FSPIOP_CALLBACK_URL_PARTIES_SUB_ID_GET:
143
- filteredResponsePartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
129
+ filteredPartyList = response.data.partyList.filter(party => party.partySubIdOrType === params.SubId) // Filter records that match partySubIdOrType
144
130
  break
145
131
  default:
146
- filteredResponsePartyList = response // Fallback to providing the standard list
132
+ filteredPartyList = response // Fallback to providing the standard list
147
133
  }
148
134
 
149
- if (!Array.isArray(filteredResponsePartyList) || !filteredResponsePartyList.length) {
150
- const errMessage = 'Requested FSP/Party not found'
151
- this.log.warn(errMessage)
152
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
135
+ if (!Array.isArray(filteredPartyList) || !filteredPartyList.length) {
136
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.emptyFilteredPartyList)
153
137
  }
154
138
 
155
- return filteredResponsePartyList
139
+ return filteredPartyList
156
140
  }
157
141
 
158
- async processOraclePartyList ({ partyList, headers, params, destination }) {
159
- const log = this.log.child({ method: 'processOraclePartyList' })
142
+ async processOraclePartyList (partyList) {
143
+ this.stepInProgress('processOraclePartyList')
144
+ const { headers, params } = this.inputs
160
145
 
161
- let sentCount = 0 // if sentCount === 0 after sending, should we restart the whole process?
146
+ let sentCount = 0 // if sentCount === 0 after sending, we send idNotFound error
162
147
  const sending = partyList.map(async party => {
163
148
  const { fspId } = party
164
- const clonedHeaders = { ...headers }
165
- if (!destination) {
166
- clonedHeaders[Headers.FSPIOP.DESTINATION] = fspId
167
- }
168
- this.deps.stepState.inProgress('validateParticipant-6')
149
+
169
150
  const schemeParticipant = await this.validateParticipant(fspId)
170
151
  if (schemeParticipant) {
171
152
  sentCount++
172
- log.info('participant is in scheme', { fspId })
153
+ this.log.info('participant is in scheme, so forwarding to it...', { fspId })
173
154
  return this.#forwardGetPartiesRequest({
174
155
  sendTo: fspId,
175
- headers: clonedHeaders,
156
+ headers: GetPartiesService.overrideDestinationHeader(headers, fspId),
176
157
  params
177
158
  })
178
159
  }
179
160
 
180
- // If the participant is not in the scheme and proxy routing is enabled,
181
- // we should check if there is a proxy for it and send the request to the proxy
182
- if (this.proxyEnabled) {
183
- this.deps.stepState.inProgress('lookupProxyByDfspId-7')
161
+ if (this.state.proxyEnabled) {
184
162
  const proxyName = await this.deps.proxyCache.lookupProxyByDfspId(fspId)
185
163
  if (!proxyName) {
186
- log.warn('no proxyMapping for participant! TODO: Delete reference in oracle...', { fspId })
187
- // todo: delete reference in oracle
188
- } else {
164
+ this.log.warn('no proxyMapping for external DFSP! Deleting reference in oracle...', { fspId })
165
+ return super.sendDeleteOracleRequest(headers, params)
166
+ // todo: check if it won't delete all parties
167
+ }
168
+
169
+ // Coz there's no destination header, it means we're inside initial inter-scheme discovery phase.
170
+ // So we should proceed only if source is in scheme (local participant)
171
+ const schemeSource = await this.validateParticipant(this.state.source)
172
+ if (schemeSource) {
189
173
  sentCount++
190
- log.info('participant is NOT in scheme, use proxy name', { fspId, proxyName })
174
+ this.log.info('participant is NOT in scheme, but source is. So forwarding to proxy...', { fspId, proxyName })
191
175
  return this.#forwardGetPartiesRequest({
192
176
  sendTo: proxyName,
193
- headers: clonedHeaders,
177
+ headers: GetPartiesService.overrideDestinationHeader(headers, fspId),
194
178
  params
195
179
  })
196
180
  }
197
181
  }
198
182
  })
199
183
  await Promise.all(sending)
200
- log.verbose('processOraclePartyList is done', { sentCount })
201
- // todo: think what if sentCount === 0 here
184
+ this.log.verbose('processOraclePartyList is done', { sentCount })
185
+
186
+ if (sentCount === 0) throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.noDiscoveryRequestsForwarded)
202
187
  }
203
188
 
204
189
  async getFilteredProxyList (proxy) {
205
- this.deps.stepState.inProgress('getAllProxies-8')
206
- if (!this.proxyEnabled) {
190
+ this.stepInProgress('getFilteredProxyList')
191
+ if (!this.state.proxyEnabled) {
207
192
  this.log.warn('proxyCache is not enabled')
208
193
  return []
209
194
  }
@@ -213,19 +198,27 @@ class GetPartiesService extends BasePartiesService {
213
198
  return proxyNames.filter(name => name !== proxy)
214
199
  }
215
200
 
216
- async triggerSendToProxiesFlow ({ proxyNames, headers, params, source }) {
217
- const log = this.log.child({ method: 'triggerSendToProxiesFlow' })
218
- this.deps.stepState.inProgress('setSendToProxiesList-10')
201
+ async triggerInterSchemeDiscoveryFlow (headers) {
202
+ const { params } = this.inputs
203
+ const { proxy, source } = this.state
204
+ const log = this.log.child({ method: 'triggerInterSchemeDiscoveryFlow' })
205
+ log.verbose('triggerInterSchemeDiscoveryFlow start...', { proxy, source })
206
+
207
+ const proxyNames = await this.getFilteredProxyList(proxy)
208
+ if (!proxyNames.length) {
209
+ return this.sendPartyNotFoundErrorCallback(headers)
210
+ }
211
+
212
+ this.stepInProgress('setSendToProxiesList-10')
219
213
  const alsReq = this.deps.partiesUtils.alsRequestDto(source, params)
220
- log.info('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
214
+ log.verbose('starting setSendToProxiesList flow: ', { proxyNames, alsReq, proxyCacheTtlSec })
221
215
 
222
216
  const isCached = await this.deps.proxyCache.setSendToProxiesList(alsReq, proxyNames, proxyCacheTtlSec)
223
217
  if (!isCached) {
224
- log.warn('failed to setSendToProxiesList')
225
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.failedToCacheSendToProxiesList)
218
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.failedToCacheSendToProxiesList, log)
226
219
  }
227
220
 
228
- this.deps.stepState.inProgress('sendingProxyRequests-11')
221
+ this.stepInProgress('sendingProxyRequests-11')
229
222
  const sending = proxyNames.map(
230
223
  sendTo => this.#forwardGetPartiesRequest({ sendTo, headers, params })
231
224
  .then(({ status, data } = {}) => ({ status, data }))
@@ -234,43 +227,34 @@ class GetPartiesService extends BasePartiesService {
234
227
  const isOk = results.some(result => result.status === 'fulfilled')
235
228
  // If, at least, one request is sent to proxy, we treat the whole flow as successful.
236
229
  // Failed requests should be handled by TTL expired/timeout handler
237
- // todo: - think, if we should handle failed requests here (e.g., by calling receivedErrorResponse)
238
- log.info('triggerSendToProxiesFlow is done:', { isOk, results, proxyNames, alsReq })
239
- this.deps.stepState.inProgress('allSent-12')
230
+ log.info('triggerInterSchemeDiscoveryFlow is done:', { isOk, results, proxyNames, alsReq })
231
+ this.stepInProgress('allSent-12')
232
+
240
233
  if (!isOk) {
241
- log.warn('no successful requests sent to proxies')
242
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, ERROR_MESSAGES.proxyConnectionError)
234
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.proxyConnectionError, log)
243
235
  }
244
236
  }
245
237
 
246
- async sendPartyNotFoundErrorCallback ({ requester, headers, params }) {
247
- this.deps.stepState.inProgress('sendErrorCallback-9')
248
- const callbackHeaders = createCallbackHeaders({
249
- requestHeaders: headers,
250
- partyIdType: params.Type,
251
- partyIdentifier: params.ID,
252
- endpointTemplate: params.SubId
253
- ? FspEndpointTemplates.PARTIES_SUB_ID_PUT_ERROR
254
- : FspEndpointTemplates.PARTIES_PUT_ERROR
255
- })
256
- const fspiopError = ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.PARTY_NOT_FOUND)
238
+ async sendPartyNotFoundErrorCallback (headers) {
239
+ const { params } = this.inputs
240
+ const fspiopError = super.createFspiopIdNotFoundError('No proxy found to start inter-scheme discovery flow')
257
241
 
258
242
  await this.sendErrorCallback({
259
- sendTo: requester,
260
243
  errorInfo: fspiopError.toApiErrorObject(this.deps.config.ERROR_HANDLING),
261
- headers: callbackHeaders,
244
+ headers: GetPartiesService.createErrorCallbackHeaders(headers, params),
262
245
  params
263
246
  })
264
247
  return fspiopError
265
248
  }
266
249
 
267
- async sendOracleDiscoveryRequest ({ headers, params, query }) {
268
- this.deps.stepState.inProgress('oracleRequest-4')
250
+ async sendOracleDiscoveryRequest () {
251
+ this.stepInProgress('sendOracleDiscoveryRequest')
252
+ const { headers, params, query } = this.inputs
269
253
  return this.deps.oracle.oracleRequest(headers, RestMethods.GET, params, query, undefined, this.deps.cache)
270
254
  }
271
255
 
272
256
  async #forwardGetPartiesRequest ({ sendTo, headers, params }) {
273
- this.deps.stepState.inProgress('forwardRequest-3')
257
+ this.stepInProgress('#forwardGetPartiesRequest')
274
258
  const callbackEndpointType = this.deps.partiesUtils.getPartyCbType(params.SubId)
275
259
  const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
276
260
 
@@ -30,49 +30,71 @@ const { ERROR_MESSAGES } = require('../../../constants')
30
30
  const BasePartiesService = require('./BasePartiesService')
31
31
 
32
32
  class PutPartiesErrorService extends BasePartiesService {
33
- // async handleRequest () {
34
- // // todo: add impl.
35
- // }
36
-
37
- async checkPayee ({ headers, params, payload, proxy }) {
38
- const notValid = this.deps.partiesUtils.isNotValidPayeeCase(payload)
39
- if (notValid) {
40
- this.deps.stepState.inProgress('notValidPayeeCase-1')
41
- this.log.warn('notValidPayee case - deleting Participants and run getPartiesByTypeAndID', { proxy, payload })
42
- const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
43
- await super.sendDeleteOracleRequest(swappedHeaders, params)
33
+ async handleRequest () {
34
+ if (this.state.proxyEnabled && this.state.proxy) {
35
+ const alsReq = this.deps.partiesUtils.alsRequestDto(this.state.destination, this.inputs.params) // or source?
36
+ const isPending = await this.deps.proxyCache.isPendingCallback(alsReq)
37
+
38
+ if (!isPending) {
39
+ // not initial inter-scheme discovery case. Cleanup oracle and trigger inter-scheme discovery
40
+ this.log.warn('Need to cleanup oracle and trigger new inter-scheme discovery flow')
41
+ await this.cleanupOracle()
42
+ return true // need to trigger inter-scheme discovery
43
+ }
44
+
45
+ const isLast = await this.checkLastProxyCallback(alsReq)
46
+ if (!isLast) {
47
+ this.log.verbose('putPartiesErrorByTypeAndID proxy callback was processed')
48
+ return
49
+ }
44
50
  }
45
- return notValid
51
+
52
+ await this.identifyDestinationForErrorCallback()
53
+ await this.sendErrorCallbackToParticipant()
54
+ this.log.info('putPartiesByTypeAndID is done')
46
55
  }
47
56
 
48
- async checkLastProxyCallback ({ destination, proxy, params }) {
49
- this.deps.stepState.inProgress('checkLastProxyCallback-2')
50
- const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params) // or source?
57
+ async cleanupOracle () {
58
+ this.stepInProgress('cleanupOracle')
59
+ const { headers, params, payload } = this.inputs
60
+ this.log.info('cleanupOracle due to error callback...', { payload })
61
+ const swappedHeaders = this.deps.partiesUtils.swapSourceDestinationHeaders(headers)
62
+ await super.sendDeleteOracleRequest(swappedHeaders, params)
63
+ }
64
+
65
+ async checkLastProxyCallback (alsReq) {
66
+ this.stepInProgress('checkLastProxyCallback')
67
+ const { proxy } = this.state
51
68
  const isLast = await this.deps.proxyCache.receivedErrorResponse(alsReq, proxy)
52
69
  this.log.info(`got${isLast ? '' : 'NOT'} last error callback from proxy`, { proxy, alsReq, isLast })
53
70
  return isLast
54
71
  }
55
72
 
56
- async identifyDestinationForErrorCallback (destination) {
57
- this.deps.stepState.inProgress('validateParticipant-3')
58
- const destinationParticipant = await super.validateParticipant(destination)
59
- if (destinationParticipant) return destination
73
+ async identifyDestinationForErrorCallback () {
74
+ this.stepInProgress('identifyDestinationForErrorCallback')
75
+ const { destination } = this.state
76
+ const schemeParticipant = await super.validateParticipant(destination)
77
+ if (schemeParticipant) {
78
+ this.state.requester = destination
79
+ return
80
+ }
60
81
 
61
- this.deps.stepState.inProgress('lookupProxyDestination-4')
62
- const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
63
- if (proxyName) return proxyName
82
+ this.stepInProgress('lookupProxyDestination-4')
83
+ const proxyName = this.state.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
84
+ if (proxyName) {
85
+ this.state.requester = proxyName
86
+ return
87
+ }
64
88
 
65
89
  const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
66
90
  this.log.warn(errMessage, { destination })
67
91
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
68
92
  }
69
93
 
70
- async sendErrorCallbackToParticipant ({ sendTo, headers, params, dataUri }) {
71
- this.deps.stepState.inProgress('sendErrorToParticipant-5')
94
+ async sendErrorCallbackToParticipant () {
95
+ const { headers, params, dataUri } = this.inputs
72
96
  const errorInfo = PutPartiesErrorService.decodeDataUriPayload(dataUri)
73
- return super.sendErrorCallback({
74
- sendTo, errorInfo, headers, params
75
- })
97
+ return super.sendErrorCallback({ errorInfo, headers, params })
76
98
  }
77
99
  }
78
100
 
@@ -32,34 +32,43 @@ const BasePartiesService = require('./BasePartiesService')
32
32
  const { RestMethods } = BasePartiesService.enums()
33
33
 
34
34
  class PutPartiesService extends BasePartiesService {
35
- // async handleRequest () {
36
- // // todo: add impl.
37
- // }
35
+ async handleRequest () {
36
+ const { destination, source, proxy } = this.state
37
+ this.log.info('handleRequest start', { destination, source, proxy })
38
38
 
39
- async validateSourceParticipant ({ source, proxy }) {
40
- this.deps.stepState.inProgress('validateSourceParticipant-1')
41
- const requesterParticipant = await super.validateParticipant(source)
39
+ await this.validateSourceParticipant()
40
+ if (proxy) {
41
+ await this.checkProxySuccessResponse()
42
+ }
43
+ await this.identifyDestinationForSuccessCallback()
44
+ await this.sendSuccessCallback()
45
+ }
46
+
47
+ async validateSourceParticipant () {
48
+ const { source, proxy, proxyEnabled } = this.state
49
+ const log = this.log.child({ source, proxy, method: 'validateSourceParticipant' })
50
+ this.stepInProgress('validateSourceParticipant-1')
42
51
 
52
+ const requesterParticipant = await super.validateParticipant(source)
43
53
  if (!requesterParticipant) {
44
- if (!this.proxyEnabled || !proxy) {
45
- const errMessage = ERROR_MESSAGES.sourceFspNotFound
46
- this.log.warn(`${errMessage} and no proxy`, { source })
47
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
54
+ if (!proxyEnabled || !proxy) {
55
+ throw super.createFspiopIdNotFoundError(ERROR_MESSAGES.sourceFspNotFound, log)
48
56
  }
57
+
49
58
  const isCached = await this.deps.proxyCache.addDfspIdToProxyMapping(source, proxy)
50
59
  if (!isCached) {
51
- const errMessage = 'failed to addDfspIdToProxyMapping'
52
- this.log.warn(errMessage, { source, proxy })
53
- throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.ID_NOT_FOUND, errMessage)
60
+ throw super.createFspiopIdNotFoundError('failed to addDfspIdToProxyMapping', log)
54
61
  }
55
62
 
56
- this.log.info('addDfspIdToProxyMapping is done', { source, proxy })
63
+ log.info('addDfspIdToProxyMapping is done', { source, proxy })
57
64
  }
58
65
  }
59
66
 
60
- async checkProxySuccessResponse ({ destination, source, headers, params }) {
61
- if (this.proxyEnabled) {
62
- this.deps.stepState.inProgress('checkProxySuccessResponse-2')
67
+ async checkProxySuccessResponse () {
68
+ if (this.state.proxyEnabled) {
69
+ this.stepInProgress('checkProxySuccessResponse')
70
+ const { headers, params } = this.inputs
71
+ const { destination, source } = this.state
63
72
  const alsReq = this.deps.partiesUtils.alsRequestDto(destination, params)
64
73
 
65
74
  const isExists = await this.deps.proxyCache.receivedSuccessResponse(alsReq)
@@ -72,24 +81,29 @@ class PutPartiesService extends BasePartiesService {
72
81
  }
73
82
  }
74
83
 
75
- async identifyDestinationForSuccessCallback (destination) {
76
- this.deps.stepState.inProgress('validateDestinationParticipant-4')
84
+ async identifyDestinationForSuccessCallback () {
85
+ const { destination } = this.state
86
+ this.stepInProgress('identifyDestinationForSuccessCallback')
77
87
  const destinationParticipant = await super.validateParticipant(destination)
78
88
  if (destinationParticipant) {
79
- return destinationParticipant.name
89
+ this.state.requester = destinationParticipant.name
90
+ return
80
91
  }
81
92
 
82
- const proxyName = this.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
93
+ const proxyName = this.state.proxyEnabled && await this.deps.proxyCache.lookupProxyByDfspId(destination)
83
94
  if (!proxyName) {
84
95
  const errMessage = ERROR_MESSAGES.partyDestinationFspNotFound
85
96
  this.log.warn(`${errMessage} and no proxy`, { destination })
86
97
  throw ErrorHandler.Factory.createFSPIOPError(ErrorHandler.Enums.FSPIOPErrorCodes.DESTINATION_FSP_ERROR, errMessage)
87
98
  }
88
- return proxyName
99
+
100
+ this.state.requester = proxyName
89
101
  }
90
102
 
91
- async sendSuccessCallback ({ sendTo, headers, params, dataUri }) {
92
- this.deps.stepState.inProgress('#sendSuccessCallback-6')
103
+ async sendSuccessCallback () {
104
+ const { headers, params, dataUri } = this.inputs
105
+ const sendTo = this.state.requester
106
+ this.stepInProgress('sendSuccessCallback')
93
107
  const payload = PutPartiesService.decodeDataUriPayload(dataUri)
94
108
  const callbackEndpointType = this.deps.partiesUtils.putPartyCbType(params.SubId)
95
109
  const options = this.deps.partiesUtils.partiesRequestOptionsDto(params)
@@ -97,11 +111,11 @@ class PutPartiesService extends BasePartiesService {
97
111
  await this.deps.participant.sendRequest(
98
112
  headers, sendTo, callbackEndpointType, RestMethods.PUT, payload, options
99
113
  )
100
- this.log.verbose('sendSuccessCallback is done', { sendTo, payload })
114
+ this.log.verbose('sendSuccessCallback is sent', { sendTo, payload })
101
115
  }
102
116
 
103
117
  async #updateOracleWithParticipantMapping ({ source, headers, params }) {
104
- this.deps.stepState.inProgress('#updateOracleWithParticipantMapping-3')
118
+ this.stepInProgress('#updateOracleWithParticipantMapping-3')
105
119
  const mappingPayload = {
106
120
  fspId: source
107
121
  }
@@ -1,3 +1,30 @@
1
+ /*****
2
+ License
3
+ --------------
4
+ Copyright © 2020-2025 Mojaloop Foundation
5
+ The Mojaloop files are made available by the Mojaloop Foundation under the Apache License, Version 2.0 (the "License") and you may not use these files except in compliance with the License. You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, the Mojaloop files are distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
10
+
11
+ Contributors
12
+ --------------
13
+ This is the official list of the Mojaloop project contributors for this file.
14
+ Names of the original copyright holders (individuals or organizations)
15
+ should be listed with a '*' in the first column. People who have
16
+ contributed from an organization can be listed under the organization
17
+ that actually holds the copyright for their contributions (see the
18
+ Mojaloop Foundation for an example). Those individuals should have
19
+ their names indented and be marked with a '-'. Email address can be added
20
+ optionally within square brackets <email>.
21
+
22
+ * Mojaloop Foundation
23
+ * Eugen Klymniuk <eugen.klymniuk@infitx.com>
24
+
25
+ --------------
26
+ ******/
27
+
1
28
  const { randomUUID } = require('node:crypto')
2
29
  const { Enum } = require('@mojaloop/central-services-shared')
3
30
  const isoFixtures = require('./iso')
@@ -20,6 +47,16 @@ const headersDto = ({
20
47
  'content-type': contentType || accept
21
48
  })
22
49
 
50
+ const partiesParamsDto = ({
51
+ Type = 'MSISDN',
52
+ ID = String(Date.now()),
53
+ SubId
54
+ } = {}) => ({
55
+ Type,
56
+ ID,
57
+ ...(SubId && { SubId })
58
+ })
59
+
23
60
  const protocolVersionsDto = () => ({
24
61
  CONTENT: {
25
62
  DEFAULT: '2.1',
@@ -142,6 +179,7 @@ const mockHapiRequestDto = ({ // https://hapi.dev/api/?v=21.3.3#request-properti
142
179
  module.exports = {
143
180
  ...isoFixtures,
144
181
  partiesCallHeadersDto,
182
+ partiesParamsDto,
145
183
  participantsCallHeadersDto,
146
184
  oracleRequestResponseDto,
147
185
  putPartiesSuccessResponseDto,
@@ -1369,7 +1369,7 @@ describe('participant Tests', () => {
1369
1369
 
1370
1370
  // Assert
1371
1371
  expect(logStub.getCall(0).firstArg).toBe(ERROR_MESSAGES.sourceFspNotFound)
1372
- expect(logStub.getCall(3).lastArg).toEqual(cbError)
1372
+ expect(logStub.getCall(2).lastArg).toEqual(cbError)
1373
1373
  })
1374
1374
 
1375
1375
  it('handles error when `oracleBatchRequest` returns no result', async () => {