Repository: moov-io/ach
Pull request #838 (2021-01-25 01:29:18)

fix fileHeader destination and origin formatting when bypass validation is set
Fixes issue #814 and extends the PR #817 

This PR fixes an issue caused by this commit https://github.com/moov-io/ach/commit/e72a6afdb4279f377d4f05282ea6c2f8b02e2907 in which a `0` gets set between the ImmediateDestination and ImmediateOrigin where it should just be a `space`

Example of the issue:
`101 231380104 1210428821806140000A094101Federal Reserve Bank   My Bank Name                   `
would get transformed to 
`101023138010401210428821806140000A094101Federal Reserve Bank   My Bank Name                   `


Patch:
diff --git a/fileHeader.go b/fileHeader.go
index 4d111f8a..ff3be7ab 100644
--- a/fileHeader.go
+++ b/fileHeader.go
@@ -297,10 +297,11 @@ func (fh *FileHeader) ImmediateDestinationField() string {
 	if fh.ImmediateDestination == "" {
 		return strings.Repeat(" ", 10)
 	}
-	if fh.validateOpts != nil && fh.validateOpts.BypassDestinationValidation {
-		return fh.stringField(strings.TrimSpace(fh.ImmediateDestination), 10)
+	fh.ImmediateDestination = strings.TrimSpace(fh.ImmediateDestination)
+	if fh.validateOpts != nil && fh.validateOpts.BypassDestinationValidation && len(fh.ImmediateDestination) == 10 {
+		return fh.ImmediateDestination
 	}
-	return " " + fh.stringField(strings.TrimSpace(fh.ImmediateDestination), 9)
+	return " " + fh.stringField(fh.ImmediateDestination, 9)
 }
 
 // ImmediateOriginField gets the immediate origin number with 0 padding
@@ -308,10 +309,11 @@ func (fh *FileHeader) ImmediateOriginField() string {
 	if fh.ImmediateOrigin == "" {
 		return strings.Repeat(" ", 10)
 	}
-	if fh.validateOpts != nil && fh.validateOpts.BypassOriginValidation {
-		return fh.stringField(strings.TrimSpace(fh.ImmediateOrigin), 10)
+	fh.ImmediateOrigin = strings.TrimSpace(fh.ImmediateOrigin)
+	if fh.validateOpts != nil && fh.validateOpts.BypassOriginValidation && len(fh.ImmediateOrigin) == 10 {
+		return fh.ImmediateOrigin
 	}
-	return " " + fh.stringField(strings.TrimSpace(fh.ImmediateOrigin), 9)
+	return " " + fh.stringField(fh.ImmediateOrigin, 9)
 }
 
 // FileCreationDateField gets the file creation date in YYMMDD (year, month, day) format


Test patch:
diff --git a/file_test.go b/file_test.go
index 0e05e035..92e9c2b1 100644
--- a/file_test.go
+++ b/file_test.go
@@ -18,6 +18,7 @@
 package ach
 
 import (
+	"bytes"
 	"encoding/json"
 	"fmt"
 	"io/ioutil"
@@ -1934,3 +1935,33 @@ func TestFile__SetValidation(t *testing.T) {
 	file.SetValidation(nil)
 	file.SetValidation(&ValidateOpts{})
 }
+
+func TestFile__FileHeaderFormattingWithValidation(t *testing.T) {
+	f := NewFile()
+	f.ID = "foo"
+	f.Header = mockFileHeader()
+	f.AddBatch(mockBatchPPD())
+	f.SetValidation(&ValidateOpts{
+		BypassOriginValidation:      true,
+		BypassDestinationValidation: true,
+	})
+	if err := f.Create(); err != nil {
+		t.Fatal(err)
+	}
+
+	var b bytes.Buffer
+	writer := NewWriter(&b)
+	if err := writer.Write(f); err != nil {
+		t.Fatal(err)
+	}
+
+	s, err := b.ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	want := fmt.Sprintf("101 %s %s", f.Header.ImmediateDestination, f.Header.ImmediateOrigin)
+	if !strings.HasPrefix(s, want) {
+		t.Fatalf("want \"%v\", got \"%v\"", want, s[:len(want)])
+	}
+}