Repository: VictorAvelar/mollie-api-go
Pull request #328 (2024-03-03 13:29:10)

balances resource api parity
<!--- Provide a general summary of your changes in the Title above -->

# Description

Ensures that the `balances` resource delivers API parity.

It also fixes a know issue when receiving an empty context value in the `BalanceTransaction` struct.

## Motivation and context

- Ensure API parity.
- Fixes: #251 
- Closes: #255 

## How has this been tested?

Please describe in detail how you tested your changes.

Include details of your testing environment, and the tests you ran to
see how your change affects other areas of the code, etc.

- [x] Unit tests added / updated
- [x] The tests run on docker (using `make test`)
- [ ] The required `test data` has been added / updated

If you are running the tests locally, please specify:

- OS: macos
- Go version 1.22

## Types of changes

What types of changes does your code introduce? Put an `x` in all the boxes that apply:

- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] This change requires a documentation update

## Checklist

Go over all the following points, and put an `x` in all the boxes that apply.

Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our continuous integration server to make sure your [tests and code style pass](https://help.github.com/articles/about-required-status-checks/).

- [x] I have read the **[CONTRIBUTING](CONTRIBUTING.md)** document.
- [x] My pull request addresses exactly one patch/feature.
- [x] I have created a branch for this patch/feature.
- [x] Each individual commit in the pull request is meaningful.
- [x] If my change requires a change to the documentation, I have updated it accordingly.

<!-- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->



Patch:
diff --git a/docs/README.md b/docs/README.md
index 748164c..729dab6 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -98,6 +98,7 @@ REST also implies a nice and clean structure for URLs or endpoints. This means y
   - [func \(c \*Config\) ToggleTesting\(\) bool](<#Config.ToggleTesting>)
 - [type ContextValue](<#ContextValue>)
 - [type ContextValues](<#ContextValues>)
+  - [func \(cv \*ContextValues\) UnmarshalJSON\(data \[\]byte\) error](<#ContextValues.UnmarshalJSON>)
 - [type CreateMollieConnectPaymentFields](<#CreateMollieConnectPaymentFields>)
 - [type CreatePayment](<#CreatePayment>)
 - [type CreatePaymentAccessTokenFields](<#CreatePaymentAccessTokenFields>)
@@ -676,7 +677,7 @@ type BalanceTransaction struct {
 ```
 
 <a name="BalanceTransactionsList"></a>
-## type [BalanceTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L215-L221>)
+## type [BalanceTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L212-L218>)
 
 BalanceTransactionsList contains an array of embedded transactions.
 
@@ -691,7 +692,7 @@ type BalanceTransactionsList struct {
 ```
 
 <a name="BalanceTransactionsListOptions"></a>
-## type [BalanceTransactionsListOptions](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L225-L228>)
+## type [BalanceTransactionsListOptions](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L222-L225>)
 
 BalanceTransactionsListOptions are valid query parameters for list balance transactions requests.
 
@@ -733,7 +734,7 @@ type BalancesService service
 ```
 
 <a name="BalancesService.Get"></a>
-### func \(\*BalancesService\) [Get](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L233>)
+### func \(\*BalancesService\) [Get](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L230>)
 
 ```go
 func (bs *BalancesService) Get(ctx context.Context, balance string) (res *Response, b *Balance, err error)
@@ -744,7 +745,7 @@ GetBalance retrieves a balance by its id.
 See: https://docs.mollie.com/reference/v2/balances-api/get-balance
 
 <a name="BalancesService.GetPrimaryReport"></a>
-### func \(\*BalancesService\) [GetPrimaryReport](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L273-L277>)
+### func \(\*BalancesService\) [GetPrimaryReport](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L270-L274>)
 
 ```go
 func (bs *BalancesService) GetPrimaryReport(ctx context.Context, options *BalanceReportOptions) (res *Response, br *BalanceReport, err error)
@@ -755,7 +756,7 @@ GetPrimaryReport returns the report for the primary balance.
 See: https://docs.mollie.com/reference/v2/balances-api/get-primary-balance-report
 
 <a name="BalancesService.GetPrimaryTransactionsList"></a>
-### func \(\*BalancesService\) [GetPrimaryTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L301-L305>)
+### func \(\*BalancesService\) [GetPrimaryTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L298-L302>)
 
 ```go
 func (bs *BalancesService) GetPrimaryTransactionsList(ctx context.Context, options *BalanceTransactionsListOptions) (res *Response, btl *BalanceTransactionsList, err error)
@@ -766,7 +767,7 @@ GetPrimaryTransactionsList retrieves the list of movements \(transactions\) for
 See: https://docs.mollie.com/reference/v2/balances-api/list-primary-balance-transactions
 
 <a name="BalancesService.GetReport"></a>
-### func \(\*BalancesService\) [GetReport](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L262-L266>)
+### func \(\*BalancesService\) [GetReport](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L259-L263>)
 
 ```go
 func (bs *BalancesService) GetReport(ctx context.Context, balance string, options *BalanceReportOptions) (res *Response, br *BalanceReport, err error)
@@ -777,7 +778,7 @@ GetReport returns the balance report for the specified balance id.
 See: https://docs.mollie.com/reference/v2/balances-api/get-balance-report
 
 <a name="BalancesService.GetTransactionsList"></a>
-### func \(\*BalancesService\) [GetTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L285-L293>)
+### func \(\*BalancesService\) [GetTransactionsList](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L282-L290>)
 
 ```go
 func (bs *BalancesService) GetTransactionsList(ctx context.Context, balance string, options *BalanceTransactionsListOptions) (res *Response, btl *BalanceTransactionsList, err error)
@@ -788,7 +789,7 @@ GetTransactionsList retrieves a list of movements \(transactions\) for the speci
 See: https://docs.mollie.com/reference/v2/balances-api/list-balance-transactions
 
 <a name="BalancesService.List"></a>
-### func \(\*BalancesService\) [List](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L251-L255>)
+### func \(\*BalancesService\) [List](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L248-L252>)
 
 ```go
 func (bs *BalancesService) List(ctx context.Context, options *BalanceListOptions) (res *Response, bl *BalancesList, err error)
@@ -799,7 +800,7 @@ List retrieves all the organization’s balances, including the primary balance,
 See: https://docs.mollie.com/reference/v2/balances-api/list-balances
 
 <a name="BalancesService.Primary"></a>
-### func \(\*BalancesService\) [Primary](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L241>)
+### func \(\*BalancesService\) [Primary](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L238>)
 
 ```go
 func (bs *BalancesService) Primary(ctx context.Context) (res *Response, b *Balance, err error)
@@ -1702,7 +1703,7 @@ type ContextValue string
 ```
 
 <a name="ContextValues"></a>
-## type [ContextValues](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/balances.go#L212>)
+## type [ContextValues](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/custom_types.go#L8>)
 
 ContextValues is a map of TransactionType to ContextValue.
 
@@ -1710,6 +1711,17 @@ ContextValues is a map of TransactionType to ContextValue.
 type ContextValues map[TransactionType]ContextValue
 ```
 
+<a name="ContextValues.UnmarshalJSON"></a>
+### func \(\*ContextValues\) [UnmarshalJSON](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/custom_types.go#L13>)
+
+```go
+func (cv *ContextValues) UnmarshalJSON(data []byte) error
+```
+
+UnmarshalJSON implements the json.Unmarshaler interface on ContextValues.
+
+See: https://github.com/VictorAvelar/mollie-api-go/issues/251
+
 <a name="CreateMollieConnectPaymentFields"></a>
 ## type [CreateMollieConnectPaymentFields](<https://github.com/VictorAvelar/mollie-api-go/blob/master/mollie/payments.go#L134-L137>)
 
diff --git a/mollie/balances.go b/mollie/balances.go
index 631accf..01b5049 100644
--- a/mollie/balances.go
+++ b/mollie/balances.go
@@ -208,9 +208,6 @@ const (
 	PlatformPaymentChargeback              TransactionType = "platform-payment-chargeback"
 )
 
-// ContextValues is a map of TransactionType to ContextValue.
-type ContextValues map[TransactionType]ContextValue
-
 // BalanceTransactionsList contains an array of embedded transactions.
 type BalanceTransactionsList struct {
 	Count    int `json:"count,omitempty"`
diff --git a/mollie/custom_types.go b/mollie/custom_types.go
new file mode 100644
index 0000000..82abbf2
--- /dev/null
+++ b/mollie/custom_types.go
@@ -0,0 +1,29 @@
+package mollie
+
+import (
+	"encoding/json"
+)
+
+// ContextValues is a map of TransactionType to ContextValue.
+type ContextValues map[TransactionType]ContextValue
+
+// UnmarshalJSON implements the json.Unmarshaler interface on ContextValues.
+//
+// See: https://github.com/VictorAvelar/mollie-api-go/issues/251
+func (cv *ContextValues) UnmarshalJSON(data []byte) error {
+	var d map[TransactionType]ContextValue
+
+	if err := json.Unmarshal(data, &d); err != nil {
+		if _, ok := err.(*json.UnmarshalTypeError); ok {
+			*cv = make(ContextValues)
+
+			return nil
+		}
+
+		return err
+	}
+
+	*cv = ContextValues(d)
+
+	return nil
+}


Test patch:
diff --git a/mollie/custom_types_test.go b/mollie/custom_types_test.go
new file mode 100644
index 0000000..e7f3cc7
--- /dev/null
+++ b/mollie/custom_types_test.go
@@ -0,0 +1,73 @@
+package mollie
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestContextValues_UnmarshalJSON(t *testing.T) {
+	tests := []struct {
+		name    string
+		data    []byte
+		want    ContextValues
+		wantErr bool
+	}{
+		// Add test cases here
+		{
+			name: "Correct decoding JSON",
+			data: []byte(`{"type1": "value1", "type2": "value2"}`),
+			want: ContextValues{
+				"type1": "value1",
+				"type2": "value2",
+			},
+			wantErr: false,
+		},
+		{
+			name:    "Handle empty JSON",
+			data:    []byte(`{}`),
+			want:    ContextValues{},
+			wantErr: false,
+		},
+		{
+			name:    "Invalid JSON",
+			data:    []byte(`{"type1": "value1", "type2": "value2"`),
+			want:    make(ContextValues),
+			wantErr: true,
+		},
+		{
+			name:    "Incorrect type in json returns an empty map",
+			data:    []byte(`{"type1":["value1", "value2"]}`),
+			want:    make(ContextValues),
+			wantErr: false,
+		},
+		{
+			name: "Test correct case described on issue #251",
+			data: []byte(`{"context": {
+      "paymentId": "tr_xxxxxxxx"
+  }}`),
+			want:    make(ContextValues),
+			wantErr: false,
+		},
+		{
+			name:    "Test failing case described on issue #251",
+			data:    []byte(`{"context": []}`),
+			want:    make(ContextValues),
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			var cv ContextValues
+			err := cv.UnmarshalJSON(tt.data)
+
+			if tt.wantErr {
+				assert.Error(t, err)
+			} else {
+				assert.NoError(t, err)
+				assert.Equal(t, tt.want, cv)
+			}
+		})
+	}
+}