Skip to content

Commit 300002f

Browse files
committedMar 30, 2017
Unmarshal transaction processor response code when empty
What === Added a type for the ProcessorResponseCode on Transaction that unmarshals itself and considers an empty XML tag as zero. Why === In some situations, e.g. a gateway reject, the processor response code field will be an empty string. The processor response code field on transaction is an int, but the default xml decoder will error when unmarshaling an empty string into an int. Why not nullable.NullInt64 === In most places we've used `nullable.NullInt64` which is a struct that wraps an Int64 to solve a similar problem. In the case of the processor response code this has been a well established part of the API and changing it from a builtin int to a struct would be more disruptive to existing integrations than to a type with an underlying type of int.
1 parent b1145c7 commit 300002f

3 files changed

+65
-1
lines changed
 

‎processor_response_code.go

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package braintree
2+
3+
import "strconv"
4+
5+
type ProcessorResponseCode int
6+
7+
func (rc ProcessorResponseCode) Int() int {
8+
return int(rc)
9+
}
10+
11+
// UnmarshalText fills the response code with the integer value if the text contains one in string form. If the text is zero length, the response code's value is unchanged but unmarshaling is successful.
12+
func (rc *ProcessorResponseCode) UnmarshalText(text []byte) error {
13+
if len(text) == 0 {
14+
return nil
15+
}
16+
17+
n, err := strconv.Atoi(string(text))
18+
if err != nil {
19+
return err
20+
}
21+
22+
*rc = ProcessorResponseCode(n)
23+
24+
return nil
25+
}
26+
27+
// MarshalText returns a string in bytes of the number, or nil in the case it is zero.
28+
func (rc ProcessorResponseCode) MarshalText() ([]byte, error) {
29+
if rc == 0 {
30+
return nil, nil
31+
}
32+
return []byte(strconv.Itoa(int(rc))), nil
33+
}

‎transaction.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ type Transaction struct {
3232
RefundId string `xml:"refund-id,omitempty"`
3333
RefundIds *[]string `xml:"refund-ids>item,omitempty"`
3434
RefundedTransactionId *string `xml:"refunded-transaction-id,omitempty"`
35-
ProcessorResponseCode int `xml:"processor-response-code,omitempty"`
35+
ProcessorResponseCode ProcessorResponseCode `xml:"processor-response-code,omitempty"`
3636
ProcessorResponseText string `xml:"processor-response-text,omitempty"`
3737
ProcessorAuthorizationCode string `xml:"processor-authorization-code,omitempty"`
3838
SettlementBatchId string `xml:"settlement-batch-id,omitempty"`

‎transaction_integration_test.go

+31
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,37 @@ func TestTransactionCreateWhenGatewayRejected(t *testing.T) {
214214
}
215215
}
216216

217+
func TestTransactionCreateWhenGatewayRejectedFraud(t *testing.T) {
218+
t.Parallel()
219+
220+
_, err := testGateway.Transaction().Create(&Transaction{
221+
Type: "sale",
222+
Amount: NewDecimal(201000, 2),
223+
PaymentMethodNonce: FakeNonceGatewayRejectedFraud,
224+
})
225+
if err == nil {
226+
t.Fatal("Did not receive error when creating invalid transaction")
227+
}
228+
229+
if err.Error() != "Gateway Rejected: fraud" {
230+
t.Fatal(err)
231+
}
232+
233+
txnID := err.(*BraintreeError).Transaction.Id
234+
txn, err := testGateway.Transaction().Find(txnID)
235+
if err != nil {
236+
t.Fatal(err)
237+
}
238+
239+
if txn.Status != "gateway_rejected" {
240+
t.Fatalf("Got status %q, want %q", txn.Status, "gateway_rejected")
241+
}
242+
243+
if txn.ProcessorResponseCode != 0 {
244+
t.Fatalf("Got processor response code %q, want %q", txn.ProcessorResponseCode, 0)
245+
}
246+
}
247+
217248
func TestFindTransaction(t *testing.T) {
218249
t.Parallel()
219250

0 commit comments

Comments
 (0)
Please sign in to comment.