2023-10-06 10:12:11 +00:00
|
|
|
package kiotviet
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"git.selly.red/Selly-Modules/natsio"
|
|
|
|
"git.selly.red/Selly-Modules/natsio/model"
|
|
|
|
"git.selly.red/Selly-Modules/natsio/subject"
|
|
|
|
|
|
|
|
"git.selly.red/Selly-Modules/3pl/util/httputil"
|
|
|
|
"git.selly.red/Selly-Modules/3pl/util/pjson"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
logTarget = "kiotviet"
|
|
|
|
)
|
|
|
|
|
|
|
|
type Client struct {
|
|
|
|
clientID string
|
|
|
|
secretKey string
|
|
|
|
retailer string
|
|
|
|
|
|
|
|
natsClient natsio.Server
|
|
|
|
|
|
|
|
auth *AuthRes
|
|
|
|
authExpireTime time.Time
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(clientID, secretKey, retailer string, natsClient natsio.Server) (*Client, error) {
|
|
|
|
if clientID == "" || secretKey == "" || retailer == "" {
|
|
|
|
return nil, fmt.Errorf("kiotviet: cannot create client with empty info")
|
|
|
|
}
|
|
|
|
return &Client{
|
|
|
|
clientID: clientID,
|
|
|
|
secretKey: secretKey,
|
|
|
|
retailer: retailer,
|
|
|
|
natsClient: natsClient,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) GetProductOnHands(req ListProductOnHandsReq) (*ListProductOnHandsRes, error) {
|
|
|
|
apiURL := c.getURL(apiPathListProductOnHands)
|
|
|
|
query := map[string]string{
|
|
|
|
"orderBy": req.OrderBy,
|
|
|
|
"lastModifiedFrom": req.LastModifiedFrom,
|
|
|
|
}
|
|
|
|
if req.PageSize > 0 {
|
|
|
|
query["pageSize"] = strconv.Itoa(req.PageSize)
|
|
|
|
}
|
|
|
|
if req.CurrentItem > 0 {
|
|
|
|
query["currentItem"] = strconv.Itoa(req.CurrentItem)
|
|
|
|
}
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodGet,
|
|
|
|
Query: query,
|
|
|
|
Header: c.getRequestHeader(),
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.GetProductOnHands - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.GetProductOnHands - requestHttpViaNats bad request %s", res.Body)
|
|
|
|
}
|
|
|
|
var data ListProductOnHandsRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.GetProductOnHands - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) GetBranches(req ListBranchesReq) (*ListBranchesRes, error) {
|
|
|
|
apiURL := c.getURL(apiPathListBranches)
|
|
|
|
query := map[string]string{
|
|
|
|
"orderBy": req.OrderBy,
|
|
|
|
"lastModifiedFrom": req.LastModifiedFrom,
|
|
|
|
"orderDirection": req.OrderDirection,
|
|
|
|
"includeRemoveIds": req.IncludeRemoveIDs,
|
|
|
|
}
|
|
|
|
if req.PageSize > 0 {
|
|
|
|
query["pageSize"] = strconv.Itoa(req.PageSize)
|
|
|
|
}
|
|
|
|
if req.CurrentItem > 0 {
|
|
|
|
query["currentItem"] = strconv.Itoa(req.CurrentItem)
|
|
|
|
}
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodGet,
|
|
|
|
Query: query,
|
|
|
|
Header: c.getRequestHeader(),
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.GetBranches - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.GetBranches - requestHttpViaNats bad request %s", res.Body)
|
|
|
|
}
|
|
|
|
var data ListBranchesRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.GetBranches - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
2023-10-12 09:24:02 +00:00
|
|
|
func (c *Client) ListWebhooks(req ListWebhookReq) (*ListWebhookRes, error) {
|
|
|
|
apiURL := c.getURL(apiPathListWebhook)
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodGet,
|
|
|
|
Header: c.getRequestHeader(),
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.ListWebhooks - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.ListWebhooks - requestHttpViaNats bad request %s", res.Body)
|
|
|
|
}
|
|
|
|
var data ListWebhookRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.ListWebhooks - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
2023-10-06 10:12:11 +00:00
|
|
|
func (c *Client) RegisterWebhook(req RegisterWebhookReq) (*RegisterWebhookRes, error) {
|
|
|
|
apiURL := c.getURL(apiPathRegisterWebhook)
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodPost,
|
|
|
|
Data: pjson.ToJSONString(req),
|
|
|
|
Header: c.getRequestHeader(),
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.RegisterWebhook - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.RegisterWebhook - requestHttpViaNats bad request %s", res.Body)
|
|
|
|
}
|
|
|
|
var data RegisterWebhookRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.RegisterWebhook - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) UnregisterWebhook(req UnregisterWebhookReq) (*UnregisterWebhookRes, error) {
|
|
|
|
apiURL := c.getURL(fmt.Sprintf(apiPathUnregisterWebhook, req.ID))
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodDelete,
|
|
|
|
Header: c.getRequestHeader(),
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.UnregisterWebhook - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.UnregisterWebhook - requestHttpViaNats bad request %s", res.Body)
|
|
|
|
}
|
|
|
|
var data UnregisterWebhookRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.UnregisterWebhook - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) Auth() (*AuthRes, error) {
|
|
|
|
v := url.Values{}
|
|
|
|
v.Add("scopes", "PublicApi.Access")
|
|
|
|
v.Add("grant_type", "client_credentials")
|
|
|
|
v.Add("client_id", c.clientID)
|
|
|
|
v.Add("client_secret", c.secretKey)
|
|
|
|
|
|
|
|
body := v.Encode()
|
|
|
|
header := map[string]string{
|
|
|
|
httputil.HeaderKeyContentType: httputil.HeaderValueApplicationURLEncoded,
|
|
|
|
}
|
|
|
|
apiURL := baseURLTokenProd + apiPathAuth
|
|
|
|
natsPayload := model.CommunicationRequestHttp{
|
|
|
|
ResponseImmediately: true,
|
|
|
|
Payload: model.HttpRequest{
|
|
|
|
URL: apiURL,
|
|
|
|
Method: http.MethodPost,
|
|
|
|
Data: body,
|
|
|
|
Header: header,
|
|
|
|
},
|
|
|
|
LogTarget: logTarget,
|
|
|
|
}
|
|
|
|
r, err := c.requestHttpViaNats(natsPayload)
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.Auth - requestHttpViaNats: %v, %s\n", err, apiURL)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
res := r.Response
|
|
|
|
if res.StatusCode >= http.StatusBadRequest {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.Auth - requestHttpViaNats %s", res.Body)
|
|
|
|
}
|
|
|
|
var data AuthRes
|
|
|
|
if err = r.ParseResponseData(&data); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.Auth - requestHttpViaNats parse response %v, %s", err, res.Body)
|
|
|
|
}
|
|
|
|
return &data, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getURL(path string) string {
|
|
|
|
return baseURLProd + path
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) requestHttpViaNats(data model.CommunicationRequestHttp) (*model.CommunicationHttpResponse, error) {
|
|
|
|
b := pjson.ToBytes(data)
|
|
|
|
msg, err := c.natsClient.Request(subject.Communication.RequestHTTP, b)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.requestHttpViaNats err: %v, url %s", err, data.Payload.URL)
|
|
|
|
}
|
|
|
|
var r model.CommunicationHttpResponse
|
|
|
|
if err = pjson.Unmarshal(msg.Data, &r); err != nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.requestHttpViaNats parse data err: %v, url %s, data %s", err, data.Payload.URL, string(msg.Data))
|
|
|
|
}
|
|
|
|
if r.Response == nil {
|
|
|
|
return nil, fmt.Errorf("kiotviet.Client.requestHttpViaNats empty reponse")
|
|
|
|
}
|
|
|
|
return &r, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getRequestHeader() map[string]string {
|
|
|
|
m := map[string]string{
|
|
|
|
httputil.HeaderKeyContentType: httputil.HeaderValueApplicationJSON,
|
|
|
|
"Retailer": c.retailer,
|
|
|
|
}
|
|
|
|
|
|
|
|
token, err := c.getToken()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("kiotviet.Client.getToken err %v\n", err)
|
|
|
|
} else {
|
|
|
|
m["Authorization"] = fmt.Sprintf("Bearer %s", token)
|
|
|
|
}
|
|
|
|
return m
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) getToken() (string, error) {
|
|
|
|
auth := c.auth
|
|
|
|
if auth != nil && c.authExpireTime.After(time.Now()) {
|
|
|
|
return auth.AccessToken, nil
|
|
|
|
}
|
|
|
|
data, err := c.Auth()
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
c.auth = data
|
|
|
|
d := time.Duration(data.ExpiresIn) * time.Second
|
|
|
|
if d.Minutes() > 30 {
|
|
|
|
d -= 30 * time.Minute
|
|
|
|
}
|
|
|
|
c.authExpireTime = time.Now().Add(d)
|
|
|
|
|
|
|
|
return data.AccessToken, nil
|
|
|
|
}
|