davinci_crd_test_kit 0.9.0 → 0.9.1

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 (39) hide show
  1. checksums.yaml +4 -4
  2. data/lib/davinci_crd_test_kit/card_responses/propose_alternate_request.json +2 -52
  3. data/lib/davinci_crd_test_kit/card_responses/request_form_completion.json +46 -31
  4. data/lib/davinci_crd_test_kit/cards_validation.rb +8 -4
  5. data/lib/davinci_crd_test_kit/client_hooks_group.rb +22 -660
  6. data/lib/davinci_crd_test_kit/client_tests/appointment_book_receive_request_test.rb +17 -6
  7. data/lib/davinci_crd_test_kit/client_tests/client_appointment_book_group.rb +70 -0
  8. data/lib/davinci_crd_test_kit/client_tests/client_encounter_discharge_group.rb +71 -0
  9. data/lib/davinci_crd_test_kit/client_tests/client_encounter_start_group.rb +70 -0
  10. data/lib/davinci_crd_test_kit/client_tests/client_order_dispatch_group.rb +70 -0
  11. data/lib/davinci_crd_test_kit/client_tests/client_order_select_group.rb +72 -0
  12. data/lib/davinci_crd_test_kit/client_tests/client_order_sign_group.rb +71 -0
  13. data/lib/davinci_crd_test_kit/client_tests/decode_auth_token_test.rb +43 -23
  14. data/lib/davinci_crd_test_kit/client_tests/encounter_discharge_receive_request_test.rb +19 -6
  15. data/lib/davinci_crd_test_kit/client_tests/encounter_start_receive_request_test.rb +18 -6
  16. data/lib/davinci_crd_test_kit/client_tests/hook_request_optional_fields_test.rb +26 -10
  17. data/lib/davinci_crd_test_kit/client_tests/hook_request_required_fields_test.rb +20 -11
  18. data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_context_test.rb +14 -10
  19. data/lib/davinci_crd_test_kit/client_tests/hook_request_valid_prefetch_test.rb +27 -110
  20. data/lib/davinci_crd_test_kit/client_tests/order_dispatch_receive_request_test.rb +18 -6
  21. data/lib/davinci_crd_test_kit/client_tests/order_select_receive_request_test.rb +18 -6
  22. data/lib/davinci_crd_test_kit/client_tests/order_sign_receive_request_test.rb +18 -6
  23. data/lib/davinci_crd_test_kit/client_tests/retrieve_jwks_test.rb +66 -29
  24. data/lib/davinci_crd_test_kit/client_tests/submitted_response_validation.rb +44 -0
  25. data/lib/davinci_crd_test_kit/client_tests/token_header_test.rb +45 -14
  26. data/lib/davinci_crd_test_kit/client_tests/token_payload_test.rb +43 -26
  27. data/lib/davinci_crd_test_kit/crd_client_suite.rb +0 -4
  28. data/lib/davinci_crd_test_kit/hook_request_field_validation.rb +240 -50
  29. data/lib/davinci_crd_test_kit/mock_service_response.rb +134 -120
  30. data/lib/davinci_crd_test_kit/routes/hook_request_endpoint.rb +26 -42
  31. data/lib/davinci_crd_test_kit/server_encounter_discharge_group.rb +24 -0
  32. data/lib/davinci_crd_test_kit/server_encounter_start_group.rb +24 -0
  33. data/lib/davinci_crd_test_kit/server_order_select_group.rb +24 -0
  34. data/lib/davinci_crd_test_kit/server_tests/coverage_information_system_action_received_test.rb +4 -1
  35. data/lib/davinci_crd_test_kit/server_tests/service_request_optional_fields_validation_test.rb +8 -10
  36. data/lib/davinci_crd_test_kit/server_tests/service_request_required_fields_validation_test.rb +5 -10
  37. data/lib/davinci_crd_test_kit/tags.rb +6 -6
  38. data/lib/davinci_crd_test_kit/version.rb +1 -1
  39. metadata +9 -2
@@ -1,5 +1,20 @@
1
1
  module DaVinciCRDTestKit
2
2
  module HookRequestFieldValidation
3
+ def request_number
4
+ if @request_number.blank?
5
+ ''
6
+ else
7
+ "Request #{@request_number}: "
8
+ end
9
+ end
10
+
11
+ def json_parse(json)
12
+ JSON.parse(json)
13
+ rescue JSON::ParserError
14
+ add_message('error', "#{request_number}Invalid JSON.")
15
+ false
16
+ end
17
+
3
18
  def hook_required_fields
