From 616ed53618f7df87f1b13c3f3c9e3821121872c2 Mon Sep 17 00:00:00 2001 From: Shulhan Date: Fri, 20 Jan 2023 17:16:29 +0700 Subject: all: implement client API for InquiryStatus The InquiryStatus get the status of previous Transfer. Ref: https://docs.duitku.com/disbursement/en/#inquiry-status --- client.go | 41 ++++++++++++++ client_test.go | 81 ++++++++++++++++++++++++++++ inquiry_status.go | 31 +++++++++++ inquiry_status_response.go | 26 +++++++++ testdata/disbursement/inquirystatus_test.txt | 52 ++++++++++++++++++ 5 files changed, 231 insertions(+) create mode 100644 inquiry_status.go create mode 100644 inquiry_status_response.go create mode 100644 testdata/disbursement/inquirystatus_test.txt diff --git a/client.go b/client.go index ae63ba4..1adecaf 100644 --- a/client.go +++ b/client.go @@ -22,6 +22,10 @@ const ( PathInquiry = `/webapi/api/disbursement/inquiry` PathInquirySandbox = `/webapi/api/disbursement/inquirysandbox` // Used for testing. + // Endpoints to check transfer status. + PathInquiryStatus = `/webapi/api/disbursement/inquirystatus` + PathInquiryStatusSandbox = `/webapi/api/disbursement/inquirystatus` // Used for testing. + PathTransfer = `/webapi/api/disbursement/transfer` PathTransferSandbox = `/webapi/api/disbursement/transfersandbox` // Used for testing. @@ -165,6 +169,43 @@ func (cl *Client) ClearingTransfer(req *ClearingTransfer) (res *ClearingTransfer return res, nil } +// InquiryStatus get the transfer status of ClearingTransfer or RtolTransfer. +func (cl *Client) InquiryStatus(disburseID int64) (res *InquiryStatusResponse, err error) { + var ( + logp = `InquiryStatus` + path = PathInquiryStatus + req = InquiryStatus{ + DisburseID: disburseID, + } + + resHttp *http.Response + resBody []byte + ) + + // Since the path is different in test environment, we check the host + // here to set it. + if cl.opts.host != hostLive { + path = PathInquiryStatusSandbox + } + + 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: %s`, logp, resHttp.Status) + } + + err = json.Unmarshal(resBody, &res) + if err != nil { + return nil, fmt.Errorf(`%s: %w`, logp, err) + } + + return res, 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 fc6ba03..3db7dd2 100644 --- a/client_test.go +++ b/client_test.go @@ -120,6 +120,87 @@ func TestClient_ClearingTransfer_sandbox(t *testing.T) { test.Assert(t, `AccountName`, `Test Account`, transferRes.AccountName) } +func TestClient_InquiryStatus_sandbox(t *testing.T) { + t.Skip(`This test require external call to server`) + + var ( + tdata *test.Data + + reqInquiry *RtolInquiry + resInquiry *RtolInquiryResponse + expInquiry *RtolInquiryResponse + + reqTransfer *RtolTransfer + resTransfer *RtolTransferResponse + expTransfer *RtolTransferResponse + + resInqueryStatus *InquiryStatusResponse + expInquiryStatus *InquiryStatusResponse + + err error + exp []byte + ) + + tdata, err = test.LoadData(`testdata/disbursement/inquirystatus_test.txt`) + if err != nil { + t.Fatal(err) + } + + err = json.Unmarshal(tdata.Input[`inquiry_request.json`], &reqInquiry) + if err != nil { + t.Fatal(err) + } + + // Do inquiry bank account ... + + resInquiry, err = testClient.RtolInquiry(reqInquiry) + if err != nil { + t.Fatal(err) + } + + exp = tdata.Output[`inquiry_response.json`] + err = json.Unmarshal(exp, &expInquiry) + if err != nil { + t.Fatal(err) + } + expInquiry.CustRefNumber = resInquiry.CustRefNumber + expInquiry.DisburseID = resInquiry.DisburseID + test.Assert(t, `RtolInquiry`, expInquiry, resInquiry) + + // Do the transfer ... + + reqTransfer = NewRtolTransfer(reqInquiry, resInquiry) + + resTransfer, err = testClient.RtolTransfer(reqTransfer) + if err != nil { + t.Fatal(err) + } + + exp = tdata.Output[`transfer_response.json`] + err = json.Unmarshal(exp, &expTransfer) + if err != nil { + t.Fatal(err) + } + expTransfer.CustRefNumber = resTransfer.CustRefNumber + expTransfer.DisburseID = resTransfer.DisburseID + test.Assert(t, `RtolTransfer`, expTransfer, resTransfer) + + // Inquiry transfer status ... + + resInqueryStatus, err = testClient.InquiryStatus(resTransfer.DisburseID) + if err != nil { + t.Fatal(err) + } + + exp = tdata.Output[`inquirystatus_response.json`] + err = json.Unmarshal(exp, &expInquiryStatus) + if err != nil { + t.Fatal(err) + } + expInquiryStatus.CustRefNumber = resInqueryStatus.CustRefNumber + test.Assert(t, `InquiryStatus`, expInquiryStatus, resInqueryStatus) +} + func TestClient_RtolInquiry_sandbox(t *testing.T) { t.Skip(`This test require external call to server`) diff --git a/inquiry_status.go b/inquiry_status.go new file mode 100644 index 0000000..66797bf --- /dev/null +++ b/inquiry_status.go @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2022 M. Shulhan +// SPDX-License-Identifier: GPL-3.0-or-later + +package duitku + +import ( + "crypto/sha256" + "encoding/hex" + "fmt" + "time" +) + +// InquiryStatus request for transfer status. +type InquiryStatus struct { + Request + + DisburseID int64 `json:"disburseId"` +} + +// Sign the request, fill the UserID, Email, Timestamp, and generate the +// Signature. +func (inq *InquiryStatus) Sign(opts ClientOptions) { + inq.UserID = opts.UserID + inq.Email = opts.Email + inq.Timestamp = time.Now().UnixMilli() + + var plain string = fmt.Sprintf(`%s%d%d%s`, inq.Email, inq.Timestamp, inq.DisburseID, opts.ApiKey) + var plainHash [sha256.Size]byte = sha256.Sum256([]byte(plain)) + + inq.Signature = hex.EncodeToString(plainHash[:]) +} diff --git a/inquiry_status_response.go b/inquiry_status_response.go new file mode 100644 index 0000000..ced3f0e --- /dev/null +++ b/inquiry_status_response.go @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2022 M. Shulhan +// SPDX-License-Identifier: GPL-3.0-or-later + +package duitku + +import "github.com/shuLhan/share/lib/math/big" + +type InquiryStatusResponse struct { + Response + + // Destination Bank Code. + BankCode string `json:"bankCode"` + + // Destination account number. + BankAccount string `json:"bankAccount"` + + // Disbursement transfer amount. + Amount *big.Rat `json:"amountTransfer"` + + // Bank Account owner. + AccountName string `json:"accountName"` + + // 9 Digit Customer reference number that will be printed when the + // transaction is successful. + CustRefNumber string `json:"custRefNumber"` +} diff --git a/testdata/disbursement/inquirystatus_test.txt b/testdata/disbursement/inquirystatus_test.txt new file mode 100644 index 0000000..9596cc3 --- /dev/null +++ b/testdata/disbursement/inquirystatus_test.txt @@ -0,0 +1,52 @@ +Test InquiryStatus. + +All of the custRefNumber and disburseId will be replaced, since its dynamic on +each request. + +>>> inquiry_request.json +{ + "amountTransfer": 10000, + "bankAccount": "8760673566", + "bankCode": "002", + "purpose": "Test Transfer Online Inquiry with duitku.", + "senderId": 123456789, + "senderName": "John Doe" +} + +<<< inquiry_response.json +{ + "responseCode": "00", + "responseDesc": "Success", + "email": "test@chakratechnology.com", + "bankCode": "002", + "bankAccount": "8760673566", + "amountTransfer": "10000", + "accountName": "Test Account", + "custRefNumber": "", + "disburseId": 0 +} + +<<< transfer_response.json +{ + "purpose": "", + "responseCode": "00", + "responseDesc": "Success", + "email": "test@chakratechnology.com", + "bankCode": "002", + "bankAccount": "8760673566", + "amountTransfer": "10000", + "accountName": "Test Account", + "custRefNumber": "", + "userId": 0 +} + +<<< inquirystatus_response.json +{ + "responseCode": "00", + "responseDesc": "Success", + "bankCode": "002", + "bankAccount": "8760673566", + "amountTransfer": "10000", + "accountName": "Test Account", + "custRefNumber": "" +} -- cgit v1.3