From 86b3a3d1350e7bcc8361438407b509b7e8eb3878 Mon Sep 17 00:00:00 2001 From: Congiary <66987756+Congiary@users.noreply.github.com> Date: Mon, 28 Oct 2024 23:41:56 +0700 Subject: [PATCH] Implement GET /payments --- client.go | 22 ++++++++++++++ go.mod | 4 ++- go.sum | 6 ++++ payments.go | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++ request.go | 4 +-- webhook.go | 6 ++-- 6 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 go.sum create mode 100644 payments.go diff --git a/client.go b/client.go index 3a21928..4763a65 100644 --- a/client.go +++ b/client.go @@ -8,6 +8,7 @@ import ( "encoding/json" "errors" "fmt" + "github.com/google/go-querystring/query" "io" "net/http" "sort" @@ -121,6 +122,27 @@ func (c *Client) PostRequestWithContext(ctx context.Context, url string, request return c.httpClient.Do(req) } +// GetRequestWithContext will automatically sign the request with token +// Use BaseRequest type to implement any API request +func (c *Client) GetRequestWithContext(ctx context.Context, url string, request RequestInterface) (*http.Response, error) { + c.secureRequest(request) + + // Add query parameters from request to URL + queryParams, err := query.Values(request) + if err != nil { + return nil, err + } + + reqURL := c.baseURL + url + "?" + queryParams.Encode() + req, err := http.NewRequestWithContext(ctx, http.MethodGet, reqURL, nil) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json") + + return c.httpClient.Do(req) +} + // Функция для генерации подписи func generateSignature(data map[string]interface{}, secretKey string) string { // Сортировка ключей diff --git a/go.mod b/go.mod index 7f37a79..5879e04 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module github.com/congiary/cdek-pay -go 1.13 \ No newline at end of file +go 1.13 + +require github.com/google/go-querystring v1.1.0 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..beaee76 --- /dev/null +++ b/go.sum @@ -0,0 +1,6 @@ +github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/payments.go b/payments.go new file mode 100644 index 0000000..b11749d --- /dev/null +++ b/payments.go @@ -0,0 +1,86 @@ +package cdek_pay + +import ( + "context" +) + +const ( + PaymentColumnId = "id" + PaymentColumnTime = "payment_time" +) + +const ( + PaymentDirectionASC = "ASC" + PaymentDirectionDESC = "DESC" +) + +const ( + PaymentStatusSuccess = "success" // успешный платеж + PaymentStatusCancelled = "cancelled" // возврат, данный платеж создается после успешного возврата + PaymentStatusSuccessCancellation = "success_cancellation" // успешная отмена + PaymentStatusCancellationRequested = "cancellation_requested" // запрошена отмена +) + +type getPaymentsRequest struct { + BaseRequest + GetPaymentsRequest +} + +// todo: сделать как-то более красиво структуры +type GetPaymentsRequest struct { + Page int `json:"p[page]" url:"p[page]"` + PerPage int `json:"p[per_page]" url:"p[per_page]"` + Column string `json:"o[column]" url:"o[column]"` + Direction string `json:"o[direction]" url:"o[direction]"` + + OrderId *int `json:"q[order_id],omitempty" url:"q[order_id],omitempty"` + AccessKey *int `json:"q[access_key],omitempty" url:"q[access_key],omitempty"` +} + +func (i *getPaymentsRequest) GetValuesForSignature() map[string]interface{} { + return FlattenStructToMap(GetPaymentsRequest{ + Page: i.Page, + PerPage: i.PerPage, + Column: i.Column, + Direction: i.Direction, + OrderId: i.OrderId, + AccessKey: i.AccessKey, + }, "") +} + +type GetPaymentsResponse struct { + TotalPayments int `json:"total_payments"` // Общее количество платежей + CurrentPage int `json:"current_page"` // Текущая страница списка платежей + TotalPages int `json:"total_pages"` // Общее количество страниц списка платежей + Payments []Payment `json:"payments"` // Массив объектов платежей +} + +type Payment struct { + ID int `json:"id"` // Идентификатор платежа + OrderID int `json:"order_id"` // Сокращенный идентификатор заказа в системе CDEKFIN + AccessKey string `json:"access_key"` // Уникальный идентификатор заказа в системе CDEKFIN + Currency string `json:"currency"` // Валюта платежа + PayAmount int `json:"pay_amount"` // Сумма платежа в копейках (отрицательная для возвратов) + Status string `json:"status"` // Статус платежа + PaymentTime int `json:"payment_time"` // Дата и время платежа в формате Timestamp +} + +// GetPayments возвращает список платежей и возвратов +func (c *Client) GetPayments(ctx context.Context, request *GetPaymentsRequest) (*GetPaymentsResponse, error) { + req := getPaymentsRequest{ + GetPaymentsRequest: *request, + } + response, err := c.GetRequestWithContext(ctx, "payments", &req) + if err != nil { + return nil, err + } + defer response.Body.Close() + + var res GetPaymentsResponse + err = c.decodeResponse(response, &res) + if err != nil { + return nil, err + } + + return &res, nil +} diff --git a/request.go b/request.go index c806cb3..d18f2de 100644 --- a/request.go +++ b/request.go @@ -1,8 +1,8 @@ package cdek_pay type BaseRequest struct { - Login string `json:"login"` - Signature string `json:"signature"` + Login string `json:"login" url:"login"` + Signature string `json:"signature" url:"signature"` } type RequestInterface interface { diff --git a/webhook.go b/webhook.go index 0503dbe..6ba26f4 100644 --- a/webhook.go +++ b/webhook.go @@ -8,11 +8,11 @@ import ( ) type Webhook struct { - Payment Payment `json:"payment"` - Signature string `json:"signature"` + Payment PaymentEvent `json:"payment"` + Signature string `json:"signature"` } -type Payment struct { +type PaymentEvent struct { Amount int `json:"pay_amount"` AccessKey string `json:"access_key"` Currency string `json:"currency"`