4
19
  {
5
20
  'hook' => String,
@@ -82,23 +97,61 @@ module DaVinciCRDTestKit
82
97
  'Medication' => 'http://hl7.org/fhir/us/core/StructureDefinition/us-core-medication',
83
98
  'Device' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-device',
84
99
  'CommunicationRequest' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-communicationrequest',
85
- 'Task' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-taskquestionnaire'
100
+ 'Task' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-taskquestionnaire',
101
+ 'Coverage' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-coverage',
102
+ 'Location' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-location',
103
+ 'Organization' => 'http://hl7.org/fhir/us/davinci-crd/StructureDefinition/profile-organization'
86
104
  }.freeze
87
105
  end
88
106
 
89
107
  def hook_request_required_fields_check(request_body, hook_name)
90
108
  hook_required_fields.each do |field, type|
91
- assert(request_body[field], "Hook request did not contain required field: `#{field}`")
92
- assert(request_body[field].is_a?(type), "Hook request field #{field} is not of type #{type}")
109
+ if request_body[field].blank?
110
+ add_message('error', "#{request_number}Hook request did not contain required field: `#{field}`")
111
+ next
112
+ end
113
+
114
+ unless request_body[field].is_a?(type)
115
+ add_message('error', "#{request_number}Hook request field #{field} is not of type #{type}")
116
+ next
117
+ end
118
+ end
119
+
120
+ if request_body['hook'] != hook_name
121
+ add_message('error',
122
+ "#{request_number}The `hook` field should be #{hook_name}, but was #{request_body['hook']}")
123
+ return
93
124
  end
94
125
 
95
- assert(request_body['hook'] == hook_name,
96
- "The `hook` field should be #{hook_name}, but was #{request_body['hook']}")
126
+ return unless request_body['fhirAuthorization'].present? && request_body['fhirServer'].blank?
97
127
 
