Repository: moov-io/ach
Pull request #139 (2017-10-09 03:01:22)

Additional tests for code coverage 

coveralls: 
[![Coverage Status](https://coveralls.io/builds/13625712/badge)](https://coveralls.io/builds/13625712)

Coverage increased (+1.4%) to 95.949% when pulling **e287977859207be3aed48da362e5032bd429417c on wadearnold:additional-tests-for-code-coverage-** into **3684831a5df8a315244bebfd5d7052b1134fc57e on moov-io:master**.


Patch:
diff --git a/.travis.yml b/.travis.yml
index 1a1925fa..c1557d8e 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -5,4 +5,4 @@ go:
 before_install:
   - go get github.com/mattn/goveralls
 script:
-  - $HOME/gopath/bin/goveralls -service=travis-ci
+  - $HOME/gopath/bin/goveralls -service=travis-ci -ignore=main,main.go,/example/,./example/
diff --git a/README.md b/README.md
index 598b5083..cabe4392 100644
--- a/README.md
+++ b/README.md
@@ -117,7 +117,7 @@ Add an entry and define if it is a single or reoccurring payment. The following
 		TransactionCode:   "22",
 		IDNumber:          "#123456",
 		IndividualName:    "Wade Arnold",
-		DiscretionaryData: "R"})
+		PaymentType: 		"R"})
 
 	addenda2 := ach.NewAddenda(ach.AddendaParam{
 		PaymentRelatedInfo: "Monthly Membership Subscription"})
