8000 [pull] master from moov-io:master by pull[bot] · Pull Request #105 · wei/ach · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

[pull] master from moov-io:master #105

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 19, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## v1.49.0 (Released 2025-05-19)

ADDITIONS

- feat: add InvalidEntries() to each batch type

IMPROVEMENTS

- cmd/achcli/describe: include IdentificationNumber on EntryDetail, add mask option
- fix: index and read fields on EntryDetail in a safer way

## v1.48.1 (Released 2025-05-16)

IMPROVEMENTS
Expand Down
46 changes: 38 additions & 8 deletions batchACK.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,35 +46,65 @@ func (batch *BatchACK) Validate() error {
if batch.Header.StandardEntryClassCode != ACK {
return batch.Error("StandardEntryClassCode", ErrBatchSECType, ACK)
}
// Range through Entries

invalidEntries := batch.InvalidEntries()
if len(invalidEntries) > 0 {
return invalidEntries[0].Error // return the first invalid entry's error
}

return nil
}

// InvalidEntries returns entries with validation errors in the batch
func (batch *BatchACK) InvalidEntries() []InvalidEntry {
var out []InvalidEntry

for _, entry := range batch.Entries {
// Amount must be zero for Acknowledgement Entries
if entry.Amount > 0 {
return batch.Error("Amount", ErrBatchAmountNonZero, entry.Amount)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("Amount", ErrBatchAmountNonZero, entry.Amount),
})
}
if len(entry.Addenda05) > 1 {
return batch.Error("AddendaCount", NewErrBatchAddendaCount(len(entry.Addenda05), 1))
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("AddendaCount", NewErrBatchAddendaCount(len(entry.Addenda05), 1)),
})
}
switch entry.TransactionCode {
case CheckingZeroDollarRemittanceCredit, SavingsZeroDollarRemittanceCredit:
default:
return batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode),
})
}
// // Verify the Amount is valid for SEC code and TransactionCode
if err := batch.ValidAmountForCodes(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify the TransactionCode is valid for a ServiceClassCode
if err := batch.ValidTranCodeForServiceClassCode(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify Addenda* FieldInclusion based on entry.Category and batchHeader.StandardEntryClassCode
if err := batch.addendaFieldInclusion(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
}

return nil
return out
}

// Create will tabulate and assemble an ACH batch into a valid state. This includes
Expand Down
25 changes: 21 additions & 4 deletions batchADV.go
EDBE
Original file line number Diff line number Diff line change
Expand Up @@ -53,21 +53,38 @@ func (batch *BatchADV) Validate() error {
if err := batch.verify(); err != nil {
return err
}
// Add configuration and type specific validation for this type.

invalidEntries := batch.InvalidEntries()
if len(invalidEntries) > 0 {
return invalidEntries[0].Error // return the first invalid entry's error
}

return nil
}

// InvalidEntries returns entries with validation errors in the batch
func (batch *BatchADV) InvalidEntries() []InvalidEntry {
var out []InvalidEntry
for _, entry := range batch.ADVEntries {
if entry.Category == CategoryForward {
switch entry.TransactionCode {
case CreditForDebitsOriginated, CreditForCreditsReceived, CreditForCreditsRejected, CreditSummary,
DebitForCreditsOriginated, DebitForDebitsReceived, DebitForDebitsRejectedBatches, DebitSummary:
default:
return batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode)
out = append(out, InvalidEntry{
ADVEntry: entry,
Error: batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode),
})
}
if entry.Addenda99 != nil {
return batch.Error("Addenda99", ErrBatchAddendaCategory, entry.Category)
out = append(out, InvalidEntry{
ADVEntry: entry,
Error: batch.Error("Addenda99", ErrBatchAddendaCategory, entry.Category),
})
}
}
}
return nil
return out
}

// Create will tabulate and assemble an ACH batch into a valid state. This includes
Expand Down
44 changes: 37 additions & 7 deletions batchARC.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,35 +64,65 @@ func (batch *BatchARC) Validate() error {
return batch.Error("ServiceClassCode", ErrBatchServiceClassCode, batch.Header.ServiceClassCode)
}

invalidEntries := batch.InvalidEntries()
if len(invalidEntries) > 0 {
return invalidEntries[0].Error // return the first invalid entry's error
}

return nil
}

// InvalidEntries returns entries with validation errors in the batch
func (batch *BatchARC) InvalidEntries() []InvalidEntry {
var out []InvalidEntry

for _, entry := range batch.Entries {
// ARC detail entries must be a debit
if entry.CreditOrDebit() != "D" {
return batch.Error("TransactionCode", ErrBatchDebitOnly, entry.TransactionCode)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("TransactionCode", ErrBatchDebitOnly, entry.TransactionCode),
})
}

// Amount must be 25,000 or less
if entry.Amount > 2500000 {
return batch.Error("Amount", NewErrBatchAmount(entry.Amount, 2500000))
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("Amount", NewErrBatchAmount(entry.Amount, 2500000)),
})
}

