From 015c121f2009d81dee9531b18f3664cfb6d18edb Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Tue, 30 Oct 2018 09:58:17 -0400 Subject: [PATCH 01/11] # 328 Support NOC for IAT Entries # 328 Support NOC for IAT Entries --- iatBatch.go | 15 +++-- iatBatch_test.go | 143 +++++++++++++++++++++++++++++----------------- iatEntryDetail.go | 5 +- 3 files changed, 105 insertions(+), 58 deletions(-) diff --git a/iatBatch.go b/iatBatch.go index cbe2dca51..37ca9be3c 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -435,10 +435,9 @@ func (batch *IATBatch) isCategory() error { category := batch.GetEntries()[0].Category if len(batch.Entries) > 1 { for i := 1; i < len(batch.Entries); i++ { - // ToDo: Need to research requirements for Notice of change fo IAT - /*if batch.Entries[i].Category == CategoryNOC { + if batch.Entries[i].Category == CategoryNOC { continue - }*/ + } if batch.Entries[i].Category != category { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Category", Msg: msgBatchForwardReturn} } @@ -505,11 +504,9 @@ func (batch *IATBatch) Validate() error { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msgBatchIATAddendum} } - // Counter for addendumer for 17, 18,, and 99 - // ToDo: Come up with a better way? - addenda17Count := 0 addenda18Count := 0 + addenda98Count := 0 addenda99Count := 0 for _, IATAddenda := range entry.Addendum { @@ -527,6 +524,12 @@ func (batch *IATBatch) Validate() error { msg := fmt.Sprintf(msgBatchIATAddendumCount, addenda18Count, "18") return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} } + case "98": + addenda98Count = addenda98Count + 1 + if addenda98Count > 1 { + msg := fmt.Sprintf(msgBatchIATAddendumCount, addenda99Count, "98") + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} + } case "99": addenda99Count = addenda99Count + 1 if addenda99Count > 1 { diff --git a/iatBatch_test.go b/iatBatch_test.go index 0a0833129..806dc718a 100644 --- a/iatBatch_test.go +++ b/iatBatch_test.go @@ -5,12 +5,11 @@ package ach import ( - "log" "testing" ) // mockIATBatch -func mockIATBatch() IATBatch { +func mockIATBatch(t testing.TB) IATBatch { mockBatch := IATBatch{} mockBatch.SetHeader(mockIATBatchHeaderFF()) mockBatch.AddEntry(mockIATEntryDetail()) @@ -22,13 +21,13 @@ func mockIATBatch() IATBatch { mockBatch.Entries[0].Addenda15 = mockAddenda15() mockBatch.Entries[0].Addenda16 = mockAddenda16() if err := mockBatch.build(); err != nil { - log.Fatal(err) + t.Fatal(err) } return mockBatch } // mockIATBatchManyEntries -func mockIATBatchManyEntries() IATBatch { +func mockIATBatchManyEntries(t testing.TB) IATBatch { mockBatch := IATBatch{} mockBatch.SetHeader(mockIATBatchHeaderFF()) @@ -67,13 +66,13 @@ func mockIATBatchManyEntries() IATBatch { mockBatch.Entries[1].AddIATAddenda(mockAddenda18E()) if err := mockBatch.build(); err != nil { - log.Fatal(err) + t.Fatal(err) } return mockBatch } // mockIATBatch -func mockInvalidIATBatch() IATBatch { +func mockInvalidIATBatch(t testing.TB) IATBatch { mockBatch := IATBatch{} mockBatch.SetHeader(mockIATBatchHeaderFF()) mockBatch.AddEntry(mockIATEntryDetail()) @@ -86,7 +85,7 @@ func mockInvalidIATBatch() IATBatch { mockBatch.Entries[0].Addenda16 = mockAddenda16() mockBatch.Entries[0].AddIATAddenda(mockInvalidAddenda17()) if err := mockBatch.build(); err != nil { - log.Fatal(err) + t.Fatal(err) } return mockBatch } @@ -111,9 +110,19 @@ func mockIATAddenda99() *Addenda99 { return addenda99 } +func mockIATAddenda98() *Addenda98 { + addenda98 := NewAddenda98() + addenda98.ChangeCode = "C01" + addenda98.OriginalTrace = 231380100000001 + addenda98.OriginalDFI = "12104288" + addenda98.CorrectedData = "89722-C3" + addenda98.TraceNumber = 121042880000001 + return addenda98 +} + // TestMockIATBatch validates mockIATBatch func TestMockIATBatch(t *testing.T) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) if err := iatBatch.verify(); err != nil { t.Error("mockIATBatch does not validate and will break other tests") } @@ -121,7 +130,7 @@ func TestMockIATBatch(t *testing.T) { // testIATBatchAddenda10Error validates IATBatch returns an error if Addenda10 is not included func testIATBatchAddenda10Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda10 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -151,7 +160,7 @@ func BenchmarkIATBatchAddenda10Error(b *testing.B) { // testIATBatchAddenda11Error validates IATBatch returns an error if Addenda11 is not included func testIATBatchAddenda11Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda11 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -181,7 +190,7 @@ func BenchmarkIATBatchAddenda11Error(b *testing.B) { // testIATBatchAddenda12Error validates IATBatch returns an error if Addenda12 is not included func testIATBatchAddenda12Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda12 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -211,7 +220,7 @@ func BenchmarkIATBatchAddenda12Error(b *testing.B) { // testIATBatchAddenda13Error validates IATBatch returns an error if Addenda13 is not included func testIATBatchAddenda13Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda13 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -241,7 +250,7 @@ func BenchmarkIATBatchAddenda13Error(b *testing.B) { // testIATBatchAddenda14Error validates IATBatch returns an error if Addenda14 is not included func testIATBatchAddenda14Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda14 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -271,7 +280,7 @@ func BenchmarkIATBatchAddenda14Error(b *testing.B) { // testIATBatchAddenda15Error validates IATBatch returns an error if Addenda15 is not included func testIATBatchAddenda15Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda15 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -301,7 +310,7 @@ func BenchmarkIATBatchAddenda15Error(b *testing.B) { // testIATBatchAddenda16Error validates IATBatch returns an error if Addenda16 is not included func testIATBatchAddenda16Error(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda16 = nil if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -332,7 +341,7 @@ func BenchmarkIATBatchAddenda16Error(b *testing.B) { // testAddenda10EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda10EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda10.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -363,7 +372,7 @@ func BenchmarkAddenda10EntryDetailSequenceNumber(b *testing.B) { // testAddenda11EntryDetailSequenceNumber validates IATBatch returns an error if EntryDetailSequenceNumber // is not valid func testAddenda11EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda11.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -394,7 +403,7 @@ func BenchmarkAddenda11EntryDetailSequenceNumber(b *testing.B) { // testAddenda12EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda12EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda12.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -425,7 +434,7 @@ func BenchmarkAddenda12EntryDetailSequenceNumber(b *testing.B) { // testAddenda13EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda13EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda13.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -456,7 +465,7 @@ func BenchmarkAddenda13EntryDetailSequenceNumber(b *testing.B) { // testAddenda14EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda14EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda14.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -487,7 +496,7 @@ func BenchmarkAddenda14EntryDetailSequenceNumber(b *testing.B) { // testAddenda15EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda15EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda15.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -518,7 +527,7 @@ func BenchmarkAddenda15EntryDetailSequenceNumber(b *testing.B) { // testAddenda16EntryDetailSequenceNumber validates IATBatch returns an error if // EntryDetailSequenceNumber is not valid func testAddenda16EntryDetailSequenceNumber(t testing.TB) { - iatBatch := mockIATBatch() + iatBatch := mockIATBatch(t) iatBatch.GetEntries()[0].Addenda16.EntryDetailSequenceNumber = 00000005 if err := iatBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -548,7 +557,7 @@ func BenchmarkAddenda16EntryDetailSequenceNumber(b *testing.B) { // testIATBatchNumberMismatch validates BatchNumber mismatch func testIATBatchNumberMismatch(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetControl().BatchNumber = 2 if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -576,7 +585,7 @@ func BenchmarkIATBatchNumberMismatch(b *testing.B) { // testIATServiceClassCodeMismatch validates ServiceClassCode mismatch func testIATServiceClassCodeMismatch(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetControl().ServiceClassCode = 225 if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -604,7 +613,7 @@ func BenchmarkIATServiceClassCodeMismatch(b *testing.B) { // testIATBatchCreditIsBatchAmount validates credit isBatchAmount func testIATBatchCreditIsBatchAmount(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) e1 := mockBatch.GetEntries()[0] e2 := mockIATEntryDetail() e2.TransactionCode = 22 @@ -650,7 +659,7 @@ func BenchmarkIATBatchCreditIsBatchAmount(b *testing.B) { // testIATBatchDebitIsBatchAmount validates debit isBatchAmount func testIATBatchDebitIsBatchAmount(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) e1 := mockBatch.GetEntries()[0] e1.TransactionCode = 27 e2 := mockIATEntryDetail() @@ -697,8 +706,8 @@ func BenchmarkIATBatchDebitIsBatchAmount(b *testing.B) { // testIATBatchFieldInclusion validates IATBatch FieldInclusion func testIATBatchFieldInclusion(t testing.TB) { - mockBatch := mockIATBatch() - mockBatch2 := mockIATBatch() + mockBatch := mockIATBatch(t) + mockBatch2 := mockIATBatch(t) mockBatch2.Header.recordType = "4" if err := mockBatch.verify(); err != nil { @@ -776,7 +785,7 @@ func BenchmarkIATBatchBuild(b *testing.B) { // testIATODFIIdentificationMismatch validates ODFIIdentification mismatch func testIATODFIIdentificationMismatch(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetControl().ODFIIdentification = "53158020" if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -804,7 +813,7 @@ func BenchmarkIATODFIIdentificationMismatch(b *testing.B) { // testIATBatchAddendaRecordIndicator validates IATEntryDetail AddendaRecordIndicator func testIATBatchAddendaRecordIndicator(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetEntries()[0].AddendaRecordIndicator = 2 if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -832,7 +841,7 @@ func BenchmarkIATBatchAddendaRecordIndicator(b *testing.B) { // testIATBatchInvalidTraceNumberODFI validates TraceNumberODFI func testIATBatchInvalidTraceNumberODFI(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetEntries()[0].SetTraceNumber("9928272", 1) if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -860,7 +869,7 @@ func BenchmarkIATBatchInvalidTraceNumberODFI(b *testing.B) { // testIATBatchControl validates BatchControl ODFIIdentification func testIATBatchControl(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.Control.ODFIIdentification = "" if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -888,7 +897,7 @@ func BenchmarkIATBatchControl(b *testing.B) { // testIATBatchEntryCountEquality validates IATBatch EntryAddendaCount func testIATBatchEntryCountEquality(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) if err := mockBatch.build(); err != nil { t.Errorf("%T: %s", err, err) } @@ -920,7 +929,7 @@ func BenchmarkIATBatchEntryCountEquality(b *testing.B) { // testIATBatchisEntryHash validates IATBatch EntryHash func testIATBatchisEntryHash(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetControl().EntryHash = 1 if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -948,7 +957,7 @@ func BenchmarkIATBatchisEntryHash(b *testing.B) { // testIATBatchIsSequenceAscending validates sequence ascending func testIATBatchIsSequenceAscending(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) e2 := mockIATEntryDetail() e2.TraceNumber = 1 mockBatch.AddEntry(e2) @@ -986,7 +995,7 @@ func BenchmarkIATBatchIsSequenceAscending(b *testing.B) { // testIATBatchIsCategory validates category func testIATBatchIsCategory(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Category = CategoryReturn if err := mockBatch.verify(); err != nil { @@ -1015,7 +1024,7 @@ func BenchmarkIATBatchIsCategory(b *testing.B) { //testIATBatchCategory tests IATBatch Category func testIATBatchCategory(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) if err := mockBatch.build(); err != nil { t.Errorf("%T: %s", err, err) @@ -1041,7 +1050,7 @@ func BenchmarkIATBatchCategory(b *testing.B) { // testIATBatchValidateEntry validates EntryDetail func testIATBatchValidateEntry(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetEntries()[0].recordType = "5" if err := mockBatch.verify(); err != nil { @@ -1070,7 +1079,7 @@ func BenchmarkIATBatchValidateEntry(b *testing.B) { // testIATBatchValidateAddenda10 validates Addenda10 func testIATBatchValidateAddenda10(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda10.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1099,7 +1108,7 @@ func BenchmarkIATBatchValidateAddenda10(b *testing.B) { // testIATBatchValidateAddenda11 validates Addenda11 func testIATBatchValidateAddenda11(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda11.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1128,7 +1137,7 @@ func BenchmarkIATBatchValidateAddenda11(b *testing.B) { // testIATBatchValidateAddenda12 validates Addenda12 func testIATBatchValidateAddenda12(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda12.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1157,7 +1166,7 @@ func BenchmarkIATBatchValidateAddenda12(b *testing.B) { // testIATBatchValidateAddenda13 validates Addenda13 func testIATBatchValidateAddenda13(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda13.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1186,7 +1195,7 @@ func BenchmarkIATBatchValidateAddenda13(b *testing.B) { // testIATBatchValidateAddenda14 validates Addenda14 func testIATBatchValidateAddenda14(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda14.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1215,7 +1224,7 @@ func BenchmarkIATBatchValidateAddenda14(b *testing.B) { // testIATBatchValidateAddenda15 validates Addenda15 func testIATBatchValidateAddenda15(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda15.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1244,7 +1253,7 @@ func BenchmarkIATBatchValidateAddenda15(b *testing.B) { // testIATBatchValidateAddenda16 validates Addenda16 func testIATBatchValidateAddenda16(t testing.TB) { - mockBatch := mockIATBatchManyEntries() + mockBatch := mockIATBatchManyEntries(t) mockBatch.GetEntries()[1].Addenda16.TypeCode = "02" if err := mockBatch.verify(); err != nil { @@ -1273,7 +1282,7 @@ func BenchmarkIATBatchValidateAddenda16(b *testing.B) { // testIATBatchValidateAddenda17 validates Addenda17 func testIATBatchValidateAddenda17(t testing.TB) { - mockBatch := mockInvalidIATBatch() + mockBatch := mockInvalidIATBatch(t) if err := mockBatch.verify(); err != nil { if e, ok := err.(*BatchError); ok { @@ -1302,7 +1311,7 @@ func BenchmarkIATBatchValidateAddenda17(b *testing.B) { // testIATBatchCreateError validates IATBatch create error func testIATBatchCreate(t testing.TB) { file := NewFile().SetHeader(mockFileHeader()) - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetHeader().recordType = "7" if err := mockBatch.Create(); err != nil { @@ -1335,7 +1344,7 @@ func BenchmarkIATBatchCreate(b *testing.B) { // testIATBatchValidate validates IATBatch validate error func testIATBatchValidate(t testing.TB) { file := NewFile().SetHeader(mockFileHeader()) - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetHeader().ServiceClassCode = 225 if err := mockBatch.Validate(); err != nil { @@ -1368,7 +1377,7 @@ func BenchmarkIATBatchValidate(b *testing.B) { // testIATBatchEntryAddendum validates IATBatch EntryAddendum error func testIATBatchEntryAddendum(t testing.TB) { file := NewFile().SetHeader(mockFileHeader()) - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.Entries[0].AddIATAddenda(mockAddenda17()) mockBatch.Entries[0].AddIATAddenda(mockAddenda17B()) mockBatch.Entries[0].AddIATAddenda(mockAddenda18()) @@ -1684,7 +1693,7 @@ func BenchmarkIATNoEntry(b *testing.B) { // testIATBatchAddendumTypeCode validates IATBatch Addendum TypeCode func testIATBatchAddendumTypeCode(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetEntries()[0].AddIATAddenda(mockAddenda12()) if err := mockBatch.build(); err != nil { @@ -1864,7 +1873,7 @@ func BenchmarkIATBatchBuildAddendaError(b *testing.B) { // testIATBatchBHODFI validates IATBatchHeader ODFI error func testIATBatchBHODFI(t testing.TB) { - mockBatch := mockIATBatch() + mockBatch := mockIATBatch(t) mockBatch.GetEntries()[0].SetTraceNumber("39387337", 1) if err := mockBatch.build(); err != nil { @@ -1905,6 +1914,7 @@ func testIATBatchAddenda99Count(t testing.TB) { mockBatch.Entries[0].Addenda15 = mockAddenda15() mockBatch.Entries[0].Addenda16 = mockAddenda16() mockBatch.Entries[0].AddIATAddenda(mockIATAddenda99()) + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda99()) mockBatch.category = CategoryReturn if err := mockBatch.build(); err != nil { @@ -1935,3 +1945,34 @@ func BenchmarkIATBatchAddenda99Count(b *testing.B) { testIATBatchAddenda99Count(b) } } + +// TestIATBatchAddenda98Count validates IATBatch Addenda98 Count +func TestIATBatchAddenda98Count(t *testing.T) { + mockBatch := IATBatch{} + mockBatch.SetHeader(mockIATReturnBatchHeaderFF()) + mockBatch.AddEntry(mockIATEntryDetail()) + mockBatch.Entries[0].Addenda10 = mockAddenda10() + mockBatch.Entries[0].Addenda11 = mockAddenda11() + mockBatch.Entries[0].Addenda12 = mockAddenda12() + mockBatch.Entries[0].Addenda13 = mockAddenda13() + mockBatch.Entries[0].Addenda14 = mockAddenda14() + mockBatch.Entries[0].Addenda15 = mockAddenda15() + mockBatch.Entries[0].Addenda16 = mockAddenda16() + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) + mockBatch.category = CategoryReturn + + if err := mockBatch.build(); err != nil { + t.Errorf("%T: %s", err, err) + } + + if err := mockBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "Addendum" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } +} diff --git a/iatEntryDetail.go b/iatEntryDetail.go index 1854cd7fb..40cefb869 100644 --- a/iatEntryDetail.go +++ b/iatEntryDetail.go @@ -322,8 +322,11 @@ func (ed *IATEntryDetail) TraceNumberField() string { // Currently this is used to add Addenda17 and Addenda18 IAT Addenda records func (ed *IATEntryDetail) AddIATAddenda(addenda Addendumer) []Addendumer { ed.AddendaRecordIndicator = 1 - // checks to make sure that we only have either or, not both switch addenda.(type) { + case *Addenda98: + ed.Category = CategoryNOC + ed.Addendum = append(ed.Addendum, addenda) + return ed.Addendum case *Addenda99: ed.Category = CategoryReturn ed.Addendum = append(ed.Addendum, addenda) From 9490edd796df90585e5c57efd98463bd633e80b2 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Tue, 30 Oct 2018 10:54:40 -0400 Subject: [PATCH 02/11] IAT code test coverage IAT code test coverage --- iatBatchHeader.go | 19 -------------- iatBatch_test.go | 65 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 19 deletions(-) diff --git a/iatBatchHeader.go b/iatBatchHeader.go index c52880207..9b43df654 100644 --- a/iatBatchHeader.go +++ b/iatBatchHeader.go @@ -278,14 +278,6 @@ func (iatBh *IATBatchHeader) Validate() error { return &FieldError{FieldName: "ISODestinationCountryCode", Value: iatBh.ISODestinationCountryCode, Msg: "invalid ISO 3166-1-alpha-2 code"} } - if err := iatBh.isAlphanumeric(iatBh.ISODestinationCountryCode); err != nil { - return &FieldError{FieldName: "ISODestinationCountryCode", - Value: iatBh.ISODestinationCountryCode, Msg: err.Error()} - } - if err := iatBh.isAlphanumeric(iatBh.OriginatorIdentification); err != nil { - return &FieldError{FieldName: "OriginatorIdentification", - Value: iatBh.OriginatorIdentification, Msg: err.Error()} - } if err := iatBh.isSECCode(iatBh.StandardEntryClassCode); err != nil { return &FieldError{FieldName: "StandardEntryClassCode", Value: iatBh.StandardEntryClassCode, Msg: err.Error()} @@ -294,25 +286,14 @@ func (iatBh *IATBatchHeader) Validate() error { return &FieldError{FieldName: "CompanyEntryDescription", Value: iatBh.CompanyEntryDescription, Msg: err.Error()} } - if !iso4217.Valid(iatBh.ISOOriginatingCurrencyCode) { return &FieldError{FieldName: "ISOOriginatingCurrencyCode", Value: iatBh.ISOOriginatingCurrencyCode, Msg: "invalid ISO 4217 code"} } - if err := iatBh.isAlphanumeric(iatBh.ISOOriginatingCurrencyCode); err != nil { - return &FieldError{FieldName: "ISOOriginatingCurrencyCode", - Value: iatBh.ISOOriginatingCurrencyCode, Msg: err.Error()} - } - if !iso4217.Valid(iatBh.ISODestinationCurrencyCode) { return &FieldError{FieldName: "ISODestinationCurrencyCode", Value: iatBh.ISODestinationCurrencyCode, Msg: "invalid ISO 4217 code"} } - if err := iatBh.isAlphanumeric(iatBh.ISODestinationCurrencyCode); err != nil { - return &FieldError{FieldName: "ISODestinationCurrencyCode", - Value: iatBh.ISODestinationCurrencyCode, Msg: err.Error()} - } - if err := iatBh.isOriginatorStatusCode(iatBh.OriginatorStatusCode); err != nil { return &FieldError{FieldName: "OriginatorStatusCode", Value: strconv.Itoa(iatBh.OriginatorStatusCode), Msg: err.Error()} diff --git a/iatBatch_test.go b/iatBatch_test.go index 806dc718a..efea97794 100644 --- a/iatBatch_test.go +++ b/iatBatch_test.go @@ -5,6 +5,7 @@ package ach import ( + "strings" "testing" ) @@ -1976,3 +1977,67 @@ func TestIATBatchAddenda98Count(t *testing.T) { } } } + +// TestMockISODestinationCountryCode validates mockIATBatch +func TestMockISODestinationCountryCode(t *testing.T) { + iatBatch := mockIATBatch(t) + iatBatch.Header.ISODestinationCountryCode = "®©" + if err := iatBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "ISODestinationCountryCode" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } + +} + +// TestMockISOOriginatingCurrencyCode validates mockIATBatch +func TestMockISOOriginatingCurrencyCode(t *testing.T) { + iatBatch := mockIATBatch(t) + iatBatch.Header.ISOOriginatingCurrencyCode = "®©" + if err := iatBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "ISOOriginatingCurrencyCode" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } + +} + +// TestMockISODestinationCurrencyCode validates mockIATBatch +func TestMockISODestinationCurrencyCode(t *testing.T) { + iatBatch := mockIATBatch(t) + iatBatch.Header.ISODestinationCurrencyCode = "®©" + if err := iatBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "ISODestinationCurrencyCode" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } + +} + +// TestParseRuneCountIATBatchHeader tests parsing an invalid RuneCount in IATBatchHeader +func TestParseRuneCountIATBatchHeader(t *testing.T) { + line := "5220 FF3 US123456789 IATTRADEPAYMTCADUSD010101" + r := NewReader(strings.NewReader(line)) + r.line = line + if err := r.parseIATBatchHeader(); err != nil { + if e, ok := err.(*ParseError); ok { + if e.Record != "BatchHeader" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } +} From 83ead4782872f029461e1951222598c4b9d26f57 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Tue, 30 Oct 2018 17:51:17 -0400 Subject: [PATCH 03/11] Support NOC for IAT Entries Support NOC for IAT Entries --- iatBatch.go | 217 ++++++++++++++++++++++------------------- iatBatchHeader.go | 5 +- iatBatchHeader_test.go | 21 +++- iatBatch_test.go | 100 ++++++++++++++++--- iatEntryDetail.go | 4 +- 5 files changed, 227 insertions(+), 120 deletions(-) diff --git a/iatBatch.go b/iatBatch.go index 37ca9be3c..c94ba474a 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -16,6 +16,8 @@ var ( msgBatchIATAddendum = "7 Addendum is the maximum for SEC code IAT" msgBatchIATAddendumCount = "%v Addenda %v for SEC Code IAT" msgBatchIATInvalidAddendumer = "invalid Addendumer for SEC Code IAT" + msgBatchIATNOC = "%v invalid for IAT NOC, should be %v" + msgBatchIATInvalidAddenda = "%v is only valid for %v entry" ) // IATBatch holds the Batch Header and Batch Control and all Entry Records for an IAT batch @@ -139,15 +141,16 @@ func (batch *IATBatch) build() error { batch.Entries[i].SetTraceNumber(batch.Header.ODFIIdentification, seq) } - // Set TraceNumber for IATEntryDetail Addenda10-16 Record Properties - entry.Addenda10.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda11.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda12.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda13.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda14.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda15.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - entry.Addenda16.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) - + if entry.Category != CategoryNOC { + // Set TraceNumber for IATEntryDetail Addenda10-16 Record Properties + entry.Addenda10.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda11.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda12.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda13.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda14.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda15.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + entry.Addenda16.EntryDetailSequenceNumber = batch.parseNumField(batch.Entries[i].TraceNumberField()[8:]) + } // Set TraceNumber for Addendumer Addenda17 and Addenda18 SequenceNumber and EntryDetailSequenceNumber seq++ addenda17Seq := 1 @@ -229,27 +232,30 @@ func (batch *IATBatch) isFieldInclusion() error { if err := batch.addendaFieldInclusion(entry); err != nil { return err } - // Verifies each Addenda* record is valid - if err := entry.Addenda10.Validate(); err != nil { - return err - } - if err := entry.Addenda11.Validate(); err != nil { - return err - } - if err := entry.Addenda12.Validate(); err != nil { - return err - } - if err := entry.Addenda13.Validate(); err != nil { - return err - } - if err := entry.Addenda14.Validate(); err != nil { - return err - } - if err := entry.Addenda15.Validate(); err != nil { - return err - } - if err := entry.Addenda16.Validate(); err != nil { - return err + + if entry.Category != CategoryNOC { + // Verifies each Addenda* record is valid + if err := entry.Addenda10.Validate(); err != nil { + return err + } + if err := entry.Addenda11.Validate(); err != nil { + return err + } + if err := entry.Addenda12.Validate(); err != nil { + return err + } + if err := entry.Addenda13.Validate(); err != nil { + return err + } + if err := entry.Addenda14.Validate(); err != nil { + return err + } + if err := entry.Addenda15.Validate(); err != nil { + return err + } + if err := entry.Addenda16.Validate(); err != nil { + return err + } } // Verifies addendumer Addenda17 and Addenda18 records are valid for _, IATAddenda := range entry.Addendum { @@ -365,33 +371,35 @@ func (batch *IATBatch) isAddendaSequence() error { // Verify Addenda* entry detail sequence numbers are valid entryTN := entry.TraceNumberField()[8:] - if entry.Addenda10.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda10.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda11.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda11.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda12.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda12.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda13.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda13.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda14.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda14.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda15.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda15.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda16.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda16.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + if entry.Category != CategoryNOC { + if entry.Addenda10.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda10.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda11.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda11.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda12.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda12.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda13.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda13.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda14.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda14.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda15.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda15.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda16.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda16.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } } // check if sequence is ascending for addendumer - Addenda17 and Addenda18 @@ -447,33 +455,36 @@ func (batch *IATBatch) isCategory() error { } func (batch *IATBatch) addendaFieldInclusion(entry *IATEntryDetail) error { - if entry.Addenda10 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda10", Msg: msg} - } - if entry.Addenda11 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda11", Msg: msg} - } - if entry.Addenda12 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda12", Msg: msg} - } - if entry.Addenda13 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda13", Msg: msg} - } - if entry.Addenda14 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda14", Msg: msg} - } - if entry.Addenda15 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda15", Msg: msg} - } - if entry.Addenda16 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda16", Msg: msg} + + if entry.Category != CategoryNOC { + if entry.Addenda10 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda10", Msg: msg} + } + if entry.Addenda11 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda11", Msg: msg} + } + if entry.Addenda12 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda12", Msg: msg} + } + if entry.Addenda13 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda13", Msg: msg} + } + if entry.Addenda14 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda14", Msg: msg} + } + if entry.Addenda15 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda15", Msg: msg} + } + if entry.Addenda16 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda16", Msg: msg} + } } return nil } @@ -499,15 +510,17 @@ func (batch *IATBatch) Validate() error { for _, entry := range batch.Entries { - // Addendum cannot be greater than 7, There can be a maximum of 2 Addenda17 and a maximum of 5 Addenda18 - if len(entry.Addendum) > 7 { - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msgBatchIATAddendum} + switch entry.Category { + + case CategoryForward: + if len(entry.Addendum) > 7 { + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msgBatchIATAddendum} + } + default: } addenda17Count := 0 addenda18Count := 0 - addenda98Count := 0 - addenda99Count := 0 for _, IATAddenda := range entry.Addendum { @@ -525,23 +538,27 @@ func (batch *IATBatch) Validate() error { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} } case "98": - addenda98Count = addenda98Count + 1 - if addenda98Count > 1 { - msg := fmt.Sprintf(msgBatchIATAddendumCount, addenda99Count, "98") - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} + if batch.GetHeader().IATIndicator != "IATCOR" { + msg := fmt.Sprintf(msgBatchIATNOC, batch.GetHeader().IATIndicator, "IATCOR") + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "IATIndicator", Msg: msg} } - case "99": - addenda99Count = addenda99Count + 1 - if addenda99Count > 1 { - msg := fmt.Sprintf(msgBatchIATAddendumCount, addenda99Count, "99") - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} + if batch.GetHeader().StandardEntryClassCode != "COR" { + msg := fmt.Sprintf(msgBatchIATNOC, batch.GetHeader().StandardEntryClassCode, "COR") + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "StandardEntryClassCode", Msg: msg} + } + switch entry.TransactionCode { + case 22, 27, 32, 37, 42, 47, 52, 55, + 23, 28, 33, 38, 43, 48, 53, + 24, 29, 34, 39, 44, 49, 54: + msg := fmt.Sprintf(msgBatchTransactionCode, entry.TransactionCode, "IATCOR") + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TransactionCode", Msg: msg} } + case "99": + // Only one Addenda99 can be added in EntryDetail.AddIATAddenda default: return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msgBatchIATInvalidAddendumer} } } } - // Add type specific validation. - // ... return nil } diff --git a/iatBatchHeader.go b/iatBatchHeader.go index 9b43df654..7d19f4a59 100644 --- a/iatBatchHeader.go +++ b/iatBatchHeader.go @@ -73,7 +73,6 @@ type IATBatchHeader struct { // ForeignExchangeReference Contains either the foreign exchange rate used to execute // the foreign exchange conversion of a cross-border entry or another reference to the foreign // exchange transaction. - // ToDo: potentially write a validator ForeignExchangeReference string `json:"foreignExchangeReference"` // ISODestinationCountryCode is the two-character code, as approved by the International @@ -180,8 +179,8 @@ func (iatBh *IATBatchHeader) Parse(record string) { iatBh.recordType = "5" // 2-4 If the entries are credits, always "220". If the entries are debits, always "225" iatBh.ServiceClassCode = iatBh.parseNumField(record[1:4]) - // 05-20 Leave Blank - It is only used for corrected IAT entries - iatBh.IATIndicator = " " + // 05-20 Blank except for corrected IAT entries + iatBh.IATIndicator = iatBh.parseStringField(record[4:20]) // 21-22 A code indicating currency conversion // “FV” Fixed-to-Variable // “VF” Variable-to-Fixed diff --git a/iatBatchHeader_test.go b/iatBatchHeader_test.go index a3db41cd7..cad76eb48 100644 --- a/iatBatchHeader_test.go +++ b/iatBatchHeader_test.go @@ -41,6 +41,23 @@ func mockIATReturnBatchHeaderFF() *IATBatchHeader { return bh } +// mockIATNOCBatchHeaderFF creates a IAT Return BatchHeader that is Fixed-Fixed +func mockIATNOCBatchHeaderFF() *IATBatchHeader { + bh := NewIATBatchHeader() + bh.ServiceClassCode = 220 + bh.IATIndicator = "IATCOR" + bh.ForeignExchangeIndicator = "FF" + bh.ForeignExchangeReferenceIndicator = 3 + bh.ISODestinationCountryCode = "US" + bh.OriginatorIdentification = "123456789" + bh.StandardEntryClassCode = "COR" + bh.CompanyEntryDescription = "TRADEPAYMT" + bh.ISOOriginatingCurrencyCode = "CAD" + bh.ISODestinationCurrencyCode = "USD" + bh.ODFIIdentification = "12104288" + return bh +} + // testMockIATBatchHeaderFF creates a IAT BatchHeader Fixed-Fixed func testMockIATBatchHeaderFF(t testing.TB) { bh := mockIATBatchHeaderFF() @@ -108,8 +125,8 @@ func testParseIATBatchHeader(t testing.TB) { if record.ServiceClassCode != 220 { t.Errorf("ServiceClassCode Expected '225' got: %v", record.ServiceClassCode) } - if record.IATIndicator != " " { - t.Errorf("IATIndicator Expected ' ' got: %v", record.IATIndicator) + if record.IATIndicator != "" { + t.Errorf("IATIndicator Expected '' got: %v", record.IATIndicator) } if record.ForeignExchangeIndicator != "FF" { t.Errorf("ForeignExchangeIndicator Expected ' ' got: %v", diff --git a/iatBatch_test.go b/iatBatch_test.go index efea97794..cbe1f1db3 100644 --- a/iatBatch_test.go +++ b/iatBatch_test.go @@ -97,7 +97,6 @@ func mockInvalidAddenda17() *Addenda17 { addenda17.TypeCode = "02" addenda17.SequenceNumber = 2 addenda17.EntryDetailSequenceNumber = 0000002 - return addenda17 } @@ -1907,6 +1906,7 @@ func testIATBatchAddenda99Count(t testing.TB) { mockBatch := IATBatch{} mockBatch.SetHeader(mockIATReturnBatchHeaderFF()) mockBatch.AddEntry(mockIATEntryDetail()) + mockBatch.GetEntries()[0].Category = CategoryReturn mockBatch.Entries[0].Addenda10 = mockAddenda10() mockBatch.Entries[0].Addenda11 = mockAddenda11() mockBatch.Entries[0].Addenda12 = mockAddenda12() @@ -1914,8 +1914,9 @@ func testIATBatchAddenda99Count(t testing.TB) { mockBatch.Entries[0].Addenda14 = mockAddenda14() mockBatch.Entries[0].Addenda15 = mockAddenda15() mockBatch.Entries[0].Addenda16 = mockAddenda16() + mockBatch.Entries[0].AddIATAddenda(mockAddenda17()) mockBatch.Entries[0].AddIATAddenda(mockIATAddenda99()) - mockBatch.Entries[0].AddIATAddenda(mockIATAddenda99()) + //mockBatch.Entries[0].AddIATAddenda(mockIATAddenda99()) mockBatch.category = CategoryReturn if err := mockBatch.build(); err != nil { @@ -1947,21 +1948,16 @@ func BenchmarkIATBatchAddenda99Count(b *testing.B) { } } -// TestIATBatchAddenda98Count validates IATBatch Addenda98 Count -func TestIATBatchAddenda98Count(t *testing.T) { +// TestIATBatchAddenda98TotalCount validates IATBatch Addenda98 TotalCount +func TestIATBatchAddenda98TotalCount(t *testing.T) { mockBatch := IATBatch{} - mockBatch.SetHeader(mockIATReturnBatchHeaderFF()) + mockBatch.SetHeader(mockIATNOCBatchHeaderFF()) mockBatch.AddEntry(mockIATEntryDetail()) - mockBatch.Entries[0].Addenda10 = mockAddenda10() - mockBatch.Entries[0].Addenda11 = mockAddenda11() - mockBatch.Entries[0].Addenda12 = mockAddenda12() - mockBatch.Entries[0].Addenda13 = mockAddenda13() - mockBatch.Entries[0].Addenda14 = mockAddenda14() - mockBatch.Entries[0].Addenda15 = mockAddenda15() - mockBatch.Entries[0].Addenda16 = mockAddenda16() + mockBatch.GetEntries()[0].TransactionCode = 21 + mockBatch.GetEntries()[0].AddendaRecords = 2 + mockBatch.GetEntries()[0].Category = CategoryNOC mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) - mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) - mockBatch.category = CategoryReturn + mockBatch.category = CategoryNOC if err := mockBatch.build(); err != nil { t.Errorf("%T: %s", err, err) @@ -1978,6 +1974,82 @@ func TestIATBatchAddenda98Count(t *testing.T) { } } +// TestIATBatchAddenda98TransactionCode validates IATBatch Transaction Code Count +func TestIATBatchAddenda98TransactionCode(t *testing.T) { + mockBatch := IATBatch{} + mockBatch.SetHeader(mockIATNOCBatchHeaderFF()) + mockBatch.AddEntry(mockIATEntryDetail()) + mockBatch.GetEntries()[0].TransactionCode = 22 + mockBatch.GetEntries()[0].Category = CategoryNOC + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) + mockBatch.category = CategoryNOC + + if err := mockBatch.build(); err != nil { + t.Errorf("%T: %s", err, err) + } + + if err := mockBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "TransactionCode" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } +} + +// TestIATBatchAddenda98IATIndicator validates IATBatch Transaction Code Count +func TestIATBatchAddenda98IATIndicator(t *testing.T) { + mockBatch := IATBatch{} + mockBatch.SetHeader(mockIATNOCBatchHeaderFF()) + mockBatch.GetHeader().IATIndicator = "B" + mockBatch.AddEntry(mockIATEntryDetail()) + mockBatch.GetEntries()[0].TransactionCode = 22 + mockBatch.GetEntries()[0].Category = CategoryNOC + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) + mockBatch.category = CategoryNOC + + if err := mockBatch.build(); err != nil { + t.Errorf("%T: %s", err, err) + } + + if err := mockBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "IATIndicator" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } +} + +func TestIATBatchAddenda98SECCode(t *testing.T) { + mockBatch := IATBatch{} + mockBatch.SetHeader(mockIATNOCBatchHeaderFF()) + mockBatch.GetHeader().StandardEntryClassCode = "IAT" + mockBatch.AddEntry(mockIATEntryDetail()) + mockBatch.GetEntries()[0].TransactionCode = 22 + mockBatch.GetEntries()[0].Category = CategoryNOC + mockBatch.Entries[0].AddIATAddenda(mockIATAddenda98()) + mockBatch.category = CategoryNOC + + if err := mockBatch.build(); err != nil { + t.Errorf("%T: %s", err, err) + } + + if err := mockBatch.Validate(); err != nil { + if e, ok := err.(*BatchError); ok { + if e.FieldName != "StandardEntryClassCode" { + t.Errorf("%T: %s", err, err) + } + } else { + t.Errorf("%T: %s", err, err) + } + } +} + // TestMockISODestinationCountryCode validates mockIATBatch func TestMockISODestinationCountryCode(t *testing.T) { iatBatch := mockIATBatch(t) diff --git a/iatEntryDetail.go b/iatEntryDetail.go index 40cefb869..22af10fa4 100644 --- a/iatEntryDetail.go +++ b/iatEntryDetail.go @@ -319,16 +319,18 @@ func (ed *IATEntryDetail) TraceNumberField() string { } // AddIATAddenda appends an Addendumer to the IATEntryDetail -// Currently this is used to add Addenda17 and Addenda18 IAT Addenda records +// Currently this is used to add Addenda17, Addenda18, Addenda98 and Addenda99 IAT Addenda records func (ed *IATEntryDetail) AddIATAddenda(addenda Addendumer) []Addendumer { ed.AddendaRecordIndicator = 1 switch addenda.(type) { case *Addenda98: ed.Category = CategoryNOC + ed.Addendum = nil ed.Addendum = append(ed.Addendum, addenda) return ed.Addendum case *Addenda99: ed.Category = CategoryReturn + ed.Addendum = nil ed.Addendum = append(ed.Addendum, addenda) return ed.Addendum default: From d19c6e9c4e50e7a741c4b29d8a41ed4c129ba0c2 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Tue, 30 Oct 2018 17:57:03 -0400 Subject: [PATCH 04/11] iatBatch update iatBatch update --- iatBatch.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iatBatch.go b/iatBatch.go index c94ba474a..a0d07bbcd 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -511,7 +511,6 @@ func (batch *IATBatch) Validate() error { for _, entry := range batch.Entries { switch entry.Category { - case CategoryForward: if len(entry.Addendum) > 7 { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msgBatchIATAddendum} @@ -538,6 +537,7 @@ func (batch *IATBatch) Validate() error { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addendum", Msg: msg} } case "98": + // Only one Addenda98 can be added in EntryDetail.AddIATAddenda if batch.GetHeader().IATIndicator != "IATCOR" { msg := fmt.Sprintf(msgBatchIATNOC, batch.GetHeader().IATIndicator, "IATCOR") return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "IATIndicator", Msg: msg} From b4c2a7242b9d8473b7c4636b9e022b2a3ab4d7d2 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Tue, 30 Oct 2018 18:10:03 -0400 Subject: [PATCH 05/11] Support_NOC-for_IAT-Entries Support_NOC-for-IAT-Entries --- iatBatch.go | 1 - 1 file changed, 1 deletion(-) diff --git a/iatBatch.go b/iatBatch.go index a0d07bbcd..b37851102 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -17,7 +17,6 @@ var ( msgBatchIATAddendumCount = "%v Addenda %v for SEC Code IAT" msgBatchIATInvalidAddendumer = "invalid Addendumer for SEC Code IAT" msgBatchIATNOC = "%v invalid for IAT NOC, should be %v" - msgBatchIATInvalidAddenda = "%v is only valid for %v entry" ) // IATBatch holds the Batch Header and Batch Control and all Entry Records for an IAT batch From 0aead2d65b7d06bd4b6f8a73e5d7e3d2625d6df6 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 11:41:02 -0400 Subject: [PATCH 06/11] Increase IAT Addenda Record Code Test Coverage Increase IAT Addenda Record Code Test Coverage --- addenda10_test.go | 2 +- addenda11_test.go | 2 +- addenda12_test.go | 2 +- addenda13_test.go | 2 +- addenda14_test.go | 2 +- addenda15_test.go | 2 +- addenda16_test.go | 2 +- addenda17_test.go | 16 ++++++++++++++-- addenda18_test.go | 2 +- 9 files changed, 22 insertions(+), 10 deletions(-) diff --git a/addenda10_test.go b/addenda10_test.go index 5a859b47c..690550508 100644 --- a/addenda10_test.go +++ b/addenda10_test.go @@ -37,7 +37,7 @@ func testAddenda10Parse(t testing.TB) { if addenda10.recordType != "7" { t.Errorf("expected %v got %v", "7", addenda10.recordType) } - if addenda10.TypeCode != "10" { + if addenda10.typeCode() != "10" { t.Errorf("expected %v got %v", "10", addenda10.TypeCode) } if addenda10.TransactionTypeCode != "ANN" { diff --git a/addenda11_test.go b/addenda11_test.go index 1c1b1d6d4..df75bef0f 100644 --- a/addenda11_test.go +++ b/addenda11_test.go @@ -35,7 +35,7 @@ func testAddenda11Parse(t testing.TB) { if Addenda11.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda11.recordType) } - if Addenda11.TypeCode != "11" { + if Addenda11.typeCode() != "11" { t.Errorf("expected %v got %v", "11", Addenda11.TypeCode) } if Addenda11.OriginatorName != "BEK Solutions" { diff --git a/addenda12_test.go b/addenda12_test.go index f8cbd5881..bf31b6340 100644 --- a/addenda12_test.go +++ b/addenda12_test.go @@ -35,7 +35,7 @@ func testAddenda12Parse(t testing.TB) { if Addenda12.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda12.recordType) } - if Addenda12.TypeCode != "12" { + if Addenda12.typeCode() != "12" { t.Errorf("expected %v got %v", "12", Addenda12.TypeCode) } if Addenda12.OriginatorCityStateProvince != "JacobsTown*PA\\" { diff --git a/addenda13_test.go b/addenda13_test.go index edefeaac2..6a8dd9c83 100644 --- a/addenda13_test.go +++ b/addenda13_test.go @@ -29,7 +29,7 @@ func testAddenda13Parse(t testing.TB) { if Addenda13.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda13.recordType) } - if Addenda13.TypeCode != "13" { + if Addenda13.typeCode() != "13" { t.Errorf("expected %v got %v", "13", Addenda13.TypeCode) } if Addenda13.ODFIName != "Wells Fargo" { diff --git a/addenda14_test.go b/addenda14_test.go index bb6cdaddc..d3260046f 100644 --- a/addenda14_test.go +++ b/addenda14_test.go @@ -37,7 +37,7 @@ func testAddenda14Parse(t testing.TB) { if Addenda14.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda14.recordType) } - if Addenda14.TypeCode != "14" { + if Addenda14.typeCode() != "14" { t.Errorf("expected %v got %v", "14", Addenda14.TypeCode) } if Addenda14.RDFIName != "Citadel Bank" { diff --git a/addenda15_test.go b/addenda15_test.go index 98aeac4e0..a08ab8645 100644 --- a/addenda15_test.go +++ b/addenda15_test.go @@ -35,7 +35,7 @@ func testAddenda15Parse(t testing.TB) { if Addenda15.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda15.recordType) } - if Addenda15.TypeCode != "15" { + if Addenda15.typeCode() != "15" { t.Errorf("expected %v got %v", "15", Addenda15.TypeCode) } if Addenda15.ReceiverIDNumber != "987465493213987" { diff --git a/addenda16_test.go b/addenda16_test.go index 41ee4a2f3..faea7bd8f 100644 --- a/addenda16_test.go +++ b/addenda16_test.go @@ -35,7 +35,7 @@ func testAddenda16Parse(t testing.TB) { if Addenda16.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda16.recordType) } - if Addenda16.TypeCode != "16" { + if Addenda16.typeCode() != "16" { t.Errorf("expected %v got %v", "16", Addenda16.TypeCode) } if Addenda16.ReceiverCityStateProvince != "LetterTown*AB\\" { diff --git a/addenda17_test.go b/addenda17_test.go index 645323f10..4bbe621f6 100644 --- a/addenda17_test.go +++ b/addenda17_test.go @@ -36,7 +36,7 @@ func testAddenda17Parse(t testing.TB) { if Addenda17.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda17.recordType) } - if Addenda17.TypeCode != "17" { + if Addenda17.typeCode() != "17" { t.Errorf("expected %v got %v", "17", Addenda17.TypeCode) } if Addenda17.PaymentRelatedInformation != "This is an international payment" { @@ -110,7 +110,7 @@ func TestValidateAddenda17RecordType(t *testing.T) { } } -func TestAddenda17TypeCodeFieldInclusion(t *testing.T) { +func TestAddenda17FieldInclusionTypeCode(t *testing.T) { addenda17 := mockAddenda17() addenda17.TypeCode = "" if err := addenda17.Validate(); err != nil { @@ -134,6 +134,18 @@ func TestAddenda17FieldInclusion(t *testing.T) { } } +func TestAddenda17FieldInclusionSequenceNumber(t *testing.T) { + addenda17 := mockAddenda17() + addenda17.SequenceNumber = 0 + if err := addenda17.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "SequenceNumber" { + t.Errorf("%T: %s", err, err) + } + } + } +} + func TestAddenda17FieldInclusionRecordType(t *testing.T) { addenda17 := mockAddenda17() addenda17.recordType = "" diff --git a/addenda18_test.go b/addenda18_test.go index 9bd99afb1..1aed0e77a 100644 --- a/addenda18_test.go +++ b/addenda18_test.go @@ -108,7 +108,7 @@ func testAddenda18Parse(t testing.TB) { if Addenda18.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda18.recordType) } - if Addenda18.TypeCode != "18" { + if Addenda18.typeCode() != "18" { t.Errorf("expected %v got %v", "18", Addenda18.TypeCode) } if Addenda18.ForeignCorrespondentBankName != "Bank of Germany" { From ac25e885197863ae752e30b2dbc555cc7cbdcfc7 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 11:51:00 -0400 Subject: [PATCH 07/11] Increase code test coverage for addenda18 Increase code test coverage for addenda18 --- addenda18_test.go | 65 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 62 insertions(+), 3 deletions(-) diff --git a/addenda18_test.go b/addenda18_test.go index 1aed0e77a..29b33fd8d 100644 --- a/addenda18_test.go +++ b/addenda18_test.go @@ -5,7 +5,6 @@ package ach import ( - "strings" "testing" ) @@ -180,7 +179,7 @@ func TestValidateAddenda18RecordType(t *testing.T) { } } -func TestAddenda18TypeCodeFieldInclusion(t *testing.T) { +func TestAddenda18FieldInclusionTypeCode(t *testing.T) { addenda18 := mockAddenda18() addenda18.TypeCode = "" if err := addenda18.Validate(); err != nil { @@ -204,12 +203,72 @@ func TestAddenda18FieldInclusion(t *testing.T) { } } +func TestAddenda18FieldInclusionSequenceNumber(t *testing.T) { + addenda18 := mockAddenda18() + addenda18.SequenceNumber = 0 + if err := addenda18.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "SequenceNumber" { + t.Errorf("%T: %s", err, err) + } + } + } +} + func TestAddenda18FieldInclusionRecordType(t *testing.T) { addenda18 := mockAddenda18() addenda18.recordType = "" if err := addenda18.Validate(); err != nil { if e, ok := err.(*FieldError); ok { - if !strings.Contains(e.Msg, msgFieldInclusion) { + if e.FieldName != "recordType" { + t.Errorf("%T: %s", err, err) + } + } + } +} + +func TestAddenda18FieldInclusionFCBankName(t *testing.T) { + addenda18 := mockAddenda18() + addenda18.ForeignCorrespondentBankName = "" + if err := addenda18.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "ForeignCorrespondentBankName" { + t.Errorf("%T: %s", err, err) + } + } + } +} + +func TestAddenda18FieldInclusionFCBankIDNumberQualifier(t *testing.T) { + addenda18 := mockAddenda18() + addenda18.ForeignCorrespondentBankIDNumberQualifier = "" + if err := addenda18.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "ForeignCorrespondentBankIDNumberQualifier" { + t.Errorf("%T: %s", err, err) + } + } + } +} + +func TestAddenda18FieldInclusionFCBankIDNumber(t *testing.T) { + addenda18 := mockAddenda18() + addenda18.ForeignCorrespondentBankIDNumber = "" + if err := addenda18.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "ForeignCorrespondentBankIDNumber" { + t.Errorf("%T: %s", err, err) + } + } + } +} + +func TestAddenda18FieldInclusionFCBankBranchCountryCode(t *testing.T) { + addenda18 := mockAddenda18() + addenda18.ForeignCorrespondentBankBranchCountryCode = "" + if err := addenda18.Validate(); err != nil { + if e, ok := err.(*FieldError); ok { + if e.FieldName != "ForeignCorrespondentBankBranchCountryCode" { t.Errorf("%T: %s", err, err) } } From 32fcf1587c2adcdf1d0aa7f950deed2bdc86aa0c Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 15:12:35 -0400 Subject: [PATCH 08/11] Support NOC for IAT entries return nill for addendaFieldInclusion when entry.Category is NOC --- iatBatch.go | 60 +++++++++++++++++++++++++++-------------------------- 1 file changed, 31 insertions(+), 29 deletions(-) diff --git a/iatBatch.go b/iatBatch.go index b37851102..5be2bc0a5 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -455,36 +455,38 @@ func (batch *IATBatch) isCategory() error { func (batch *IATBatch) addendaFieldInclusion(entry *IATEntryDetail) error { - if entry.Category != CategoryNOC { - if entry.Addenda10 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda10", Msg: msg} - } - if entry.Addenda11 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda11", Msg: msg} - } - if entry.Addenda12 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda12", Msg: msg} - } - if entry.Addenda13 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda13", Msg: msg} - } - if entry.Addenda14 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda14", Msg: msg} - } - if entry.Addenda15 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda15", Msg: msg} - } - if entry.Addenda16 == nil { - msg := fmt.Sprint(msgIATBatchAddendaRequired) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda16", Msg: msg} - } + if entry.Category == CategoryNOC { + return nil + } + if entry.Addenda10 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda10", Msg: msg} } + if entry.Addenda11 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda11", Msg: msg} + } + if entry.Addenda12 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda12", Msg: msg} + } + if entry.Addenda13 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda13", Msg: msg} + } + if entry.Addenda14 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda14", Msg: msg} + } + if entry.Addenda15 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda15", Msg: msg} + } + if entry.Addenda16 == nil { + msg := fmt.Sprint(msgIATBatchAddendaRequired) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "Addenda16", Msg: msg} + } + return nil } From c5ca21f093dde1a1d50109249b61247b7a0da868 Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 15:32:15 -0400 Subject: [PATCH 09/11] Support NOC for IAT Remove typeCode() fucntion from Addenda10-Addenda16 types as they are not Addendumer --- addenda10.go | 5 ----- addenda10_test.go | 2 +- addenda11.go | 5 ----- addenda11_test.go | 2 +- addenda12.go | 5 ----- addenda12_test.go | 2 +- addenda13.go | 5 ----- addenda13_test.go | 2 +- addenda14.go | 5 ----- addenda14_test.go | 2 +- addenda15.go | 5 ----- addenda15_test.go | 2 +- addenda16.go | 5 ----- addenda16_test.go | 2 +- iatBatch_test.go | 2 +- 15 files changed, 8 insertions(+), 43 deletions(-) diff --git a/addenda10.go b/addenda10.go index f14564927..5129b348b 100644 --- a/addenda10.go +++ b/addenda10.go @@ -190,11 +190,6 @@ func (addenda10 *Addenda10) reservedField() string { return addenda10.alphaField(addenda10.reserved, 6) } -// TypeCode Defines the specific explanation and format for the addenda10 information left padded -func (addenda10 *Addenda10) typeCode() string { - return addenda10.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda10 *Addenda10) EntryDetailSequenceNumberField() string { return addenda10.numericField(addenda10.EntryDetailSequenceNumber, 7) diff --git a/addenda10_test.go b/addenda10_test.go index 690550508..5a859b47c 100644 --- a/addenda10_test.go +++ b/addenda10_test.go @@ -37,7 +37,7 @@ func testAddenda10Parse(t testing.TB) { if addenda10.recordType != "7" { t.Errorf("expected %v got %v", "7", addenda10.recordType) } - if addenda10.typeCode() != "10" { + if addenda10.TypeCode != "10" { t.Errorf("expected %v got %v", "10", addenda10.TypeCode) } if addenda10.TransactionTypeCode != "ANN" { diff --git a/addenda11.go b/addenda11.go index 61ed96123..3b4903823 100644 --- a/addenda11.go +++ b/addenda11.go @@ -159,11 +159,6 @@ func (addenda11 *Addenda11) reservedField() string { return addenda11.alphaField(addenda11.reserved, 14) } -// TypeCode Defines the specific explanation and format for the addenda11 information left padded -func (addenda11 *Addenda11) typeCode() string { - return addenda11.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda11 *Addenda11) EntryDetailSequenceNumberField() string { return addenda11.numericField(addenda11.EntryDetailSequenceNumber, 7) diff --git a/addenda11_test.go b/addenda11_test.go index df75bef0f..1c1b1d6d4 100644 --- a/addenda11_test.go +++ b/addenda11_test.go @@ -35,7 +35,7 @@ func testAddenda11Parse(t testing.TB) { if Addenda11.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda11.recordType) } - if Addenda11.typeCode() != "11" { + if Addenda11.TypeCode != "11" { t.Errorf("expected %v got %v", "11", Addenda11.TypeCode) } if Addenda11.OriginatorName != "BEK Solutions" { diff --git a/addenda12.go b/addenda12.go index 1eef911dd..b46f5be35 100644 --- a/addenda12.go +++ b/addenda12.go @@ -167,11 +167,6 @@ func (addenda12 *Addenda12) reservedField() string { return addenda12.alphaField(addenda12.reserved, 14) } -// TypeCode Defines the specific explanation and format for the addenda12 information left padded -func (addenda12 *Addenda12) typeCode() string { - return addenda12.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda12 *Addenda12) EntryDetailSequenceNumberField() string { return addenda12.numericField(addenda12.EntryDetailSequenceNumber, 7) diff --git a/addenda12_test.go b/addenda12_test.go index bf31b6340..f8cbd5881 100644 --- a/addenda12_test.go +++ b/addenda12_test.go @@ -35,7 +35,7 @@ func testAddenda12Parse(t testing.TB) { if Addenda12.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda12.recordType) } - if Addenda12.typeCode() != "12" { + if Addenda12.TypeCode != "12" { t.Errorf("expected %v got %v", "12", Addenda12.TypeCode) } if Addenda12.OriginatorCityStateProvince != "JacobsTown*PA\\" { diff --git a/addenda13.go b/addenda13.go index 1440a157e..b6467678f 100644 --- a/addenda13.go +++ b/addenda13.go @@ -221,11 +221,6 @@ func (addenda13 *Addenda13) reservedField() string { return addenda13.alphaField(addenda13.reserved, 10) } -// TypeCode Defines the specific explanation and format for the addenda13 information left padded -func (addenda13 *Addenda13) typeCode() string { - return addenda13.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda13 *Addenda13) EntryDetailSequenceNumberField() string { return addenda13.numericField(addenda13.EntryDetailSequenceNumber, 7) diff --git a/addenda13_test.go b/addenda13_test.go index 6a8dd9c83..edefeaac2 100644 --- a/addenda13_test.go +++ b/addenda13_test.go @@ -29,7 +29,7 @@ func testAddenda13Parse(t testing.TB) { if Addenda13.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda13.recordType) } - if Addenda13.typeCode() != "13" { + if Addenda13.TypeCode != "13" { t.Errorf("expected %v got %v", "13", Addenda13.TypeCode) } if Addenda13.ODFIName != "Wells Fargo" { diff --git a/addenda14.go b/addenda14.go index 3af38d927..38c544f66 100644 --- a/addenda14.go +++ b/addenda14.go @@ -217,11 +217,6 @@ func (addenda14 *Addenda14) reservedField() string { return addenda14.alphaField(addenda14.reserved, 10) } -// TypeCode Defines the specific explanation and format for the addenda14 information left padded -func (addenda14 *Addenda14) typeCode() string { - return addenda14.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda14 *Addenda14) EntryDetailSequenceNumberField() string { return addenda14.numericField(addenda14.EntryDetailSequenceNumber, 7) diff --git a/addenda14_test.go b/addenda14_test.go index d3260046f..bb6cdaddc 100644 --- a/addenda14_test.go +++ b/addenda14_test.go @@ -37,7 +37,7 @@ func testAddenda14Parse(t testing.TB) { if Addenda14.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda14.recordType) } - if Addenda14.typeCode() != "14" { + if Addenda14.TypeCode != "14" { t.Errorf("expected %v got %v", "14", Addenda14.TypeCode) } if Addenda14.RDFIName != "Citadel Bank" { diff --git a/addenda15.go b/addenda15.go index 30c22e290..850d81891 100644 --- a/addenda15.go +++ b/addenda15.go @@ -153,11 +153,6 @@ func (addenda15 *Addenda15) reservedField() string { return addenda15.alphaField(addenda15.reserved, 34) } -// TypeCode Defines the specific explanation and format for the addenda15 information left padded -func (addenda15 *Addenda15) typeCode() string { - return addenda15.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda15 *Addenda15) EntryDetailSequenceNumberField() string { return addenda15.numericField(addenda15.EntryDetailSequenceNumber, 7) diff --git a/addenda15_test.go b/addenda15_test.go index a08ab8645..98aeac4e0 100644 --- a/addenda15_test.go +++ b/addenda15_test.go @@ -35,7 +35,7 @@ func testAddenda15Parse(t testing.TB) { if Addenda15.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda15.recordType) } - if Addenda15.typeCode() != "15" { + if Addenda15.TypeCode != "15" { t.Errorf("expected %v got %v", "15", Addenda15.TypeCode) } if Addenda15.ReceiverIDNumber != "987465493213987" { diff --git a/addenda16.go b/addenda16.go index afa3db989..f1245519b 100644 --- a/addenda16.go +++ b/addenda16.go @@ -165,11 +165,6 @@ func (addenda16 *Addenda16) reservedField() string { return addenda16.alphaField(addenda16.reserved, 14) } -// TypeCode Defines the specific explanation and format for the addenda16 information left padded -func (addenda16 *Addenda16) typeCode() string { - return addenda16.TypeCode -} - // EntryDetailSequenceNumberField returns a zero padded EntryDetailSequenceNumber string func (addenda16 *Addenda16) EntryDetailSequenceNumberField() string { return addenda16.numericField(addenda16.EntryDetailSequenceNumber, 7) diff --git a/addenda16_test.go b/addenda16_test.go index faea7bd8f..41ee4a2f3 100644 --- a/addenda16_test.go +++ b/addenda16_test.go @@ -35,7 +35,7 @@ func testAddenda16Parse(t testing.TB) { if Addenda16.recordType != "7" { t.Errorf("expected %v got %v", "7", Addenda16.recordType) } - if Addenda16.typeCode() != "16" { + if Addenda16.TypeCode != "16" { t.Errorf("expected %v got %v", "16", Addenda16.TypeCode) } if Addenda16.ReceiverCityStateProvince != "LetterTown*AB\\" { diff --git a/iatBatch_test.go b/iatBatch_test.go index cbe1f1db3..8fab1de0a 100644 --- a/iatBatch_test.go +++ b/iatBatch_test.go @@ -1694,7 +1694,7 @@ func BenchmarkIATNoEntry(b *testing.B) { // testIATBatchAddendumTypeCode validates IATBatch Addendum TypeCode func testIATBatchAddendumTypeCode(t testing.TB) { mockBatch := mockIATBatch(t) - mockBatch.GetEntries()[0].AddIATAddenda(mockAddenda12()) + mockBatch.GetEntries()[0].AddIATAddenda(mockAddenda17()) if err := mockBatch.build(); err != nil { t.Errorf("%T: %s", err, err) From 342b595388f4f16cc59dca79bc7d0136951c0d7e Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 15:59:31 -0400 Subject: [PATCH 10/11] Support for IAT NOC Return nil if entry.Category = NOC --- iatBatch.go | 59 +++++++++++++++++++++++++++-------------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/iatBatch.go b/iatBatch.go index 5be2bc0a5..4d8823786 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -370,35 +370,36 @@ func (batch *IATBatch) isAddendaSequence() error { // Verify Addenda* entry detail sequence numbers are valid entryTN := entry.TraceNumberField()[8:] - if entry.Category != CategoryNOC { - if entry.Addenda10.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda10.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda11.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda11.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda12.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda12.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda13.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda13.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda14.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda14.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda15.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda15.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } - if entry.Addenda16.EntryDetailSequenceNumberField() != entryTN { - msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda16.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) - return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} - } + if entry.Category == CategoryNOC { + return nil + } + if entry.Addenda10.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda10.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda11.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda11.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda12.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda12.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda13.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda13.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda14.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda14.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda15.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda15.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} + } + if entry.Addenda16.EntryDetailSequenceNumberField() != entryTN { + msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda16.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) + return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg} } // check if sequence is ascending for addendumer - Addenda17 and Addenda18 From fb681e7362223d7003a12aaf98012216fb0a14da Mon Sep 17 00:00:00 2001 From: Brooke E Kline Jr Date: Wed, 31 Oct 2018 16:00:55 -0400 Subject: [PATCH 11/11] Support NOC for IAT entries Support NOC for IAT entries --- iatBatch.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/iatBatch.go b/iatBatch.go index 4d8823786..b3bbc65b9 100644 --- a/iatBatch.go +++ b/iatBatch.go @@ -367,12 +367,13 @@ func (batch *IATBatch) isAddendaSequence() error { if entry.AddendaRecordIndicator != 1 { return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "AddendaRecordIndicator", Msg: msgIATBatchAddendaIndicator} } - // Verify Addenda* entry detail sequence numbers are valid - entryTN := entry.TraceNumberField()[8:] if entry.Category == CategoryNOC { return nil } + + // Verify Addenda* entry detail sequence numbers are valid + entryTN := entry.TraceNumberField()[8:] if entry.Addenda10.EntryDetailSequenceNumberField() != entryTN { msg := fmt.Sprintf(msgBatchAddendaTraceNumber, entry.Addenda10.EntryDetailSequenceNumberField(), entry.TraceNumberField()[8:]) return &BatchError{BatchNumber: batch.Header.BatchNumber, FieldName: "TraceNumber", Msg: msg}