aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2022-11-07 14:02:03 +0700
committerShulhan <ms@kilabit.info>2022-11-07 14:13:41 +0700
commitb633c4bb046138db8b5d7f47f1cdf5d97e4de818 (patch)
tree7a8c922c713b9b00b8909220acc7f54c28906b33
parenteeacdd3063b6fc718fe513517808cb9fde72217b (diff)
downloadduitku-b633c4bb046138db8b5d7f47f1cdf5d97e4de818.tar.xz
all: implement client API for Clearing Transfer
The ClearingTransfer method do the clearing transfer using request and response from Clearing Inquiry.
-rw-r--r--clearing_transfer.go72
-rw-r--r--clearing_transfer_response.go8
-rw-r--r--client.go44
-rw-r--r--client_test.go39
-rw-r--r--testdata/disbursement/clearing_transfer_test.txt41
5 files changed, 204 insertions, 0 deletions
diff --git a/clearing_transfer.go b/clearing_transfer.go
new file mode 100644
index 0000000..2e51897
--- /dev/null
+++ b/clearing_transfer.go
@@ -0,0 +1,72 @@
+package duitku
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "time"
+)
+
+// clearingTransfer contains request parameter for Clearing Transfer.
+//
+// Formula to generate signature:
+//
+// SHA256(email + timestamp + bankCode + type + bankAccount +
+// accountName + custRefNumber + amountTransfer + purpose +
+// disburseId + apiKey)
+//
+// Ref: https://docs.duitku.com/disbursement/en/#clearing-transfer-request
+type clearingTransfer struct {
+ Type string `json:"type"`
+
+ rtolTransfer
+}
+
+// createClearingTransfer create clearingTransfer from Clearing Inquiry
+// request and response.
+//
+// The following fields are set from response: AccountName, CustRefNumber,
+// DisburseID, and Type.
+func createClearingTransfer(inqReq ClearingInquiry, inqRes ClearingInquiryResponse) (trf clearingTransfer) {
+ trf.Amount = inqReq.Amount
+ trf.BankAccount = inqReq.BankAccount
+ trf.BankCode = inqReq.BankCode
+ trf.Purpose = inqReq.Purpose
+
+ trf.AccountName = inqRes.AccountName
+ trf.CustRefNumber = inqRes.CustRefNumber
+ trf.DisburseID = inqRes.DisburseID
+ trf.Type = inqRes.Type
+
+ return trf
+}
+
+func (trf *clearingTransfer) sign(opts ClientOptions) {
+ var (
+ now = time.Now()
+
+ bb bytes.Buffer
+ plainHash [sha256.Size]byte
+ )
+
+ trf.UserID = opts.UserID
+ trf.Email = opts.Email
+ trf.Timestamp = now.UnixMilli()
+
+ bb.WriteString(trf.Email)
+ fmt.Fprintf(&bb, `%d`, trf.Timestamp)
+ bb.WriteString(trf.BankCode)
+ bb.WriteString(trf.Type)
+ bb.WriteString(trf.BankAccount)
+ bb.WriteString(trf.AccountName)
+ bb.WriteString(trf.CustRefNumber)
+ fmt.Fprintf(&bb, `%d`, trf.Amount)
+ bb.WriteString(trf.Purpose)
+ fmt.Fprintf(&bb, `%d`, trf.DisburseID)
+ bb.WriteString(opts.ApiKey)
+
+ plainHash = sha256.Sum256(bb.Bytes())
+
+ trf.Signature = hex.EncodeToString(plainHash[:])
+}
diff --git a/clearing_transfer_response.go b/clearing_transfer_response.go
new file mode 100644
index 0000000..773e8ee
--- /dev/null
+++ b/clearing_transfer_response.go
@@ -0,0 +1,8 @@
+package duitku
+
+// ClearingTransferResponse contains response from Clearing Transfer.
+type ClearingTransferResponse struct {
+ Type string `json:"type"`
+
+ RtolTransferResponse
+}
diff --git a/client.go b/client.go
index 6c9eea6..d4d4d9f 100644
--- a/client.go
+++ b/client.go
@@ -130,6 +130,50 @@ func (cl *Client) ClearingInquiry(req ClearingInquiry) (res *ClearingInquiryResp
return res, nil
}
+// ClearingTransfer do the clearing transfer using request and response from
+// Clearing Inquiry.
+//
+// The following fields are set from response: AccountName, CustRefNumber,
+// DisburseID, and Type.
+func (cl *Client) ClearingTransfer(inquiryReq ClearingInquiry, inquiryRes ClearingInquiryResponse) (
+ transferRes *ClearingTransferResponse, err error,
+) {
+ var (
+ logp = `ClearingTransfer`
+ path = PathDisbursementTransferClearing
+ transferReq = createClearingTransfer(inquiryReq, inquiryRes)
+
+ httpRes *http.Response
+ resBody []byte
+ )
+
+ transferReq.sign(cl.opts)
+
+ // Since the path is different in test environment, we check the host
+ // here to set it.
+ if cl.opts.host != hostLive {
+ path = PathDisbursementTransferClearingSandbox
+ }
+
+ httpRes, resBody, err = cl.PostJSON(path, nil, transferReq)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+ if httpRes.StatusCode >= 500 {
+ return nil, fmt.Errorf(`%s: %s`, logp, httpRes.Status)
+ }
+
+ err = json.Unmarshal(resBody, &transferRes)
+ if err != nil {
+ return nil, fmt.Errorf(`%s: %w`, logp, err)
+ }
+ if transferRes.Code != resCodeSuccess {
+ return nil, fmt.Errorf(`%s: %s: %s`, logp, transferRes.Code, transferRes.Desc)
+ }
+
+ return transferRes, nil
+}
+
// tListBank fetch list of banks for disbursement.
func (cl *Client) ListBank() (banks []Bank, err error) {
var (
diff --git a/client_test.go b/client_test.go
index bcb5c3d..c896c60 100644
--- a/client_test.go
+++ b/client_test.go
@@ -77,6 +77,45 @@ func TestClient_ClearingInquiry_sandbox(t *testing.T) {
test.Assert(t, `AccountName`, `Test Account`, inquiryRes.AccountName)
}
+func TestClient_ClearingTransfer_sandbox(t *testing.T) {
+ t.Skip(`This test require external call to server`)
+
+ var (
+ inquiryReq ClearingInquiry
+ inquiryRes ClearingInquiryResponse
+
+ err error
+ tdata *test.Data
+ transferRes *ClearingTransferResponse
+ )
+
+ tdata, err = test.LoadData(`testdata/disbursement/clearing_transfer_test.txt`)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = json.Unmarshal(tdata.Input[`inquiry_request.json`], &inquiryReq)
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = json.Unmarshal(tdata.Input[`inquiry_response.json`], &inquiryRes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ transferRes, err = testClient.ClearingTransfer(inquiryReq, inquiryRes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // We cannot compare the response, because for each call to server
+ // it will return different DisburseID.
+
+ t.Logf(`transferRes: %+v`, transferRes)
+
+ test.Assert(t, `AccountName`, `Test Account`, transferRes.AccountName)
+}
+
func TestClient_RtolInquiry_sandbox(t *testing.T) {
t.Skip(`This test require external call to server`)
diff --git a/testdata/disbursement/clearing_transfer_test.txt b/testdata/disbursement/clearing_transfer_test.txt
new file mode 100644
index 0000000..375b60d
--- /dev/null
+++ b/testdata/disbursement/clearing_transfer_test.txt
@@ -0,0 +1,41 @@
+>>> inquiry_request.json
+{
+ "userId": 3551,
+ "email": "test@chakratechnology.com",
+ "amountTransfer": 10000,
+ "bankCode": "014",
+ "bankAccount": "8760673466",
+ "purpose": "Test Clearing Inquiry with duitku.",
+ "timestamp": 1506486841000,
+ "custRefNumber": "12345789",
+ "senderId": 123456789,
+ "senderName": "John Doe",
+ "type": "LLG"
+}
+
+>>> inquiry_response.json
+{
+ "email": "test@chakratechnology.com",
+ "bankCode": "014",
+ "bankAccount": "8760673466",
+ "amountTransfer": 10000,
+ "accountName": "Test Account",
+ "custRefNumber": "12345789",
+ "disburseId": 121012,
+ "type": "LLG",
+ "responseCode": "00",
+ "responseDesc": "Approved or completed successfully"
+}
+
+<<< transfer_response.json
+{
+ "email": "test@chakratechnology.com",
+ "bankCode": "014",
+ "bankAccount": "8760673466",
+ "amountTransfer": 10000,
+ "accountName": "Test Account",
+ "custRefNumber": "12345789",
+ "type": "LLG",
+ "responseCode": "00",
+ "responseDesc": "Approved or completed successfully"
+}