From e420e8c851ac16ad2e9729aeb51c2238683ca437 Mon Sep 17 00:00:00 2001 From: Henrique Gasques Date: Fri, 3 Mar 2023 18:22:38 -0300 Subject: [PATCH 1/3] Fix reading files with SD1700 in company descriptive date field --- Gemfile.lock | 1 + lib/ach/ach_file.rb | 10 +++++++++- lib/ach/string_formatting_helper.rb | 7 +++++-- spec/ach/fixtures/return_noc.txt | 4 ++-- spec/ach/parse_spec.rb | 24 +++++++++++++++++++++++- 5 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index f2b9f24..bfb66a9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,6 +41,7 @@ GEM PLATFORMS ruby x86_64-darwin-20 + x86_64-linux DEPENDENCIES ach! diff --git a/lib/ach/ach_file.rb b/lib/ach/ach_file.rb index 15afce6..66324b1 100644 --- a/lib/ach/ach_file.rb +++ b/lib/ach/ach_file.rb @@ -114,7 +114,7 @@ def parse data bh.full_company_identification = line[40..49] bh.standard_entry_class_code = line[50..52].strip bh.company_entry_description = line[53..62].strip - bh.company_descriptive_date = Date.parse(line[63..68]) rescue nil # this can be various formats + bh.company_descriptive_date = parse_descriptive_date(line[63..68]) bh.effective_entry_date = Date.parse(line[69..74]) bh.originating_dfi_identification = line[79..86].strip when '6' @@ -156,5 +156,13 @@ def parse data self.batches << batch unless batch.nil? to_s end + + def parse_descriptive_date(date_string) + return if date_string.strip.empty? + + Data.parse(date_string.strip) + rescue + date_string + end end end diff --git a/lib/ach/string_formatting_helper.rb b/lib/ach/string_formatting_helper.rb index b496535..8703096 100644 --- a/lib/ach/string_formatting_helper.rb +++ b/lib/ach/string_formatting_helper.rb @@ -3,7 +3,10 @@ module StringFormattingHelper # Passing in SD to the date signifies same-day to banks. This is used for the company_descriptive_date def self.stringify_with_same_day(f) return f.upcase if f.to_s.upcase.match(/^SD\d+$/) - f.strftime('%y%m%d') + + Date.strptime(f, '%y%m%d') + rescue + f end end -end \ No newline at end of file +end diff --git a/spec/ach/fixtures/return_noc.txt b/spec/ach/fixtures/return_noc.txt index e78ac9c..d258d5a 100644 --- a/spec/ach/fixtures/return_noc.txt +++ b/spec/ach/fixtures/return_noc.txt @@ -1,5 +1,5 @@ 101 191001234 9922222261210151518A094101Certification Bank-SiliCERTIFICATION BANK-SILIRETURNS -5200COMPANY INC DISC DATA 1412345678CORDESCRIPT 1210151210150001992222220000001 +5200COMPANY INC DISC DATA 1412345678CORDESCRIPT SD17001210150001992222220000001 6211211403993300911569 0000000000A38LTNY2 NAME ONE 1121140390280747 798C05992222220280489 1211403932 121140390280747 820000000200121140390000000000000000000000001412345678 992222220000001 @@ -7,7 +7,7 @@ 6261211403993300911569 0000002536GKGQT9VK NAME TWO 1121140390280738 799R07992222220280393 12114039INVALID 121140390280738 820000000200121140390000000025360000000000001412345678 992222220000002 -5200COMPANY INC DISC DATA 1412345678PPDDESCRIPT 1210150001992222220000003 +5200COMPANY INC DISC DATA 1412345678PPDDESCRIPT nodate1210150001992222220000003 6261211403993300911569 0000002417KYU341VP NAME THREE 1121140390280729 799R03992222220280389 12114039 121140390280729 820000000200121140390000000024170000000000001412345678 992222220000003 diff --git a/spec/ach/parse_spec.rb b/spec/ach/parse_spec.rb index 64f1e46..1247632 100644 --- a/spec/ach/parse_spec.rb +++ b/spec/ach/parse_spec.rb @@ -38,7 +38,29 @@ expect(bh.full_company_identification).to eq("1412345678") expect(bh.standard_entry_class_code).to eq('COR') expect(bh.company_entry_description).to eq("DESCRIPT") - expect(bh.company_descriptive_date).to eq(Date.parse('121015')) + expect(bh.company_descriptive_date).to eq('SD1700') + expect(bh.effective_entry_date).to eq(Date.parse('121015')) + expect(bh.originating_dfi_identification).to eq("99222222") + + second_batch = ach.batches[1] + bh = second_batch.header + expect(bh.company_name).to eq("COMPANY INC") + expect(bh.company_identification).to eq("412345678") + expect(bh.full_company_identification).to eq("1412345678") + expect(bh.standard_entry_class_code).to eq('PPD') + expect(bh.company_entry_description).to eq("DESCRIPT") + expect(bh.company_descriptive_date).to eq('121015') + expect(bh.effective_entry_date).to eq(Date.parse('121015')) + expect(bh.originating_dfi_identification).to eq("99222222") + + third_batch = ach.batches[2] + bh = third_batch.header + expect(bh.company_name).to eq("COMPANY INC") + expect(bh.company_identification).to eq("412345678") + expect(bh.full_company_identification).to eq("1412345678") + expect(bh.standard_entry_class_code).to eq('PPD') + expect(bh.company_entry_description).to eq("DESCRIPT") + expect(bh.company_descriptive_date).to eq('nodate') expect(bh.effective_entry_date).to eq(Date.parse('121015')) expect(bh.originating_dfi_identification).to eq("99222222") From 962d16f99dd41a9b7db42907710f21956e1968f1 Mon Sep 17 00:00:00 2001 From: Henrique Gasques Date: Mon, 6 Mar 2023 14:15:48 -0300 Subject: [PATCH 2/3] Parse special same day values used in company_descriptive_date field to DateTime --- README.md | 2 +- lib/ach/ach_file.rb | 14 ++++++++++++-- spec/ach/parse_spec.rb | 5 ++++- 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index caffe78..5ee5d2f 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ bh.company_name = 'Company Name' bh.company_identification = '123456789' # Use 10 characters if you're not using an EIN bh.standard_entry_class_code = 'PPD' bh.company_entry_description = 'DESCRIPTION' -bh.company_descriptive_date = Date.today +bh.company_descriptive_date = Date.today # Or string with 'SDHHMM' for same day ACH bh.effective_entry_date = ACH::NextFederalReserveEffectiveDate.new(Date.today).result bh.originating_dfi_identification = '00000000' ach.batches << batch diff --git a/lib/ach/ach_file.rb b/lib/ach/ach_file.rb index 66324b1..d1335bf 100644 --- a/lib/ach/ach_file.rb +++ b/lib/ach/ach_file.rb @@ -158,9 +158,19 @@ def parse data end def parse_descriptive_date(date_string) - return if date_string.strip.empty? + date_string.strip! - Data.parse(date_string.strip) + return if date_string.empty? + + date_time = date_string.match(/^SD(\d{2})(\d{2})$/) do + same_day_hour, same_day_minute = _1.captures.map(&:to_f) + + Date.today.to_datetime + same_day_hour/24 + same_day_minute/60 + end + + return date_time unless date_time.nil? + + Data.parse(date_string) rescue date_string end diff --git a/spec/ach/parse_spec.rb b/spec/ach/parse_spec.rb index 1247632..e83326c 100644 --- a/spec/ach/parse_spec.rb +++ b/spec/ach/parse_spec.rb @@ -20,6 +20,9 @@ end it "should parse return/notification of change file" do + fake_current_datetime = Date.new(2012, 10, 15) # SD1700 + allow(Date).to receive(:today).and_return(fake_current_datetime) + ach = ACH::ACHFile.new(@data) fh = ach.header expect(fh.immediate_destination).to eq("191001234") @@ -38,7 +41,7 @@ expect(bh.full_company_identification).to eq("1412345678") expect(bh.standard_entry_class_code).to eq('COR') expect(bh.company_entry_description).to eq("DESCRIPT") - expect(bh.company_descriptive_date).to eq('SD1700') + expect(bh.company_descriptive_date).to eq(fake_current_datetime + 17.0/24) expect(bh.effective_entry_date).to eq(Date.parse('121015')) expect(bh.originating_dfi_identification).to eq("99222222") From dadaca6762267f775ba9634f26d00329ca3844b7 Mon Sep 17 00:00:00 2001 From: Henrique Gasques Date: Mon, 6 Mar 2023 16:32:23 -0300 Subject: [PATCH 3/3] Make parse_descriptive_date dynamic parse SDHHMM --- lib/ach/ach_file.rb | 10 +++------- spec/ach/fixtures/return_noc.txt | 2 +- spec/ach/parse_spec.rb | 5 +++-- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/lib/ach/ach_file.rb b/lib/ach/ach_file.rb index d1335bf..b2c5e28 100644 --- a/lib/ach/ach_file.rb +++ b/lib/ach/ach_file.rb @@ -114,7 +114,7 @@ def parse data bh.full_company_identification = line[40..49] bh.standard_entry_class_code = line[50..52].strip bh.company_entry_description = line[53..62].strip - bh.company_descriptive_date = parse_descriptive_date(line[63..68]) + bh.company_descriptive_date = parse_descriptive_date(line[63..68].strip) bh.effective_entry_date = Date.parse(line[69..74]) bh.originating_dfi_identification = line[79..86].strip when '6' @@ -158,19 +158,15 @@ def parse data end def parse_descriptive_date(date_string) - date_string.strip! - return if date_string.empty? date_time = date_string.match(/^SD(\d{2})(\d{2})$/) do same_day_hour, same_day_minute = _1.captures.map(&:to_f) - Date.today.to_datetime + same_day_hour/24 + same_day_minute/60 + Date.today.to_datetime + (same_day_hour + same_day_minute/60) / 24 end - return date_time unless date_time.nil? - - Data.parse(date_string) + date_time || Data.parse(date_string) rescue date_string end diff --git a/spec/ach/fixtures/return_noc.txt b/spec/ach/fixtures/return_noc.txt index d258d5a..7e77125 100644 --- a/spec/ach/fixtures/return_noc.txt +++ b/spec/ach/fixtures/return_noc.txt @@ -1,5 +1,5 @@ 101 191001234 9922222261210151518A094101Certification Bank-SiliCERTIFICATION BANK-SILIRETURNS -5200COMPANY INC DISC DATA 1412345678CORDESCRIPT SD17001210150001992222220000001 +5200COMPANY INC DISC DATA 1412345678CORDESCRIPT SD19321210150001992222220000001 6211211403993300911569 0000000000A38LTNY2 NAME ONE 1121140390280747 798C05992222220280489 1211403932 121140390280747 820000000200121140390000000000000000000000001412345678 992222220000001 diff --git a/spec/ach/parse_spec.rb b/spec/ach/parse_spec.rb index e83326c..afdb266 100644 --- a/spec/ach/parse_spec.rb +++ b/spec/ach/parse_spec.rb @@ -20,7 +20,8 @@ end it "should parse return/notification of change file" do - fake_current_datetime = Date.new(2012, 10, 15) # SD1700 + fake_current_datetime = Date.new(2012, 10, 15) + expected_datetime = DateTime.new(2012, 10, 15, 19, 32) allow(Date).to receive(:today).and_return(fake_current_datetime) ach = ACH::ACHFile.new(@data) @@ -41,7 +42,7 @@ expect(bh.full_company_identification).to eq("1412345678") expect(bh.standard_entry_class_code).to eq('COR') expect(bh.company_entry_description).to eq("DESCRIPT") - expect(bh.company_descriptive_date).to eq(fake_current_datetime + 17.0/24) + expect(bh.company_descriptive_date).to eq(expected_datetime) expect(bh.effective_entry_date).to eq(Date.parse('121015')) expect(bh.originating_dfi_identification).to eq("99222222")