Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions app/lib/tind_spread/tind_batch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ def format_errors
end

def attachments(attachment_name)
if @all_errors.empty?
{ "#{attachment_name}.csv" => @csv.to_s }
elsif @csv.count("\n") > 1
{ "#{attachment_name}.csv" => @csv.to_s, "ERRORREPORT_#{attachment_name}.csv" => @errors_csv.to_s,
"ERRORREPORT_#{attachment_name}.txt" => format_errors }
else
{ "ERRORREPORT_#{attachment_name}.csv" => @errors_csv.to_s,
"ERRORREPORT_#{attachment_name}.txt" => format_errors }
return { "ERRORREPORT_#{attachment_name}.txt" => format_errors } if @all_errors.key?(1)

return { "#{attachment_name}.csv" => @csv.to_s } if @all_errors.empty?

if @csv.count("\n") > 1
return { "#{attachment_name}.csv" => @csv.to_s,
"ERRORREPORT_#{attachment_name}.csv" => @errors_csv.to_s,
"ERRORREPORT_#{attachment_name}.txt" => format_errors }
end

{ "ERRORREPORT_#{attachment_name}.csv" => @errors_csv.to_s,
"ERRORREPORT_#{attachment_name}.txt" => format_errors }
end

# rubocop:disable Metrics/AbcSize
Expand Down Expand Up @@ -65,19 +68,37 @@ def create_rows(all_rows)
end
# rubocop:enable Metrics/MethodLength

def validate_header_row(headers)
header_errors = []
headers.each do |header|
header_errors << "Invalid header name: #{header.gsub(/^\d+:/, '')}" unless TindSpread::TindValidation.valid_header?(header)
end
header_errors
end

# rubocop:disable Metrics/MethodLength
def run
t = TindSpread::SpreadTool.new(@xlsx_path, @extension, @form_info[:directory])
all_rows = t.spread
@all_errors = {}

# Validate header row
header_errors = validate_header_row(all_rows.first.keys)
@all_errors[1] = header_errors if header_errors.any?

return send_email if header_errors.any?

@csv = TindSpread::MakeBatch.make_header(t.header(all_rows.first.keys), @form_info).encode('UTF-8')
@errors_csv = TindSpread::MakeBatch.make_header(t.header(all_rows.first.keys), @form_info, remove_filename: false).encode('UTF-8')
@all_errors = {}

create_rows(all_rows)
@csv.to_s.gsub!("\xEF\xBB\xBF".force_encoding('UTF-8'), '')
@errors_csv.to_s.gsub!("\xEF\xBB\xBF".force_encoding('UTF-8'), '')
# File.write('output.csv', @csv)
# File.write('errors.csv', @errors_csv)
send_email
end
# rubocop:enable Metrics/MethodLength
# rubocop:enable Metrics/AbcSize
end
end
8 changes: 8 additions & 0 deletions app/lib/tind_spread/tind_validation.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
require 'net/http'
require 'open-uri'
module TindSpread
# rubocop:disable Metrics/ModuleLength
module TindValidation

# validates the header rown
def self.valid_header?(str)
str.match?(/\d{3}[_|\d]{2}[a-zA-Z0-9]$/) || str.match?(/\d{3}[_|\d]{2}[a-zA-Z0-9]-\d$/) || str.match?(/Filename|FFT/i)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might want to elaborate on the comment (include examples of what the REGEX is matching there)

I'm not 100% sure, I'm rusty w/regular expressions, but is the first 1s match necessary? Could this be slightly simplified by removing the first match and change the 2nd match by wrapping the -d in parens and adding a '?' after it?
example: ...a-zA-Z0-9?$/

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point about the comments. Just added some more.

For the reg expression having a ? at the end would work but be too permissive. The option (-1) has to be a dash followed by a number

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so (-\d)? wouldn't work....?

Copy link
Copy Markdown
Contributor Author

@davezuckerman davezuckerman Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually if I add a "$" after the ? looks like it works.
"/\d{3}[_|\d]{2}a-zA-Z0-9?$/)"

I'll change the expression

end

# runs a set of validations against a single row.
# Row should be an array of hashes, key being the column header for the row.
# rubocop:disable Metrics/MethodLength
Expand All @@ -28,6 +34,7 @@ def self.validate_row(row)

# private
class << self

private

def filename_error(row, errors)
Expand Down Expand Up @@ -149,4 +156,5 @@ def valid_500__3?(key, row)