diff --git a/batchWeb.go b/batchWeb.go
index 0bc00ac5..89a70aab 100644
--- a/batchWeb.go
+++ b/batchWeb.go
@@ -79,8 +79,8 @@ func (batch *BatchWEB) Create() error {
 // "S" For a Single-Entry WEB Entry
 func (batch *BatchWEB) isPaymentTypeCode() error {
 	for _, entry := range batch.entries {
-		if !strings.Contains(strings.ToUpper(entry.PaymentType()), "S") && !strings.Contains(strings.ToUpper(entry.PaymentType()), "R") {
-			msg := fmt.Sprintf(msgBatchWebPaymentType, entry.PaymentType())
+		if !strings.Contains(strings.ToUpper(entry.PaymentTypeField()), "S") && !strings.Contains(strings.ToUpper(entry.PaymentTypeField()), "R") {
+			msg := fmt.Sprintf(msgBatchWebPaymentType, entry.PaymentTypeField())
 			return &BatchError{BatchNumber: batch.header.BatchNumber, FieldName: "PaymentType", Msg: msg}
 		}
 	}
diff --git a/entryDetail.go b/entryDetail.go
index d62ff10f..6fc6b26e 100644
--- a/entryDetail.go
+++ b/entryDetail.go
@@ -7,6 +7,7 @@ package ach
 import (
 	"fmt"
 	"strconv"
+	"strings"
 )
 
 // EntryDetail contains the actual transaction data for an individual entry.
@@ -90,6 +91,7 @@ type EntryParam struct {
 	IndividualName    string `json:"individual_name,omitempty"`
 	ReceivingCompany  string `json:"receiving_company,omitempty"`
 	DiscretionaryData string `json:"discretionary_data,omitempty"`
+	PaymentType       string `json:"payment_type,omitempty"`
 	TransactionCode   string `json:"transaction_code"`
 }
 
@@ -108,7 +110,11 @@ func NewEntryDetail(params ...EntryParam) *EntryDetail {
 		} else {
 			entry.IndividualName = params[0].ReceivingCompany
 		}
-		entry.DiscretionaryData = params[0].DiscretionaryData
+		if params[0].PaymentType != "" {
+			entry.SetPaymentType(params[0].PaymentType)
+		} else {
+			entry.DiscretionaryData = params[0].DiscretionaryData
+		}
 		entry.TransactionCode = entry.parseNumField(params[0].TransactionCode)
 
 		entry.setTraceNumber(entry.RDFIIdentification, 1)
@@ -136,6 +142,7 @@ func (ed *EntryDetail) Parse(record string) {
 	// 55-76 The name of the receiver, usually the name on the bank account
 	ed.IndividualName = record[54:76]
 	// 77-78 allows ODFIs to include codes of significance only to them
+	// For WEB transaction this field is the PaymentType which is either R(reoccurring) or S(single)
 	// normally blank
 	ed.DiscretionaryData = record[76:78]
 	// 79-79 1 if addenda exists 0 if it does not
@@ -273,17 +280,30 @@ func (ed *EntryDetail) ReceivingCompanyField() string {
 	return ed.IndividualNameField()
 }
 
+func (ed *EntryDetail) SetReceivingCompany(s string) {
+	ed.IndividualName = s
+}
+
 // DiscretionaryDataField returns a space padded string of DiscretionaryData
 func (ed *EntryDetail) DiscretionaryDataField() string {
 	return ed.alphaField(ed.DiscretionaryData, 2)
 }
 
-// PaymentType returns the discretionary data field used in web batch files
-func (ed *EntryDetail) PaymentType() string {
-	if ed.DiscretionaryData == "" {
+// PaymentType returns the discretionary data field used in WEB batch files
+func (ed *EntryDetail) PaymentTypeField() string {
+	// because DiscretionaryData can be changed outside of PaymentType we reset the value for safety
+	ed.SetPaymentType(ed.DiscretionaryData)
+	return ed.DiscretionaryData
+}
+
+// SetPaymentType as R (Reoccuring) all other values will result in S (single)
+func (ed *EntryDetail) SetPaymentType(t string) {
+	t = strings.ToUpper(strings.TrimSpace(t))
+	if t == "R" {
+		ed.DiscretionaryData = "R"
+	} else {
 		ed.DiscretionaryData = "S"
 	}
-	return ed.DiscretionaryDataField()
 }
 
 // TraceNumberField returns a zero padded traceNumber string
diff --git a/example/simple-file-creation/main.go b/example/simple-file-creation/main.go
index bfedfafa..7ec754f2 100644
--- a/example/simple-file-creation/main.go
+++ b/example/simple-file-creation/main.go
@@ -71,13 +71,13 @@ func main() {
 	// The following is a reoccuring payment for $7.99
 
 	entry2 := ach.NewEntryDetail(ach.EntryParam{
-		ReceivingDFI:      "102001017",
-		RDFIAccount:       "5343121",
-		Amount:            "799",
-		TransactionCode:   "22",
-		IDNumber:          "#123456",
-		IndividualName:    "Wade Arnold",
-		DiscretionaryData: "R"})
+		ReceivingDFI:    "102001017",
+		RDFIAccount:     "5343121",
+		Amount:          "799",
+		TransactionCode: "22",
+		IDNumber:        "#123456",
+		IndividualName:  "Wade Arnold",
+		PaymentType:     "R"})
 
 	addenda2 := ach.NewAddenda(ach.AddendaParam{
 		PaymentRelatedInfo: "Monthly Membership Subscription"})


Test patch:
diff --git a/addenda_internal_test.go b/addenda_internal_test.go
index b127d62f..82425c83 100644
--- a/addenda_internal_test.go
+++ b/addenda_internal_test.go
@@ -133,3 +133,15 @@ func TestAddendaPaymentRelatedInformationAlphaNumeric(t *testing.T) {
 		}
 	}
 }
+
+func TestAddendaTyeCodeNil(t *testing.T) {
+	addenda := mockAddenda()
+	addenda.TypeCode = ""
+	if err := addenda.Validate(); err != nil {
+		if e, ok := err.(*FieldError); ok {
+			if e.FieldName != "TypeCode" {
+				t.Errorf("%T: %s", err, err)
+			}
+		}
+	}
+}
diff --git a/batchCCD_test.go b/batchCCD_test.go
index f1608b87..b3292e9e 100644
--- a/batchCCD_test.go
+++ b/batchCCD_test.go
@@ -1,6 +1,8 @@
 package ach
 
-import "testing"
+import (
+	"testing"
+)
 
 func mockBatchCCDHeader() *BatchHeader {
 	bh := NewBatchHeader()
@@ -20,7 +22,7 @@ func mockCCDEntryDetail() *EntryDetail {
 	entry.DFIAccountNumber = "744-5678-99"
 	entry.Amount = 5000000
 	entry.IdentificationNumber = "location #23"
-	entry.IndividualName = "Best Co. #23"
+	entry.SetReceivingCompany("Best Co. #23")
 	entry.TraceNumber = 123456789
 	entry.DiscretionaryData = "S"
 	return entry
@@ -57,7 +59,7 @@ func TestBatchCCDAddendumCount(t *testing.T) {
 func TestBatchCCDReceivingCompanyName(t *testing.T) {
 	mockBatch := mockBatchCCD()
 	// modify the Individual name / receiving company to nothing
-	mockBatch.GetEntries()[0].IndividualName = ""
+	mockBatch.GetEntries()[0].SetReceivingCompany("")
 	if err := mockBatch.Validate(); err != nil {
 		if e, ok := err.(*BatchError); ok {
 			if e.FieldName != "IndividualName" {
@@ -98,3 +100,52 @@ func TestBatchCCDSEC(t *testing.T) {
 		}
 	}
 }
+
+func TestBatchCCDAddendaCount(t *testing.T) {
+	mockBatch := mockBatchCCD()
+	mockBatch.GetEntries()[0].AddAddenda(mockAddenda())
+	mockBatch.Create()
+	if err := mockBatch.Validate(); err != nil {
+		if e, ok := err.(*BatchError); ok {
+			if e.FieldName != "AddendaCount" {
+				t.Errorf("%T: %s", err, err)
+			}
+		} else {
+			t.Errorf("%T: %s", err, err)
+		}
+	}
+}
+
+func TestBatchCCDCreate(t *testing.T) {
+	mockBatch := mockBatchCCD()
+	// Batch Header information is required to Create a batch.
+	mockBatch.GetHeader().ServiceClassCode = 0
+	mockBatch.Create()
+	if err := mockBatch.Validate(); err != nil {
+		if e, ok := err.(*BatchError); ok {
+			if e.FieldName != "ServiceClassCode" {
+				t.Errorf("%T: %s", err, err)
+			}
+		} else {
+			t.Errorf("%T: %s", err, err)
+		}
+	}
+}
+
+func TestBatchCCDParam(t *testing.T) {
+
+	batch, _ := NewBatch(BatchParam{
+		ServiceClassCode:        "220",
+		CompanyName:             "Your Company, inc",
+		StandardEntryClass:      "CCD",
+		CompanyIdentification:   "123456789",
+		CompanyEntryDescription: "Vndr Pay",
+		CompanyDescriptiveDate:  "Oct 23",
+		ODFIIdentification:      "123456789"})
+
+	_, ok := batch.(*BatchCCD)
+	if !ok {
+		t.Error("Expecting BachCCD")
+	}
+
+}
diff --git a/batchPPD_test.go b/batchPPD_test.go
index f456be26..20a741cf 100644
--- a/batchPPD_test.go
+++ b/batchPPD_test.go
@@ -40,6 +40,40 @@ func TestBatchServiceClassCodeEquality(t *testing.T) {
 	}
 }
 
+func TestBatchPPDCreate(t *testing.T) {
+	mockBatch := mockBatchPPD()
+	// can not have default values in Batch Header to build batch
+	mockBatch.GetHeader().ServiceClassCode = 0
+	mockBatch.Create()
+	if err := mockBatch.Validate(); err != nil {
+		if e, ok := err.(*BatchError); ok {
+			if e.FieldName != "ServiceClassCode" {
+				t.Errorf("%T: %s", err, err)
+			}
+		} else {
+			t.Errorf("%T: %s", err, err)
+		}
+	}
+}
+
+func TestBatchPPDTypeCode(t *testing.T) {
+	mockBatch := mockBatchPPD()
+	// change an addendum to an invalid type code
+	a := mockAddenda()
+	a.TypeCode = "63"
+	mockBatch.GetEntries()[0].AddAddenda(a)
+	mockBatch.Create()
+	if err := mockBatch.Validate(); err != nil {
+		if e, ok := err.(*BatchError); ok {
+			if e.FieldName != "TypeCode" {
+				t.Errorf("%T: %s", err, err)
+			}
+		} else {
+			t.Errorf("%T: %s", err, err)
+		}
+	}
+}
+
 func TestBatchCompanyIdentification(t *testing.T) {
 	mockBatch := mockBatchPPD()
 	mockBatch.GetControl().CompanyIdentification = "XYZ Inc"
diff --git a/batchWEB_test.go b/batchWEB_test.go
index 074ddb17..50301d71 100644
--- a/batchWEB_test.go
+++ b/batchWEB_test.go
@@ -21,7 +21,7 @@ func mockWEBEntryDetail() *EntryDetail {
 	entry.Amount = 100000000
 	entry.IndividualName = "Wade Arnold"
 	entry.TraceNumber = 123456789
-	entry.DiscretionaryData = "S"
+	entry.SetPaymentType("S")
 	return entry
 }
 
@@ -129,3 +129,18 @@ func TestBatchWebPaymentType(t *testing.T) {
 		}
 	}
 }
+
+func TestBatchWebCreate(t *testing.T) {
+	mockBatch := mockBatchWEB()
+	// Must have valid batch header to create a batch
+	mockBatch.GetHeader().ServiceClassCode = 63
+	if err := mockBatch.Create(); err != nil {
+		if e, ok := err.(*FieldError); ok {
+			if e.FieldName != "ServiceClassCode" {
+				t.Errorf("%T: %s", err, err)
+			}
+		} else {
+			t.Errorf("%T: %s", err, err)
+		}
+	}
+}
diff --git a/recordParams_test.go b/recordParams_test.go
index 49dda68a..ad2aac61 100644
--- a/recordParams_test.go
+++ b/recordParams_test.go
@@ -55,6 +55,35 @@ func TestEntryParam(t *testing.T) {
 	}
 }
 
+func TestEntryParamPaymentType(t *testing.T) {
+	entry := NewEntryDetail(EntryParam{
+		ReceivingDFI:    "102001017",
+		RDFIAccount:     "5343121",
+		Amount:          "17500",
+		TransactionCode: "27",
+		IDNumber:        "ABC##jvkdjfuiwn",
+		IndividualName:  "Bob Smith",
+		PaymentType:     "R"})
+
+	if err := entry.Validate(); err != nil {
+		t.Errorf("%T: %s", err, err)
+	}
+}
+
+func TestEntryParamReceivingCompany(t *testing.T) {
+	entry := NewEntryDetail(EntryParam{
+		ReceivingDFI:     "102001017",
+		RDFIAccount:      "5343121",
+		Amount:           "17500",
+		TransactionCode:  "27",
+		IDNumber:         "location #23",
+		ReceivingCompany: "Best Co. #23"})
+
+	if err := entry.Validate(); err != nil {
+		t.Errorf("%T: %s", err, err)
+	}
+}
+
 func TestAddendaParam(t *testing.T) {
 	addenda := NewAddenda(AddendaParam{
 		PaymentRelatedInfo: "Currently string needs ASC X12 Interchange Control Structures",
@@ -128,13 +157,13 @@ func TestBuildFileParam(t *testing.T) {
 	// The following is a reoccuring payment for $7.99
 
 	entry = NewEntryDetail(EntryParam{
-		ReceivingDFI:      "102001017",
-		RDFIAccount:       "5343121",
-		Amount:            "799",
-		TransactionCode:   "22",
-		IDNumber:          "#123456",
-		IndividualName:    "Wade Arnold",
-		DiscretionaryData: "R"})
+		ReceivingDFI:    "102001017",
+		RDFIAccount:     "5343121",
+		Amount:          "799",
+		TransactionCode: "22",
+		IDNumber:        "#123456",
+		IndividualName:  "Wade Arnold",
+		PaymentType:     "R"})
 
 	addenda = NewAddenda(AddendaParam{
 		PaymentRelatedInfo: "Monthly Membership Subscription"})