From 5f58965975cc4202a09f5783d09197c29eadcec1 Mon Sep 17 00:00:00 2001 From: Sinh Date: Fri, 16 Sep 2022 17:43:13 +0700 Subject: [PATCH 01/12] define onpoint client --- go.mod | 2 +- go.sum | 2 + partnerapi/onpoint/const.go | 21 +++ partnerapi/onpoint/env.go | 9 ++ partnerapi/onpoint/error.go | 14 ++ partnerapi/onpoint/model_request.go | 83 ++++++++++ partnerapi/onpoint/model_response.go | 52 +++++++ partnerapi/onpoint/onpoint.go | 220 +++++++++++++++++++++++++++ partnerapi/onpoint/status.go | 17 +++ partnerapi/onpoint/util.go | 18 +++ 10 files changed, 437 insertions(+), 1 deletion(-) create mode 100644 partnerapi/onpoint/const.go create mode 100644 partnerapi/onpoint/env.go create mode 100644 partnerapi/onpoint/error.go create mode 100644 partnerapi/onpoint/model_request.go create mode 100644 partnerapi/onpoint/model_response.go create mode 100644 partnerapi/onpoint/onpoint.go create mode 100644 partnerapi/onpoint/status.go create mode 100644 partnerapi/onpoint/util.go diff --git a/go.mod b/go.mod index 881b3a0..926675b 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.17 require ( github.com/Selly-Modules/logger v0.0.1 - github.com/Selly-Modules/natsio v1.0.2-0.20220826163751-df340fefda0a + github.com/Selly-Modules/natsio v1.0.2-0.20220913022818-738089755ab0 github.com/nats-io/nats.go v1.13.0 github.com/thoas/go-funk v0.9.1 ) diff --git a/go.sum b/go.sum index bb59017..68d9a75 100644 --- a/go.sum +++ b/go.sum @@ -2,6 +2,8 @@ github.com/Selly-Modules/logger v0.0.1 h1:dwLLtW53FfVBlklhdtFRB63eP0ofIh0IUQ/Gjg github.com/Selly-Modules/logger v0.0.1/go.mod h1:RWhSQ3F01an8KD00VjzRBZOMcE5eV2Cy0/l4ZkeieyU= github.com/Selly-Modules/natsio v1.0.2-0.20220826163751-df340fefda0a h1:QmJ8iqksbU+1vUa2SijsAMSLnw1C5X4R8PYjuNPNCCE= github.com/Selly-Modules/natsio v1.0.2-0.20220826163751-df340fefda0a/go.mod h1:q9dqmiMyl9MUVYZsvAWDI85083rnLEGAEFfYajLOLUU= +github.com/Selly-Modules/natsio v1.0.2-0.20220913022818-738089755ab0 h1:viwbSgCFHHsiWIR2aOr6f0fuKgkWs9DR8A+xQgyoCDs= +github.com/Selly-Modules/natsio v1.0.2-0.20220913022818-738089755ab0/go.mod h1:q9dqmiMyl9MUVYZsvAWDI85083rnLEGAEFfYajLOLUU= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go new file mode 100644 index 0000000..cc7fda3 --- /dev/null +++ b/partnerapi/onpoint/const.go @@ -0,0 +1,21 @@ +package onpoint + +const ( + baseURLStaging = "https://dev-api.onpoint.vn" + + apiPathCreateOrder = "/v1/orders" + apiPathUpdateDelivery = "/v1/orders/delivery/update" + apiPathCancelOrder = "/v1/orders/cancel" + apiPathGetChannels = "/v1/channels" + + headerXAPIKey = "x-api-key" + headerXTimestamp = "x-timestamp" + headerXSignature = "x-signature" +) + +var ( + baseURLENVMapping = map[ENV]string{ + // EnvProd: baseURLProd, + EnvStaging: baseURLStaging, + } +) diff --git a/partnerapi/onpoint/env.go b/partnerapi/onpoint/env.go new file mode 100644 index 0000000..ebcc363 --- /dev/null +++ b/partnerapi/onpoint/env.go @@ -0,0 +1,9 @@ +package onpoint + +// ENV ... +type ENV string + +const ( + EnvStaging ENV = "STAGING" + EnvProd ENV = "PROD" +) diff --git a/partnerapi/onpoint/error.go b/partnerapi/onpoint/error.go new file mode 100644 index 0000000..660d39a --- /dev/null +++ b/partnerapi/onpoint/error.go @@ -0,0 +1,14 @@ +package onpoint + +import "fmt" + +// Error ... +type Error struct { + Message string `json:"message"` + Status string `json:"status"` +} + +// Error ... +func (e Error) Error() string { + return fmt.Sprintf("onpoint_err: status %s, message: %s", e.Status, e.Message) +} diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go new file mode 100644 index 0000000..cd5754a --- /dev/null +++ b/partnerapi/onpoint/model_request.go @@ -0,0 +1,83 @@ +package onpoint + +import "time" + +/* + * Request payload + */ + +// CreateOrderRequest ... +type CreateOrderRequest struct { + PartnerOrderCode string `json:"partner_order_code"` + OrderDate time.Time `json:"order_date"` + ChannelCode string `json:"channel_code"` + FullName string `json:"full_name"` + Email string `json:"email"` + Phone string `json:"phone"` + Address string `json:"address"` + DistrictCode string `json:"district_code"` + WardCode string `json:"ward_code"` + ProvinceCode string `json:"province_code"` + Note string `json:"note"` + SubtotalPrice int `json:"subtotal_price"` + ShippingFee int `json:"shipping_fee"` + TotalDiscounts int `json:"total_discounts"` + TotalPrice int `json:"total_price"` + PaymentMethod string `json:"payment_method"` + DeliveryPlatform string `json:"delivery_platform"` + Items []OrderItem `json:"items"` +} + +// OrderItem ... +type OrderItem struct { + SellingPrice int `json:"selling_price"` + Quantity int `json:"quantity"` + Uom string `json:"uom"` + Amount int `json:"amount"` + Name string `json:"name"` + PartnerSku string `json:"partner_sku"` +} + +// UpdateOrderDeliveryRequest ... +type UpdateOrderDeliveryRequest struct { + OrderNo string `json:"order_no"` // required + DeliveryPlatform string `json:"delivery_platform"` // required + DeliveryTrackingNumber string `json:"delivery_tracking_number"` + ShippingLabel string `json:"shipping_label"` +} + +// CancelOrderRequest ... +type CancelOrderRequest struct { + OrderNo string `json:"order_no"` +} + +/** + * WEBHOOK ONPOINT + */ + +// WebhookPayload ... +type WebhookPayload struct { + Event string `json:"event"` + RequestedAt time.Time `json:"requested_at"` + Data interface{} `json:"data"` +} + +// WebhookDataUpdateInventory ... +type WebhookDataUpdateInventory struct { + Sku string `json:"sku"` + PartnerSku string `json:"partner_sku"` + WarehouseCode string `json:"warehouse_code"` + AvailableQuantity int `json:"available_quantity"` + CommittedQuantity int `json:"committed_quantity"` + TotalQuantity int `json:"total_quantity"` + UpdatedAt time.Time `json:"updated_at"` +} + +// WebhookDataUpdateOrderStatus ... +type WebhookDataUpdateOrderStatus struct { + PartnerOrderCode string `json:"partner_order_code"` + OrderNo string `json:"order_no"` + Status string `json:"status"` + DeliveryStatus string `json:"delivery_status"` + UpdatedAt time.Time `json:"updated_at"` +} diff --git a/partnerapi/onpoint/model_response.go b/partnerapi/onpoint/model_response.go new file mode 100644 index 0000000..784042d --- /dev/null +++ b/partnerapi/onpoint/model_response.go @@ -0,0 +1,52 @@ +package onpoint + +import "time" + +// CreateOrderResponse ... +type CreateOrderResponse struct { + PartnerOrderCode string `json:"partner_order_code"` + OrderNo string `json:"order_no"` + OrderDate time.Time `json:"order_date"` + ChannelCode string `json:"channel_code"` + FullName string `json:"full_name"` + Email string `json:"email"` + Phone string `json:"phone"` + Address string `json:"address"` + FullAddress string `json:"full_address"` + District string `json:"district"` + Ward string `json:"ward"` + Province string `json:"province"` + DistrictCode string `json:"district_code"` + WardCode string `json:"ward_code"` + ProvinceCode string `json:"province_code"` + Note string `json:"note"` + SubtotalPrice int `json:"subtotal_price"` + ShippingFee int `json:"shipping_fee"` + TotalDiscounts int `json:"total_discounts"` + TotalPrice int `json:"total_price"` + PaymentMethod string `json:"payment_method"` + DeliveryPlatform string `json:"delivery_platform"` + Status string `json:"status"` + UpdatedAt time.Time `json:"updated_at"` + InsertedAt time.Time `json:"inserted_at"` + Items []OrderItem `json:"items"` +} + +// UpdateOrderDeliveryResponse ... +type UpdateOrderDeliveryResponse struct { + DeliveryPlatform string `json:"delivery_platform"` + DeliveryTrackingNumber string `json:"delivery_tracking_number"` + ShippingLabel string `json:"shipping_label"` +} + +// CancelOrderResponse ... +type CancelOrderResponse struct { + OrderNo string `json:"order_no"` + Status string `json:"status"` +} + +// ChannelResponse ... +type ChannelResponse struct { + Code string `json:"code"` + Name string `json:"name"` +} diff --git a/partnerapi/onpoint/onpoint.go b/partnerapi/onpoint/onpoint.go new file mode 100644 index 0000000..f8ce7f9 --- /dev/null +++ b/partnerapi/onpoint/onpoint.go @@ -0,0 +1,220 @@ +package onpoint + +import ( + "errors" + "fmt" + "net/http" + "strconv" + "strings" + "time" + + "github.com/Selly-Modules/natsio" + "github.com/Selly-Modules/natsio/model" + "github.com/Selly-Modules/natsio/subject" + + "github.com/Selly-Modules/3pl/util/pjson" +) + +// Client ... +type Client struct { + env ENV + apiKey string + secretKey string + natsClient natsio.Server +} + +// NewClient generate OnPoint client +func NewClient(env ENV, apiKey, secretKey string, nc natsio.Server) (*Client, error) { + if apiKey == "" { + return nil, errors.New("onpoint: cannot init with empty api key") + } + return &Client{ + env: env, + apiKey: apiKey, + secretKey: secretKey, + natsClient: nc, + }, nil +} + +// CreateOrder ... +func (c *Client) CreateOrder(p CreateOrderRequest) (*CreateOrderResponse, error) { + url := c.getBaseURL() + apiPathCreateOrder + natsPayload := model.CommunicationRequestHttp{ + ResponseImmediately: true, + Payload: model.HttpRequest{ + URL: url, + Method: http.MethodPost, + Data: pjson.ToJSONString(p), + }, + } + var ( + r model.CommunicationHttpResponse + errRes Error + dataRes struct { + Data CreateOrderResponse `json:"data"` + } + ) + if err := c.requestHttpViaNats(natsPayload, &r); err != nil { + return nil, err + } + res := r.Response + if res == nil { + return nil, fmt.Errorf("onpoint.Client.CreateOrder: empty_response") + } + if res.StatusCode >= http.StatusBadRequest { + if err := r.ParseResponseData(&errRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.CreateOrder: parse_response_err: %v", err) + } + return nil, errRes + } + if err := r.ParseResponseData(&dataRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.CreateOrder: parse_response_data: %v", err) + } + + return &dataRes.Data, nil +} + +// UpdateDelivery ... +func (c *Client) UpdateDelivery(p UpdateOrderDeliveryRequest) (*UpdateOrderDeliveryResponse, error) { + url := c.getBaseURL() + apiPathUpdateDelivery + natsPayload := model.CommunicationRequestHttp{ + ResponseImmediately: true, + Payload: model.HttpRequest{ + URL: url, + Method: http.MethodPost, + Data: pjson.ToJSONString(p), + }, + } + var ( + r model.CommunicationHttpResponse + errRes Error + dataRes struct { + Data UpdateOrderDeliveryResponse `json:"data"` + } + ) + if err := c.requestHttpViaNats(natsPayload, &r); err != nil { + return nil, err + } + res := r.Response + if res == nil { + return nil, fmt.Errorf("onpoint.Client.UpdateDelivery: empty_response") + } + if res.StatusCode >= http.StatusBadRequest { + if err := r.ParseResponseData(&errRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.UpdateDelivery: parse_response_err: %v", err) + } + return nil, errRes + } + if err := r.ParseResponseData(&dataRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.UpdateDelivery: parse_response_data: %v", err) + } + + return &dataRes.Data, nil +} + +// CancelOrder ... +func (c *Client) CancelOrder(p CancelOrderRequest) (*CancelOrderResponse, error) { + url := c.getBaseURL() + apiPathCancelOrder + natsPayload := model.CommunicationRequestHttp{ + ResponseImmediately: true, + Payload: model.HttpRequest{ + URL: url, + Method: http.MethodPost, + Data: pjson.ToJSONString(p), + }, + } + var ( + r model.CommunicationHttpResponse + errRes Error + dataRes struct { + Data CancelOrderResponse `json:"data"` + } + ) + if err := c.requestHttpViaNats(natsPayload, &r); err != nil { + return nil, err + } + res := r.Response + if res == nil { + return nil, fmt.Errorf("onpoint.Client.CancelOrder: empty_response") + } + if res.StatusCode >= http.StatusBadRequest { + if err := r.ParseResponseData(&errRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.CancelOrder: parse_response_err: %v", err) + } + return nil, errRes + } + if err := r.ParseResponseData(&dataRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.CancelOrder: parse_response_data: %v", err) + } + + return &dataRes.Data, nil +} + +// GetChannels ... +func (c *Client) GetChannels() ([]ChannelResponse, error) { + url := c.getBaseURL() + apiPathGetChannels + natsPayload := model.CommunicationRequestHttp{ + ResponseImmediately: true, + Payload: model.HttpRequest{ + URL: url, + Method: http.MethodGet, + }, + } + var ( + r model.CommunicationHttpResponse + errRes Error + dataRes struct { + Data []ChannelResponse `json:"data"` + } + ) + if err := c.requestHttpViaNats(natsPayload, &r); err != nil { + return nil, err + } + res := r.Response + if res == nil { + return nil, fmt.Errorf("onpoint.Client.GetChannels: empty_response") + } + if res.StatusCode >= http.StatusBadRequest { + if err := r.ParseResponseData(&errRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.GetChannels: parse_response_err: %v", err) + } + return nil, errRes + } + if err := r.ParseResponseData(&dataRes); err != nil { + return nil, fmt.Errorf("onpoint.Client.GetChannels: parse_response_data: %v", err) + } + + return dataRes.Data, nil +} + +func (c *Client) requestHttpViaNats(data model.CommunicationRequestHttp, res interface{}) error { + ec, err := c.natsClient.NewJSONEncodedConn() + if err != nil { + return fmt.Errorf("onpoint: request via nats %v", err) + } + qs := "" + for k, v := range data.Payload.Query { + qs += k + "=" + v + } + now := time.Now().Unix() + ts := strconv.FormatInt(now, 10) + arr := []string{ + qs, + data.Payload.Data, + ts, + } + s := strings.Join(arr, ".") + // sign data + sign := hashSHA256AndUppercase(s, c.secretKey) + data.Payload.Header = map[string]string{ + headerXAPIKey: c.apiKey, + headerXSignature: sign, + headerXTimestamp: ts, + } + + return ec.Request(subject.Communication.RequestHTTP, data, res) +} + +func (c *Client) getBaseURL() string { + return baseURLENVMapping[c.env] +} diff --git a/partnerapi/onpoint/status.go b/partnerapi/onpoint/status.go new file mode 100644 index 0000000..96cc880 --- /dev/null +++ b/partnerapi/onpoint/status.go @@ -0,0 +1,17 @@ +package onpoint + +const ( + OrderStatusNew = "new" + OrderStatusPendingWarehouse = "pending_warehouse" + OrderStatusWhProcessing = "wh_processing" + OrderStatusWhCompleted = "wh_completed" + OrderStatusDlPending = "dl_pending" + OrderStatusDlIntransit = "dl_intransit" + OrderStatusDLDelivered = "dl_delivered" + OrderStatusDLReturning = "dl_returning" + OrderStatusReturned = "returned" + OrderStatusPartialCancelled = "partial_cancelled" + OrderStatusCancelled = "cancelled" + OrderStatusCompleted = "completed" + OrderStatusUnknown = "unknown" +) diff --git a/partnerapi/onpoint/util.go b/partnerapi/onpoint/util.go new file mode 100644 index 0000000..1e0ee51 --- /dev/null +++ b/partnerapi/onpoint/util.go @@ -0,0 +1,18 @@ +package onpoint + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "strings" +) + +func hashSHA256(data, key string) string { + h := hmac.New(sha256.New, []byte(key)) + h.Write([]byte(data)) + return hex.EncodeToString(h.Sum(nil)) +} + +func hashSHA256AndUppercase(data, key string) string { + return strings.ToUpper(hashSHA256(data, key)) +} From 26390c46331f67c2bb50e442c45e334d547e6c46 Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 19 Sep 2022 14:34:55 +0700 Subject: [PATCH 02/12] add webhook util for onpoint --- partnerapi/onpoint/const.go | 3 ++ partnerapi/onpoint/model_request.go | 50 ++++++++++++++++++++++++----- util/pjson/marshal.go | 15 +++++++++ util/pjson/unmarshal.go | 8 ++--- 4 files changed, 62 insertions(+), 14 deletions(-) create mode 100644 util/pjson/marshal.go diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index cc7fda3..509d2e7 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -11,6 +11,9 @@ const ( headerXAPIKey = "x-api-key" headerXTimestamp = "x-timestamp" headerXSignature = "x-signature" + + webhookEventUpdateOrderStatus = "update_order_status" + webhookEventUpdateInventory = "update_inventory" ) var ( diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go index cd5754a..42e7b6f 100644 --- a/partnerapi/onpoint/model_request.go +++ b/partnerapi/onpoint/model_request.go @@ -1,6 +1,10 @@ package onpoint -import "time" +import ( + "time" + + "github.com/Selly-Modules/3pl/util/pjson" +) /* * Request payload @@ -55,13 +59,6 @@ type CancelOrderRequest struct { * WEBHOOK ONPOINT */ -// WebhookPayload ... -type WebhookPayload struct { - Event string `json:"event"` - RequestedAt time.Time `json:"requested_at"` - Data interface{} `json:"data"` -} - // WebhookDataUpdateInventory ... type WebhookDataUpdateInventory struct { Sku string `json:"sku"` @@ -81,3 +78,40 @@ type WebhookDataUpdateOrderStatus struct { DeliveryStatus string `json:"delivery_status"` UpdatedAt time.Time `json:"updated_at"` } + +// WebhookPayload ... +type WebhookPayload struct { + Event string `json:"event"` + RequestedAt time.Time `json:"requested_at"` + Data interface{} `json:"data"` +} + +// GetDataEventUpdateOrderStatus ... +func (p WebhookPayload) GetDataEventUpdateOrderStatus() (data *WebhookDataUpdateOrderStatus, ok bool) { + if p.Event != webhookEventUpdateOrderStatus { + return nil, false + } + b, err := pjson.Marshal(p.Data) + if err != nil { + return nil, false + } + if err = pjson.Unmarshal(b, &data); err != nil { + return nil, false + } + return data, true +} + +// GetDataEventUpdateInventory ... +func (p WebhookPayload) GetDataEventUpdateInventory() (data *WebhookDataUpdateInventory, ok bool) { + if p.Event != webhookEventUpdateInventory { + return nil, false + } + b, err := pjson.Marshal(p.Data) + if err != nil { + return nil, false + } + if err = pjson.Unmarshal(b, &data); err != nil { + return nil, false + } + return data, true +} diff --git a/util/pjson/marshal.go b/util/pjson/marshal.go new file mode 100644 index 0000000..3484fae --- /dev/null +++ b/util/pjson/marshal.go @@ -0,0 +1,15 @@ +package pjson + +import ( + "encoding/json" + "log" +) + +// Marshal ... +func Marshal(data interface{}) ([]byte, error) { + b, err := json.Marshal(data) + if err != nil { + log.Printf("3pl/util/pjson.Marshal: err %v, payload %v", err, data) + } + return b, err +} diff --git a/util/pjson/unmarshal.go b/util/pjson/unmarshal.go index ca804f0..641067d 100644 --- a/util/pjson/unmarshal.go +++ b/util/pjson/unmarshal.go @@ -2,18 +2,14 @@ package pjson import ( "encoding/json" - - "github.com/Selly-Modules/logger" + "log" ) // Unmarshal ... func Unmarshal(b []byte, resultP interface{}) error { err := json.Unmarshal(b, resultP) if err != nil { - logger.Error("pjson.Unmarshal", logger.LogData{ - "raw": string(b), - "err": err.Error(), - }) + log.Printf("3pl/util/pjson.Unmarshal: err %v, payload %s", err, string(b)) } return err } From 7343221d5eeadc5711091d8cc6125fe77786d47e Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 3 Oct 2022 10:04:50 +0700 Subject: [PATCH 03/12] change onpoint base url --- partnerapi/onpoint/const.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index 509d2e7..89270cc 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -1,7 +1,8 @@ package onpoint const ( - baseURLStaging = "https://dev-api.onpoint.vn" + baseURLStaging = "https://dev-selly-api.onpoint.vn" + baseURLProd = "https://selly-api.onpoint.vn" apiPathCreateOrder = "/v1/orders" apiPathUpdateDelivery = "/v1/orders/delivery/update" @@ -18,7 +19,7 @@ const ( var ( baseURLENVMapping = map[ENV]string{ - // EnvProd: baseURLProd, + EnvProd: baseURLProd, EnvStaging: baseURLStaging, } ) From ee4024dbe465a3056976859f8b9afc1cb409a729 Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 3 Oct 2022 11:04:14 +0700 Subject: [PATCH 04/12] change onpoint api path --- partnerapi/onpoint/const.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index 89270cc..997fcf7 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -4,8 +4,8 @@ const ( baseURLStaging = "https://dev-selly-api.onpoint.vn" baseURLProd = "https://selly-api.onpoint.vn" - apiPathCreateOrder = "/v1/orders" - apiPathUpdateDelivery = "/v1/orders/delivery/update" + apiPathCreateOrder = "/v1/orders/create" + apiPathUpdateDelivery = "/v1/orders/update_delivery" apiPathCancelOrder = "/v1/orders/cancel" apiPathGetChannels = "/v1/channels" From d3a7fe684bacef87ee759c9b0b218fded5c26c95 Mon Sep 17 00:00:00 2001 From: Sinh Date: Tue, 4 Oct 2022 15:45:29 +0700 Subject: [PATCH 05/12] update onpoint payload --- partnerapi/onpoint/const.go | 2 ++ partnerapi/onpoint/error.go | 19 +++++++++--- partnerapi/onpoint/model_request.go | 44 ++++++++++++---------------- partnerapi/onpoint/model_response.go | 24 +++------------ partnerapi/onpoint/onpoint.go | 38 +----------------------- 5 files changed, 40 insertions(+), 87 deletions(-) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index 997fcf7..cb073b0 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -15,6 +15,8 @@ const ( webhookEventUpdateOrderStatus = "update_order_status" webhookEventUpdateInventory = "update_inventory" + + CodeSuccess = "SUCCESS" ) var ( diff --git a/partnerapi/onpoint/error.go b/partnerapi/onpoint/error.go index 660d39a..445d921 100644 --- a/partnerapi/onpoint/error.go +++ b/partnerapi/onpoint/error.go @@ -1,14 +1,25 @@ package onpoint -import "fmt" +import ( + "fmt" + "strings" +) // Error ... type Error struct { - Message string `json:"message"` - Status string `json:"status"` + Message string `json:"message"` + Code string `json:"code"` + Errors map[string][]string `json:"errors"` } // Error ... func (e Error) Error() string { - return fmt.Sprintf("onpoint_err: status %s, message: %s", e.Status, e.Message) + msg := fmt.Sprintf("onpoint_err: code %s, message: %s", e.Code, e.Message) + if len(e.Errors) > 0 { + msg += "\ndetail: " + for k, v := range e.Errors { + msg += fmt.Sprintf("field %s - error %s", k, strings.Join(v, ",")) + } + } + return msg } diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go index 42e7b6f..efdc2cf 100644 --- a/partnerapi/onpoint/model_request.go +++ b/partnerapi/onpoint/model_request.go @@ -12,39 +12,31 @@ import ( // CreateOrderRequest ... type CreateOrderRequest struct { - PartnerOrderCode string `json:"partner_order_code"` - OrderDate time.Time `json:"order_date"` - ChannelCode string `json:"channel_code"` - FullName string `json:"full_name"` - Email string `json:"email"` - Phone string `json:"phone"` - Address string `json:"address"` - DistrictCode string `json:"district_code"` - WardCode string `json:"ward_code"` - ProvinceCode string `json:"province_code"` - Note string `json:"note"` - SubtotalPrice int `json:"subtotal_price"` - ShippingFee int `json:"shipping_fee"` - TotalDiscounts int `json:"total_discounts"` - TotalPrice int `json:"total_price"` - PaymentMethod string `json:"payment_method"` - DeliveryPlatform string `json:"delivery_platform"` - Items []OrderItem `json:"items"` + OrderCode string `json:"order_code"` + OrderDate time.Time `json:"order_date"` + PickupLocationCode string `json:"pickup_location_code"` + Note string `json:"note"` + SubtotalPrice int `json:"subtotal_price"` + TotalDiscounts int `json:"total_discounts"` + TotalPrice int `json:"total_price"` + PaymentMethod string `json:"payment_method"` + Items []OrderItem `json:"items"` } // OrderItem ... type OrderItem struct { - SellingPrice int `json:"selling_price"` - Quantity int `json:"quantity"` - Uom string `json:"uom"` - Amount int `json:"amount"` - Name string `json:"name"` - PartnerSku string `json:"partner_sku"` + SellingPrice int `json:"selling_price"` + Quantity int `json:"quantity"` + Uom string `json:"uom"` + Amount int `json:"amount"` + Name string `json:"name"` + PartnerSku string `json:"sku"` + DiscountPrice int `json:"discount_price"` } // UpdateOrderDeliveryRequest ... type UpdateOrderDeliveryRequest struct { - OrderNo string `json:"order_no"` // required + OrderCode string `json:"order_code"` // required DeliveryPlatform string `json:"delivery_platform"` // required DeliveryTrackingNumber string `json:"delivery_tracking_number"` ShippingLabel string `json:"shipping_label"` @@ -52,7 +44,7 @@ type UpdateOrderDeliveryRequest struct { // CancelOrderRequest ... type CancelOrderRequest struct { - OrderNo string `json:"order_no"` + OrderNo string `json:"order_code"` } /** diff --git a/partnerapi/onpoint/model_response.go b/partnerapi/onpoint/model_response.go index 784042d..6ed84e0 100644 --- a/partnerapi/onpoint/model_response.go +++ b/partnerapi/onpoint/model_response.go @@ -1,34 +1,18 @@ package onpoint -import "time" - // CreateOrderResponse ... type CreateOrderResponse struct { - PartnerOrderCode string `json:"partner_order_code"` - OrderNo string `json:"order_no"` - OrderDate time.Time `json:"order_date"` - ChannelCode string `json:"channel_code"` - FullName string `json:"full_name"` - Email string `json:"email"` - Phone string `json:"phone"` - Address string `json:"address"` - FullAddress string `json:"full_address"` - District string `json:"district"` - Ward string `json:"ward"` - Province string `json:"province"` - DistrictCode string `json:"district_code"` - WardCode string `json:"ward_code"` - ProvinceCode string `json:"province_code"` + OrderCode string `json:"order_code"` + OnpointOrderCode string `json:"onpoint_order_code"` + OrderDate string `json:"order_date"` Note string `json:"note"` SubtotalPrice int `json:"subtotal_price"` - ShippingFee int `json:"shipping_fee"` TotalDiscounts int `json:"total_discounts"` TotalPrice int `json:"total_price"` PaymentMethod string `json:"payment_method"` DeliveryPlatform string `json:"delivery_platform"` Status string `json:"status"` - UpdatedAt time.Time `json:"updated_at"` - InsertedAt time.Time `json:"inserted_at"` + UpdatedAt string `json:"updated_at"` Items []OrderItem `json:"items"` } diff --git a/partnerapi/onpoint/onpoint.go b/partnerapi/onpoint/onpoint.go index f8ce7f9..1d73753 100644 --- a/partnerapi/onpoint/onpoint.go +++ b/partnerapi/onpoint/onpoint.go @@ -51,6 +51,7 @@ func (c *Client) CreateOrder(p CreateOrderRequest) (*CreateOrderResponse, error) r model.CommunicationHttpResponse errRes Error dataRes struct { + Code string `json:"code"` Data CreateOrderResponse `json:"data"` } ) @@ -150,43 +151,6 @@ func (c *Client) CancelOrder(p CancelOrderRequest) (*CancelOrderResponse, error) return &dataRes.Data, nil } -// GetChannels ... -func (c *Client) GetChannels() ([]ChannelResponse, error) { - url := c.getBaseURL() + apiPathGetChannels - natsPayload := model.CommunicationRequestHttp{ - ResponseImmediately: true, - Payload: model.HttpRequest{ - URL: url, - Method: http.MethodGet, - }, - } - var ( - r model.CommunicationHttpResponse - errRes Error - dataRes struct { - Data []ChannelResponse `json:"data"` - } - ) - if err := c.requestHttpViaNats(natsPayload, &r); err != nil { - return nil, err - } - res := r.Response - if res == nil { - return nil, fmt.Errorf("onpoint.Client.GetChannels: empty_response") - } - if res.StatusCode >= http.StatusBadRequest { - if err := r.ParseResponseData(&errRes); err != nil { - return nil, fmt.Errorf("onpoint.Client.GetChannels: parse_response_err: %v", err) - } - return nil, errRes - } - if err := r.ParseResponseData(&dataRes); err != nil { - return nil, fmt.Errorf("onpoint.Client.GetChannels: parse_response_data: %v", err) - } - - return dataRes.Data, nil -} - func (c *Client) requestHttpViaNats(data model.CommunicationRequestHttp, res interface{}) error { ec, err := c.natsClient.NewJSONEncodedConn() if err != nil { From 04cc91bb5fd27d0815c24cf813254c4d5e307672 Mon Sep 17 00:00:00 2001 From: Sinh Date: Tue, 4 Oct 2022 16:29:34 +0700 Subject: [PATCH 06/12] add header content type for OP --- partnerapi/globalcare/globale_care.go | 3 ++- partnerapi/onpoint/onpoint.go | 8 +++++--- partnerapi/tnc/tnc.go | 5 +++-- util/httputil/const.go | 8 ++++++++ 4 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 util/httputil/const.go diff --git a/partnerapi/globalcare/globale_care.go b/partnerapi/globalcare/globale_care.go index 3a2ab0c..a8cb0c6 100644 --- a/partnerapi/globalcare/globale_care.go +++ b/partnerapi/globalcare/globale_care.go @@ -18,6 +18,7 @@ import ( "github.com/thoas/go-funk" "github.com/Selly-Modules/3pl/util/base64" + "github.com/Selly-Modules/3pl/util/httputil" "github.com/Selly-Modules/3pl/util/pjson" ) @@ -72,7 +73,7 @@ func (c *Client) CreateOrder(data CreateOrderPayload) (*CreateOrderResponseDecod Method: http.MethodPost, Data: pjson.ToJSONString(body), Header: map[string]string{ - "Content-Type": "application/json", + httputil.HeaderKeyContentType: httputil.HeaderValueApplicationJSON, }, }, } diff --git a/partnerapi/onpoint/onpoint.go b/partnerapi/onpoint/onpoint.go index 1d73753..000f57f 100644 --- a/partnerapi/onpoint/onpoint.go +++ b/partnerapi/onpoint/onpoint.go @@ -12,6 +12,7 @@ import ( "github.com/Selly-Modules/natsio/model" "github.com/Selly-Modules/natsio/subject" + "github.com/Selly-Modules/3pl/util/httputil" "github.com/Selly-Modules/3pl/util/pjson" ) @@ -171,9 +172,10 @@ func (c *Client) requestHttpViaNats(data model.CommunicationRequestHttp, res int // sign data sign := hashSHA256AndUppercase(s, c.secretKey) data.Payload.Header = map[string]string{ - headerXAPIKey: c.apiKey, - headerXSignature: sign, - headerXTimestamp: ts, + headerXAPIKey: c.apiKey, + headerXSignature: sign, + headerXTimestamp: ts, + httputil.HeaderKeyContentType: httputil.HeaderValueApplicationJSON, } return ec.Request(subject.Communication.RequestHTTP, data, res) diff --git a/partnerapi/tnc/tnc.go b/partnerapi/tnc/tnc.go index de2c7e0..be3a583 100644 --- a/partnerapi/tnc/tnc.go +++ b/partnerapi/tnc/tnc.go @@ -12,6 +12,7 @@ import ( "github.com/Selly-Modules/natsio/subject" "github.com/nats-io/nats.go" + "github.com/Selly-Modules/3pl/util/httputil" "github.com/Selly-Modules/3pl/util/pjson" ) @@ -230,7 +231,7 @@ func (c *Client) auth() (*authRes, error) { body := v.Encode() header := map[string]string{ - "Content-Type": "application/x-www-form-urlencoded", + httputil.HeaderKeyContentType: httputil.HeaderValueApplicationURLEncoded, } apiURL := baseURLAuthENVMapping[c.env] + fmt.Sprintf(apiPathAuth, c.realm) natsPayload := model.CommunicationRequestHttp{ @@ -276,7 +277,7 @@ func (c *Client) auth() (*authRes, error) { func (c *Client) getRequestHeader() map[string]string { m := map[string]string{ - "Content-Type": "application/json", + httputil.HeaderKeyContentType: httputil.HeaderValueApplicationJSON, } token, err := c.getToken() if err != nil { diff --git a/util/httputil/const.go b/util/httputil/const.go new file mode 100644 index 0000000..c708838 --- /dev/null +++ b/util/httputil/const.go @@ -0,0 +1,8 @@ +package httputil + +const ( + HeaderKeyContentType = "Content-Type" + + HeaderValueApplicationJSON = "application/json" + HeaderValueApplicationURLEncoded = "application/x-www-form-urlencoded" +) From 00d2d0f89537056538194509bfa2e7db30a888c6 Mon Sep 17 00:00:00 2001 From: Sinh Date: Fri, 14 Oct 2022 14:39:57 +0700 Subject: [PATCH 07/12] update onpoint webhook payload --- partnerapi/onpoint/const.go | 8 ++++++-- partnerapi/onpoint/model_request.go | 23 +++++++++++------------ 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index cb073b0..dffc4d9 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -1,5 +1,11 @@ package onpoint +const ( + CodeSuccess = "SUCCESS" + + TimeLayout = "2006-01-02T15:04:05Z" +) + const ( baseURLStaging = "https://dev-selly-api.onpoint.vn" baseURLProd = "https://selly-api.onpoint.vn" @@ -15,8 +21,6 @@ const ( webhookEventUpdateOrderStatus = "update_order_status" webhookEventUpdateInventory = "update_inventory" - - CodeSuccess = "SUCCESS" ) var ( diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go index 2da4a7d..a79b3a3 100644 --- a/partnerapi/onpoint/model_request.go +++ b/partnerapi/onpoint/model_request.go @@ -53,22 +53,21 @@ type CancelOrderRequest struct { // WebhookDataUpdateInventory ... type WebhookDataUpdateInventory struct { - Sku string `json:"sku"` - PartnerSku string `json:"partner_sku"` - WarehouseCode string `json:"warehouse_code"` - AvailableQuantity int `json:"available_quantity"` - CommittedQuantity int `json:"committed_quantity"` - TotalQuantity int `json:"total_quantity"` - UpdatedAt time.Time `json:"updated_at"` + Sku string `json:"sku"` + PartnerSku string `json:"partner_sku"` + WarehouseCode string `json:"warehouse_code"` + AvailableQuantity int `json:"available_quantity"` + CommittedQuantity int `json:"committed_quantity"` + TotalQuantity int `json:"total_quantity"` + UpdatedAt string `json:"updated_at"` } // WebhookDataUpdateOrderStatus ... type WebhookDataUpdateOrderStatus struct { - PartnerOrderCode string `json:"partner_order_code"` - OrderNo string `json:"order_no"` - Status string `json:"status"` - DeliveryStatus string `json:"delivery_status"` - UpdatedAt time.Time `json:"updated_at"` + OrderCode string `json:"order_code"` + OnpointOrderCode string `json:"onpoint_order_code"` + Status string `json:"status"` + UpdatedAt string `json:"updated_at"` } // WebhookPayload ... From 9807db0739cfd6b61f05f41c935218b9cb691684 Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 17 Oct 2022 14:32:28 +0700 Subject: [PATCH 08/12] add OP const --- partnerapi/onpoint/const.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index dffc4d9..a547f69 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -1,5 +1,11 @@ package onpoint +const ( + PaymentMethodCOD = "cod" + PaymentMethodBankTransfer = "bank_transfer" + PaymentMethodWallet = "wallet" +) + const ( CodeSuccess = "SUCCESS" From 9124e39283c70132274cd882b65c0492d3007b4d Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 17 Oct 2022 16:28:13 +0700 Subject: [PATCH 09/12] update event value OP --- partnerapi/onpoint/const.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/partnerapi/onpoint/const.go b/partnerapi/onpoint/const.go index a547f69..e9573bc 100644 --- a/partnerapi/onpoint/const.go +++ b/partnerapi/onpoint/const.go @@ -25,7 +25,7 @@ const ( headerXTimestamp = "x-timestamp" headerXSignature = "x-signature" - webhookEventUpdateOrderStatus = "update_order_status" + webhookEventUpdateOrderStatus = "UPDATE_ORDER_STATUS" webhookEventUpdateInventory = "update_inventory" ) From ba87bb90be88a3f353eeaa11c491cff806633d7d Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 17 Oct 2022 16:48:53 +0700 Subject: [PATCH 10/12] update webhook payload OP --- partnerapi/onpoint/model_request.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go index a79b3a3..3fb8875 100644 --- a/partnerapi/onpoint/model_request.go +++ b/partnerapi/onpoint/model_request.go @@ -74,7 +74,7 @@ type WebhookDataUpdateOrderStatus struct { type WebhookPayload struct { Event string `json:"event"` RequestedAt time.Time `json:"requested_at"` - Data interface{} `json:"data"` + Payload interface{} `json:"payload"` } // GetDataEventUpdateOrderStatus ... @@ -82,7 +82,7 @@ func (p WebhookPayload) GetDataEventUpdateOrderStatus() (data *WebhookDataUpdate if p.Event != webhookEventUpdateOrderStatus { return nil, false } - b, err := pjson.Marshal(p.Data) + b, err := pjson.Marshal(p.Payload) if err != nil { return nil, false } @@ -97,7 +97,7 @@ func (p WebhookPayload) GetDataEventUpdateInventory() (data *WebhookDataUpdateIn if p.Event != webhookEventUpdateInventory { return nil, false } - b, err := pjson.Marshal(p.Data) + b, err := pjson.Marshal(p.Payload) if err != nil { return nil, false } From ce8344fdc99dddad3fde2b194d6afb83709185be Mon Sep 17 00:00:00 2001 From: Sinh Date: Tue, 18 Oct 2022 14:58:48 +0700 Subject: [PATCH 11/12] update OP method --- partnerapi/onpoint/model_request.go | 1 + 1 file changed, 1 insertion(+) diff --git a/partnerapi/onpoint/model_request.go b/partnerapi/onpoint/model_request.go index 3fb8875..708f349 100644 --- a/partnerapi/onpoint/model_request.go +++ b/partnerapi/onpoint/model_request.go @@ -39,6 +39,7 @@ type UpdateOrderDeliveryRequest struct { OrderCode string `json:"order_code"` // required DeliveryPlatform string `json:"delivery_platform"` // required DeliveryTrackingNumber string `json:"delivery_tracking_number"` + DeliveryStatus string `json:"delivery_status"` ShippingLabel string `json:"shipping_label"` } From e9f66f611ea766b164bbe858816ea060128850f2 Mon Sep 17 00:00:00 2001 From: Sinh Date: Mon, 24 Oct 2022 18:00:46 +0700 Subject: [PATCH 12/12] update gc car payload --- partnerapi/globalcare/model_request.go | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/partnerapi/globalcare/model_request.go b/partnerapi/globalcare/model_request.go index 2da031f..3b3b258 100644 --- a/partnerapi/globalcare/model_request.go +++ b/partnerapi/globalcare/model_request.go @@ -1,7 +1,6 @@ package globalcare import ( - "encoding/json" "time" ) @@ -41,20 +40,7 @@ type VehicleInfo struct { // CarOccupantAccidentInsuranceObj ... type CarOccupantAccidentInsuranceObj struct { NumberOfSeats int `json:"numberOfSeats"` -} - -func (c *CarOccupantAccidentInsuranceObj) MarshalJSON() ([]byte, error) { - buy := 1 - if c.NumberOfSeats <= 0 { - buy = 2 - } - return json.Marshal(&struct { - Buy int `json:"buy"` - NumberOfSeats int `json:"numberOfSeats"` - }{ - Buy: buy, - NumberOfSeats: c.NumberOfSeats, - }) + Buy int `json:"buy"` } // InsuredInfo ...