end
end
# rubocop:enable Metrics/ModuleLength
end
38 changes: 30 additions & 8 deletions spec/lib/tind_spread/tind_batch_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@
let(:args) { { directory:, '982__a': 'test' } }
let(:tind_batch) { described_class.new(args, xlsx, extension, email) }
let(:spread_tool) { instance_double(TindSpread::SpreadTool) }
let(:all_rows) { [{ 'Header1' => 'Data1', 'Header2' => 'Data2' }, { 'Header1' => 'Data3', 'Header2' => 'Data4' }] }
let(:all_rows) { [{ '001__a' => 'Data1', '245__a' => 'Data2' }, { '001__a' => 'Data3', '245__a' => 'Data4' }] }

before do
allow(TindSpread::SpreadTool).to receive(:new).with(xlsx, extension, directory).and_return(spread_tool)
allow(spread_tool).to receive(:spread).and_return(all_rows)
allow(spread_tool).to receive(:header).with(any_args).and_return(%w[Header1 Header2])
allow(TindSpread::MakeBatch).to receive(:make_header).with(any_args).and_return("Header1,Header2\n")
allow(spread_tool).to receive(:header).with(any_args).and_return(%w[001__a 245__a])
allow(TindSpread::MakeBatch).to receive(:make_header).with(any_args).and_return("001__a,245__a\n")
allow(TindSpread::MakeBatch).to receive(:add_row).with(any_args).and_return("Data1,Data2\n")
allow(TindSpread::TindValidation).to receive(:validate_row).with(any_args).and_return([])
# rubocop:disable RSpec/MessageChain
Expand Down Expand Up @@ -49,15 +49,15 @@
describe '#send_email' do
it 'sends an email with the correct attachments' do
tind_batch.instance_variable_set(:@all_errors, {})
tind_batch.instance_variable_set(:@csv, "Header1,Header2\nData1,Data2\n")
tind_batch.instance_variable_set(:@errors_csv, "Header1,Header2\n")
tind_batch.instance_variable_set(:@csv, "001__a,245__a\nData1,Data2\n")
tind_batch.instance_variable_set(:@errors_csv, "001__a,245__a\n")
allow(Time).to receive(:current).and_return(Time.parse('2023-10-01 12:00:00 UTC'))
attachment_name = 'test_2023-10-01'
expect(RequestMailer).to receive(:tind_spread_email).with(
email,
'Tind batch load for test',
'No errors found',
{ "#{attachment_name}.csv" => "Header1,Header2\nData1,Data2\n" }
{ "#{attachment_name}.csv" => "001__a,245__a\nData1,Data2\n" }
).and_return(double(deliver_now: true))
tind_batch.send_email
end
Expand All @@ -74,12 +74,34 @@
end
end

describe '#validate_header_row' do
it 'returns an empty array for valid headers' do
headers = %w[001__a 245__a 500__3]
errors = tind_batch.validate_header_row(headers)
expect(errors).to be_empty
end

it 'returns error messages for invalid headers' do
headers = %w[Header1 Header2]
errors = tind_batch.validate_header_row(headers)
expect(errors).to include('Invalid header name: Header1')
expect(errors).to include('Invalid header name: Header2')
end

it 'returns errors only for invalid headers in a mixed list' do
headers = %w[001__a InvalidHeader 245__a]
errors = tind_batch.validate_header_row(headers)
expect(errors).to include('Invalid header name: InvalidHeader')
expect(errors.length).to eq(1)
end
end

describe '#run' do
it 'runs the batch process' do
allow(tind_batch).to receive(:send_email)
tind_batch.run
expect(tind_batch.instance_variable_get(:@csv)).to eq("Header1,Header2\nData1,Data2\nData1,Data2\n")
expect(tind_batch.instance_variable_get(:@errors_csv)).to eq("Header1,Header2\n")
expect(tind_batch.instance_variable_get(:@csv)).to eq("001__a,245__a\nData1,Data2\nData1,Data2\n")
expect(tind_batch.instance_variable_get(:@errors_csv)).to eq("001__a,245__a\n")
end
end
end
22 changes: 22 additions & 0 deletions spec/lib/tind_spread/tind_validation_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -108,4 +108,26 @@
expect(described_class.send(:corresponding_6?, '800__6', row)).to be false
end
end

describe '.valid_header?' do
it 'returns true for a valid header with standard format' do
expect(described_class.valid_header?('001__a')).to be true
expect(described_class.valid_header?('245__a')).to be true
expect(described_class.valid_header?('Filename')).to be true
expect(described_class.valid_header?('100_1a')).to be true
end

it 'returns true for a valid header with suffix format' do
expect(described_class.valid_header?('001__a-1')).to be true
expect(described_class.valid_header?('245__a-2')).to be true
expect(described_class.valid_header?('500__3-5')).to be true
end

it 'returns false for invalid headers' do
expect(described_class.valid_header?('abc')).to be false
expect(described_class.valid_header?('12__a')).to be false
expect(described_class.valid_header?('001__a-')).to be false
expect(described_class.valid_header?('001__a-ab')).to be false
end
end
end
Loading