Skip to content

Commit c0c5c78

Browse files
authored
cashLetterControl: settlement date should not be mandatory (#319)
1 parent 0435ccd commit c0c5c78

File tree

4 files changed

+48
-23
lines changed

4 files changed

+48
-23
lines changed

Diff for: cashLetter.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ func (cl *CashLetter) Validate() error {
106106
}
107107
}
108108

109-
if err := cl.CashLetterControl.Validate(cl.CashLetterHeader.CollectionTypeIndicator); err != nil {
109+
if err := cl.CashLetterControl.Validate(); err != nil {
110110
return err
111111
}
112112

Diff for: cashLetterControl.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ func (clc *CashLetterControl) String() string {
128128

129129
// Validate performs imagecashletter format rule checks on the record and returns an error if not Validated
130130
// The first error encountered is returned and stops the parsing.
131-
func (clc *CashLetterControl) Validate(collectionTypeIndicator string) error {
132-
if err := clc.fieldInclusion(collectionTypeIndicator); err != nil {
131+
func (clc *CashLetterControl) Validate() error {
132+
if err := clc.fieldInclusion(); err != nil {
133133
return err
134134
}
135135
if clc.recordType != "90" {
@@ -149,7 +149,7 @@ func (clc *CashLetterControl) Validate(collectionTypeIndicator string) error {
149149

150150
// fieldInclusion validate mandatory fields are not default values. If fields are
151151
// invalid the Electronic Exchange will be returned.
152-
func (clc *CashLetterControl) fieldInclusion(collectionTypeIndicator string) error {
152+
func (clc *CashLetterControl) fieldInclusion() error {
153153
if clc.recordType == "" {
154154
return &FieldError{FieldName: "recordType",
155155
Value: clc.recordType,
@@ -165,12 +165,15 @@ func (clc *CashLetterControl) fieldInclusion(collectionTypeIndicator string) err
165165
Value: clc.CashLetterTotalAmountField(),
166166
Msg: msgFieldInclusion + ", did you use CashLetterControl()?"}
167167
}
168-
// If the type of the cash letter control is `Return`, we do not require to have this field present.
169-
if clc.SettlementDate.IsZero() && !isReturnCollectionType(collectionTypeIndicator) {
170-
return &FieldError{FieldName: "SettlementDate",
171-
Value: clc.SettlementDate.String(),
172-
Msg: msgFieldInclusion + ", did you use CashLetterControl()?"}
168+
169+
// optional field - if present, year must be between 1993 and 9999
170+
if date := clc.SettlementDate; !date.IsZero() {
171+
if date.Year() < 1993 || date.Year() > 9999 {
172+
return &FieldError{FieldName: "SettlementDate",
173+
Value: clc.SettlementDateField(), Msg: msgInvalidDate + ": year must be between 1993 and 9999"}
174+
}
173175
}
176+
174177
return nil
175178
}
176179

Diff for: cashLetterControl_test.go

+33-11
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func mockCashLetterControl() *CashLetterControl {
2828
// TestMockCashLetterControl creates a CashLetterControl
2929
func TestMockCashLetterControl(t *testing.T) {
3030
clc := mockCashLetterControl()
31-
require.NoError(t, clc.Validate("01"))
31+
require.NoError(t, clc.Validate())
3232
require.Equal(t, "90", clc.recordType)
3333
require.Equal(t, 1, clc.CashLetterBundleCount)
3434
require.Equal(t, 7, clc.CashLetterItemsCount)
@@ -45,7 +45,7 @@ func TestParseCashLetterControl(t *testing.T) {
4545
r.line = line
4646
clh := mockCashLetterHeader()
4747
r.addCurrentCashLetter(NewCashLetter(clh))
48-
require.NoError(t, r.parseCashLetterControl("03"))
48+
require.NoError(t, r.parseCashLetterControl())
4949
record := r.currentCashLetter.CashLetterControl
5050

5151
require.Equal(t, "90", record.recordType)
@@ -66,7 +66,7 @@ func testCLCString(t testing.TB) {
6666
r.line = line
6767
clh := mockCashLetterHeader()
6868
r.addCurrentCashLetter(NewCashLetter(clh))
69-
require.NoError(t, r.parseCashLetterControl("01"))
69+
require.NoError(t, r.parseCashLetterControl())
7070
record := r.currentCashLetter.CashLetterControl
7171
require.Equal(t, line, record.String())
7272
}
@@ -88,7 +88,7 @@ func BenchmarkCLCString(b *testing.B) {
8888
func TestCLCRecordType(t *testing.T) {
8989
clc := mockCashLetterControl()
9090
clc.recordType = "00"
91-
err := clc.Validate("01")
91+
err := clc.Validate()
9292
var fieldErr *FieldError
9393
require.ErrorAs(t, err, &fieldErr)
9494
require.Equal(t, "recordType", fieldErr.FieldName)
@@ -98,7 +98,7 @@ func TestCLCRecordType(t *testing.T) {
9898
func TestECEInstitutionName(t *testing.T) {
9999
clc := mockCashLetterControl()
100100
clc.ECEInstitutionName = "®©"
101-
err := clc.Validate("01")
101+
err := clc.Validate()
102102
var fieldErr *FieldError
103103
require.ErrorAs(t, err, &fieldErr)
104104
require.Equal(t, "ECEInstitutionName", fieldErr.FieldName)
@@ -108,7 +108,7 @@ func TestECEInstitutionName(t *testing.T) {
108108
func TestCLCCreditTotalIndicator(t *testing.T) {
109109
clc := mockCashLetterControl()
110110
clc.CreditTotalIndicator = 9
111-
err := clc.Validate("01")
111+
err := clc.Validate()
112112
var fieldErr *FieldError
113113
require.ErrorAs(t, err, &fieldErr)
114114
require.Equal(t, "CreditTotalIndicator", fieldErr.FieldName)
@@ -118,7 +118,7 @@ func TestCLCCreditTotalIndicator(t *testing.T) {
118118
func TestCLCFieldInclusionRecordType(t *testing.T) {
119119
clc := mockCashLetterControl()
120120
clc.recordType = ""
121-
err := clc.Validate("01")
121+
err := clc.Validate()
122122
var fieldErr *FieldError
123123
require.ErrorAs(t, err, &fieldErr)
124124
require.Equal(t, "recordType", fieldErr.FieldName)
@@ -128,7 +128,7 @@ func TestCLCFieldInclusionRecordType(t *testing.T) {
128128
func TestFieldInclusionCashLetterItemsCount(t *testing.T) {
129129
clc := mockCashLetterControl()
130130
clc.CashLetterItemsCount = 0
131-
err := clc.Validate("01")
131+
err := clc.Validate()
132132
var fieldErr *FieldError
133133
require.ErrorAs(t, err, &fieldErr)
134134
require.Equal(t, "CashLetterItemsCount", fieldErr.FieldName)
@@ -138,7 +138,7 @@ func TestFieldInclusionCashLetterItemsCount(t *testing.T) {
138138
func TestFieldInclusionCashLetterTotalAmount(t *testing.T) {
139139
clc := mockCashLetterControl()
140140
clc.CashLetterTotalAmount = 0
141-
err := clc.Validate("01")
141+
err := clc.Validate()
142142
var fieldErr *FieldError
143143
require.ErrorAs(t, err, &fieldErr)
144144
require.Equal(t, "CashLetterTotalAmount", fieldErr.FieldName)
@@ -147,8 +147,9 @@ func TestFieldInclusionCashLetterTotalAmount(t *testing.T) {
147147
// TestFieldInclusionSettlementDate validates FieldInclusion
148148
func TestFieldInclusionRecordTypeSettlementDate(t *testing.T) {
149149
clc := mockCashLetterControl()
150-
clc.SettlementDate = time.Time{}
151-
err := clc.Validate("01")
150+
// if present (non-zero), SettlementDate.Year() must be between 1993 and 9999
151+
clc.SettlementDate = time.Date(40010, time.November, 9, 0, 0, 0, 0, time.UTC)
152+
err := clc.Validate()
152153
var fieldErr *FieldError
153154
require.ErrorAs(t, err, &fieldErr)
154155
require.Equal(t, "SettlementDate", fieldErr.FieldName)
@@ -162,3 +163,24 @@ func TestCashLetterControlRuneCountInString(t *testing.T) {
162163

163164
require.Equal(t, 0, clc.CashLetterBundleCount)
164165
}
166+
167+
func TestCashLetterControl_isReturnCollectionType(t *testing.T) {
168+
tests := []struct {
169+
collectionType string
170+
expected bool
171+
}{
172+
{"03", true},
173+
{"04", true},
174+
{"05", true},
175+
{"06", true},
176+
{"07", false},
177+
{"01", false},
178+
{"", false},
179+
}
180+
181+
for _, tt := range tests {
182+
t.Run(tt.collectionType, func(t *testing.T) {
183+
require.Equal(t, tt.expected, isReturnCollectionType(tt.collectionType))
184+
})
185+
}
186+
}

Diff for: reader.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ func (r *Reader) parseLine() error { //nolint:gocyclo
303303
if header == nil {
304304
return errors.New("missing CashLetterHeader")
305305
}
306-
if err := r.parseCashLetterControl(header.CollectionTypeIndicator); err != nil {
306+
if err := r.parseCashLetterControl(); err != nil {
307307
return err
308308
}
309309
if err := r.currentCashLetter.Validate(); err != nil {
@@ -707,15 +707,15 @@ func (r *Reader) parseRoutingNumberSummary() error {
707707
}
708708

709709
// parseCashLetterControl takes the input record string and parses the CashLetterControl values
710-
func (r *Reader) parseCashLetterControl(collectionTypeIndicator string) error {
710+
func (r *Reader) parseCashLetterControl() error {
711711
r.recordName = "CashLetterControl"
712712
if r.currentCashLetter.CashLetterHeader == nil {
713713
// CashLetterControl without a current CashLetter
714714
return r.error(&FileError{Msg: msgFileCashLetterControl})
715715
}
716716
r.currentCashLetter.GetControl().Parse(r.decodeLine(r.line))
717717
// Ensure valid CashLetterControl
718-
if err := r.currentCashLetter.GetControl().Validate(collectionTypeIndicator); err != nil {
718+
if err := r.currentCashLetter.GetControl().Validate(); err != nil {
719719
return r.error(err)
720720
}
721721
return nil

0 commit comments

Comments
 (0)