aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2023-02-01 14:56:51 +0700
committerShulhan <ms@kilabit.info>2023-02-01 15:26:41 +0700
commit78469f295acd5931d64c8af483c0261ff2eb6183 (patch)
treeff055c4b6759ff4e40f8bc3175de1968cb21e8a5
parentdd24a0248dc011fe43540b7a8f1487ed7d1e5d90 (diff)
downloadduitku-78469f295acd5931d64c8af483c0261ff2eb6183.tar.xz
all: implement API to check merchant transaction status
The MerchantTxStatus method check the payment status by its orderID and payment method. Reference: https://docs.duitku.com/api/en/#check-transaction
-rw-r--r--client.go44
-rw-r--r--client_test.go22
-rw-r--r--testdata/merchant/inquiry_test.txt9
-rw-r--r--transaction_status.go32
-rw-r--r--transaction_status_response.go28
5 files changed, 133 insertions, 2 deletions
diff --git a/client.go b/client.go
index 4d4ceca..0933840 100644
--- a/client.go
+++ b/client.go
@@ -7,6 +7,7 @@ import (
"encoding/json"
"fmt"
"net/http"
+ "net/url"
"sort"
"strings"
@@ -36,8 +37,9 @@ const (
PathTransferClearing = `/webapi/api/disbursement/transferclearing`
PathTransferClearingSandbox = `/webapi/api/disbursement/transferclearingsandbox` // Used for testing.
- PathMerchantPaymentMethod = `/webapi/api/merchant/paymentmethod/getpaymentmethod`
- PathMerchantInquiry = `/webapi/api/merchant/v2/inquiry`
+ PathMerchantInquiry = `/webapi/api/merchant/v2/inquiry`
+ PathMerchantPaymentMethod = `/webapi/api/merchant/paymentmethod/getpaymentmethod`
+ PathMerchantTransactionStatus = `/webapi/api/merchant/transactionStatus`
)
type Client struct {
@@ -323,6 +325,44 @@ func (cl *Client) MerchantPaymentMethod(req *PaymentMethod) (resp *PaymentMethod
return resp, nil
}
+// [MerchantTxStatus] get the status of payment from customer.
+//
+// [MerchantTxStatus]: https://docs.duitku.com/api/en/#check-transaction
+func (cl *Client) MerchantTxStatus(orderID, paymentMethod string) (resp *TxStatusResponse, err error) {
+ var (
+ logp = `MerchantTxStatus`
+ req = transactionStatus{
+ OrderID: orderID,
+ }
+
+ params url.Values
+ httpRes *http.Response
+ resBody []byte
+ )
+
+ req.sign(cl.opts, paymentMethod)
+
+ params, err = libhttp.MarshalForm(req)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ httpRes, resBody, err = cl.PostForm(PathMerchantTransactionStatus, nil, params)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+ if httpRes.StatusCode >= 400 {
+ return nil, fmt.Errorf(`%s: %s: %s`, logp, httpRes.Status, resBody)
+ }
+
+ err = json.Unmarshal(resBody, &resp)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ return resp, nil
+}
+
// Options return the current client configuration.
func (cl *Client) Options() (opts ClientOptions) {
return cl.opts
diff --git a/client_test.go b/client_test.go
index 832bf3a..2c58db5 100644
--- a/client_test.go
+++ b/client_test.go
@@ -254,6 +254,28 @@ func TestClient_MerchantInquiry(t *testing.T) {
t.Logf(`MerchantInquiry: response: %s`, got)
test.Assert(t, `MerchantInquiry`, string(exp), string(got))
+
+ // Test checking the transaction status.
+
+ var (
+ txResp *TxStatusResponse
+ )
+
+ txResp, err = testClientMerchant.MerchantTxStatus(req.MerchantOrderId, req.PaymentMethod)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ got, err = json.MarshalIndent(txResp, ``, ` `)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ tag = `tx_status_response.json`
+ exp = tdata.Output[tag]
+ exp = bytes.ReplaceAll(exp, []byte(`$ref`), []byte(resp.Reference))
+ t.Logf(`MerchantTxStatus: response: %s`, got)
+ test.Assert(t, `MerchantTxStatus`, string(exp), string(got))
}
func TestClient_MerchantPaymentMethod(t *testing.T) {
diff --git a/testdata/merchant/inquiry_test.txt b/testdata/merchant/inquiry_test.txt
index c597b22..05262d7 100644
--- a/testdata/merchant/inquiry_test.txt
+++ b/testdata/merchant/inquiry_test.txt
@@ -19,3 +19,12 @@
"qrString": "",
"amount": "10000"
}
+
+<<< tx_status_response.json
+{
+ "merchantOrderId": "1",
+ "reference": "$ref",
+ "amount": "10000",
+ "statusCode": "01",
+ "statusMessage": "PROCESS"
+}
diff --git a/transaction_status.go b/transaction_status.go
new file mode 100644
index 0000000..7ddae30
--- /dev/null
+++ b/transaction_status.go
@@ -0,0 +1,32 @@
+// SPDX-FileCopyrightText: 2023 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package duitku
+
+import (
+ "crypto/md5"
+ "encoding/hex"
+ "fmt"
+)
+
+type transactionStatus struct {
+ MerchantCode string `form:"merchantCode"`
+ OrderID string `form:"merchantOrderId"`
+
+ // Transaction identification code.
+ // Formula: md5(merchantCode + merchantOrderId + apiKey).
+ Signature string `form:"signature"`
+}
+
+func (tx *transactionStatus) sign(opts ClientOptions, paymentMethod string) {
+ var merchant = opts.Merchant(paymentMethod)
+
+ tx.MerchantCode = merchant.Code
+
+ var (
+ plain = fmt.Sprintf(`%s%s%s`, tx.MerchantCode, tx.OrderID, merchant.ApiKey)
+ md5Plain = md5.Sum([]byte(plain))
+ )
+
+ tx.Signature = hex.EncodeToString(md5Plain[:])
+}
diff --git a/transaction_status_response.go b/transaction_status_response.go
new file mode 100644
index 0000000..cba2fee
--- /dev/null
+++ b/transaction_status_response.go
@@ -0,0 +1,28 @@
+// SPDX-FileCopyrightText: 2023 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package duitku
+
+// List of valid Code in TxStatusResponse.
+const (
+ MerchantTxStatusSuccess = `00`
+ MerchantTxStatusProcess = `01`
+ MerchantTxStatusFailed = `02`
+)
+
+// TxStatusResponse contains response from checking merchant payment
+// status.
+type TxStatusResponse struct {
+ OrderID string `json:"merchantOrderId"`
+ Reference string `json:"reference"`
+ Amount string `json:"amount"`
+
+ // Status code transaction.
+ // - 00 - Success
+ // - 01 - Process
+ // - 02 - Failed/Expired
+ Code string `json:"statusCode"`
+
+ // Description that explain the status Code.
+ Message string `json:"statusMessage"`
+}