diff --git a/examples/gl-debit.ach b/examples/gl-debit.ach new file mode 100644 index 00000000..7eb0697b --- /dev/null +++ b/examples/gl-debit.ach @@ -0,0 +1,11 @@ +101 231380104 1210428821906240000A094101Federal Reserve Bank My Bank Name +5225Name on Account 121042882 PPDREG.SALARY 190625 1121042880000001 +64723138010412345678 0100000000 Receiver Account Name 0121042880000001 +82250000010023138010000100000000000000000000121042882 121042880000001 +9000001000001000000010023138010000100000000000000000000 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + diff --git a/examples/loan-credit.ach b/examples/loan-credit.ach new file mode 100644 index 00000000..511cbf4e --- /dev/null +++ b/examples/loan-credit.ach @@ -0,0 +1,11 @@ +101 231380104 1210428821906240000A094101Federal Reserve Bank My Bank Name +5220Name on Account 121042882 PPDREG.SALARY 190625 1121042880000001 +65223138010412345678 0100000000 Receiver Account Name 0121042880000001 +82200000010023138010000000000000000100000000121042882 121042880000001 +9000001000001000000010023138010000000000000000100000000 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 +9999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999 + diff --git a/go.sum b/go.sum index 11539c8c..aaac4ee4 100644 --- a/go.sum +++ b/go.sum @@ -123,8 +123,6 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= go.opentelemetry.io/otel v1.29.0 h1:PdomN/Al4q/lN6iBJEN3AwPvUiHPMlt93c8bqTG5Llw= go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= @@ -133,14 +131,10 @@ go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0 h1:R3X6Z go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.28.0/go.mod h1:QWFXnDavXWwMx2EEcZsf3yxgEKAqsxQ+Syjp+seyInw= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0 h1:EVSnY9JbEEW92bEkIYOVMw4q1WJxIAGoFTrtYOzWuRQ= go.opentelemetry.io/otel/exporters/stdout/stdouttrace v1.28.0/go.mod h1:Ea1N1QQryNXpCD0I1fdLibBAIpQuBkznMmkdKrapk1Y= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= go.opentelemetry.io/otel/metric v1.29.0 h1:vPf/HFWTNkPu1aYeIsc98l4ktOQaL6LeSoeV2g+8YLc= go.opentelemetry.io/otel/metric v1.29.0/go.mod h1:auu/QWieFVWx+DmQOUMgj0F8LHWdgalxXqvp7BII/W8= go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= go.opentelemetry.io/otel/trace v1.29.0 h1:J/8ZNK4XgR7a21DZUAsbF8pZ5Jcw1VhACmnYt39JTi4= go.opentelemetry.io/otel/trace v1.29.0/go.mod h1:eHl3w0sp3paPkYstJOmAimxhiFXPg+MMTlEh3nsQgWQ= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= diff --git a/pkg/response/entry_transformer.go b/pkg/response/entry_transformer.go index 12bf8132..88472697 100644 --- a/pkg/response/entry_transformer.go +++ b/pkg/response/entry_transformer.go @@ -47,9 +47,13 @@ func (t *CorrectionTransformer) MorphEntry(ctx context.Context, fh ach.FileHeade // Set the TransactionCode from the EntryDetail switch ed.TransactionCode { - case ach.CheckingCredit, ach.CheckingDebit, ach.SavingsCredit, ach.SavingsDebit: + case ach.CheckingCredit, ach.CheckingDebit, ach.SavingsCredit, ach.SavingsDebit, + ach.GLCredit, ach.GLDebit, ach.LoanCredit: out.TransactionCode = ed.TransactionCode - 1 + case ach.LoanDebit: + out.TransactionCode += 1 // LoanDebit (55) -> LoanReturnNOCDebit (56) + case ach.CheckingPrenoteCredit, ach.CheckingPrenoteDebit, ach.SavingsPrenoteCredit, ach.SavingsPrenoteDebit, ach.GLPrenoteCredit, ach.GLPrenoteDebit, ach.LoanPrenoteCredit: out.TransactionCode = ed.TransactionCode - 2 @@ -127,9 +131,13 @@ func (t *ReturnTransformer) MorphEntry(ctx context.Context, fh ach.FileHeader, b // Set the TransactionCode from the EntryDetail switch ed.TransactionCode { - case ach.CheckingCredit, ach.CheckingDebit, ach.SavingsCredit, ach.SavingsDebit: + case ach.CheckingCredit, ach.CheckingDebit, ach.SavingsCredit, ach.SavingsDebit, + ach.GLCredit, ach.GLDebit, ach.LoanCredit: out.TransactionCode = ed.TransactionCode - 1 + case ach.LoanDebit: + out.TransactionCode = ed.TransactionCode + 1 // LoanDebit (55) -> LoanReturnNOCDebit (56) + case ach.CheckingPrenoteCredit, ach.CheckingPrenoteDebit, ach.SavingsPrenoteCredit, ach.SavingsPrenoteDebit, ach.GLPrenoteCredit, ach.GLPrenoteDebit, ach.LoanPrenoteCredit: out.TransactionCode = ed.TransactionCode - 2 diff --git a/pkg/response/entry_transformer_test.go b/pkg/response/entry_transformer_test.go index 9c330870..22f6924f 100644 --- a/pkg/response/entry_transformer_test.go +++ b/pkg/response/entry_transformer_test.go @@ -5,6 +5,7 @@ import ( "fmt" "path/filepath" "testing" + "time" "github.com/moov-io/ach" "github.com/moov-io/ach-test-harness/pkg/service" @@ -34,6 +35,7 @@ func TestMorphEntry__Correction(t *testing.T) { t.Fatal("exected Addenda98 record") } require.NotEqual(t, ed.TraceNumber, out.TraceNumber) + require.Equal(t, ach.CheckingReturnNOCDebit, out.TransactionCode) require.Equal(t, ed.TraceNumber, out.Addenda98.OriginalTrace) require.Equal(t, "C01", out.Addenda98.ChangeCode) require.Equal(t, "45111616", out.Addenda98.CorrectedData) @@ -71,6 +73,7 @@ func TestMorphEntry__Return(t *testing.T) { t.Fatal("exected Addenda99 record") } require.NotEqual(t, ed.TraceNumber, out.TraceNumber) + require.Equal(t, ach.CheckingReturnNOCDebit, out.TransactionCode) require.Equal(t, "12104288", out.RDFIIdentification) require.Equal(t, "2", out.CheckDigit) require.Equal(t, ed.TraceNumber, out.Addenda99.OriginalTrace) @@ -78,6 +81,88 @@ func TestMorphEntry__Return(t *testing.T) { require.Equal(t, "23138010", out.Addenda99.OriginalDFI) } +func TestMorphEntry_Return_GL(t *testing.T) { + file, err := ach.ReadFile(filepath.Join("..", "..", "examples", "gl-debit.ach")) + require.NoError(t, err) + + xform := &ReturnTransformer{} + action := service.Action{ + Return: &service.Return{ + Code: "R03", + }, + } + bh := file.Batches[0].GetHeader() + ed := file.Batches[0].GetEntries()[0] + out, err := xform.MorphEntry(context.Background(), file.Header, bh, ed, &action) + require.NoError(t, err) + + if out.Addenda98 != nil { + t.Fatal("unexpected Addenda98") + } + if out.Addenda99 == nil { + t.Fatal("exected Addenda99 record") + } + require.NotEqual(t, ed.TraceNumber, out.TraceNumber) + require.Equal(t, ach.GLReturnNOCDebit, out.TransactionCode) + require.Equal(t, "12104288", out.RDFIIdentification) + require.Equal(t, "2", out.CheckDigit) + require.Equal(t, ed.TraceNumber, out.Addenda99.OriginalTrace) + require.Equal(t, "R03", out.Addenda99.ReturnCode) + require.Equal(t, "23138010", out.Addenda99.OriginalDFI) + + // Try the reversal + err = file.Reversal(time.Now()) + require.NoError(t, err) + + bh = file.Batches[0].GetHeader() + ed = file.Batches[0].GetEntries()[0] + + out, err = xform.MorphEntry(context.Background(), file.Header, bh, ed, &action) + require.NoError(t, err) + require.Equal(t, ach.GLReturnNOCCredit, out.TransactionCode) +} + +func TestMorphEntry_Return_Loan(t *testing.T) { + file, err := ach.ReadFile(filepath.Join("..", "..", "examples", "loan-credit.ach")) + require.NoError(t, err) + + xform := &ReturnTransformer{} + action := service.Action{ + Return: &service.Return{ + Code: "R03", + }, + } + bh := file.Batches[0].GetHeader() + ed := file.Batches[0].GetEntries()[0] + out, err := xform.MorphEntry(context.Background(), file.Header, bh, ed, &action) + require.NoError(t, err) + + if out.Addenda98 != nil { + t.Fatal("unexpected Addenda98") + } + if out.Addenda99 == nil { + t.Fatal("exected Addenda99 record") + } + require.NotEqual(t, ed.TraceNumber, out.TraceNumber) + require.Equal(t, ach.LoanReturnNOCCredit, out.TransactionCode) + require.Equal(t, "12104288", out.RDFIIdentification) + require.Equal(t, "2", out.CheckDigit) + require.Equal(t, ed.TraceNumber, out.Addenda99.OriginalTrace) + require.Equal(t, "R03", out.Addenda99.ReturnCode) + require.Equal(t, "23138010", out.Addenda99.OriginalDFI) + + // Try the reversal + err = file.Reversal(time.Now()) + require.NoError(t, err) + + bh = file.Batches[0].GetHeader() + ed = file.Batches[0].GetEntries()[0] + + out, err = xform.MorphEntry(context.Background(), file.Header, bh, ed, &action) + require.NoError(t, err) + require.Equal(t, ach.LoanReturnNOCDebit, out.TransactionCode) +} + func TestMorphEntry__Prenote(t *testing.T) { file, err := ach.ReadFile(filepath.Join("..", "..", "testdata", "prenote.ach")) require.NoError(t, err) @@ -142,4 +227,12 @@ func TestMorphEntry__Prenote(t *testing.T) { require.Equal(t, "R01", out.Addenda99.ReturnCode, msg) } }) + + t.Run("loan", func(t *testing.T) { + // TODO(adam): + }) + + t.Run("general-ledger", func(t *testing.T) { + // TODO(adam): + }) }