98
- return unless request_body['fhirAuthorization']
128
+ add_message('error', %(
129
+ #{request_number}Missing `fhirServer` field: If `fhirAuthorization` is provided, this field is
130
+ #REQUIRED.))
131
+ end
132
+
133
+ def fhir_auth_fields_valid?(fhir_authorization_required_fields, fhir_authorization)
134
+ fhir_auth_valid = true
135
+ fhir_authorization_required_fields.each do |field, type|
136
+ if fhir_authorization[field].blank?
137
+ add_message('error', "#{request_number}`fhirAuthorization` did not contain required field: `#{field}`")
138
+ fhir_auth_valid = false
139
+ end
140
+ unless fhir_authorization[field].is_a?(type)
141
+ add_message('error', "#{request_number}`fhirAuthorization` field #{field} is not of type #{type}")
142
+ fhir_auth_valid = false
143
+ end
144
+ end
145
+ fhir_auth_valid
146
+ end
99
147
 
100
- assert(request_body['fhirServer'],
101
- 'Missing `fhirServer` field: If `fhirAuthorization` is provided, this field is REQUIRED.')
148
+ def check_patient_scope_requirement(scopes, fhir_authorization)
149
+ if scopes.any? { |scope| scope.start_with?('patient/') } &&
150
+ !(fhir_authorization['patient'] && fhir_authorization['patient'].is_a?(String))
151
+ info %(
152
+ #{request_number}The `patient` field for request SHOULD be populated to identify the FHIR id of that
153
+ patient when the granted SMART scopes include patient scopes)
154
+ end
102
155
  end
103
156
 
104
157
  def hook_request_fhir_auth_check(request_body)
@@ -106,36 +159,27 @@ module DaVinciCRDTestKit
106
159
 
107
160
  fhir_authorization = request_body['fhirAuthorization']
108
161
 
109
- fhir_authorization_required_fields.each do |field, type|
110
- assert(fhir_authorization[field], "`fhirAuthorization` did not contain required field: `#{field}`")
111
- assert(fhir_authorization[field].is_a?(type), "`fhirAuthorization` field #{field} is not of type #{type}")
112
- end
162
+ return unless fhir_auth_fields_valid?(fhir_authorization_required_fields, fhir_authorization)
113
163
 
114
- assert(fhir_authorization['token_type'] == 'Bearer',
115
- "`fhirAuthorization` `token_type` field is not set to 'Bearer'")
164
+ if fhir_authorization['token_type'] != 'Bearer'
165
+ add_message('error', "#{request_number}`fhirAuthorization` `token_type` field is not set to 'Bearer'")
166
+ end
116
167
 
117
168
  access_token = fhir_authorization['access_token']
118
169
 
119
170
  scopes = fhir_authorization['scope'].split
120
171
 
121
- if scopes.any? { |scope| scope.start_with?('patient/') }
122
- info do
123
- assert(fhir_authorization['patient'] && fhir_authorization['patient'].is_a?(String),
124
- %(The `patient` field SHOULD be populated to identify the FHIR id of that patient when the granted
125
- SMART scopes include patient scopes))
126
- end
127
- end
172
+ check_patient_scope_requirement(scopes, fhir_authorization)
128
173
  end
129
174
  { fhir_server_uri: request_body['fhirServer'], fhir_access_token: access_token }
130
175
  end
131
176
 
132
177
  def hook_request_optional_fields_check(request_body)
133
178
  hook_optional_fields.each do |field, type|
134
- info do
135
- assert(request_body[field], "Hook request did not contain optional field: `#{field}`")
136
- end
137
- if request_body[field]
138
- assert(request_body[field].is_a?(type), "Hook request field #{field} is not of type #{type}")
179
+ info "#{request_number}Hook request did not contain optional field: `#{field}`" if request_body[field].blank?
180
+
181
+ if request_body[field] && !request_body[field].is_a?(type)
182
+ add_message('error', "#{request_number}Hook request field #{field} is not of type #{type}")
139
183
  end
140
184
  end
141
185
  hook_request_fhir_auth_check(request_body)
@@ -165,7 +209,8 @@ module DaVinciCRDTestKit
165
209
  def hook_request_context_check(context, hook_name)
166
210
  required_fields = context_required_fields_by_hook[hook_name]
167
211
  required_fields.each do |field, type|
168
- validate_presence_and_type(context, field, type, "#{hook_name} request context")
212
+ validate_presence_and_type(context, field, type,
213
+ "#{request_number}#{hook_name} request context")
169
214
  end
170
215
  context_validate_optional_fields(context, hook_name)
171
216
  hook_specific_context_check(context, hook_name)
@@ -195,7 +240,7 @@ module DaVinciCRDTestKit
195
240
  resource_type, resource_id = reference.split('/')
196
241
 
197
242
  if supported_resource_types && !supported_resource_types.include?(resource_type)
198
- error_msg = "Unsupported resource type: `#{field_name}` type should be one " \
243
+ error_msg = "#{request_number}Unsupported resource type: `#{field_name}` type should be one " \
199
244
  "of the following: #{supported_resource_types.to_sentence}, but " \
200
245
  "received #{resource_type}."
201
246
 
@@ -210,7 +255,10 @@ module DaVinciCRDTestKit
210
255
  resource_type, resource_id = reference.split('/')
211
256
  return true if resource_type.present? && resource_id.present?
212
257
 
213
- add_message('error', "Invalid `#{field_name}` format. Expected `{resourceType}/{id}`, received `#{reference}`.")
258
+ add_message('error', %(
259
+ #{request_number}Invalid `#{field_name}` format. Expected `{resourceType}/{id}`,
260
+ received `#{reference}`.
261
+ ))
214
262
  false
215
263
  end
216
264
 
@@ -228,7 +276,9 @@ module DaVinciCRDTestKit
228
276
 
229
277
  def valid_id_format?(field, hook_name, resource_id)
230
278
  if resource_id.include?('/')
231
- error_msg = "`#{field}` in #{hook_name} context should be a plain ID, not a reference. Got: `#{resource_id}`."
279
+ error_msg = %(
280
+ #{request_number}`#{field}` in #{hook_name} context should be a plain ID, not a reference.
281
+ Got: `#{resource_id}`.)
232
282
  add_message('error', error_msg)
233
283
  false
234
284
  end
@@ -237,9 +287,9 @@ module DaVinciCRDTestKit
237
287
 
238
288
  def bundle_entries_check(context, context_field_name, bundle, resource_types, status = nil)
239
289
  target_resources = bundle.entry.map(&:resource).select { |r| resource_types.include?(r.resourceType) }
240
- unless target_resources.present?
241
- error_msg = "`#{context_field_name}` bundle must contain at least one of the expected resource types: " \
242
- "#{resource_types.to_sentence}. In Context `#{context}`"
290
+ if target_resources.blank?
291
+ error_msg = "#{request_number}`#{context_field_name}` bundle must contain at least one of the " \
292
+ "expected resource types: #{resource_types.to_sentence}. In Context `#{context}`"
243
293
  add_message('error', error_msg)
244
294
  return
245
295
  end
@@ -254,24 +304,24 @@ module DaVinciCRDTestKit
254
304
  def status_check(context, context_field_name, status, resources)
255
305
  return unless status && !resources.all? { |resource| resource.status == status }
256
306
 
257
- error_msg = "All #{resources.map(&:resourceType).uniq.to_sentence} resources in `#{context_field_name}` " \
258
- "bundle must have a `#{status}` status. In Context `#{context}`"
307
+ error_msg = "#{request_number}All #{resources.map(&:resourceType).uniq.to_sentence} resources in " \
308
+ "`#{context_field_name}` bundle must have a `#{status}` status. In Context `#{context}`"
259
309
  add_message('error', error_msg)
260
310
  end
261
311
 
262
312
  def parse_fhir_bundle_from_context(context_field_name, context)
263
313
  fhir_bundle = FHIR.from_contents(context[context_field_name].to_json)
264
- unless fhir_bundle
265
- error_msg = "`#{context_field_name}` field is not a FHIR resource: `#{context[context_field_name]}`. " \
266
- "In Context `#{context}`"
314
+ if fhir_bundle.blank?
315
+ error_msg = "#{request_number}`#{context_field_name}` field is not a FHIR resource: " \
316
+ "`#{context[context_field_name]}`. In Context `#{context}`"
267
317
  add_message('error', error_msg)
268
318
  return
269
319
  end
270
320
 
271
321
  return fhir_bundle if fhir_bundle.is_a?(FHIR::Bundle)
272
322
 
273
- error_msg = "Wrong context resource type: Expected `Bundle`, got `#{fhir_bundle.resourceType}`. " \
274
- "In Context `#{context}`"
323
+ error_msg = "#{request_number}Wrong context resource type: Expected `Bundle`, got " \
324
+ "`#{fhir_bundle.resourceType}`. In Context `#{context}`"
275
325
  add_message('error', error_msg)
276
326
  nil
277
327
  end
@@ -283,7 +333,7 @@ module DaVinciCRDTestKit
283
333
  resource_reference_check(reference, 'selections item', supported_resource_types: expected_resource_types)
284
334
  next if order_refs.include?(reference)
285
335
 
286
- error_msg = '`selections` field must reference FHIR resources in `draftOrders`. ' \
336
+ error_msg = "#{request_number}`selections` field must reference FHIR resources in `draftOrders`. " \
287
337
  "#{reference} is not in `draftOrders`. In Context `#{context}`"
288
338
  add_message('error', error_msg)
289
339
  end
@@ -294,7 +344,7 @@ module DaVinciCRDTestKit
294
344
  id_only_fields_check('appointment-book', context, ['patientId'])
295
345
 
296
346
  appointment_bundle = parse_fhir_bundle_from_context('appointments', context)
297
- return unless appointment_bundle
347
+ return if appointment_bundle.blank?
298
348
 
299
349
  expected_resource_types = ['Appointment']
300
350
  bundle_entries_check(context, 'appointments', appointment_bundle, expected_resource_types, 'proposed')
@@ -310,7 +360,7 @@ module DaVinciCRDTestKit
310
360
  id_only_fields_check(hook_name, context, ['patientId'])
311
361
 
312
362
  draft_orders_bundle = parse_fhir_bundle_from_context('draftOrders', context)
313
- return unless draft_orders_bundle
363
+ return if draft_orders_bundle.blank?
314
364
 
315
365
  expected_resource_types = [
316
366
  'DeviceRequest', 'MedicationRequest', 'NutritionOrder',
@@ -352,15 +402,20 @@ module DaVinciCRDTestKit
352
402
  fhir_read(resource_type, resource_id)
353
403
  status = request.response[:status]
354
404
  unless status == 200
355
- add_message('error', "Unexpected response status: expected 200, but received #{status}")
405
+ add_message('error', "#{request_number}Unexpected response status: expected 200, but received #{status}")
356
406
  return
357
407
  end
358
408
  unless resource.resourceType == resource_type
359
- add_message('error', "Unexpected resource type: Expected `#{resource_type}`. Got `#{resource.resourceType}`.")
409
+ add_message('error', %(
410
+ #{request_number}Unexpected resource type: Expected `#{resource_type}`. Got
411
+ `#{resource.resourceType}`.
412
+ ))
360
413
  return
361
414
  end
362
415
  unless resource.id == resource_id
363
- add_message('error', "Requested resource with id #{resource_id}, received resource with id #{resource.id}")
416
+ add_message('error', %(
417
+ #{request_number}Requested resource with id #{resource_id}, received resource with id #{resource.id}
418
+ ))
364
419
  return
365
420
  end
366
421
 
@@ -370,7 +425,7 @@ module DaVinciCRDTestKit
370
425
 
371
426
  def context_validate_optional_fields(hook_context, hook_name)
372
427
  hook_optional_context_fields = context_optional_fields_by_hook[hook_name]
373
- return unless hook_optional_context_fields.present?
428
+ return if hook_optional_context_fields.blank?
374
429
 
375
430
  hook_optional_context_fields.each do |field, type|
376
431
  validate_presence_and_type(hook_context, field, type, "#{hook_name} request context") if hook_context[field]
@@ -394,17 +449,152 @@ module DaVinciCRDTestKit
394
449
  hash_context_fields.each do |field, entry|
395
450
  resource_json = entry.to_json
396
451
  fhir_resource = FHIR.from_contents(resource_json)
397
- unless fhir_resource
398
- add_message('error', "Field `#{field}` is not a FHIR resource.")
452
+ if fhir_resource.blank?
453
+ add_message('error', "#{request_number}Field `#{field}` is not a FHIR resource.")
399
454
  next
400
455
  end
401
456
  resource_type = optional_field_resource_types[field]
402
457
  unless fhir_resource.resourceType == resource_type
403
- add_message('error', "Field `#{field}` must be a `#{resource_type}`. Got `#{fhir_resource.resourceType}`.")
458
+ add_message('error', %(
459
+ #{request_number}Field `#{field}` must be a `#{resource_type}`. Got
460
+ `#{fhir_resource.resourceType}`.
461
+ ))
404
462
  next
405
463
  end
406
464
  resource_is_valid?(resource: fhir_resource)
407
465
  end
408
466
  end
467
+
468
+ def hook_request_prefetch_check(advertised_prefetch_fields, received_prefetch, received_context)
469
+ advertised_prefetch_fields.each do |advertised_prefetch_key, advertised_prefetch_template|
470
+ next if received_prefetch[advertised_prefetch_key].blank?
471
+
472
+ unless received_prefetch[advertised_prefetch_key].is_a?(Hash)
473
+ add_message('error', "#{request_number}Prefetch field `#{advertised_prefetch_key}` is not of type `Hash`.")
474
+ next
475
+ end
476
+
477
+ received_prefetch_resource = FHIR.from_contents(received_prefetch[advertised_prefetch_key].to_json)
478
+
479
+ if advertised_prefetch_template.include?('?')
480
+ advertised_prefetch_fhir_search = advertised_prefetch_template.gsub(/{|}/, '').split('?')
481
+ advertised_prefetch_resource_type = advertised_prefetch_fhir_search.first
482
+
483
+ if advertised_prefetch_resource_type == 'Coverage'
484
+ advertised_coverage_query_params = Rack::Utils.parse_nested_query(advertised_prefetch_fhir_search.last)
485
+
486
+ advertised_patient_token = advertised_coverage_query_params['patient']
487
+ advertised_context_patient_id_key = advertised_patient_token.split('.').last
488
+ received_context_patient_id = received_context[advertised_context_patient_id_key]
489
+
490
+ advertised_status_param = advertised_coverage_query_params['status']
491
+
492
+ validate_prefetch_coverage(received_prefetch_resource, advertised_prefetch_key, received_context_patient_id,
493
+ advertised_status_param)
494
+ end
495
+ else
496
+ advertised_prefetch_token = advertised_prefetch_template.gsub(/{|}/, '').split('/')
497
+ advertised_context_id = advertised_prefetch_token.last.split('.').last
498
+
499
+ if advertised_prefetch_token.length == 1
500
+ received_context_reference = FHIR::Reference.new(reference: received_context[advertised_context_id])
501
+ received_context_resource_type = received_context_reference.resource_type
502
+ received_context_id = received_context_reference.reference_id
503
+ else
504
+ received_context_id = received_context[advertised_context_id]
505
+ received_context_resource_type = advertised_prefetch_token.first
506
+ end
507
+ validate_prefetch_resource(received_prefetch_resource, advertised_prefetch_key,
508
+ received_context_resource_type, received_context_id)
509
+ end
510
+ end
511
+ end
512
+
513
+ def validate_prefetch_coverage(received_resource, advertised_prefetch_key,
514
+ received_context_patient_id, advertised_status)
515
+ unless received_resource.resourceType == 'Bundle'
516
+ add_message('error', %(
517
+ #{request_number}Unexpected resource type: Expected `Bundle`. Got
518
+ `#{received_resource.resourceType}`.
519
+ ))
520
+ return
521
+ end
522
+
523
+ if received_resource.entry.empty?
524
+ add_message('error', "#{request_number}Bundle of coverage resources received from prefetch is empty")
525
+ return
526
+ end
527
+
528
+ coverage_resource = received_resource.entry.first.resource
529
+ unless coverage_resource.resourceType == 'Coverage'
530
+ add_message('error', %(
531
+ #{request_number}Unexpected resource type: Expected `Coverage`. Got
532
+ `#{coverage_resource.resourceType}`.
533
+ ))
534
+ return
535
+ end
536
+
537
+ resource_is_valid?(resource: coverage_resource,
538
+ profile_url: structure_definition_map['Coverage'])
539
+
540
+ coverage_beneficiary_reference = coverage_resource.beneficiary
541
+ coverage_beneficiary_patient_id = coverage_beneficiary_reference.reference_id
542
+ if coverage_beneficiary_patient_id.blank?
543
+ add_message('error', %(
544
+ #{request_number}Could not get beneficiary reference id from `#{advertised_prefetch_key}` field's Coverage
545
+ resource
546
+ ))
547
+ return
548
+ end
549
+
550
+ if coverage_beneficiary_patient_id != received_context_patient_id
551
+ add_message('error', %(
552
+ #{request_number}Expected `#{advertised_prefetch_key}` field's Coverage resource to have a `beneficiary`
553
+ reference id of '#{received_context_patient_id}', instead was '#{coverage_beneficiary_patient_id}'
554
+ ))
555
+ return
556
+ end
557
+
558
+ coverage_status = coverage_resource.status
559
+ return unless coverage_status != advertised_status
560
+
561
+ add_message('error', %(
562
+ #{request_number}Expected `#{advertised_prefetch_key}` field's Coverage resource to have a `status` of
563
+ '#{advertised_status}', instead was '#{coverage_status}'
564
+ ))
565
+ end
566
+
567
+ def validate_prefetch_resource(received_resource, advertised_prefetch_key, context_field_resource_type,
568
+ context_field_id)
569
+ unless received_resource.resourceType == context_field_resource_type
570
+ add_message('error', %(
571
+ #{request_number}Unexpected resource type: Expected `#{context_field_resource_type}`. Got
572
+ `#{received_resource.resourceType}`.
573
+ ))
574
+ return
575
+ end
576
+
577
+ if hook_name == 'order-dispatch'
578
+ resource_is_valid?(resource: received_resource)
579
+ else
580
+ resource_is_valid?(resource: received_resource,
581
+ profile_url: structure_definition_map[context_field_resource_type])
582
+ end
583
+
584
+ received_prefetch_resource_id = received_resource.id
585
+ if received_prefetch_resource_id.blank?
586
+ add_message('error', %(
587
+ #{request_number}#{advertised_prefetch_key}` field's FHIR resource does not contain the `id` field
588
+ ))
589
+ return
590
+ end
591
+
592
+ return unless received_prefetch_resource_id != context_field_id
593
+
594
+ add_message('error', %(
595
+ #{request_number}Expected `#{advertised_prefetch_key}` field's FHIR resource to have an `id` of
596
+ '#{context_field_id}', instead was '#{received_prefetch_resource_id}'
597
+ ))
598
+ end
409
599
  end
410
600
  end