From 3de8a5eb37c61c93a720610f7e7cf6201ed7de47 Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Wed, 16 Aug 2023 18:15:16 -0600 Subject: [PATCH 1/6] add missing return statements to error cases --- fileHeader.go | 7 +++++++ reader.go | 7 ++++--- reader_test.go | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/fileHeader.go b/fileHeader.go index 9e4527c2..2c78b498 100644 --- a/fileHeader.go +++ b/fileHeader.go @@ -102,6 +102,13 @@ func NewFileHeader() FileHeader { return fh } +func (fh *FileHeader) IsZero() bool { + if fh == nil { + return true + } + return *fh == (FileHeader{}) || *fh == NewFileHeader() +} + func (fh *FileHeader) setRecordType() { if fh == nil { return diff --git a/reader.go b/reader.go index 2bd97d1c..5247fa91 100644 --- a/reader.go +++ b/reader.go @@ -279,7 +279,7 @@ func (r *Reader) parseLine() error { //nolint:gocyclo return err } if r.currentCashLetter.currentBundle == nil { - r.error(&FileError{Msg: msgFileBundleControl}) + return r.error(&FileError{Msg: msgFileBundleControl}) } // Add Bundle or ReturnBundle to CashLetter if r.currentCashLetter.currentBundle != nil { @@ -326,10 +326,11 @@ func (r *Reader) parseLine() error { //nolint:gocyclo // parseFileHeader takes the input record string and parses the FileHeader values func (r *Reader) parseFileHeader() error { r.recordName = "FileHeader" - if (FileHeader{}) != r.File.Header { + if !r.File.Header.IsZero() { // There can only be one File Header per File - r.error(&FileError{Msg: msgFileHeader}) + return r.error(&FileError{Msg: msgFileHeader}) } + r.File.Header.Parse(r.decodeLine(r.line)) // Ensure valid FileHeader if err := r.File.Header.Validate(); err != nil { diff --git a/reader_test.go b/reader_test.go index fa26702c..79230dba 100644 --- a/reader_test.go +++ b/reader_test.go @@ -155,7 +155,7 @@ func TestTwoFileHeaders(t *testing.T) { r := NewReader(strings.NewReader(twoHeaders)) _, err := r.Read() fileErr := getFileError(t, err) - require.Equal(t, msgFileControl, fileErr.Msg) + require.Equal(t, msgFileHeader, fileErr.Msg) } // TestCashLetterHeaderErr validates error flows back from the parser From efee15d2a307c55b7348655be02962b23bb0d2ba Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Wed, 16 Aug 2023 21:33:23 -0600 Subject: [PATCH 2/6] reader: minor cleanup in parsing logic --- fileControl.go | 7 ++++++ reader.go | 58 ++++++++++++++------------------------------------ reader_test.go | 48 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 42 deletions(-) diff --git a/fileControl.go b/fileControl.go index 57e8c727..f7a6dfc6 100644 --- a/fileControl.go +++ b/fileControl.go @@ -52,6 +52,13 @@ func NewFileControl() FileControl { return fc } +func (fc *FileControl) IsZero() bool { + if fc == nil { + return true + } + return *fc == (FileControl{}) || *fc == NewFileControl() +} + func (fc *FileControl) setRecordType() { if fc == nil { return diff --git a/reader.go b/reader.go index 5247fa91..0fe8efb6 100644 --- a/reader.go +++ b/reader.go @@ -191,16 +191,18 @@ func (r *Reader) Read() (File, error) { return r.File, r.error(err) } - if (FileHeader{}) == r.File.Header { - // There must be at least one File Header + // the file must have a non-zero header record + if r.File.Header.IsZero() { r.recordName = "FileHeader" return r.File, r.error(&FileError{Msg: msgFileHeader}) } - if (FileControl{}) == r.File.Control { - // There must be at least one File Control + + // the file must have a non-zero control record + if r.File.Control.IsZero() { r.recordName = "FileControl" return r.File, r.error(&FileError{Msg: msgFileControl}) } + return r.File, nil } @@ -288,7 +290,7 @@ func (r *Reader) parseLine() error { //nolint:gocyclo return r.error(err) } r.currentCashLetter.AddBundle(r.currentCashLetter.currentBundle) - r.currentCashLetter.currentBundle = new(Bundle) + r.currentCashLetter.currentBundle = nil } case routingNumberSummaryPos, routingNumberSummaryEbcPos: if err := r.parseRoutingNumberSummary(); err != nil { @@ -343,7 +345,7 @@ func (r *Reader) parseFileHeader() error { func (r *Reader) parseCashLetterHeader() error { r.recordName = "CashLetterHeader" if r.currentCashLetter.CashLetterHeader != nil { - // CashLetterHeader inside of current cash letter + // found duplicate cash letter header return r.error(&FileError{Msg: msgFileCashLetterInside}) } clh := NewCashLetterHeader() @@ -352,6 +354,7 @@ func (r *Reader) parseCashLetterHeader() error { if err := clh.Validate(); err != nil { return r.error(err) } + // Passing CashLetterHeader into NewCashLetter creates a CashLetter cl := NewCashLetter(clh) r.addCurrentCashLetter(cl) @@ -361,11 +364,10 @@ func (r *Reader) parseCashLetterHeader() error { // parseBundleHeader takes the input record string and parses the BundleHeader values func (r *Reader) parseBundleHeader() error { r.recordName = "BundleHeader" - if r.currentCashLetter.currentBundle != nil { + if r.currentCashLetter.currentBundle != nil && + r.currentCashLetter.currentBundle.BundleHeader != nil { // BundleHeader inside of current Bundle - if r.currentCashLetter.currentBundle.BundleHeader != nil { - return r.error(&FileError{Msg: msgFileBundleInside}) - } + return r.error(&FileError{Msg: msgFileBundleInside}) } // Ensure we have a valid bundle header before building a bundle. bh := NewBundleHeader() @@ -392,10 +394,10 @@ func (r *Reader) parseCheckDetail() error { if err := cd.Validate(); err != nil { return r.error(err) } + // Add CheckDetail - if r.currentCashLetter.currentBundle.BundleHeader != nil { - r.currentCashLetter.currentBundle.AddCheckDetail(cd) - } + r.currentCashLetter.currentBundle.AddCheckDetail(cd) + return nil } @@ -412,7 +414,6 @@ func (r *Reader) parseCheckDetailAddendumA() error { return r.error(err) } entryIndex := len(r.currentCashLetter.currentBundle.GetChecks()) - 1 - // r.currentCashLetter.currentBundle.Checks[entryIndex].CheckDetailAddendumA = cdAddendumA r.currentCashLetter.currentBundle.Checks[entryIndex].AddCheckDetailAddendumA(cdAddendumA) return nil } @@ -462,9 +463,7 @@ func (r *Reader) parseReturnDetail() error { if err := rd.Validate(); err != nil { return r.error(err) } - if r.currentCashLetter.currentBundle.BundleHeader != nil { - r.currentCashLetter.currentBundle.AddReturnDetail(rd) - } + r.currentCashLetter.currentBundle.AddReturnDetail(rd) return nil } @@ -523,7 +522,6 @@ func (r *Reader) parseReturnDetailAddendumC() error { // parseReturnDetail*AddendumD takes the input record string and parses the ReturnDetail*AddendumD values func (r *Reader) parseReturnDetailAddendumD() error { r.recordName = "ReturnDetailAddendumD" - if r.currentCashLetter.currentBundle.GetReturns() == nil { msg := fmt.Sprint(msgFileBundleOutside) return r.error(&FileError{FieldName: "ReturnDetailAddendumD", Msg: msg}) @@ -541,14 +539,6 @@ func (r *Reader) parseReturnDetailAddendumD() error { // parseImageViewDetail takes the input record string and parses the ImageViewDetail values func (r *Reader) parseImageViewDetail() error { r.recordName = "ImageViewDetail" - if err := r.ImageViewDetail(); err != nil { - return err - } - return nil -} - -// ImageViewDetail takes the input record string and parses ImageViewDetail for a check -func (r *Reader) ImageViewDetail() error { if r.currentCashLetter.currentBundle.GetChecks() != nil { ivDetail := NewImageViewDetail() ivDetail.Parse(r.decodeLine(r.line)) @@ -577,14 +567,6 @@ func (r *Reader) ImageViewDetail() error { // parseImageViewData takes the input record string and parses the ImageViewData values func (r *Reader) parseImageViewData() error { r.recordName = "ImageViewData" - if err := r.ImageViewData(); err != nil { - return err - } - return nil -} - -// ImageViewData takes the input record string and parses ImageViewData for a check -func (r *Reader) ImageViewData() error { if r.currentCashLetter.currentBundle.GetChecks() != nil { ivData := NewImageViewData() ivData.ParseAndDecode(r.line, r.decodeLine) @@ -613,14 +595,6 @@ func (r *Reader) ImageViewData() error { // parseImageViewAnalysis takes the input record string and parses ImageViewAnalysis values func (r *Reader) parseImageViewAnalysis() error { r.recordName = "ImageViewAnalysis" - if err := r.ImageViewAnalysis(); err != nil { - return err - } - return nil -} - -// ImageViewAnalysis takes the input record string and parses ImageViewAnalysis for a check -func (r *Reader) ImageViewAnalysis() error { if r.currentCashLetter.currentBundle.GetChecks() != nil { ivAnalysis := NewImageViewAnalysis() ivAnalysis.Parse(r.decodeLine(r.line)) diff --git a/reader_test.go b/reader_test.go index 79230dba..d9d57815 100644 --- a/reader_test.go +++ b/reader_test.go @@ -861,3 +861,51 @@ func TestICLFile_LargeCheckImage(t *testing.T) { _, err = r.Read() require.NoError(t, err) } + +func TestRead_multipleBundlesInCashLetter(t *testing.T) { + r := NewReader(strings.NewReader(multipleBundles)) + f, err := r.Read() + require.NoError(t, err) + require.Equal(t, 2, len(f.CashLetters[0].Bundles)) + require.Equal(t, "1", f.CashLetters[0].Bundles[0].BundleHeader.BundleSequenceNumber) + require.Equal(t, "2", f.CashLetters[0].Bundles[1].BundleHeader.BundleSequenceNumber) +} + +const multipleBundles = `0135T231380104121042882201810101237NCitadel Wells Fargo US +100123138010412104288220181010201810101237IGA1 Contact Name 5558675552 +62 123456789 031300012 5558881000000001000001 G101 +200123138010412104288220181010201810109999 1 01 +25 123456789 031300012 555888100001000001 GD1Y030B +261121042882201810101 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2802121042882201810101 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +25 123456789 031300012 555888100001000002 GD1Y030B +262121042882201810102 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2803121042882201810102 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +70001400000020000000000020000000002 0 +200123138010412104288220181010201810109999 2 01 +25 123456789 031300012 555888100001000001 GD1Y030B +261121042882201810101 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2802121042882201810101 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +25 123456789 031300012 555888100001000002 GD1Y030B +262121042882201810102 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2803121042882201810102 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +8511112222300000000100000000001 +70001400000020000000000020000000002 0 +900000010000001400000000200000000000002 201810100 +9900000200000038000000280000000000400000 0 ` From e7a4ef971551038cb84b35753c11e9e7887289f3 Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Wed, 16 Aug 2023 22:42:38 -0600 Subject: [PATCH 3/6] reader: parse deposit ticket in bundle credit record --- bundle.go | 51 ++++++++++++++++++++++++------- credit.go | 12 ++++++++ file.go | 2 +- imageViewDetail_test.go | 1 - reader.go | 66 +++++++++++++++++++++-------------------- reader_test.go | 42 ++++++++++++++++++++++++++ 6 files changed, 130 insertions(+), 44 deletions(-) diff --git a/bundle.go b/bundle.go index 30f757d4..d66f7c51 100644 --- a/bundle.go +++ b/bundle.go @@ -44,6 +44,8 @@ type Bundle struct { ID string `json:"id"` // BundleHeader is a Bundle Header Record BundleHeader *BundleHeader `json:"bundleHeader,omitempty"` + // Credits may be included as part of a bundle, and are often used to represent deposit tickets + Credits []*Credit `json:"credits,omitempty"` // Checks are Check Items: Check Detail Records, Check Detail Addendum Records, and Image Views Checks []*CheckDetail `json:"checks,omitempty"` // Returns are Return Items: Return Detail Records, Return Detail Addendum Records, and Image Views @@ -65,6 +67,9 @@ func (b *Bundle) setRecordType() { return } b.BundleHeader.setRecordType() + for i := range b.Credits { + b.Credits[i].setRecordType() + } for i := range b.Checks { b.Checks[i].setRecordType() } @@ -92,8 +97,8 @@ func (b *Bundle) Validate() error { return nil } -// build creates a valid Bundle by building BundleControl. An error is returned if -// the bundle being built has invalid records. +// build creates a valid Bundle by building BundleControl. An error is returned if the bundle being +// built has invalid records. func (b *Bundle) build() error { // Requires a valid BundleHeader if err := b.BundleHeader.Validate(); err != nil { @@ -107,9 +112,21 @@ func (b *Bundle) build() error { bundleTotalAmount := 0 micrValidTotalAmount := 0 bundleImagesCount := 0 - // The current Implementation doe snot support CreditItems as part of a bundle so BundleControl.CreditIndicator = 0 + // The current Implementation does not support CreditItems as part of a bundle so BundleControl.CreditIndicator = 0 creditIndicator := 0 + // Credit items + for _, cr := range b.Credits { + if err := b.ValidateCredit(cr); err != nil { + return err + } + + // A credit record within a Bundle is typically used to present a + // deposit ticket, and its amount is not included in the bundle total + itemCount++ + bundleImagesCount += len(cr.ImageViewDetail) + } + // Forward Items for _, cd := range b.Checks { @@ -118,13 +135,13 @@ func (b *Bundle) build() error { return err } - itemCount = itemCount + 1 - bundleTotalAmount = bundleTotalAmount + cd.ItemAmount + itemCount++ + bundleTotalAmount += cd.ItemAmount if cd.MICRValidIndicator == 1 { - micrValidTotalAmount = micrValidTotalAmount + cd.ItemAmount + micrValidTotalAmount += cd.ItemAmount } - bundleImagesCount = bundleImagesCount + len(cd.ImageViewDetail) + bundleImagesCount += len(cd.ImageViewDetail) } // Return Items @@ -134,9 +151,9 @@ func (b *Bundle) build() error { if err := b.ValidateReturnItems(rd); err != nil { return err } - itemCount = itemCount + 1 - bundleTotalAmount = bundleTotalAmount + rd.ItemAmount - bundleImagesCount = bundleImagesCount + len(rd.ImageViewDetail) + itemCount++ + bundleTotalAmount += rd.ItemAmount + bundleImagesCount += len(rd.ImageViewDetail) } // build a BundleControl record @@ -196,6 +213,20 @@ func (b *Bundle) GetReturns() []*ReturnDetail { return b.Returns } +func (b *Bundle) ValidateCredit(cr *Credit) error { + for _, ivDetail := range cr.ImageViewDetail { + if err := ivDetail.Validate(); err != nil { + return err + } + } + for _, ivData := range cr.ImageViewData { + if err := ivData.Validate(); err != nil { + return err + } + } + return nil +} + // ValidateForwardItems calls Validate function for check items func (b *Bundle) ValidateForwardItems(cd *CheckDetail) error { // Validate items diff --git a/credit.go b/credit.go index d410c444..c58ca477 100644 --- a/credit.go +++ b/credit.go @@ -47,6 +47,10 @@ type Credit struct { DebitCreditIndicator string `json:"debitCreditIndicator,omitempty"` // reserved is a field reserved for future use. Reserved should be blank. reserved string + + ImageViewDetail []ImageViewDetail `json:"imageViewDetail"` + ImageViewData []ImageViewData `json:"imageViewData"` + // validator is composed for image cash letter data validation validator // converters is composed for image cash letter to golang Converters @@ -264,3 +268,11 @@ func (cr *Credit) DebitCreditIndicatorField() string { func (cr *Credit) reservedField() string { return cr.alphaField(cr.reserved, 3) } + +func (cr *Credit) AddImageViewData(ivData ImageViewData) { + cr.ImageViewData = append(cr.ImageViewData, ivData) +} + +func (cr *Credit) AddImageViewDetail(ivDetail ImageViewDetail) { + cr.ImageViewDetail = append(cr.ImageViewDetail, ivDetail) +} diff --git a/file.go b/file.go index e7c743e5..269999e6 100644 --- a/file.go +++ b/file.go @@ -88,7 +88,7 @@ var ( msgFileCashLetterID = "%s is not unique" msgRecordType = "received expecting %d" msgFileCreditItem = "Credit item outside of cash letter" - msgFileCredit = "Credit outside of cash letter" + msgFileCredit = "Credit outside of cash letter or bundle" ) // FileError is an error describing issues validating a file diff --git a/imageViewDetail_test.go b/imageViewDetail_test.go index d330a364..6b465de7 100644 --- a/imageViewDetail_test.go +++ b/imageViewDetail_test.go @@ -57,7 +57,6 @@ func TestMockImageViewDetail(t *testing.T) { require.Equal(t, "", ivDetail.reserved) require.Equal(t, "0", ivDetail.OverrideIndicator) require.Equal(t, "", ivDetail.reservedTwo) - } // TestParseIVDetail validates parsing an ImageViewDetail diff --git a/reader.go b/reader.go index 0fe8efb6..c1855838 100644 --- a/reader.go +++ b/reader.go @@ -539,23 +539,21 @@ func (r *Reader) parseReturnDetailAddendumD() error { // parseImageViewDetail takes the input record string and parses the ImageViewDetail values func (r *Reader) parseImageViewDetail() error { r.recordName = "ImageViewDetail" + ivDetail := NewImageViewDetail() + ivDetail.Parse(r.decodeLine(r.line)) + if err := ivDetail.Validate(); err != nil { + return r.error(err) + } + if r.currentCashLetter.currentBundle.GetChecks() != nil { - ivDetail := NewImageViewDetail() - ivDetail.Parse(r.decodeLine(r.line)) - if err := ivDetail.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetChecks()) - 1 r.currentCashLetter.currentBundle.Checks[entryIndex].AddImageViewDetail(ivDetail) - } else if r.currentCashLetter.currentBundle.GetReturns() != nil { - ivDetail := NewImageViewDetail() - ivDetail.Parse(r.decodeLine(r.line)) - if err := ivDetail.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetReturns()) - 1 r.currentCashLetter.currentBundle.Returns[entryIndex].AddImageViewDetail(ivDetail) + } else if len(r.currentCashLetter.currentBundle.Credits) > 0 { + entryIndex := len(r.currentCashLetter.currentBundle.Credits) - 1 + r.currentCashLetter.currentBundle.Credits[entryIndex].AddImageViewDetail(ivDetail) } else { msg := fmt.Sprint(msgFileBundleOutside) return r.error(&FileError{FieldName: "ImageViewDetail", Msg: msg}) @@ -567,23 +565,22 @@ func (r *Reader) parseImageViewDetail() error { // parseImageViewData takes the input record string and parses the ImageViewData values func (r *Reader) parseImageViewData() error { r.recordName = "ImageViewData" + ivData := NewImageViewData() + ivData.ParseAndDecode(r.line, r.decodeLine) + if err := ivData.Validate(); err != nil { + return r.error(err) + } + if r.currentCashLetter.currentBundle.GetChecks() != nil { - ivData := NewImageViewData() - ivData.ParseAndDecode(r.line, r.decodeLine) - if err := ivData.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetChecks()) - 1 r.currentCashLetter.currentBundle.Checks[entryIndex].AddImageViewData(ivData) } else if r.currentCashLetter.currentBundle.GetReturns() != nil { - ivData := NewImageViewData() - ivData.ParseAndDecode(r.line, r.decodeLine) - if err := ivData.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetReturns()) - 1 r.currentCashLetter.currentBundle.Returns[entryIndex].AddImageViewData(ivData) + } else if len(r.currentCashLetter.currentBundle.Credits) > 0 { + entryIndex := len(r.currentCashLetter.currentBundle.Credits) - 1 + r.currentCashLetter.currentBundle.Credits[entryIndex].AddImageViewData(ivData) } else { msg := fmt.Sprint(msgFileBundleOutside) return r.error(&FileError{FieldName: "ImageViewData", Msg: msg}) @@ -595,21 +592,17 @@ func (r *Reader) parseImageViewData() error { // parseImageViewAnalysis takes the input record string and parses ImageViewAnalysis values func (r *Reader) parseImageViewAnalysis() error { r.recordName = "ImageViewAnalysis" + ivAnalysis := NewImageViewAnalysis() + ivAnalysis.Parse(r.decodeLine(r.line)) + if err := ivAnalysis.Validate(); err != nil { + return r.error(err) + } + if r.currentCashLetter.currentBundle.GetChecks() != nil { - ivAnalysis := NewImageViewAnalysis() - ivAnalysis.Parse(r.decodeLine(r.line)) - if err := ivAnalysis.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetChecks()) - 1 r.currentCashLetter.currentBundle.Checks[entryIndex].AddImageViewAnalysis(ivAnalysis) } else if r.currentCashLetter.currentBundle.GetReturns() != nil { - ivAnalysis := NewImageViewAnalysis() - ivAnalysis.Parse(r.decodeLine(r.line)) - if err := ivAnalysis.Validate(); err != nil { - return r.error(err) - } entryIndex := len(r.currentCashLetter.currentBundle.GetReturns()) - 1 r.currentCashLetter.currentBundle.Returns[entryIndex].AddImageViewAnalysis(ivAnalysis) } else { @@ -624,7 +617,8 @@ func (r *Reader) parseImageViewAnalysis() error { func (r *Reader) parseCredit() error { // Current implementation has the credit letter outside the bundle but within the cash letter r.recordName = "Credit" - if r.currentCashLetter.CashLetterHeader == nil { + if r.currentCashLetter.CashLetterHeader == nil && + r.currentCashLetter.currentBundle == nil { return r.error(&FileError{Msg: msgFileCredit}) } cr := new(Credit) @@ -632,6 +626,14 @@ func (r *Reader) parseCredit() error { if err := cr.Validate(); err != nil { return r.error(err) } + + // if we have an incomplete bundle, add the credit to the bundle + if r.currentCashLetter.currentBundle != nil { + r.currentCashLetter.currentBundle.Credits = append(r.currentCashLetter.currentBundle.Credits, cr) + return nil + } + + // otherwise add the credit to the cash letter r.currentCashLetter.AddCredit(cr) return nil } diff --git a/reader_test.go b/reader_test.go index d9d57815..5e770a03 100644 --- a/reader_test.go +++ b/reader_test.go @@ -871,6 +871,20 @@ func TestRead_multipleBundlesInCashLetter(t *testing.T) { require.Equal(t, "2", f.CashLetters[0].Bundles[1].BundleHeader.BundleSequenceNumber) } +func TestRead_CreditInBundle(t *testing.T) { + r := NewReader(strings.NewReader(depositTicketAsCredit)) + f, err := r.Read() + require.NoError(t, err) + + bundles := f.CashLetters[0].Bundles + require.Equal(t, 1, len(bundles)) + credits := bundles[0].Credits + require.Equal(t, 1, len(credits)) + credit := credits[0] + require.Equal(t, 2, len(credit.ImageViewDetail)) + require.Equal(t, 2, len(credit.ImageViewData)) +} + const multipleBundles = `0135T231380104121042882201810101237NCitadel Wells Fargo US 100123138010412104288220181010201810101237IGA1 Contact Name 5558675552 62 123456789 031300012 5558881000000001000001 G101 @@ -909,3 +923,31 @@ const multipleBundles = `0135T231380104121042882201810101237NCitadel W 70001400000020000000000020000000002 0 900000010000001400000000200000000000002 201810100 9900000200000038000000280000000000400000 0 ` + +const depositTicketAsCredit = `0135T231380104121042882201810101237NCitadel Wells Fargo US +100123138010412104288220181010201810101237IGA1 Contact Name 5558675552 +62 123456789 031300012 5558881000000001000001 G101 +200123138010412104288220181010201810109999 1 01 +61010910999940910 99992006050920060509383521210000010208812345 G13 +501031300012201809050000000000000000000000000000000000000 0 +52121042882202308161 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +5010313000122023081600000000000100000 000000000000000 0 +52121042882202308161 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +25 123456789 031300012 555888100001000001 GD1Y030B +261121042882201810101 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2802121042882201810101 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +25 123456789 031300012 555888100001000002 GD1Y030B +262121042882201810102 938383 01 Test Payee Y10 +2711A 00340 CD Addendum B +2803121042882201810102 Y10A 0 +501031300012201810100000000000000000000000000000000000000 0 +52121042882201810101 1 Sec Orig Name Sec Auth Name SECURE 0 00000 0000001 +542202222222 10222222222222 +8511112222300000000100000000001 +70001400000020000000000020000000002 0 +900000010000001400000000200000000000002 201810100 +9900000200000038000000280000000000400000 0 ` From 8d164d25f074b5199994b8f75a0a9e40637fe77e Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Fri, 18 Aug 2023 18:06:52 -0600 Subject: [PATCH 4/6] address linter errors --- bundle_test.go | 16 ++++++---------- cmd/webui/main.go | 1 + file_test.go | 8 +++----- reader_test.go | 2 +- 4 files changed, 11 insertions(+), 16 deletions(-) diff --git a/bundle_test.go b/bundle_test.go index 4d5c8c72..07dadaf8 100644 --- a/bundle_test.go +++ b/bundle_test.go @@ -11,7 +11,7 @@ import ( ) // mockBundleChecks -func mockBundleChecks() *Bundle { +func mockBundleChecks(t *testing.T) *Bundle { bundle := &Bundle{} bundle.SetHeader(mockBundleHeader()) bundle.AddCheckDetail(mockCheckDetail()) @@ -21,14 +21,12 @@ func mockBundleChecks() *Bundle { bundle.Checks[0].AddImageViewDetail(mockImageViewDetail()) bundle.Checks[0].AddImageViewData(mockImageViewData()) bundle.Checks[0].AddImageViewAnalysis(mockImageViewAnalysis()) - if err := bundle.build(); err != nil { - panic(err) - } + require.NoError(t, bundle.build()) return bundle } // mockBundleReturns -func mockBundleReturns() *Bundle { +func mockBundleReturns(t *testing.T) *Bundle { bundle := &Bundle{} bundle.SetHeader(mockBundleHeader()) bundle.AddReturnDetail(mockReturnDetail()) @@ -39,15 +37,13 @@ func mockBundleReturns() *Bundle { bundle.Returns[0].AddImageViewDetail(mockImageViewDetail()) bundle.Returns[0].AddImageViewData(mockImageViewData()) bundle.Returns[0].AddImageViewAnalysis(mockImageViewAnalysis()) - if err := bundle.build(); err != nil { - panic(err) - } + require.NoError(t, bundle.build()) return bundle } // TestMockBundleChecks creates a Bundle of checks func TestMockBundleChecks(t *testing.T) { - bundle := mockBundleChecks() + bundle := mockBundleChecks(t) require.NoError(t, bundle.Validate()) bundle = nil // ensure we don't panic @@ -59,7 +55,7 @@ func TestMockBundleChecks(t *testing.T) { // TestMockBundleReturns creates a Bundle of returns func TestMockBundleReturns(t *testing.T) { - bundle := mockBundleReturns() + bundle := mockBundleReturns(t) require.NoError(t, bundle.Validate()) bundle = nil // ensure we don't panic diff --git a/cmd/webui/main.go b/cmd/webui/main.go index 03525da0..875c89a4 100644 --- a/cmd/webui/main.go +++ b/cmd/webui/main.go @@ -121,6 +121,7 @@ func addPingRoute(r *mux.Router) { func addAssetsPath(r *mux.Router, assetPath string) { if _, err := os.Stat(assetPath); err != nil { + //nolint:forbidigo panic(fmt.Sprintf("ERROR: unable to stat %s: %v", assetPath, err)) } r.Methods("GET").PathPrefix("/").Handler(http.StripPrefix(*flagBasePath, http.FileServer(http.Dir(assetPath)))) diff --git a/file_test.go b/file_test.go index 9d1aa94d..e69fb53f 100644 --- a/file_test.go +++ b/file_test.go @@ -13,21 +13,19 @@ import ( ) // mockFile creates an imagecashletter file -func mockFile() *File { +func mockFile(t *testing.T) *File { f := NewFile() f.SetHeader(mockFileHeader()) clh := mockCashLetterHeader() mockCashLetter := NewCashLetter(clh) mockCashLetter.CashLetterControl = mockCashLetterControl() f.AddCashLetter(mockCashLetter) - if err := f.Create(); err != nil { - panic(err) - } + require.NoError(t, f.Create()) return f } func TestFileCreate(t *testing.T) { - file := mockFile() + file := mockFile(t) require.NoError(t, file.Validate()) } diff --git a/reader_test.go b/reader_test.go index 5e770a03..67b7c9eb 100644 --- a/reader_test.go +++ b/reader_test.go @@ -924,7 +924,7 @@ const multipleBundles = `0135T231380104121042882201810101237NCitadel W 900000010000001400000000200000000000002 201810100 9900000200000038000000280000000000400000 0 ` -const depositTicketAsCredit = `0135T231380104121042882201810101237NCitadel Wells Fargo US +const depositTicketAsCredit = `0135T123456789123456789201810101237NCitadel Wells Fargo US 100123138010412104288220181010201810101237IGA1 Contact Name 5558675552 62 123456789 031300012 5558881000000001000001 G101 200123138010412104288220181010201810109999 1 01 From 76cbd5278ef01e1cd820bbd4e423bc40162f67d7 Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Wed, 10 Apr 2024 12:07:06 -0600 Subject: [PATCH 5/6] update go.mod version --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index a68d3854..f7c363a2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/moov-io/imagecashletter -go 1.22 +go 1.22.2 require ( github.com/antihax/optional v1.0.0 From 2b325a3c8aeca16a9ad2d4d37c6e1672fae03c0a Mon Sep 17 00:00:00 2001 From: Daniel Tonks Date: Thu, 11 Apr 2024 10:19:51 -0600 Subject: [PATCH 6/6] fix build --- go.mod | 2 +- go.sum | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/go.mod b/go.mod index f7c363a2..bfae777d 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/moov-io/imagecashletter -go 1.22.2 +go 1.20 require ( github.com/antihax/optional v1.0.0 diff --git a/go.sum b/go.sum index 07f2b23e..6688e278 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,4 @@ github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= -github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/antihax/optional v1.0.0 h1:xK2lYat7ZLaVVcIuj82J8kIro4V6kDe0AUDFboUCwcg= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -18,13 +17,11 @@ github.com/go-kit/log v0.2.1/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBj github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/moov-io/base v0.48.5 h1:QaTyTo6eFFFV35R9l/GdePQN40IJti9knD5hqdWPnnM= @@ -42,7 +39,6 @@ github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3c github.com/rickar/cal/v2 v2.1.13 h1:FENBPXxDPyL1OWGf9ZdpWGcEiGoSjt0UZED8VOxvK0c= github.com/rickar/cal/v2 v2.1.13/go.mod h1:/fdlMcx7GjPlIBibMzOM9gMvDBsrK+mOtRXdTzUqV/A= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= -github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/vincent-petithory/dataurl v1.0.0 h1:cXw+kPto8NLuJtlMsI152irrVw9fRDX8AbShPRpg2CI= @@ -87,6 +83,5 @@ google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGm google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= -gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=