diff options
| author | Shulhan <ms@kilabit.info> | 2022-11-07 14:02:03 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2022-11-07 14:13:41 +0700 |
| commit | b633c4bb046138db8b5d7f47f1cdf5d97e4de818 (patch) | |
| tree | 7a8c922c713b9b00b8909220acc7f54c28906b33 | |
| parent | eeacdd3063b6fc718fe513517808cb9fde72217b (diff) | |
| download | duitku-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.go | 72 | ||||
| -rw-r--r-- | clearing_transfer_response.go | 8 | ||||
| -rw-r--r-- | client.go | 44 | ||||
| -rw-r--r-- | client_test.go | 39 | ||||
| -rw-r--r-- | testdata/disbursement/clearing_transfer_test.txt | 41 |
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 +} @@ -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" +} |
