aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--client.go33
-rw-r--r--client_test.go48
-rw-r--r--duitku_test.go28
-rw-r--r--payment_fee.go25
-rw-r--r--payment_method.go64
-rw-r--r--payment_method_response.go11
-rw-r--r--testdata/merchant/payment_method_test.txt106
7 files changed, 314 insertions, 1 deletions
diff --git a/client.go b/client.go
index e91890b..b831c06 100644
--- a/client.go
+++ b/client.go
@@ -35,6 +35,8 @@ const (
PathTransferClearing = `/webapi/api/disbursement/transferclearing`
PathTransferClearingSandbox = `/webapi/api/disbursement/transferclearingsandbox` // Used for testing.
+
+ PathMerchantPaymentMethod = `/webapi/api/merchant/paymentmethod/getpaymentmethod`
)
type Client struct {
@@ -256,6 +258,37 @@ func (cl *Client) ListBank() (banks []Bank, err error) {
return banks, nil
}
+// MerchantPaymentMethod get active payment methods from the merchant (your)
+// project.
+//
+// Ref: https://docs.duitku.com/api/en/#get-payment-method
+func (cl *Client) MerchantPaymentMethod(req *PaymentMethod) (resp *PaymentMethodResponse, err error) {
+ var (
+ logp = `MerchantPaymentMethod`
+ path = PathMerchantPaymentMethod
+
+ resHttp *http.Response
+ resBody []byte
+ )
+
+ req.Sign(cl.opts)
+
+ resHttp, resBody, err = cl.PostJSON(path, nil, req)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+ if resHttp.StatusCode >= 500 {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ 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 67865ae..a4c9a1e 100644
--- a/client_test.go
+++ b/client_test.go
@@ -199,6 +199,54 @@ func TestClient_InquiryStatus_sandbox(t *testing.T) {
test.Assert(t, `InquiryStatus`, expInquiryStatus, resInqueryStatus)
}
+func TestClient_MerchantPaymentMethod(t *testing.T) {
+ var (
+ tdata *test.Data
+ err error
+ )
+
+ err = initClientMerchant()
+ if err != nil {
+ t.Skip(err)
+ }
+
+ tdata, err = test.LoadData(`testdata/merchant/payment_method_test.txt`)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var (
+ req *PaymentMethod
+ resp *PaymentMethodResponse
+ tag string
+ )
+
+ tag = `payment_method_request.json`
+ err = json.Unmarshal(tdata.Input[tag], &req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ resp, err = testClientMerchant.MerchantPaymentMethod(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var (
+ exp []byte
+ got []byte
+ )
+
+ got, err = json.MarshalIndent(resp, ``, ` `)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ tag = `payment_method_response.json`
+ exp = tdata.Output[tag]
+ test.Assert(t, `PaymentMethod`, string(exp), string(got))
+}
+
func TestClient_RtolInquiry_sandbox(t *testing.T) {
var (
err error
diff --git a/duitku_test.go b/duitku_test.go
index 9f158c5..f92d884 100644
--- a/duitku_test.go
+++ b/duitku_test.go
@@ -4,13 +4,15 @@
package duitku
import (
+ "fmt"
"log"
"os"
"testing"
)
var (
- testClient *Client
+ testClient *Client
+ testClientMerchant *Client
)
func TestMain(m *testing.M) {
@@ -31,3 +33,27 @@ func TestMain(m *testing.M) {
os.Exit(m.Run())
}
+
+func initClientMerchant() (err error) {
+ if testClientMerchant != nil {
+ return nil
+ }
+
+ var (
+ logp = `initClientMerchant`
+
+ opts *ClientOptions
+ )
+
+ opts, err = LoadClientOptions(`client.conf`)
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ testClientMerchant, err = NewClient(*opts)
+ if err != nil {
+ return fmt.Errorf(`%s: %w`, logp, err)
+ }
+
+ return nil
+}
diff --git a/payment_fee.go b/payment_fee.go
new file mode 100644
index 0000000..4b8f10f
--- /dev/null
+++ b/payment_fee.go
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: 2023 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package duitku
+
+// [PaymentFee] contains fee for payment method.
+//
+// If the settings in the merchant portal fees are charged to the
+// merchant, the TotalFee will appear 0.
+// The TotalFee will appear if it is charged to the customer.
+//
+// [PaymentFee]: https://docs.duitku.com/api/en/#payment-fee
+type PaymentFee struct {
+ // Payment method code.
+ PaymentMethod string `json:"paymentMethod"`
+
+ // Payment method name.
+ PaymentName string `json:"paymentName"`
+
+ // Payment method image url.
+ PaymentImage string `json:"paymentImage"`
+
+ // Payment Fee.
+ TotalFee string `json:"totalFee"`
+}
diff --git a/payment_method.go b/payment_method.go
new file mode 100644
index 0000000..b5e95fa
--- /dev/null
+++ b/payment_method.go
@@ -0,0 +1,64 @@
+// SPDX-FileCopyrightText: 2023 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package duitku
+
+import (
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "time"
+)
+
+const (
+ // PaymentMethodDatetimeLayout define the date and time format for
+ // PaymentMethod.DateTime.
+ PaymentMethodDatetimeLayout = time.DateTime
+)
+
+// PaymentMethod contains request for client MerchantPaymentMethod.
+type PaymentMethod struct {
+ // [REQ] Merchant code from Duitku.
+ // Set by calling sign from ClientOptions.
+ MerchantCode string `json:"merchantcode"`
+
+ // [REQ] Format: yyyy-MM-dd HH:mm:ss
+ // If empty, it will be set during sign using current date time.
+ DateTime string `json:"datetime"`
+
+ // [REQ] Formula: Sha256(merchantcode + paymentAmount + datetime +
+ // apiKey).
+ // The value of hash is stored as lowercase hexadecimal.
+ Signature string `json:"signature"`
+
+ // [REQ] Transaction amount. No decimal code (.) and no decimal digit.
+ Amount int64 `json:"amount"`
+}
+
+// SetDateTime set the field DateTime using t.
+func (req *PaymentMethod) SetDateTime(t time.Time) {
+ req.DateTime = t.Format(PaymentMethodDatetimeLayout)
+}
+
+// Sign the request.
+// Set the MerchantCode and DateTime if its empty, and then generate the
+// Signature.
+func (req *PaymentMethod) Sign(opts ClientOptions) {
+ var (
+ plain string
+ hash [sha256.Size]byte
+ )
+
+ if len(req.MerchantCode) == 0 {
+ req.MerchantCode = opts.MerchantCode
+ }
+
+ if len(req.DateTime) == 0 {
+ req.SetDateTime(time.Now())
+ }
+
+ plain = fmt.Sprintf(`%s%d%s%s`, req.MerchantCode, req.Amount, req.DateTime, opts.MerchantApiKey)
+ hash = sha256.Sum256([]byte(plain))
+
+ req.Signature = hex.EncodeToString(hash[:])
+}
diff --git a/payment_method_response.go b/payment_method_response.go
new file mode 100644
index 0000000..4d901d8
--- /dev/null
+++ b/payment_method_response.go
@@ -0,0 +1,11 @@
+// SPDX-FileCopyrightText: 2023 M. Shulhan <ms@kilabit.info>
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+package duitku
+
+// PaymentMethodResponse contains list of payments enabled by merchant.
+type PaymentMethodResponse struct {
+ Response
+
+ PaymentFee []PaymentFee `json:"paymentFee"`
+}
diff --git a/testdata/merchant/payment_method_test.txt b/testdata/merchant/payment_method_test.txt
new file mode 100644
index 0000000..9ecca1e
--- /dev/null
+++ b/testdata/merchant/payment_method_test.txt
@@ -0,0 +1,106 @@
+>>> payment_method_request.json
+{}
+
+<<< payment_method_response.json
+{
+ "responseCode": "00",
+ "responseDesc": "",
+ "paymentFee": [
+ {
+ "paymentMethod": "VA",
+ "paymentName": "MAYBANK VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/VA.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "BT",
+ "paymentName": "PERMATA VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/PERMATA.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "B1",
+ "paymentName": "CIMB NIAGA VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/B1.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "A1",
+ "paymentName": "ATM BERSAMA VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/A1.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "OV",
+ "paymentName": "OVO",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/OV.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "F5",
+ "paymentName": "MANDIRI VA DEPOSIT",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "M1",
+ "paymentName": "MANDIRI VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/MV.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "M2",
+ "paymentName": "MANDIRI VA H2H",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/MV.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "AG",
+ "paymentName": "ARTHA GRAHA VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/AG.JPG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "S1",
+ "paymentName": "SAMPOERNA VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/S1.JPG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "SP",
+ "paymentName": "SHOPEEPAY QRIS",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/SHOPEEPAY.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "SA",
+ "paymentName": "SHOPEEPAY APP",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/SHOPEEPAY.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "SL",
+ "paymentName": "SHOPEEPAY LINK",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/SHOPEEPAY.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "BR",
+ "paymentName": "BRI VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/BR.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "NC",
+ "paymentName": "BNC VA",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/NC.PNG",
+ "totalFee": "0"
+ },
+ {
+ "paymentMethod": "IR",
+ "paymentName": "INDOMARET",
+ "paymentImage": "https://images.duitku.com/hotlink-ok/IR.PNG",
+ "totalFee": "0"
+ }
+ ]
+}