Class: Form1095::New1095BsJob

Inherits:
Object
  • Object
show all
Includes:
Sidekiq::Job
Defined in:
app/sidekiq/form1095/new1095_bs_job.rb

Instance Method Summary collapse

Instance Method Details

#bucketObject



9
10
11
12
13
14
15
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 9

def bucket
  @bucket ||= Aws::S3::Resource.new(
    region: Settings.form1095_b.s3.region,
    access_key_id: Settings.form1095_b.s3.aws_access_key_id,
    secret_access_key: Settings.form1095_b.s3.aws_secret_access_key
  ).bucket(Settings.form1095_b.s3.bucket)
end

#download_and_process_file?(file_name) ⇒ Boolean

downloading file to the disk and then reading that file, this will allow us to read large S3 files without exhausting resources/crashing the system

Returns:

  • (Boolean)


172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 172

def download_and_process_file?(file_name)
  Rails.logger.info "processing file: #{file_name}"

  @form_count = 0
  @error_count = 0

  file_details = parse_file_name(file_name)

  return false if file_details.blank?

  # downloads S3 file into local file, allows for processing large files this way
  temp_file = Tempfile.new(file_name, encoding: 'ascii-8bit')

  # downloads file into temp_file
  bucket.object(file_name).get(response_target: temp_file)

  process_file?(temp_file, file_details)
rescue => e
  Rails.logger.error(e.message)
  false
end

#gen_address(addr1, addr2, addr3) ⇒ Object



39
40
41
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 39

def gen_address(addr1, addr2, addr3)
  addr1.concat(' ', addr2 || '', ' ', addr3 || '').strip
end

#get_bucket_filesObject



17
18
19
20
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 17

def get_bucket_files
  # grabs available file names from bucket
  bucket.objects({ prefix: 'MEC', delimiter: '/' }).collect(&:key)
end

#get_coverage_array(form_fields) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 59

def get_coverage_array(form_fields)
  coverage_arr = []
  i = 1
  while i <= 13
    val = "H#{i < 10 ? '0' : ''}#{i}"

    field = form_fields[val.to_sym]
    coverage_arr.push(field && field.strip == 'Y' ? true : false)

    i += 1
  end

  coverage_arr
end

#get_form_fields(data) ⇒ Object



43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 43

def get_form_fields(data)
  fields = {}
  data.each_with_index do |field, ndx|
    next if ndx < 3

    vals = field.split('=')

    value = nil
    value = vals[1] if vals[1] && vals[1].downcase != 'null'

    fields[vals[0].to_sym] = value
  end

  fields
end

#parse_file_name(file_name) ⇒ Object



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 22

def parse_file_name(file_name)
  return {} if file_name.blank?

  file_values = file_name.sub('.txt', '').split('_')

  year = file_values[3].to_i
  ts = file_values[-1]

  {
    is_dep_file?: file_values.include?('B'),
    isOg?: file_values.include?('O'),
    tax_year: year,
    timestamp: ts,
    name: file_name
  }
end

#parse_form(form) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 96

def parse_form(form)
  data = form.split('^')

  unique_id = data[2]

  form_fields = get_form_fields(data)

  coverage_arr = get_coverage_array(form_fields)

  produce_1095_hash(form_fields, unique_id, coverage_arr)
end

#performObject



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 194

def perform
  Rails.logger.info 'Checking for new 1095-B data'

  file_names = get_bucket_files
  if file_names.empty?
    Rails.logger.info 'No new 1095 files found'
  else
    Rails.logger.info "#{file_names.size} files found"
  end

  files_read_count = 0
  file_names.each do |file_name|
    if download_and_process_file?(file_name)
      files_read_count += 1
      Rails.logger.info "Successfully read #{@form_count} 1095B forms from #{file_name}, deleting file from S3"
      bucket.delete_objects(delete: { objects: [{ key: file_name }] })
    else
      Rails.logger.error  "failed to save #{@error_count} forms from file: #{file_name};"\
                          " successfully saved #{@form_count} forms"
    end
  end

  Rails.logger.info "#{files_read_count}/#{file_names.size} files read successfully"
end

#process_file?(temp_file, file_details) ⇒ Boolean

Returns:

  • (Boolean)


151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 151

def process_file?(temp_file, file_details)
  all_succeeded = true
  lines = 0
  temp_file.each_line do |form|
    lines += 1
    successful_line = process_line?(form, file_details)
    all_succeeded = false if !successful_line && all_succeeded
  end

  temp_file.close
  temp_file.unlink

  all_succeeded
rescue => e
  Rails.logger.error "#{e.message}."
  log_exception_to_sentry(e, 'context' => "Error processing file: #{file_details}, on line #{lines}")
  false
end

#process_line?(form, file_details) ⇒ Boolean

Returns:

  • (Boolean)


129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 129

def process_line?(form, file_details)
  data = parse_form(form)

  corrected = !file_details[:isOg?]

  data[:tax_year] = file_details[:tax_year]
  data[:form_data][:is_corrected] = corrected
  data[:form_data][:is_beneficiary] = file_details[:is_dep_file?]
  data[:form_data] = data[:form_data].to_json

  unique_id = data[:unique_id]
  data.delete(:unique_id)

  unless save_data?(data, corrected)
    @error_count += 1
    Rails.logger.warn "Failed to save form with unique ID: #{unique_id}"
    return false
  end

  true
end

#produce_1095_hash(form_fields, unique_id, coverage_arr) ⇒ Object



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 74

def produce_1095_hash(form_fields, unique_id, coverage_arr)
  {
    unique_id:,
    veteran_icn: form_fields[:A15].gsub(/\A0{6}|0{6}\z/, ''),
    form_data: {
      last_name: form_fields[:A01] || '',
      first_name: form_fields[:A02] || '',
      middle_name: form_fields[:A03] || '',
      last_4_ssn: form_fields[:A16] ? form_fields[:A16][-4...] : '',
      birth_date: form_fields[:N03] || '',
      address: gen_address(form_fields[:B01] || ''.dup, form_fields[:B02], form_fields[:B03]),
      city: form_fields[:B04] || '',
      state: form_fields[:B05] || '',
      country: form_fields[:B06] || '',
      zip_code: form_fields[:B07] || '',
      foreign_zip: form_fields[:B08] || '',
      province: form_fields[:B10] || '',
      coverage_months: coverage_arr
    }
  }
end

#save_data?(form_data, corrected) ⇒ Boolean

Returns:

  • (Boolean)


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'app/sidekiq/form1095/new1095_bs_job.rb', line 108

def save_data?(form_data, corrected)
  existing_form = Form1095B.find_by(veteran_icn: form_data[:veteran_icn], tax_year: form_data[:tax_year])

  if !corrected && existing_form.present? # returns true to indicate successful entry
    return true
  elsif corrected && existing_form.nil?
    Rails.logger.warn "Form for year #{form_data[:tax_year]} not found, but file is for Corrected 1095-B forms."
  end

  rv = false
  if existing_form.nil?
    form = Form1095B.new(form_data)
    rv = form.save
  else
    rv = existing_form.update(form_data)
  end

  @form_count += 1 if rv
  rv
end