diff --git a/batchSHR.go b/batchSHR.go index 43bf020a4..71a020618 100644 --- a/batchSHR.go +++ b/batchSHR.go @@ -58,16 +58,21 @@ func (batch *BatchSHR) Validate() error { return batch.Error("StandardEntryClassCode", ErrBatchSECType, SHR) } - // SHR detail entries can only be a debit, ServiceClassCode must allow debits + // SHR entries can be debit, credit or mixed ServiceClassCode switch batch.Header.ServiceClassCode { - case MixedDebitsAndCredits, CreditsOnly: + case MixedDebitsAndCredits, CreditsOnly, DebitsOnly: + // do nothing + default: return batch.Error("ServiceClassCode", ErrBatchServiceClassCode, batch.Header.ServiceClassCode) } for _, entry := range batch.Entries { - // SHR detail entries must be a debit - if entry.CreditOrDebit() != "D" { - return batch.Error("TransactionCode", ErrBatchDebitOnly, entry.TransactionCode) + // SHR detail entries can be debit or credit + switch entry.CreditOrDebit() { + case "C", "D": + // do nothing + default: + return batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode) } if err := entry.isCardTransactionType(entry.DiscretionaryData); err != nil { return batch.Error("CardTransactionType", ErrBatchInvalidCardTransactionType, entry.DiscretionaryData) diff --git a/batchSHR_test.go b/batchSHR_test.go index b4edf5ebc..ab077e6dd 100644 --- a/batchSHR_test.go +++ b/batchSHR_test.go @@ -18,6 +18,7 @@ package ach import ( + "path/filepath" "testing" "github.com/moov-io/base" @@ -220,22 +221,20 @@ func BenchmarkBatchSHRAutomatedAccountingAdvices(b *testing.B) { } } -// testBatchSHRTransactionCode validates BatchSHR TransactionCode is not a credit +// testBatchSHRTransactionCode validates BatchSHR TransactionCode is credit or debit func testBatchSHRTransactionCode(t testing.TB) { mockBatch := mockBatchSHR(t) - mockBatch.GetEntries()[0].TransactionCode = CheckingCredit + mockBatch.GetEntries()[0].TransactionCode = AutomatedAccountingAdvices err := mockBatch.Create() - if !base.Match(err, ErrBatchDebitOnly) { - t.Errorf("%T: %s", err, err) - } + require.ErrorContains(t, err, "batch #1 (SHR) FieldError TransactionCode 280 is an invalid Transaction Code") } -// TestBatchSHRTransactionCode tests validating BatchSHR TransactionCode is not a credit +// TestBatchSHRTransactionCode tests validating BatchSHR TransactionCode is a credit or debit func TestBatchSHRTransactionCode(t *testing.T) { testBatchSHRTransactionCode(t) } -// BenchmarkBatchSHRTransactionCode benchmarks validating BatchSHR TransactionCode is not a credit +// BenchmarkBatchSHRTransactionCode benchmarks validating BatchSHR TransactionCode is a credit or debit func BenchmarkBatchSHRTransactionCode(b *testing.B) { b.ReportAllocs() for i := 0; i < b.N; i++ { @@ -568,3 +567,23 @@ func TestBatchSHRTerminalState(t *testing.T) { t.Errorf("%T: %s", err, err) } } + +func TestBatchSHR_AcceptCredits(t *testing.T) { + file, err := ReadFile(filepath.Join("test", "testdata", "shr-credit.ach")) + require.ErrorContains(t, err, "*ach.FieldError CardExpirationDate 00 is an invalid month") + require.Len(t, file.Batches, 1) + + b := file.Batches[0] + require.ErrorContains(t, b.Create(), "CardExpirationDate 00 is an invalid month") + require.ErrorContains(t, b.Validate(), "CardExpirationDate 00 is an invalid month") + + bh := b.GetHeader() + require.Equal(t, SHR, bh.StandardEntryClassCode) + require.Equal(t, MixedDebitsAndCredits, bh.ServiceClassCode) + + entries := b.GetEntries() + require.Len(t, entries, 14) + + require.NoError(t, file.Create()) + require.ErrorContains(t, err, "*ach.FieldError CardExpirationDate 00 is an invalid month") +} diff --git a/test/testdata/shr-credit.ach b/test/testdata/shr-credit.ach new file mode 100644 index 000000000..ccbd33373 --- /dev/null +++ b/test/testdata/shr-credit.ach @@ -0,0 +1,32 @@ +101 041205259 6910001341311201446C094101Silverlake Bank & TrustASF APPLICATION SUPERVI +5200FDR DEBIT CARD 1470535472SHRVISA DEBIT1308221308220001111010170000033 +62204120525983133 0000002689000074692168200Adams Electric 131111010170008354 +702MVN3BV5969 000000915 HSN*HSN 265742136 800-284-3900 FL111010170008354 +62204120525983133 000000389800007441295822BAdams Electric 131111010170008433 +702E40VTL5533 000000914 O'REILLY #620 SAN ANTONIO TX111010170008433 +62204120525983133 000000059400007449280823DAdams Electric 131111010170008552 +702WMMKVM5999 00000091500000NBEAUTYFIRST #641002 SAN ANTONIO TX111010170008552 +62204120525983133 000001512400007444500826ZAdams Electric 131111010170008581 +7027JLPL15311 000000914 NORDSTROM DIRECT #0808 CEDAR RAPIDS IA111010170008581 +62204120525983133 00000054110000743079282S6Adams Electric 131111010170008597 +7026KQ8J05712 00000091400000NMATTFIRM GA 7999 HOUSTON TX111010170008597 +62204120525983133 000000250000007416407820HAdams Electric 131111010170008699 +7022E71KR3405 000000915 ENTERPRISE RENT-A-CAR SAN ANTONIO TX111010170008699 +62204120525983133 000001338700007444500836ZAdams Electric 131111010170008785 +702RX5G6D5310 000000915 STEIN-MART #0024 SAN ANTONIO TX111010170008785 +62204120525983133 000000025900007438894826NAdams Electric 131111010170008883 +702AVGY2W5251 000000915000000SUNSET RIDGE HOME & HD SAN ANTONIO TX111010170008883 +62204120525983133 0000004999000074610438203Adams Electric 131111010170008915 +702RFNPP94899 000000914 ONE TIME/DISH NETWORK 800-333-3474 CO111010170008915 +62204120525983133 000001251300007416407820HAdams Electric 131111010170008963 +7022E746G3405 000000915 ENTERPRISE RENT-A-CAR SAN ANTONIO TX111010170008963 +62204120525983133 000000185400007449280823DAdams Electric 131111010170009170 +702WMPNH47394 00000091400000NNATIONSRENT #316-L SAN ANTONIO TX111010170009170 +62204120525983133 000000172700007416407822LAdams Electric 131111010170009254 +702RQAP6G5310 000000915 TARGET 00010678 SAN ANTONIO TX111010170009254 +62204120525983133 0000002699000074455018115Adams Electric 131111010170009269 +70286H8HX5399 000000914045884TUESDAY MORNING #0340 SAN ANTONIO TX111010170009269 +62204120525983133 000000106200007413829829HAdams Electric 131111010170009420 +702D4HJ0B5211 000000914 LOWE'S #1088 SAN ANTONIO TX111010170009420 +820000002800576873500000000000000000000687161470535472 111010170000033 +9000665001188000105450247745675000256439381000842046309