From 4c73db46f8432da6fe26e9898ca9863291b083ba Mon Sep 17 00:00:00 2001 From: Rockwell Windsor Rice <129893414+rockwellwindsor-va@users.noreply.github.com> Date: Tue, 30 May 2023 10:02:40 -0500 Subject: [PATCH] Api 24833 526 v2 section 6 service info validation part 1 v2 (#12789) * Service Information validation - Part 1 API-24833 - Part 1 AC points 1 - 12 * Adds RSpec tests for validating service information elements for AC points 1 - 12 * Adds methods in validation file for validating service information elements * Updates 526 schema, and related JSON files, for the updated type for confinements Changes to be committed: modified: modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb modified: modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json modified: modules/claims_api/config/schemas/v2/526.json modified: modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/example.json modified: modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/request.json modified: modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json modified: modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb modified: spec/support/schemas/claims_api/v2/forms/disability/submission.json * Service Information validation - Part 1 API-24833 - Part 1 AC points 1 - 12 Alters the AC points covered, now part 1 covers 1 - 9 and adjusts RSpec and validation file in line with that. Changes to be committed: modified: modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb modified: modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb * Removes RSpec tests that moved over to part 2 * Fixes my misunderstood structure for confinements * Removes a log out and gets the brakeman update --- .../v2/disability_compensation_validation.rb | 47 ++++ .../swagger/claims_api/v2/dev/swagger.json | 135 +++++++---- modules/claims_api/config/schemas/v2/526.json | 33 ++- .../disability_compensation/example.json | 13 +- .../disability_compensation/request.json | 31 ++- .../form_526_json_api.json | 18 +- .../disability_compensation_request_spec.rb | 225 ++++++++++++++++++ .../v2/forms/disability/submission.json | 81 ++++--- 8 files changed, 476 insertions(+), 107 deletions(-) diff --git a/modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb b/modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb index b736e4ce2e3..2ec7e241aab 100644 --- a/modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb +++ b/modules/claims_api/app/controllers/concerns/claims_api/v2/disability_compensation_validation.rb @@ -16,6 +16,8 @@ def validate_form_526_submission_values! validate_form_526_veteran_homelessness! # ensure treament centers information is valid validate_form_526_treatments! + # ensure service information is valid + validate_form_526_service_information! end def validate_form_526_submission_claim_date! @@ -165,6 +167,51 @@ def collect_primary_secondary_disability_names(disabilities) end names end + + def validate_form_526_service_information! + service_information = form_attributes['serviceInformation'] + + if service_information.blank? + raise ::Common::Exceptions::UnprocessableEntity.new( + detail: 'Service information is required' + ) + end + + validate_service_periods! + validate_confinements! + end + + def validate_service_periods! + service_information = form_attributes['serviceInformation'] + + service_information['servicePeriods'].each do |sp| + if Date.parse(sp['activeDutyBeginDate']) > Date.parse(sp['activeDutyEndDate']) + raise ::Common::Exceptions::UnprocessableEntity.new( + detail: 'Active Duty End Date needs to be after Active Duty Start Date' + ) + end + + if Date.parse(sp['activeDutyEndDate']) > Time.zone.now && sp['separationLocationCode'].empty? + raise ::Common::Exceptions::UnprocessableEntity.new( + detail: 'If Active Duty End Date is in the future a Separation Location Code is required.' + ) + end + end + end + + def validate_confinements! + service_information = form_attributes['serviceInformation'] + + service_information['confinements'].each do |confinement| + approximate_begin_date = confinement['approximateBeginDate'] + approximate_end_date = confinement['approximateEndDate'] + if Date.parse(approximate_begin_date) > Date.parse(approximate_end_date) + raise ::Common::Exceptions::UnprocessableEntity.new( + detail: 'Approximate end date must be after approximate begin date.' + ) + end + end + end end end end diff --git a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json index f55b4e6461e..c915d1ee045 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json @@ -2109,15 +2109,20 @@ "example": "2018-03-02" }, "treatedDisabilityNames": { - "description": "Names of disability treated.", + "description": "Name(s) of Disabilities treated in this time frame.", "type": "array", "minItems": 1, "maxItems": 101, - "uniqueItems": true, "items": { - "description": "Name of Disabilities Veteran was Treated for.", "type": "string", - "example": "PTSD (post traumatic stress disorder)" + "additionalProperties": false, + "properties": { + "type": "string", + "example": [ + "PTSD (post traumatic stress disorder)", + "Trauma" + ] + } } }, "center": { @@ -2247,18 +2252,33 @@ } }, "confinements": { - "type": "object", + "type": "array", "description": "", - "properties": { - "approximateBeginDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" - }, - "approximateEndDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" + "uniqueItems": true, + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "confinement": { + "type": "object", + "additionalProperties": false, + "required": [ + "approximateBeginDate", + "approximateEndDate" + ], + "properties": { + "approximateBeginDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "approximateEndDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-08-04" + } + } + } } } }, @@ -2266,11 +2286,30 @@ "type": "object", "additionalProperties": false, "required": [ - "obligationTermOfServiceFromDate", - "obligationTermOfServiceToDate", + "obligationTermsOfService", "unitName" ], "properties": { + "obligationTermsOfService": { + "type": "object", + "additionalProperties": false, + "required": [ + "startDate", + "endDate" + ], + "properties": { + "startDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "endDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + } + } + }, "component": { "type": "array", "description": "", @@ -2301,14 +2340,6 @@ } } }, - "obligationTermOfServiceFromDate": { - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" - }, - "obligationTermOfServiceToDate": { - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" - }, "unitName": { "type": "string", "pattern": "([a-zA-Z0-9\\-'.,# ][a-zA-Z0-9\\-'.,# ]?)*$" @@ -3390,18 +3421,27 @@ } }, "confinements": { - "type": "object", + "type": "array", "description": "", - "properties": { - "approximateBeginDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" - }, - "approximateEndDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" + "uniqueItems": true, + "items": { + "additionalProperties": false, + "type": "object", + "required": [ + "approximateBeginDate", + "approximateEndDate" + ], + "properties": { + "approximateBeginDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "approximateEndDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-08-04" + } } } }, @@ -3816,7 +3856,7 @@ "exposureOrEventOrInjury": "" } ], - "isRelatedToToxicExposure": true, + "isRelatedToToxicExposure": false, "exposureOrEventOrInjury": "" } ], @@ -3855,10 +3895,16 @@ "separationLocationCode": "V01D" } ], - "confinements": { - "approximateBeginDate": "2016-11-06", - "approximateEndDate": "2016-11-09" - }, + "confinements": [ + { + "approximateBeginDate": "2016-11-06", + "approximateEndDate": "2016-11-09" + }, + { + "approximateBeginDate": "2019-11-06", + "approximateEndDate": "2019-11-09" + } + ], "reservesNationalGuardService": { "obligationTermsOfService": { "startDate": "2016-11-24", @@ -3877,7 +3923,8 @@ "receivingInactiveDutyTrainingPay": true }, "alternateNames": [ - "John Jacob Jingleheimer-Schmidt" + "John Jacob Jingleheimer-Schmidt", + "Johnathon" ], "servedInActiveCombatSince911": false }, @@ -4547,8 +4594,8 @@ "id": "1", "type": "intent_to_file", "attributes": { - "creationDate": "2023-05-22", - "expirationDate": "2024-05-22", + "creationDate": "2023-05-24", + "expirationDate": "2024-05-24", "type": "compensation", "status": "active" } diff --git a/modules/claims_api/config/schemas/v2/526.json b/modules/claims_api/config/schemas/v2/526.json index ce417de0492..2b6fc6ef851 100644 --- a/modules/claims_api/config/schemas/v2/526.json +++ b/modules/claims_api/config/schemas/v2/526.json @@ -784,21 +784,30 @@ } }, "confinements": { - "type": "object", + "type": "array", "description": "", - "properties": { - "approximateBeginDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" - }, - "approximateEndDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" + "uniqueItems": true, + "items": { + "additionalProperties": false, + "type": "object", + "required": [ + "approximateBeginDate", + "approximateEndDate" + ], + "properties": { + "approximateBeginDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "approximateEndDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-08-04" + } } } - }, + }, "reservesNationalGuardService": { "type": "object", "additionalProperties": false, diff --git a/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/example.json b/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/example.json index 3ffd285c329..cbe3952ab41 100644 --- a/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/example.json +++ b/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/example.json @@ -141,10 +141,16 @@ "separationLocationCode": "V01D" } ], - "confinements": { + "confinements": [ + { "approximateBeginDate": "2016-11-06", "approximateEndDate": "2016-11-09" - }, + }, + { + "approximateBeginDate": "2019-11-06", + "approximateEndDate": "2019-11-09" + } + ], "reservesNationalGuardService": { "obligationTermsOfService": { "startDate":"2016-11-24", @@ -163,7 +169,8 @@ "receivingInactiveDutyTrainingPay": true }, "alternateNames": [ - "John Jacob Jingleheimer-Schmidt" + "John Jacob Jingleheimer-Schmidt", + "Johnathon" ], "servedInActiveCombatSince911": false }, diff --git a/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/request.json b/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/request.json index 9eff2bc18ee..275ca0cc601 100644 --- a/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/request.json +++ b/modules/claims_api/config/schemas/v2/request_bodies/disability_compensation/request.json @@ -785,18 +785,27 @@ } }, "confinements": { - "type": "object", + "type": "array", "description": "", - "properties": { - "approximateBeginDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" - }, - "approximateEndDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" + "uniqueItems": true, + "items": { + "additionalProperties": false, + "type": "object", + "required": [ + "approximateBeginDate", + "approximateEndDate" + ], + "properties": { + "approximateBeginDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "approximateEndDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-08-04" + } } } }, diff --git a/modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json b/modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json index 12698e2a42f..29c9158e468 100644 --- a/modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json +++ b/modules/claims_api/spec/fixtures/v2/veterans/disability_compensation/form_526_json_api.json @@ -34,14 +34,20 @@ "separationLocationCode": "ABCDEFGHIJKLMN" } ], - "confinements": { - "approximateBeginDate": "8349-11-06", - "approximateEndDate": "2884-12-09" - }, + "confinements": [ + { + "approximateBeginDate": "2018-06-04", + "approximateEndDate": "2018-07-04" + } , + { + "approximateBeginDate": "2020-06-04", + "approximateEndDate": "2020-07-04" + } + ], "reservesNationalGuardService": { "obligationTermsOfService": { - "startDate":"3995-11-24", - "endDate":"8502-11-17" + "startDate":"2019-06-04", + "endDate":"2020-06-04" }, "unitName": "''c'5'l'#l#2z", "component": "Active", diff --git a/modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb b/modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb index a37001b24a7..0a6bf1b1570 100644 --- a/modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb +++ b/modules/claims_api/spec/requests/v2/veterans/disability_compensation_request_spec.rb @@ -1152,6 +1152,231 @@ end end end + + describe 'Validation of service information elements' do + context 'when the serviceBranch is empty' do + let(:service_branch) { '' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['servicePeriods'][0]['serviceBranch'] = + service_branch + data = json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when the activeDutyBeginDate is after the activeDutyEndDate' do + let(:active_duty_end_date) { '1979-01-02' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['servicePeriods'][0]['activeDutyEndDate'] = + active_duty_end_date + data = json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when the activeDutyBeginDate is not formatted correctly' do + let(:active_duty_begin_date) { '25-06-1979' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['servicePeriods'][0]['activeDutyEndDate'] = + active_duty_begin_date + data = json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when the activeDutyEndDate is not formatted correctly' do + let(:active_duty_end_date) { '28-07-1995' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['servicePeriods'][0]['activeDutyEndDate'] = + active_duty_end_date + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when the activeDutyEndDate is in the future' do + let(:active_duty_end_date) { 2.months.from_now.strftime('%Y-%m-%d') } + + context 'and the seperationLocationCode is present' do + it 'responds with a 200' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['servicePeriods'][0]['activeDutyEndDate'] = + active_duty_end_date + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:ok) + end + end + end + end + + context 'and the seperationLocationCode is blank' do + let(:separation_location_code) { nil } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + service_period = json['data']['attributes']['serviceInformation']['servicePeriods'][0] + service_period['activeDutyEndDate'] = active_duty_end_date + service_period['separationLocationCode'] = separation_location_code + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'and the seperationLocationCode is an empty string' do + let(:separation_location_code) { '' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + service_period = json['data']['attributes']['serviceInformation']['servicePeriods'][0] + service_period['activeDutyEndDate'] = active_duty_end_date + service_period['separationLocationCode'] = separation_location_code + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + end + end + + context 'when there are mutiple confinements' do + let(:confinements) do + [ + { + approximateBeginDate: '2016-01-01', + approximateEndDate: '2016-01-06' + }, + { + approximateBeginDate: '2017-01-01', + approximateEndDate: '2017-01-06' + } + ] + end + + it 'responds with a 200' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + json['data']['attributes']['serviceInformation']['confinements'] = confinements + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:ok) + end + end + end + end + end + + context 'when confinements.confinement.approximateBeginDate is formatted incorrectly' do + let(:approximate_begin_date) { '11-24-2021' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + confinement = json['data']['attributes']['serviceInformation']['confinements'][0] + confinement['approximateBeginDate'] = approximate_begin_date + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when confinements.confinement.approximateEndDate is formatted incorrectly' do + let(:approximate_end_date) { '11-24-2022' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + confinement = json['data']['attributes']['serviceInformation']['confinements'][0] + confinement['approximateEndDate'] = approximate_end_date + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + + context 'when confinements.confinement.approximateBeginDate is after approximateEndDate' do + let(:approximate_end_date) { '2017-05-06' } + + it 'responds with a 422' do + with_okta_user(scopes) do |auth_header| + VCR.use_cassette('evss/claims/claims') do + VCR.use_cassette('brd/countries') do + json = JSON.parse(data) + confinement = json['data']['attributes']['serviceInformation']['confinements'][0] + confinement['approximateEndDate'] = approximate_end_date + data = json.to_json + post path, params: data, headers: headers.merge(auth_header) + expect(response).to have_http_status(:unprocessable_entity) + end + end + end + end + end + end end context 'validate' do diff --git a/spec/support/schemas/claims_api/v2/forms/disability/submission.json b/spec/support/schemas/claims_api/v2/forms/disability/submission.json index 1f01431d441..cfc3620f636 100644 --- a/spec/support/schemas/claims_api/v2/forms/disability/submission.json +++ b/spec/support/schemas/claims_api/v2/forms/disability/submission.json @@ -672,15 +672,17 @@ "example": "2018-03-02" }, "treatedDisabilityNames": { - "description": "Names of disability treated.", + "description": "Name(s) of Disabilities treated in this time frame.", "type": "array", "minItems": 1, "maxItems": 101, - "uniqueItems": true, "items": { - "description": "Name of Disabilities Veteran was Treated for.", "type": "string", - "example": "PTSD (post traumatic stress disorder)" + "additionalProperties": false, + "properties": { + "type": "string", + "example": ["PTSD (post traumatic stress disorder)","Trauma"] + } } }, "center": { @@ -810,18 +812,27 @@ } }, "confinements": { - "type": "object", + "type": "array", "description": "", - "properties": { - "approximateBeginDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" - }, - "approximateEndDate": { - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", - "type": "string", - "example": "2018-06-04" + "uniqueItems": true, + "items": { + "additionalProperties": false, + "type": "object", + "required": [ + "approximateBeginDate", + "approximateEndDate" + ], + "properties": { + "approximateBeginDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "approximateEndDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-08-04" + } } } }, @@ -829,11 +840,27 @@ "type": "object", "additionalProperties": false, "required": [ - "obligationTermOfServiceFromDate", - "obligationTermOfServiceToDate", + "obligationTermsOfService", "unitName" ], "properties": { + "obligationTermsOfService": { + "type": "object", + "additionalProperties": false, + "required": ["startDate","endDate"], + "properties": { + "startDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + }, + "endDate": { + "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$", + "type": "string", + "example": "2018-06-04" + } + } + }, "component": { "type": "array", "description": "", @@ -864,14 +891,6 @@ } } }, - "obligationTermOfServiceFromDate": { - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" - }, - "obligationTermOfServiceToDate": { - "type": "string", - "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$" - }, "unitName": { "type": "string", "pattern": "([a-zA-Z0-9\\-'.,# ][a-zA-Z0-9\\-'.,# ]?)*$" @@ -905,11 +924,11 @@ "maxItems": 100, "uniqueItems": true, "items": { - "type": "string", - "additionalProperties": false, - "examples": ["jane", "janey lee", "jane lee MacDonald"] - } - }, + "type": "string", + "additionalProperties": false, + "examples": ["jane", "janey lee", "jane lee MacDonald"] + } + }, "servedInActiveCombatSince911": { "type": "boolean", "description": "Did Veteran serve in a combat zone since 9-11-2001?", @@ -1108,4 +1127,4 @@ } } } -} \ No newline at end of file +}