From 74c492731cbc3dcbe7341250162ed3886ab74322 Mon Sep 17 00:00:00 2001 From: Jose Date: Mon, 22 May 2023 13:01:52 -0500 Subject: [PATCH 1/6] adding ValidateOpts --- checkDetail.go | 10 ++++++-- checkDetail_test.go | 9 +++++++ cmd/writeImageCashLetter/main.go | 40 ++++++++++++++++++++++++++++++++ file.go | 38 ++++++++++++++++++++++++++++++ reader.go | 2 +- returnDetail.go | 10 ++++++-- returnDetail_test.go | 9 +++++++ 7 files changed, 113 insertions(+), 5 deletions(-) diff --git a/checkDetail.go b/checkDetail.go index b01bb9ba..57c3c37f 100644 --- a/checkDetail.go +++ b/checkDetail.go @@ -243,7 +243,13 @@ func (cd *CheckDetail) String() string { // Validate performs imagecashletter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. -func (cd *CheckDetail) Validate() error { +func (cd *CheckDetail) Validate(opts ...*ValidateOpts) error { + + var opt *ValidateOpts + if len(opts) > 0 { + opt = opts[0] + } + if err := cd.fieldInclusion(); err != nil { return err } @@ -284,7 +290,7 @@ func (cd *CheckDetail) Validate() error { } } // Conditional - if cd.ArchiveTypeIndicator != "" { + if cd.ArchiveTypeIndicator != "" && opt.IsArchiveTypeIndicator() { if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()} } diff --git a/checkDetail_test.go b/checkDetail_test.go index 2a4f6c34..623a6a8d 100644 --- a/checkDetail_test.go +++ b/checkDetail_test.go @@ -294,6 +294,15 @@ func TestCDArchiveTypeIndicator(t *testing.T) { } } +// TestCDArchiveTypeIndicatorWithValidationOption validation +func TestCDArchiveTypeIndicatorWithValidationOption(t *testing.T) { + cd := mockCheckDetail() + cd.ArchiveTypeIndicator = "W" + if err := cd.Validate(&ValidateOpts{ArchiveTypeIndicator: false}); err != nil { + t.Errorf("%T: %s", err, err) + } +} + // Field Inclusion // TestCDFIRecordType validation diff --git a/cmd/writeImageCashLetter/main.go b/cmd/writeImageCashLetter/main.go index 023f95f3..09d3e532 100644 --- a/cmd/writeImageCashLetter/main.go +++ b/cmd/writeImageCashLetter/main.go @@ -20,6 +20,12 @@ var ( // output formats flagJson = flag.Bool("json", false, "Output file in json") + + flagPretty = flag.Bool("pretty", false, "Display all values in their human readable format") + flagPrettyAmounts = flag.Bool("pretty.amounts", false, "Display human readable amounts instead of exact values") + + flagSkipValidation = flag.Bool("skip-validation", false, "Skip all validation checks") + flagValidateOpts = flag.String("validate", "", "Path to config file in json format to enable validation opts") ) // main creates an ICL File with 2 CashLetters @@ -72,6 +78,12 @@ func write(path string) { file := imagecashletter.NewFile() file.SetHeader(fh) + // Read validation options from the command + validateOpts := readValidationOpts(*flagValidateOpts) + if validateOpts != nil { + file.SetValidation(validateOpts) + } + // Create 4 CashLetters for i := 0; i < 4; i++ { @@ -284,3 +296,31 @@ func write(path string) { fmt.Printf("Wrote %s\n", path) } + +func readValidationOpts(path string) *imagecashletter.ValidateOpts { + if path != "" { + // read config file + bs, readErr := os.ReadFile(path) + if readErr != nil { + fmt.Printf("ERROR: reading validate opts failed: %v\n", readErr) + os.Exit(1) + } + + var opts imagecashletter.ValidateOpts + if err := json.Unmarshal(bs, &opts); err != nil { + fmt.Printf("ERROR: unmarshal of validate opts failed: %v\n", err) + os.Exit(1) + } + if *flagSkipValidation { + opts.SkipAll = true + } + return &opts + } + + if *flagSkipValidation { + var opts imagecashletter.ValidateOpts + opts.SkipAll = true + } + + return nil +} diff --git a/file.go b/file.go index e7c743e5..ce9c45e1 100644 --- a/file.go +++ b/file.go @@ -91,6 +91,15 @@ var ( msgFileCredit = "Credit outside of cash letter" ) +// ValidateOpts contains specific overrides from the default set of validations +type ValidateOpts struct { + // SkipAll will disable all validation checks of a File. It has no effect when set on records. + SkipAll bool `json:"skipAll"` + + // ArchiveTypeIndicator can be set to enable archiveTypeIndicator validation + ArchiveTypeIndicator bool `json:"ArchiveTypeIndicator"` +} + // FileError is an error describing issues validating a file type FileError struct { FieldName string @@ -119,6 +128,8 @@ type File struct { Bundles []Bundle `json:"bundle,omitempty"` // FileControl is an imagecashletter FileControl Control FileControl `json:"fileControl"` + + validateOpts *ValidateOpts } // NewFile constructs a file template with a FileHeader and FileControl. @@ -322,3 +333,30 @@ func (f *File) setRecordTypes() { } f.Control.setRecordType() } + +// SetValidation stores ValidateOpts +func (f *File) SetValidation(opts *ValidateOpts) { + if f == nil || opts == nil { + return + } + + f.validateOpts = opts +} + +// ValidateOpts returns Validation option +func (f *File) ValidateOpts() *ValidateOpts { + return f.validateOpts +} + +// IsArchiveTypeIndicator indicate to enable ArchiveTypeIndicator validation +func (v *ValidateOpts) IsArchiveTypeIndicator() bool { + if v == nil { + return true + } + + if v.SkipAll || v.ArchiveTypeIndicator == false { + return false + } + + return true +} diff --git a/reader.go b/reader.go index cd105cf9..d338dc30 100644 --- a/reader.go +++ b/reader.go @@ -384,7 +384,7 @@ func (r *Reader) parseCheckDetail() error { cd := new(CheckDetail) cd.Parse(r.decodeLine(r.line)) // Ensure valid CheckDetail - if err := cd.Validate(); err != nil { + if err := cd.Validate(r.File.ValidateOpts()); err != nil { return r.error(err) } // Add CheckDetail diff --git a/returnDetail.go b/returnDetail.go index c574cd5c..69fcd712 100644 --- a/returnDetail.go +++ b/returnDetail.go @@ -265,7 +265,13 @@ func (rd *ReturnDetail) String() string { // Validate performs image cash letter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. -func (rd *ReturnDetail) Validate() error { +func (rd *ReturnDetail) Validate(opts ...*ValidateOpts) error { + + var opt *ValidateOpts + if len(opts) > 0 { + opt = opts[0] + } + if err := rd.fieldInclusion(); err != nil { return err } @@ -288,7 +294,7 @@ func (rd *ReturnDetail) Validate() error { return &FieldError{FieldName: "ReturnNotificationIndicator", Value: rd.ReturnNotificationIndicatorField(), Msg: err.Error()} } } - if rd.ArchiveTypeIndicator != "" { + if rd.ArchiveTypeIndicator != "" && opt.IsArchiveTypeIndicator() { if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()} } diff --git a/returnDetail_test.go b/returnDetail_test.go index 573d3c9a..a0255443 100644 --- a/returnDetail_test.go +++ b/returnDetail_test.go @@ -248,6 +248,15 @@ func TestRDArchiveTypeIndicator(t *testing.T) { } } +// TestRDArchiveTypeIndicatorWithValidationOption validation +func TestRDArchiveTypeIndicatorWithValidationOption(t *testing.T) { + rd := mockReturnDetail() + rd.ArchiveTypeIndicator = "W" + if err := rd.Validate(&ValidateOpts{ArchiveTypeIndicator: false}); err != nil { + t.Errorf("%T: %s", err, err) + } +} + // TestRDTimesReturned validation func TestRDTimesReturned(t *testing.T) { rd := mockReturnDetail() From 1aa2813863669fb122a8825d9b01f56248796fab Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 23 May 2023 09:55:39 -0500 Subject: [PATCH 2/6] updating naming --- checkDetail.go | 2 +- checkDetail_test.go | 2 +- cmd/writeImageCashLetter/main.go | 4 ++-- file.go | 17 ++--------------- returnDetail.go | 2 +- returnDetail_test.go | 2 +- 6 files changed, 8 insertions(+), 21 deletions(-) diff --git a/checkDetail.go b/checkDetail.go index 57c3c37f..208b2c14 100644 --- a/checkDetail.go +++ b/checkDetail.go @@ -290,7 +290,7 @@ func (cd *CheckDetail) Validate(opts ...*ValidateOpts) error { } } // Conditional - if cd.ArchiveTypeIndicator != "" && opt.IsArchiveTypeIndicator() { + if cd.ArchiveTypeIndicator != "" && !(opt != nil && opt.AllowInvalidArchiveTypeIndicator) { if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()} } diff --git a/checkDetail_test.go b/checkDetail_test.go index 623a6a8d..16489016 100644 --- a/checkDetail_test.go +++ b/checkDetail_test.go @@ -298,7 +298,7 @@ func TestCDArchiveTypeIndicator(t *testing.T) { func TestCDArchiveTypeIndicatorWithValidationOption(t *testing.T) { cd := mockCheckDetail() cd.ArchiveTypeIndicator = "W" - if err := cd.Validate(&ValidateOpts{ArchiveTypeIndicator: false}); err != nil { + if err := cd.Validate(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { t.Errorf("%T: %s", err, err) } } diff --git a/cmd/writeImageCashLetter/main.go b/cmd/writeImageCashLetter/main.go index 09d3e532..d8da5986 100644 --- a/cmd/writeImageCashLetter/main.go +++ b/cmd/writeImageCashLetter/main.go @@ -21,8 +21,8 @@ var ( // output formats flagJson = flag.Bool("json", false, "Output file in json") - flagPretty = flag.Bool("pretty", false, "Display all values in their human readable format") - flagPrettyAmounts = flag.Bool("pretty.amounts", false, "Display human readable amounts instead of exact values") + //flagPretty = flag.Bool("pretty", false, "Display all values in their human readable format") + //flagPrettyAmounts = flag.Bool("pretty.amounts", false, "Display human readable amounts instead of exact values") flagSkipValidation = flag.Bool("skip-validation", false, "Skip all validation checks") flagValidateOpts = flag.String("validate", "", "Path to config file in json format to enable validation opts") diff --git a/file.go b/file.go index ce9c45e1..9ca08aeb 100644 --- a/file.go +++ b/file.go @@ -96,8 +96,8 @@ type ValidateOpts struct { // SkipAll will disable all validation checks of a File. It has no effect when set on records. SkipAll bool `json:"skipAll"` - // ArchiveTypeIndicator can be set to enable archiveTypeIndicator validation - ArchiveTypeIndicator bool `json:"ArchiveTypeIndicator"` + // AllowInvalidArchiveTypeIndicator can be set to disable archiveTypeIndicator validation + AllowInvalidArchiveTypeIndicator bool `json:"ArchiveTypeIndicator"` } // FileError is an error describing issues validating a file @@ -347,16 +347,3 @@ func (f *File) SetValidation(opts *ValidateOpts) { func (f *File) ValidateOpts() *ValidateOpts { return f.validateOpts } - -// IsArchiveTypeIndicator indicate to enable ArchiveTypeIndicator validation -func (v *ValidateOpts) IsArchiveTypeIndicator() bool { - if v == nil { - return true - } - - if v.SkipAll || v.ArchiveTypeIndicator == false { - return false - } - - return true -} diff --git a/returnDetail.go b/returnDetail.go index 69fcd712..30cce6f3 100644 --- a/returnDetail.go +++ b/returnDetail.go @@ -294,7 +294,7 @@ func (rd *ReturnDetail) Validate(opts ...*ValidateOpts) error { return &FieldError{FieldName: "ReturnNotificationIndicator", Value: rd.ReturnNotificationIndicatorField(), Msg: err.Error()} } } - if rd.ArchiveTypeIndicator != "" && opt.IsArchiveTypeIndicator() { + if rd.ArchiveTypeIndicator != "" && !(opt != nil && opt.AllowInvalidArchiveTypeIndicator) { if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()} } diff --git a/returnDetail_test.go b/returnDetail_test.go index a0255443..caa33a02 100644 --- a/returnDetail_test.go +++ b/returnDetail_test.go @@ -252,7 +252,7 @@ func TestRDArchiveTypeIndicator(t *testing.T) { func TestRDArchiveTypeIndicatorWithValidationOption(t *testing.T) { rd := mockReturnDetail() rd.ArchiveTypeIndicator = "W" - if err := rd.Validate(&ValidateOpts{ArchiveTypeIndicator: false}); err != nil { + if err := rd.Validate(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { t.Errorf("%T: %s", err, err) } } From 64bf1e196cab6aa4d18b5a813999cc1808f0f85c Mon Sep 17 00:00:00 2001 From: Jose Date: Tue, 23 May 2023 10:10:55 -0500 Subject: [PATCH 3/6] adding test case --- cmd/writeImageCashLetter/main.go | 1 + cmd/writeImageCashLetter/main_test.go | 35 +++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/cmd/writeImageCashLetter/main.go b/cmd/writeImageCashLetter/main.go index d8da5986..abcfef45 100644 --- a/cmd/writeImageCashLetter/main.go +++ b/cmd/writeImageCashLetter/main.go @@ -320,6 +320,7 @@ func readValidationOpts(path string) *imagecashletter.ValidateOpts { if *flagSkipValidation { var opts imagecashletter.ValidateOpts opts.SkipAll = true + return &opts } return nil diff --git a/cmd/writeImageCashLetter/main_test.go b/cmd/writeImageCashLetter/main_test.go index e423bca6..2cb605ce 100644 --- a/cmd/writeImageCashLetter/main_test.go +++ b/cmd/writeImageCashLetter/main_test.go @@ -1,8 +1,11 @@ package main import ( + "encoding/json" "os" "testing" + + "github.com/moov-io/imagecashletter" ) // TestFileCreate tests creating an ICL File @@ -36,3 +39,35 @@ func testFileWrite(t testing.TB) { t.Fatal("expected non-empty file") } } + +// TestReadValidationOpts +func TestReadValidationOpts(t *testing.T) { + tmp, err := os.CreateTemp("", "config") + if err != nil { + t.Fatal(err.Error()) + } + defer os.Remove(tmp.Name()) + + f, err := os.Create(tmp.Name()) + if err != nil { + t.Fatal(err.Error()) + } + + buf, _ := json.Marshal(&imagecashletter.ValidateOpts{}) + f.Write(buf) + f.Close() + + if opt := readValidationOpts(tmp.Name()); opt == nil { + t.Fatal("unable to create config") + } + + if opt := readValidationOpts(""); opt != nil { + t.Fatal("does not to create any config") + } + + *flagSkipValidation = true + if opt := readValidationOpts(""); opt == nil { + t.Fatal("unable to create config") + } + +} From 79642767b719c2a13f2f8892565586cd809c3021 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 31 May 2023 12:28:37 -0500 Subject: [PATCH 4/6] splitting validation and validation with opts functions --- checkDetail.go | 22 +++++++++++++--------- checkDetail_test.go | 2 +- file.go | 5 ++++- reader.go | 2 +- returnDetail.go | 20 ++++++++++++-------- returnDetail_test.go | 2 +- 6 files changed, 32 insertions(+), 21 deletions(-) diff --git a/checkDetail.go b/checkDetail.go index 208b2c14..1fd31203 100644 --- a/checkDetail.go +++ b/checkDetail.go @@ -243,12 +243,12 @@ func (cd *CheckDetail) String() string { // Validate performs imagecashletter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. -func (cd *CheckDetail) Validate(opts ...*ValidateOpts) error { +func (cd *CheckDetail) Validate() error { + return cd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior +} - var opt *ValidateOpts - if len(opts) > 0 { - opt = opts[0] - } +// ValidateWithOpts performs imagecashletter format rule checks with validate opts +func (cd *CheckDetail) ValidateWithOpts(opts ValidateOpts) error { if err := cd.fieldInclusion(); err != nil { return err @@ -289,12 +289,16 @@ func (cd *CheckDetail) Validate(opts ...*ValidateOpts) error { return &FieldError{FieldName: "CorrectionIndicator", Value: cd.CorrectionIndicatorField(), Msg: err.Error()} } } - // Conditional - if cd.ArchiveTypeIndicator != "" && !(opt != nil && opt.AllowInvalidArchiveTypeIndicator) { - if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil { - return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()} + + if !opts.SkipAll { + // Conditional + if cd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator { + if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil { + return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()} + } } } + return nil } diff --git a/checkDetail_test.go b/checkDetail_test.go index 16489016..8416b574 100644 --- a/checkDetail_test.go +++ b/checkDetail_test.go @@ -298,7 +298,7 @@ func TestCDArchiveTypeIndicator(t *testing.T) { func TestCDArchiveTypeIndicatorWithValidationOption(t *testing.T) { cd := mockCheckDetail() cd.ArchiveTypeIndicator = "W" - if err := cd.Validate(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { + if err := cd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { t.Errorf("%T: %s", err, err) } } diff --git a/file.go b/file.go index 9ca08aeb..cc30ca36 100644 --- a/file.go +++ b/file.go @@ -97,7 +97,7 @@ type ValidateOpts struct { SkipAll bool `json:"skipAll"` // AllowInvalidArchiveTypeIndicator can be set to disable archiveTypeIndicator validation - AllowInvalidArchiveTypeIndicator bool `json:"ArchiveTypeIndicator"` + AllowInvalidArchiveTypeIndicator bool `json:"allowInvalidArchiveType"` } // FileError is an error describing issues validating a file @@ -345,5 +345,8 @@ func (f *File) SetValidation(opts *ValidateOpts) { // ValidateOpts returns Validation option func (f *File) ValidateOpts() *ValidateOpts { + if f.validateOpts == nil { + return &ValidateOpts{} + } return f.validateOpts } diff --git a/reader.go b/reader.go index d338dc30..bf992eee 100644 --- a/reader.go +++ b/reader.go @@ -384,7 +384,7 @@ func (r *Reader) parseCheckDetail() error { cd := new(CheckDetail) cd.Parse(r.decodeLine(r.line)) // Ensure valid CheckDetail - if err := cd.Validate(r.File.ValidateOpts()); err != nil { + if err := cd.ValidateWithOpts(*r.File.ValidateOpts()); err != nil { return r.error(err) } // Add CheckDetail diff --git a/returnDetail.go b/returnDetail.go index 30cce6f3..e2c7ce5c 100644 --- a/returnDetail.go +++ b/returnDetail.go @@ -265,12 +265,12 @@ func (rd *ReturnDetail) String() string { // Validate performs image cash letter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. -func (rd *ReturnDetail) Validate(opts ...*ValidateOpts) error { +func (rd *ReturnDetail) Validate() error { + return rd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior +} - var opt *ValidateOpts - if len(opts) > 0 { - opt = opts[0] - } +// ValidateWithOpts performs imagecashletter format rule checks with validate opts +func (rd *ReturnDetail) ValidateWithOpts(opts ValidateOpts) error { if err := rd.fieldInclusion(); err != nil { return err @@ -294,11 +294,15 @@ func (rd *ReturnDetail) Validate(opts ...*ValidateOpts) error { return &FieldError{FieldName: "ReturnNotificationIndicator", Value: rd.ReturnNotificationIndicatorField(), Msg: err.Error()} } } - if rd.ArchiveTypeIndicator != "" && !(opt != nil && opt.AllowInvalidArchiveTypeIndicator) { - if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil { - return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()} + + if !opts.SkipAll { + if rd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator { + if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil { + return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()} + } } } + if rd.TimesReturnedField() != " " && rd.TimesReturnedField() != "" { if err := rd.isTimesReturned(rd.TimesReturned); err != nil { return &FieldError{FieldName: "TimesReturned", Value: rd.TimesReturnedField(), Msg: err.Error()} diff --git a/returnDetail_test.go b/returnDetail_test.go index caa33a02..a11ebbe5 100644 --- a/returnDetail_test.go +++ b/returnDetail_test.go @@ -252,7 +252,7 @@ func TestRDArchiveTypeIndicator(t *testing.T) { func TestRDArchiveTypeIndicatorWithValidationOption(t *testing.T) { rd := mockReturnDetail() rd.ArchiveTypeIndicator = "W" - if err := rd.Validate(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { + if err := rd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { t.Errorf("%T: %s", err, err) } } From 7c2ee0c4f3ae62084bac73bba13b7afa468b1b61 Mon Sep 17 00:00:00 2001 From: Jose Date: Wed, 31 May 2023 14:23:42 -0500 Subject: [PATCH 5/6] remov unused codes --- cmd/writeImageCashLetter/main.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/writeImageCashLetter/main.go b/cmd/writeImageCashLetter/main.go index abcfef45..ca97b22a 100644 --- a/cmd/writeImageCashLetter/main.go +++ b/cmd/writeImageCashLetter/main.go @@ -21,9 +21,6 @@ var ( // output formats flagJson = flag.Bool("json", false, "Output file in json") - //flagPretty = flag.Bool("pretty", false, "Display all values in their human readable format") - //flagPrettyAmounts = flag.Bool("pretty.amounts", false, "Display human readable amounts instead of exact values") - flagSkipValidation = flag.Bool("skip-validation", false, "Skip all validation checks") flagValidateOpts = flag.String("validate", "", "Path to config file in json format to enable validation opts") ) From d15b6eeed9175bf329536842c399570b377c6d3e Mon Sep 17 00:00:00 2001 From: Jose Date: Fri, 2 Jun 2023 12:29:25 -0500 Subject: [PATCH 6/6] updating validtion function --- checkDetail.go | 23 +++++++++++++---------- checkDetail_test.go | 3 ++- file.go | 3 --- reader.go | 6 +++++- returnDetail.go | 21 ++++++++++++--------- returnDetail_test.go | 3 ++- 6 files changed, 34 insertions(+), 25 deletions(-) diff --git a/checkDetail.go b/checkDetail.go index 1fd31203..801df42a 100644 --- a/checkDetail.go +++ b/checkDetail.go @@ -151,6 +151,8 @@ type CheckDetail struct { validator // converters is composed for imagecashletter to golang Converters converters + + validateOpts *ValidateOpts } // NewCheckDetail returns a new CheckDetail with default values for non exported fields @@ -167,6 +169,14 @@ func (cd *CheckDetail) setRecordType() { cd.recordType = "25" } +// SetValidation stores ValidateOpts on the CheckDetail which are to be used to override +func (cd *CheckDetail) SetValidation(opts *ValidateOpts) { + if cd == nil { + return + } + cd.validateOpts = opts +} + // Parse takes the input record string and parses the CheckDetail values func (cd *CheckDetail) Parse(record string) { if utf8.RuneCountInString(record) < 80 { @@ -244,12 +254,6 @@ func (cd *CheckDetail) String() string { // Validate performs imagecashletter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. func (cd *CheckDetail) Validate() error { - return cd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior -} - -// ValidateWithOpts performs imagecashletter format rule checks with validate opts -func (cd *CheckDetail) ValidateWithOpts(opts ValidateOpts) error { - if err := cd.fieldInclusion(); err != nil { return err } @@ -289,10 +293,9 @@ func (cd *CheckDetail) ValidateWithOpts(opts ValidateOpts) error { return &FieldError{FieldName: "CorrectionIndicator", Value: cd.CorrectionIndicatorField(), Msg: err.Error()} } } - - if !opts.SkipAll { - // Conditional - if cd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator { + // Conditional + if cd.ArchiveTypeIndicator != "" { + if cd.validateOpts == nil || cd.validateOpts.SkipAll || !cd.validateOpts.AllowInvalidArchiveTypeIndicator { if err := cd.isArchiveTypeIndicator(cd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: cd.ArchiveTypeIndicator, Msg: err.Error()} } diff --git a/checkDetail_test.go b/checkDetail_test.go index 8416b574..da033272 100644 --- a/checkDetail_test.go +++ b/checkDetail_test.go @@ -298,7 +298,8 @@ func TestCDArchiveTypeIndicator(t *testing.T) { func TestCDArchiveTypeIndicatorWithValidationOption(t *testing.T) { cd := mockCheckDetail() cd.ArchiveTypeIndicator = "W" - if err := cd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { + cd.SetValidation(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}) + if err := cd.Validate(); err != nil { t.Errorf("%T: %s", err, err) } } diff --git a/file.go b/file.go index cc30ca36..d8fa2ac8 100644 --- a/file.go +++ b/file.go @@ -345,8 +345,5 @@ func (f *File) SetValidation(opts *ValidateOpts) { // ValidateOpts returns Validation option func (f *File) ValidateOpts() *ValidateOpts { - if f.validateOpts == nil { - return &ValidateOpts{} - } return f.validateOpts } diff --git a/reader.go b/reader.go index bf992eee..40839ead 100644 --- a/reader.go +++ b/reader.go @@ -383,8 +383,10 @@ func (r *Reader) parseCheckDetail() error { } cd := new(CheckDetail) cd.Parse(r.decodeLine(r.line)) + // setting validate opts based on file + cd.SetValidation(r.File.ValidateOpts()) // Ensure valid CheckDetail - if err := cd.ValidateWithOpts(*r.File.ValidateOpts()); err != nil { + if err := cd.Validate(); err != nil { return r.error(err) } // Add CheckDetail @@ -454,6 +456,8 @@ func (r *Reader) parseReturnDetail() error { } rd := new(ReturnDetail) rd.Parse(r.decodeLine(r.line)) + // setting validate opts based on file + rd.SetValidation(r.File.ValidateOpts()) if err := rd.Validate(); err != nil { return r.error(err) } diff --git a/returnDetail.go b/returnDetail.go index e2c7ce5c..c3edcee3 100644 --- a/returnDetail.go +++ b/returnDetail.go @@ -147,6 +147,8 @@ type ReturnDetail struct { validator // converters is composed for image cash letter to golang Converters converters + + validateOpts *ValidateOpts } // CustomerReturnCode are customer return reason codes as defined in Part 6.2 of the ANSI X9.100-188-2018 Return @@ -175,6 +177,14 @@ func (rd *ReturnDetail) setRecordType() { rd.recordType = "31" } +// SetValidation stores ValidateOpts on the CheckDetail which are to be used to override +func (rd *ReturnDetail) SetValidation(opts *ValidateOpts) { + if rd == nil { + return + } + rd.validateOpts = opts +} + // Parse takes the input record string and parses the ReturnDetail values func (rd *ReturnDetail) Parse(record string) { if utf8.RuneCountInString(record) < 72 { @@ -266,11 +276,6 @@ func (rd *ReturnDetail) String() string { // Validate performs image cash letter format rule checks on the record and returns an error if not Validated // The first error encountered is returned and stops the parsing. func (rd *ReturnDetail) Validate() error { - return rd.ValidateWithOpts(ValidateOpts{}) // all options should be defined so the default value (false) results in the default (current) behavior -} - -// ValidateWithOpts performs imagecashletter format rule checks with validate opts -func (rd *ReturnDetail) ValidateWithOpts(opts ValidateOpts) error { if err := rd.fieldInclusion(); err != nil { return err @@ -294,15 +299,13 @@ func (rd *ReturnDetail) ValidateWithOpts(opts ValidateOpts) error { return &FieldError{FieldName: "ReturnNotificationIndicator", Value: rd.ReturnNotificationIndicatorField(), Msg: err.Error()} } } - - if !opts.SkipAll { - if rd.ArchiveTypeIndicator != "" && !opts.AllowInvalidArchiveTypeIndicator { + if rd.ArchiveTypeIndicator != "" { + if rd.validateOpts == nil || rd.validateOpts.SkipAll || !rd.validateOpts.AllowInvalidArchiveTypeIndicator { if err := rd.isArchiveTypeIndicator(rd.ArchiveTypeIndicator); err != nil { return &FieldError{FieldName: "ArchiveTypeIndicator", Value: rd.ArchiveTypeIndicatorField(), Msg: err.Error()} } } } - if rd.TimesReturnedField() != " " && rd.TimesReturnedField() != "" { if err := rd.isTimesReturned(rd.TimesReturned); err != nil { return &FieldError{FieldName: "TimesReturned", Value: rd.TimesReturnedField(), Msg: err.Error()} diff --git a/returnDetail_test.go b/returnDetail_test.go index a11ebbe5..f8cb107f 100644 --- a/returnDetail_test.go +++ b/returnDetail_test.go @@ -252,7 +252,8 @@ func TestRDArchiveTypeIndicator(t *testing.T) { func TestRDArchiveTypeIndicatorWithValidationOption(t *testing.T) { rd := mockReturnDetail() rd.ArchiveTypeIndicator = "W" - if err := rd.ValidateWithOpts(ValidateOpts{AllowInvalidArchiveTypeIndicator: true}); err != nil { + rd.SetValidation(&ValidateOpts{AllowInvalidArchiveTypeIndicator: true}) + if err := rd.Validate(); err != nil { t.Errorf("%T: %s", err, err) } }