Skip to content

Commit c5aae98

Browse files
costacalvinCalvin Costa
andauthored
mms endpoint updates (#26948)
* mms endpoint updates * update due to new directives for MMS * lint fixes * public veteran_name method fix * lint fixes * copilot suggestion * remove date formatting to be consistent --------- Co-authored-by: Calvin Costa <calvin.costa@va.com>
1 parent f3c0d21 commit c5aae98

File tree

8 files changed

+314
-294
lines changed

8 files changed

+314
-294
lines changed

app/models/concerns/ibm_data_dictionary.rb

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -126,11 +126,22 @@ def format_phone_for_ibm(phone_number)
126126
end
127127

128128
# Build checkbox value
129-
# Returns true for checked, false for unchecked (IBM MMS convention)
129+
# Returns 1 for checked, 0 for unchecked (IBM MMS VBA Data Dictionary convention)
130130
# @param value [Boolean, nil]
131-
# @return [Boolean]
131+
# @return [Integer]
132132
def build_checkbox_value(value)
133-
value == true
133+
value == true ? 1 : 0
134+
end
135+
136+
# Format currency value for IBM MMS
137+
# Formats with commas and 2 decimal places (no dollar sign)
138+
# @param amount [String, Integer, Float, nil] Numeric amount
139+
# @return [String, nil] Formatted currency (e.g., "1,138.00") or nil
140+
def format_currency_for_ibm(amount)
141+
return nil if amount.nil? || amount.to_s.strip.empty?
142+
143+
numeric_value = amount.to_s.gsub(/[^0-9.]/, '').to_f
144+
format('%<amount>.2f', amount: numeric_value).gsub(/(\d)(?=(\d{3})+\.)/, '\1,')
134145
end
135146

136147
# Build form metadata fields

app/models/saved_claim/form210779.rb

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,6 @@ def to_pdf(file_name = nil, fill_options = {})
3939
PdfFill::Forms::Va210779.stamp_signature(pdf_path, parsed_form)
4040
end
4141

42-
def veteran_name
43-
first = parsed_form.dig('veteranInformation', 'fullName', 'first')
44-
last = parsed_form.dig('veteranInformation', 'fullName', 'last')
45-
"#{first} #{last}".strip.presence || 'Veteran'
46-
end
47-
4842
def metadata_for_benefits_intake
4943
{ veteranFirstName: parsed_form.dig('veteranInformation', 'fullName', 'first'),
5044
veteranLastName: parsed_form.dig('veteranInformation', 'fullName', 'last'),
@@ -61,6 +55,12 @@ def to_ibm
6155
build_ibm_payload(parsed_form)
6256
end
6357

58+
def veteran_name
59+
first = parsed_form.dig('veteranInformation', 'fullName', 'first')
60+
last = parsed_form.dig('veteranInformation', 'fullName', 'last')
61+
"#{first} #{last}".strip.presence || 'Veteran'
62+
end
63+
6464
private
6565

6666
def zip_code_for_metadata
@@ -84,9 +84,11 @@ def build_ibm_payload(form)
8484
def build_veteran_fields(form)
8585
vet_info = form['veteranInformation'] || {}
8686
vet_id = vet_info['veteranId'] || {}
87+
full_name = vet_info['fullName'] || {}
8788

8889
build_veteran_basic_fields(vet_info)
8990
.merge({
91+
'VETERAN_NAME' => build_full_name(full_name),
9092
'VETERAN_SSN' => vet_id['ssn'],
9193
'VA_FILE_NUMBER' => vet_id['vaFileNumber']
9294
})
@@ -98,14 +100,18 @@ def build_veteran_fields(form)
98100
def build_claimant_fields_section(form)
99101
claimant_info = form['claimantInformation'] || {}
100102
claimant_id = claimant_info['veteranId'] || {}
103+
full_name = claimant_info['fullName'] || {}
101104

102105
fields = build_claimant_fields(claimant_info)
103106

107+
# Add full name field
108+
fields['CLAIMANT_NAME'] = build_full_name(full_name)
109+
104110
# Override SSN with correct path (from veteranId object)
105111
fields['CLAIMANT_SSN'] = claimant_id['ssn']
106112

107-
# Box 7: VA File Number (note the typo from the spec: CL_FILE_NUMER)
108-
fields['CL_FILE_NUMER'] = claimant_id['vaFileNumber']
113+
# Box 7: VA File Number
114+
fields['CL_FILE_NUMBER'] = claimant_id['vaFileNumber']
109115

110116
fields
111117
end
@@ -136,35 +142,46 @@ def build_nursing_home_fields(form)
136142
def build_general_information_fields(form)
137143
general_info = form['generalInformation'] || {}
138144

145+
build_medicaid_fields(general_info)
146+
.merge(build_cost_and_care_fields(general_info))
147+
.merge(build_nursing_official_fields(general_info))
148+
end
149+
150+
# Build Medicaid-related fields (Boxes 12-14)
151+
def build_medicaid_fields(general_info)
139152
{
140-
# Box 11: Date admitted to nursing home (MM/DD/YYYY format)
141153
'DATE_ADMISSION_TO_FACILITY_C' => format_date_for_ibm(general_info['admissionDate']),
142-
# Box 12: Is the nursing home a Medicaid approved facility? (always include both Y/N)
143154
'MEDICAID_APPROVED_Y' => build_checkbox_value(general_info['medicaidFacility'] == true),
144155
'MEDICAID_APPROVED_N' => build_checkbox_value(general_info['medicaidFacility'] == false),
145-
# Box 13: Has the patient applied for Medicaid? (always include both Y/N)
146156
'MEDICAID_APPLIED_Y' => build_checkbox_value(general_info['medicaidApplication'] == true),
147157
'MEDICAID_APPLIED_N' => build_checkbox_value(general_info['medicaidApplication'] == false),
148-
# Box 14A: Is the patient covered by Medicaid? (always include both Y/N)
149158
'MEDICAID_COVERAGE_Y' => build_checkbox_value(general_info['patientMedicaidCovered'] == true),
150159
'MEDICAID_COVERAGE_N' => build_checkbox_value(general_info['patientMedicaidCovered'] == false),
151-
# Box 14B: Date Medicaid plan began (MM/DD/YYYY format)
152-
'MEDICAID_START' => format_date_for_ibm(general_info['medicaidStartDate']),
153-
# Box 15: Monthly amount patient is responsible for out of pocket
154-
'OUT_OF_POCKET' => general_info['monthlyCosts'],
155-
# Box 16: Type of care (skilled or intermediate - always include both)
160+
'MEDICAID_START' => format_date_for_ibm(general_info['medicaidStartDate'])
161+
}
162+
end
163+
164+
# Build cost and care type fields (Boxes 15-16)
165+
def build_cost_and_care_fields(general_info)
166+
monthly_costs = general_info['monthlyCosts']
167+
168+
{
169+
'OUT_OF_POCKET' => format_currency_for_ibm(monthly_costs),
170+
'OUT_OF_POCKET_THSNDS' => extract_currency_thousands(monthly_costs),
171+
'OUT_OF_POCKET_HNDRDS' => extract_currency_hundreds(monthly_costs),
172+
'OUT_OF_POCKET_CENTS' => extract_currency_cents(monthly_costs),
156173
'SKILLED_CARE' => build_checkbox_value(general_info['certificationLevelOfCare'] == 'skilled'),
157-
'INTERMEDIATE_CARE' => build_checkbox_value(general_info['certificationLevelOfCare'] == 'intermediate'),
158-
# Box 17: Nursing home official's name
174+
'INTERMEDIATE_CARE' => build_checkbox_value(general_info['certificationLevelOfCare'] == 'intermediate')
175+
}
176+
end
177+
178+
# Build nursing home official fields (Boxes 17-21)
179+
def build_nursing_official_fields(general_info)
180+
{
159181
'NAME_COMPLETING_WORKSHEET_C' => general_info['nursingOfficialName'],
160-
# Box 18: Nursing home official's title
161182
'ROLE_PERFORM_AT_FACILITY_C' => general_info['nursingOfficialTitle'],
162-
# Box 19: Nursing home official's office telephone number
163183
'FACILITY_TELEPHONE_NUMBER_C' => format_phone_for_ibm(general_info['nursingOfficialPhoneNumber']),
164-
'INT_PHONE_NUMBER' => format_phone_for_ibm(general_info['nursingOfficialInternationalPhoneNumber']),
165-
# Box 20: Signature of nursing home official
166184
'SIGNATURE_OF_PROVIDER_C' => general_info['signature'],
167-
# Box 21: Date signed (MM/DD/YYYY format)
168185
'SIGNATURE_DATE_PROVIDER_C' => format_date_for_ibm(general_info['signatureDate'])
169186
}
170187
end
@@ -175,8 +192,43 @@ def build_form_metadata_fields
175192
{
176193
'FLASH_TEXT' => nil,
177194
'CB_VA_STAMP' => nil,
178-
'FORM_TYPE' => '21-0779',
179-
'FORM_TYPE_1' => '21-0779'
195+
'FORM_TYPE_1' => 'VA FORM 0779, NOV 2023'
180196
}
181197
end
198+
199+
# Extract thousands portion from currency amount
200+
# Fixed 3-digit format, returns "000" if no thousands
201+
# @param amount [String, Integer, Float, nil] Numeric amount
202+
# @return [String] Thousands portion (e.g., "130" from 130000.50, "000" from 9.50)
203+
def extract_currency_thousands(amount)
204+
return '000' if amount.nil? || amount.to_s.strip.empty?
205+
206+
numeric_value = amount.to_s.gsub(/[^0-9.]/, '').to_f
207+
thousands = (numeric_value / 1000).floor
208+
thousands.positive? ? thousands.to_s : '000'
209+
end
210+
211+
# Extract hundreds portion from currency amount
212+
# Fixed 3-digit format with leading zeros
213+
# @param amount [String, Integer, Float, nil] Numeric amount
214+
# @return [String] Hundreds portion with leading zeros (e.g., "000" from 3000.50, "009" from 9.50)
215+
def extract_currency_hundreds(amount)
216+
return '000' if amount.nil? || amount.to_s.strip.empty?
217+
218+
numeric_value = amount.to_s.gsub(/[^0-9.]/, '').to_f
219+
hundreds = (numeric_value % 1000).floor
220+
format('%03d', hundreds)
221+
end
222+
223+
# Extract cents portion from currency amount
224+
# Fixed 2-digit format with leading zeros
225+
# @param amount [String, Integer, Float, nil] Numeric amount
226+
# @return [String] Cents portion (e.g., "50" from 3000.50, "00" from 9.00)
227+
def extract_currency_cents(amount)
228+
return '00' if amount.nil? || amount.to_s.strip.empty?
229+
230+
numeric_value = amount.to_s.gsub(/[^0-9.]/, '').to_f
231+
cents = ((numeric_value % 1) * 100).round
232+
format('%02d', cents)
233+
end
182234
end

app/models/saved_claim/form214192.rb

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -85,10 +85,6 @@ def to_ibm
8585

8686
private
8787

88-
def zip_code_for_metadata
89-
parsed_form.dig('employmentInformation', 'employerAddress', 'postalCode') || DEFAULT_ZIP_CODE
90-
end
91-
9288
def employer_name
9389
parsed_form.dig('employmentInformation', 'employerName') || 'Employer'
9490
end
@@ -99,28 +95,20 @@ def veteran_name
9995
"#{first} #{last}".strip.presence || 'Veteran'
10096
end
10197

98+
def zip_code_for_metadata
99+
parsed_form.dig('employmentInformation', 'employerAddress', 'postalCode') || DEFAULT_ZIP_CODE
100+
end
101+
102102
# Build the IBM data dictionary payload from the parsed claim form
103+
# Per AUG 2024 Data Dictionary: Form 21-4192 has only 3 fields
104+
# This form is completed by employers, not veterans, so no veteran fields in IBM payload
103105
# @param form [Hash]
104106
# @return [Hash]
105107
def build_ibm_payload(form)
106-
build_veteran_fields(form)
107-
.merge(build_employer_fields(form))
108+
build_employer_fields(form)
108109
.merge(build_form_metadata_fields)
109110
end
110111

111-
# Build veteran identification fields (Section 1)
112-
# @param form [Hash]
113-
# @return [Hash]
114-
def build_veteran_fields(form)
115-
vet_info = form['veteranInformation'] || {}
116-
117-
basic_fields = build_veteran_basic_fields(vet_info)
118-
basic_fields['VETERAN_INITIAL'] = basic_fields.delete('VETERAN_MIDDLE_INITIAL')
119-
basic_fields['VA_FILE_NUMBER'] ||= ''
120-
121-
basic_fields
122-
end
123-
124112
# Build employer information fields (Box 1)
125113
# @param form [Hash]
126114
# @return [Hash]
@@ -130,15 +118,15 @@ def build_employer_fields(form)
130118

131119
{
132120
'EMPLOYER_NAME_ADDRESS' => build_employer_name_and_address(employment['employerName'], employer_address)
133-
}.compact
121+
}
134122
end
135123

136124
# Build form metadata
137125
# @return [Hash]
138126
def build_form_metadata_fields
139127
{
140-
'FORM_TYPE' => '21-4192',
141-
'FORM_TYPE_1' => '21-4192'
128+
'FORM_TYPE' => 'VA FORM 21-4192, AUG 2024',
129+
'FORM_TYPE_1' => 'VA FORM 21-4192, AUG 2024'
142130
}
143131
end
144132

0 commit comments

Comments
 (0)