From bbf03f572658671f289c8f612389f5d4af9f414c Mon Sep 17 00:00:00 2001 From: zombozo12 Date: Thu, 25 May 2023 14:34:21 +0700 Subject: [PATCH 1/3] feat: added report api --- example/report/main.go | 44 ++++++++++ integration_test/main.go | 1 + integration_test/report.go | 28 ++++++ report.go | 21 +++++ report/client.go | 82 ++++++++++++++++++ report/example_test.go | 40 +++++++++ report/params.go | 20 +++++ report/report.go | 39 +++++++++ report/report_test.go | 171 +++++++++++++++++++++++++++++++++++++ 9 files changed, 446 insertions(+) create mode 100644 example/report/main.go create mode 100644 integration_test/report.go create mode 100644 report.go create mode 100644 report/client.go create mode 100644 report/example_test.go create mode 100644 report/params.go create mode 100644 report/report.go create mode 100644 report/report_test.go diff --git a/example/report/main.go b/example/report/main.go new file mode 100644 index 00000000..f4230ab0 --- /dev/null +++ b/example/report/main.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "github.com/joho/godotenv" + "github.com/xendit/xendit-go" + "github.com/xendit/xendit-go/report" + "log" + "os" +) + +func main() { + godotenvErr := godotenv.Load() + if godotenvErr != nil { + log.Fatal(godotenvErr) + } + + xendit.Opt.SecretKey = os.Getenv("SECRET_KEY") + + generateReportData := report.GenerateReportParams{ + Type: "BALANCE_HISTORY", // "BALANCE_HISTORY", "TRANSACTIONS", "UPCOMING_TRANSACTIONS" + Filter: report.Filter{ + From: "2020-01-01T00:00:00.000Z", + To: "2020-12-31T23:59:59.999Z", + }, + } + + resp, err := report.GenerateReport(&generateReportData) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("generated report: %+v\n", resp) + + getReportData := report.GetReportParams{ + ReportID: resp.ID, + } + + resp, err = report.GetReport(&getReportData) + if err != nil { + log.Fatal(err) + } + fmt.Printf("retrieved report: %+v\n", resp) +} diff --git a/integration_test/main.go b/integration_test/main.go index 7c609353..a5ca1258 100644 --- a/integration_test/main.go +++ b/integration_test/main.go @@ -26,6 +26,7 @@ var testFunctions = []func(){ transactionTest, accountTest, paymentmethodTest, + reportTest, } func main() { diff --git a/integration_test/report.go b/integration_test/report.go new file mode 100644 index 00000000..4461ea39 --- /dev/null +++ b/integration_test/report.go @@ -0,0 +1,28 @@ +package main + +import ( + "fmt" + "github.com/xendit/xendit-go/report" + "log" +) + +func reportTest() { + respReport, err := report.GenerateReport(&report.GenerateReportParams{ + Type: "BALANCE_HISTORY", // "BALANCE_HISTORY", "TRANSACTIONS", "UPCOMING_TRANSACTIONS" + Filter: report.Filter{ + From: "2020-01-01T00:00:00.000Z", + To: "2020-12-31T23:59:59.999Z", + }, + }) + if err != nil { + log.Panic(err) + } + + _, err = report.GetReport(&report.GetReportParams{ + ReportID: respReport.ID, + }) + if err != nil { + log.Panic(err) + } + fmt.Println("report integration tests done!") +} diff --git a/report.go b/report.go new file mode 100644 index 00000000..9a8e3ed9 --- /dev/null +++ b/report.go @@ -0,0 +1,21 @@ +package xendit + +import "time" + +type Report struct { + ID string `json:"id"` + Type string `json:"type"` + Filter Filter `json:"filter"` + Format string `json:"format"` + Status string `json:"status"` + Url string `json:"url"` + Currency string `json:"currency"` + BusinessID string `json:"business_id"` + Created *time.Time `json:"created"` + Updated *time.Time `json:"updated"` +} + +type Filter struct { + From string `json:"from"` + To string `json:"to"` +} diff --git a/report/client.go b/report/client.go new file mode 100644 index 00000000..df18d64a --- /dev/null +++ b/report/client.go @@ -0,0 +1,82 @@ +package report + +import ( + "context" + "fmt" + "github.com/xendit/xendit-go" + "github.com/xendit/xendit-go/utils/validator" + "net/http" +) + +type Client struct { + Opt *xendit.Option + APIRequester xendit.APIRequester +} + +// GenerateReport creates a report +func (c *Client) GenerateReport(data *GenerateReportParams) (*xendit.Report, *xendit.Error) { + return c.GenerateReportWithContext(context.Background(), data) +} + +// GenerateReportWithContext creates a report with context +func (c *Client) GenerateReportWithContext(ctx context.Context, data *GenerateReportParams) (*xendit.Report, *xendit.Error) { + if err := validator.ValidateRequired(ctx, data); err != nil { + return nil, validator.APIValidatorErr(err) + } + + response := &xendit.Report{} + + header := http.Header{} + if data.ForUserID != "" { + header.Add("for-user-id", data.ForUserID) + } + + err := c.APIRequester.Call( + ctx, + "POST", + fmt.Sprintf("%s/reports", c.Opt.XenditURL), + c.Opt.SecretKey, + header, + data, + response, + ) + if err != nil { + return nil, err + } + + return response, nil +} + +// GetReport gets a report +func (c *Client) GetReport(data *GetReportParams) (*xendit.Report, *xendit.Error) { + return c.GetReportWithContext(context.Background(), data) +} + +// GetReportWithContext gets a report with context +func (c *Client) GetReportWithContext(ctx context.Context, data *GetReportParams) (*xendit.Report, *xendit.Error) { + if err := validator.ValidateRequired(ctx, data); err != nil { + return nil, validator.APIValidatorErr(err) + } + + response := &xendit.Report{} + + header := http.Header{} + if data.ForUserID != "" { + header.Add("for-user-id", data.ForUserID) + } + + err := c.APIRequester.Call( + ctx, + "GET", + fmt.Sprintf("%s/reports/%s", c.Opt.XenditURL, data.ReportID), + c.Opt.SecretKey, + header, + nil, + response, + ) + if err != nil { + return nil, err + } + + return response, nil +} diff --git a/report/example_test.go b/report/example_test.go new file mode 100644 index 00000000..5e46a9d6 --- /dev/null +++ b/report/example_test.go @@ -0,0 +1,40 @@ +package report + +import ( + "github.com/xendit/xendit-go" + "log" +) + +func ExampleGenerateReport() { + xendit.Opt.SecretKey = "examplesecretkey" + + generateReport := GenerateReportParams{ + Type: "BALANCE_HISTORY", // "BALANCE_HISTORY", "TRANSACTIONS", "UPCOMING_TRANSACTIONS" + Filter: Filter{ + From: "2020-01-01T00:00:00.000Z", + To: "2020-12-31T23:59:59.999Z", + }, + } + + resp, err := GenerateReport(&generateReport) + if err != nil { + log.Fatal(err.ErrorCode) + } + + log.Printf("generated report: %+v\n", resp) +} + +func ExampleGetReport() { + xendit.Opt.SecretKey = "examplesecretkey" + + getReport := GetReportParams{ + ReportID: "report_5c1b34a2-6ceb-4c24-aba9-c836bac82b28", + } + + resp, err := GetReport(&getReport) + if err != nil { + log.Fatal(err.ErrorCode) + } + + log.Printf("retrieved report: %+v\n", resp) +} diff --git a/report/params.go b/report/params.go new file mode 100644 index 00000000..bd5595ba --- /dev/null +++ b/report/params.go @@ -0,0 +1,20 @@ +package report + +type Filter struct { + From string `json:"from"` + To string `json:"to"` +} + +type GenerateReportParams struct { + ForUserID string `json:"-"` + Type string `json:"type" validate:"required"` + Filter Filter `json:"filter" validate:"required"` + Format string `json:"format"` + Currency string `json:"currency"` + ReportVersion string `json:"report_version"` +} + +type GetReportParams struct { + ForUserID string `json:"-"` + ReportID string `json:"report_id" validate:"required"` +} diff --git a/report/report.go b/report/report.go new file mode 100644 index 00000000..892458b3 --- /dev/null +++ b/report/report.go @@ -0,0 +1,39 @@ +package report + +import ( + "context" + "github.com/xendit/xendit-go" +) + +func GenerateReport(data *GenerateReportParams) (*xendit.Report, *xendit.Error) { + return GenerateReportWithContext(context.Background(), data) +} + +func GenerateReportWithContext(ctx context.Context, data *GenerateReportParams) (*xendit.Report, *xendit.Error) { + client, err := getClient() + if err != nil { + return nil, err + } + + return client.GenerateReportWithContext(ctx, data) +} + +func GetReport(data *GetReportParams) (*xendit.Report, *xendit.Error) { + return GetReportWithContext(context.Background(), data) +} + +func GetReportWithContext(ctx context.Context, data *GetReportParams) (*xendit.Report, *xendit.Error) { + client, err := getClient() + if err != nil { + return nil, err + } + + return client.GetReportWithContext(ctx, data) +} + +func getClient() (*Client, *xendit.Error) { + return &Client{ + Opt: &xendit.Opt, + APIRequester: xendit.GetAPIRequester(), + }, nil +} diff --git a/report/report_test.go b/report/report_test.go new file mode 100644 index 00000000..332f1d8a --- /dev/null +++ b/report/report_test.go @@ -0,0 +1,171 @@ +package report + +import ( + "context" + "encoding/json" + "errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/xendit/xendit-go" + "github.com/xendit/xendit-go/utils/validator" + "net/http" + "testing" + "time" +) + +func initTesting(apiRequesterMockObj xendit.APIRequester) { + xendit.Opt.SecretKey = "examplesecretkey" + xendit.SetAPIRequester(apiRequesterMockObj) +} + +type apiRequesterMock struct { + mock.Mock +} + +func (m *apiRequesterMock) Call(ctx context.Context, method string, url string, secretKey string, header http.Header, body interface{}, result interface{}) *xendit.Error { + m.Called(ctx, method, url, secretKey, header, body, result) + + resultString := `{ + "id": "report_5c1b34a2-6ceb-4c24-aba9-c836bac82b28", + "type": "BALANCE_HISTORY", + "status": "COMPLETED", + "filter": { + "from": "2021-06-23T04:01:55.574Z", + "to": "2021-06-24T04:01:55.574Z" + }, + "format": "CSV", + "url": "https://transaction-report-files.s3-us-west-2.amazonaws.com/{report_name}", + "currency": "IDR", + "business_id": "5f34f60535ba7c1c0eed846a", + "created": "2021-06-24T04:01:55.570Z", + "updated": "2021-06-24T04:01:55.570Z" + }` + + _ = json.Unmarshal([]byte(resultString), &result) + + return nil +} + +func TestGenerateReport(t *testing.T) { + apiRequesterMockObj := new(apiRequesterMock) + initTesting(apiRequesterMockObj) + + created := time.Date(2021, 6, 24, 04, 01, 55, 570000000, time.UTC) + updated := time.Date(2021, 6, 24, 04, 01, 55, 570000000, time.UTC) + + testCases := []struct { + desc string + data *GenerateReportParams + expectedRes *xendit.Report + expectedErr *xendit.Error + }{ + { + desc: "should generate report", + data: &GenerateReportParams{ + Type: "BALANCE_HISTORY", // "BALANCE_HISTORY", "TRANSACTIONS", "UPCOMING_TRANSACTIONS" + Filter: Filter{ + From: "2021-06-23T04:01:55.574Z", + To: "2021-06-24T04:01:55.574Z", + }, + }, + expectedRes: &xendit.Report{ + ID: "report_5c1b34a2-6ceb-4c24-aba9-c836bac82b28", + Type: "BALANCE_HISTORY", + Status: "COMPLETED", + Filter: xendit.Filter{ + From: "2021-06-23T04:01:55.574Z", + To: "2021-06-24T04:01:55.574Z", + }, + Format: "CSV", + Url: "https://transaction-report-files.s3-us-west-2.amazonaws.com/{report_name}", + Currency: "IDR", + BusinessID: "5f34f60535ba7c1c0eed846a", + Created: &created, + Updated: &updated, + }, + }, + { + desc: "should report error", + data: &GenerateReportParams{}, + expectedErr: validator.APIValidatorErr(errors.New("Missing required fields: 'Type'")), + }, + } + + for _, tC := range testCases { + t.Run(tC.desc, func(t *testing.T) { + apiRequesterMockObj.On("Call", + context.Background(), + "POST", + xendit.Opt.XenditURL+"/reports", + xendit.Opt.SecretKey, + mock.Anything, + mock.Anything, + &xendit.Report{}, + ).Return(nil) + + resp, err := GenerateReport(tC.data) + assert.Equal(t, tC.expectedRes, resp) + assert.Equal(t, tC.expectedErr, err) + }) + } +} + +func TestGetReport(t *testing.T) { + apiRequesterMockObj := new(apiRequesterMock) + initTesting(apiRequesterMockObj) + + created := time.Date(2021, 6, 24, 04, 01, 55, 570000000, time.UTC) + updated := time.Date(2021, 6, 24, 04, 01, 55, 570000000, time.UTC) + + testCases := []struct { + desc string + data *GetReportParams + expectedRes *xendit.Report + expectedErr *xendit.Error + }{ + { + desc: "should generate report", + data: &GetReportParams{ + ReportID: "report_5c1b34a2-6ceb-4c24-aba9-c836bac82b28", + }, + expectedRes: &xendit.Report{ + ID: "report_5c1b34a2-6ceb-4c24-aba9-c836bac82b28", + Type: "BALANCE_HISTORY", + Status: "COMPLETED", + Filter: xendit.Filter{ + From: "2021-06-23T04:01:55.574Z", + To: "2021-06-24T04:01:55.574Z", + }, + Format: "CSV", + Url: "https://transaction-report-files.s3-us-west-2.amazonaws.com/{report_name}", + Currency: "IDR", + BusinessID: "5f34f60535ba7c1c0eed846a", + Created: &created, + Updated: &updated, + }, + }, + { + desc: "should report error", + data: &GetReportParams{}, + expectedErr: validator.APIValidatorErr(errors.New("Missing required fields: 'ReportID'")), + }, + } + + for _, tC := range testCases { + t.Run(tC.desc, func(t *testing.T) { + apiRequesterMockObj.On("Call", + context.Background(), + "GET", + xendit.Opt.XenditURL+"/reports/"+tC.data.ReportID, + xendit.Opt.SecretKey, + mock.Anything, + mock.Anything, + &xendit.Report{}, + ).Return(nil) + + resp, err := GetReport(tC.data) + assert.Equal(t, tC.expectedRes, resp) + assert.Equal(t, tC.expectedErr, err) + }) + } +} From 95033b76e96e2c2a50048dc8dc3fdd49e0fc364f Mon Sep 17 00:00:00 2001 From: zombozo12 Date: Thu, 25 May 2023 14:44:19 +0700 Subject: [PATCH 2/3] fix: add comments --- report/report.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/report/report.go b/report/report.go index 892458b3..725e7ce1 100644 --- a/report/report.go +++ b/report/report.go @@ -5,10 +5,12 @@ import ( "github.com/xendit/xendit-go" ) +// GenerateReport generates a report func GenerateReport(data *GenerateReportParams) (*xendit.Report, *xendit.Error) { return GenerateReportWithContext(context.Background(), data) } +// GenerateReportWithContext generates a report with context func GenerateReportWithContext(ctx context.Context, data *GenerateReportParams) (*xendit.Report, *xendit.Error) { client, err := getClient() if err != nil { @@ -18,10 +20,12 @@ func GenerateReportWithContext(ctx context.Context, data *GenerateReportParams) return client.GenerateReportWithContext(ctx, data) } +// GetReport gets a report func GetReport(data *GetReportParams) (*xendit.Report, *xendit.Error) { return GetReportWithContext(context.Background(), data) } +// GetReportWithContext gets a report with context func GetReportWithContext(ctx context.Context, data *GetReportParams) (*xendit.Report, *xendit.Error) { client, err := getClient() if err != nil { From 21438dc481ba6a76b3305afee0c04bd0716d8824 Mon Sep 17 00:00:00 2001 From: Wiguna R <21243980+zombozo12@users.noreply.github.com> Date: Fri, 26 May 2023 02:10:14 +0000 Subject: [PATCH 3/3] fix: minor fix from review --- client/api.go | 3 +++ report.go | 20 ++++++++++---------- report/report_test.go | 8 ++++---- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/client/api.go b/client/api.go index 54c8cc0e..9e2733ed 100644 --- a/client/api.go +++ b/client/api.go @@ -15,6 +15,7 @@ import ( "github.com/xendit/xendit-go/payout" "github.com/xendit/xendit-go/qrcode" "github.com/xendit/xendit-go/recurringpayment" + "github.com/xendit/xendit-go/report" "github.com/xendit/xendit-go/retailoutlet" "github.com/xendit/xendit-go/virtualaccount" ) @@ -35,6 +36,7 @@ type API struct { Disbursement *disbursement.Client QRCode *qrcode.Client Customer *customer.Client + Report *report.Client } func (a *API) init() { @@ -50,6 +52,7 @@ func (a *API) init() { a.Disbursement = &disbursement.Client{Opt: &a.opt, APIRequester: a.apiRequester} a.QRCode = &qrcode.Client{Opt: &a.opt, APIRequester: a.apiRequester} a.Customer = &customer.Client{Opt: &a.opt, APIRequester: a.apiRequester} + a.Report = &report.Client{Opt: &a.opt, APIRequester: a.apiRequester} } // New creates a new Xendit API client diff --git a/report.go b/report.go index 9a8e3ed9..1256c198 100644 --- a/report.go +++ b/report.go @@ -3,16 +3,16 @@ package xendit import "time" type Report struct { - ID string `json:"id"` - Type string `json:"type"` - Filter Filter `json:"filter"` - Format string `json:"format"` - Status string `json:"status"` - Url string `json:"url"` - Currency string `json:"currency"` - BusinessID string `json:"business_id"` - Created *time.Time `json:"created"` - Updated *time.Time `json:"updated"` + ID string `json:"id"` + Type string `json:"type"` + Filter Filter `json:"filter"` + Format string `json:"format"` + Status string `json:"status"` + Url string `json:"url,omitempty"` + Currency string `json:"currency"` + BusinessID string `json:"business_id"` + Created time.Time `json:"created"` + Updated time.Time `json:"updated"` } type Filter struct { diff --git a/report/report_test.go b/report/report_test.go index 332f1d8a..2e98c8f8 100644 --- a/report/report_test.go +++ b/report/report_test.go @@ -80,8 +80,8 @@ func TestGenerateReport(t *testing.T) { Url: "https://transaction-report-files.s3-us-west-2.amazonaws.com/{report_name}", Currency: "IDR", BusinessID: "5f34f60535ba7c1c0eed846a", - Created: &created, - Updated: &updated, + Created: created, + Updated: updated, }, }, { @@ -140,8 +140,8 @@ func TestGetReport(t *testing.T) { Url: "https://transaction-report-files.s3-us-west-2.amazonaws.com/{report_name}", Currency: "IDR", BusinessID: "5f34f60535ba7c1c0eed846a", - Created: &created, - Updated: &updated, + Created: created, + Updated: updated, }, }, {