// CheckSerialNumber underlying IdentificationNumber, must be defined
if entry.IdentificationNumber == "" {
return batch.Error("CheckSerialNumber", ErrBatchCheckSerialNumber)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("CheckSerialNumber", ErrBatchCheckSerialNu F438 mber),
})
}
// Verify the Amount is valid for SEC code and TransactionCode
if err := batch.ValidAmountForCodes(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify the TransactionCode is valid for a ServiceClassCode
if err := batch.ValidTranCodeForServiceClassCode(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify Addenda* FieldInclusion based on entry.Category and batchHeader.StandardEntryClassCode
if err := batch.addendaFieldInclusion(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
}
return nil
return out
}

// Create will tabulate and assemble an ACH batch into a valid state. This includes
Expand Down
50 changes: 42 additions & 8 deletions batchATX.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,43 +54,77 @@ func (batch *BatchATX) Validate() error {
return batch.Error("StandardEntryClassCode", ErrBatchSECType, ATX)
}

invalidEntries := batch.InvalidEntries()
if len(invalidEntries) > 0 {
return invalidEntries[0].Error // return the first invalid entry's error
}

return nil
}

// InvalidEntries returns entries with validation errors in the batch
func (batch *BatchATX) InvalidEntries() []InvalidEntry {
var out []InvalidEntry

for _, entry := range batch.Entries {
// Amount must be zero for Acknowledgement Entries
if entry.Amount > 0 {
return batch.Error("Amount", ErrBatchAmountNonZero, entry.Amount)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("Amount", ErrBatchAmountNonZero, entry.Amount),
})
}
switch entry.TransactionCode {
case CheckingZeroDollarRemittanceCredit, SavingsZeroDollarRemittanceCredit, CheckingReturnNOCCredit:
default:
return batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("TransactionCode", ErrBatchTransactionCode, entry.TransactionCode),
})
}

// Trapping this error, as entry.ATXAddendaRecordsField() can not be greater than 9999
if len(entry.Addenda05) > 9999 {
return batch.Error("AddendaCount", NewErrBatchAddendaCount(len(entry.Addenda05), 9999))
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("AddendaCount", NewErrBatchAddendaCount(len(entry.Addenda05), 9999)),
})

}

// validate ATXAddendaRecord Field is equal to the actual number of Addenda records
// use 0 value if there is no Addenda records
addendaRecords, _ := strconv.Atoi(entry.CATXAddendaRecordsField())
if len(entry.Addenda05) != addendaRecords {
return batch.Error("AddendaCount", NewErrBatchExpectedAddendaCount(len(entry.Addenda05), addendaRecords))
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("AddendaCount", NewErrBatchExpectedAddendaCount(len(entry.Addenda05), addendaRecords)),
})
}
// Verify the Amount is valid for SEC code and TransactionCode
if err := batch.ValidAmountForCodes(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify the TransactionCode is valid for a ServiceClassCode
if err := batch.ValidTranCodeForServiceClassCode(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify Addenda* FieldInclusion based on entry.Category and batchHeader.StandardEntryClassCode
if err := batch.addendaFieldInclusion(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
}
return nil

return out
}

// Create will tabulate and assemble an ACH batch into a valid state. This includes
Expand Down
45 changes: 38 additions & 7 deletions batchBOC.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,35 +69,66 @@ func (batch *BatchBOC) Validate() error {
return batch.Error("ServiceClassCode", ErrBatchServiceClassCode, batch.Header.ServiceClassCode)
}

invalidEntries := batch.InvalidEntries()
if len(invalidEntries) > 0 {
return invalidEntries[0].Error // return the first invalid entry's error
}

return nil
}

// InvalidEntries returns entries with validation errors in the batch
func (batch *BatchBOC) InvalidEntries() []InvalidEntry {
var out []InvalidEntry

for _, entry := range batch.Entries {
// BOC detail entries must be a debit
if entry.CreditOrDebit() != "D" {
return batch.Error("TransactionCode", ErrBatchDebitOnly, entry.TransactionCode)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("TransactionCode", ErrBatchDebitOnly, entry.TransactionCode),
})
}

// Amount must be 25,000 or less
if entry.Amount > 2500000 {
return batch.Error("Amount", NewErrBatchAmount(entry.Amount, 2500000))
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("Amount", NewErrBatchAmount(entry.Amount, 2500000)),
})
}

// CheckSerialNumber underlying IdentificationNumber, must be defined
if entry.IdentificationNumber == "" {
return batch.Error("CheckSerialNumber", ErrBatchCheckSerialNumber)
out = append(out, InvalidEntry{
Entry: entry,
Error: batch.Error("CheckSerialNumber", ErrBatchCheckSerialNumber),
})
}
// Verify the Amount is valid for SEC code and TransactionCode
if err := batch.ValidAmountForCodes(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify the TransactionCode is valid for a ServiceClassCode
if err := batch.ValidTranCodeForServiceClassCode(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
// Verify Addenda* FieldInclusion based on entry.Category and batchHeader.StandardEntryClassCode
if err := batch.addendaFieldInclusion(entry); err != nil {
return err
out = append(out, InvalidEntry{
Entry: entry,
Error: err,
})
}
}
return nil

return out
}

// Create will tabulate and assemble an ACH batch into a valid state. This includes
Expand Down
Loading
0