master #14
			
				
			
		
		
		
	| 
						 | 
				
			
			@ -0,0 +1,39 @@
 | 
			
		|||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
 | 
			
		||||
	"git.selly.red/Selly-Modules/natsio"
 | 
			
		||||
 | 
			
		||||
	"git.selly.red/Selly-Modules/3pl/partnerapi/kiotviet"
 | 
			
		||||
	"git.selly.red/Selly-Modules/3pl/util/pjson"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var (
 | 
			
		||||
		client   = "45575d3e-5785-***"
 | 
			
		||||
		secret   = "65ACE104EC4232***"
 | 
			
		||||
		retailer = "****"
 | 
			
		||||
	)
 | 
			
		||||
	if err := natsio.Connect(natsio.Config{URL: "localhost:4222"}); err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	c, err := kiotviet.New(client, secret, retailer, natsio.GetServer())
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	data, err := c.GetBranches(kiotviet.ListBranchesReq{})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
	fmt.Println(pjson.ToJSONString(data))
 | 
			
		||||
 | 
			
		||||
	prod, err := c.GetProductOnHands(kiotviet.ListProductOnHandsReq{
 | 
			
		||||
		PageSize: 10,
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		panic(err)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	fmt.Println(pjson.ToJSONString(prod))
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								go.mod
								
								
								
								
							
							
						
						
									
										2
									
								
								go.mod
								
								
								
								
							| 
						 | 
				
			
			@ -4,7 +4,7 @@ go 1.17
 | 
			
		|||
 | 
			
		||||
require (
 | 
			
		||||
	git.selly.red/Selly-Modules/logger v0.0.2-0.20221010053254-567df039afdb
 | 
			
		||||
	git.selly.red/Selly-Modules/natsio v1.0.2-0.20221010041139-c11419a3ad33
 | 
			
		||||
	git.selly.red/Selly-Modules/natsio v1.0.3-0.20231020090841-5edec97ee393
 | 
			
		||||
	github.com/nats-io/nats.go v1.17.0
 | 
			
		||||
	github.com/thoas/go-funk v0.9.2
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										4
									
								
								go.sum
								
								
								
								
							
							
						
						
									
										4
									
								
								go.sum
								
								
								
								
							| 
						 | 
				
			
			@ -2,6 +2,10 @@ git.selly.red/Selly-Modules/logger v0.0.2-0.20221010053254-567df039afdb h1:AmcYd
 | 
			
		|||
git.selly.red/Selly-Modules/logger v0.0.2-0.20221010053254-567df039afdb/go.mod h1:Q1//Z6HRmfa7VyjH2J6YyT0YV2jT8+K6SIgwnYuS4II=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.2-0.20221010041139-c11419a3ad33 h1:GvQjelaV4XZm++AOihYAKOD6k9510aMAr6B6MGnrXPs=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.2-0.20221010041139-c11419a3ad33/go.mod h1:KNODhfeBqxRmHHQHHU+p3JfH42t8s5aNxfgr6X8fr6g=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.3-0.20231006093940-b3bde5cd0960 h1:wL/BW1xGoB/EXeA2HtxT6Nr/cXpPJYVNfToV3aFtGls=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.3-0.20231006093940-b3bde5cd0960/go.mod h1:KNODhfeBqxRmHHQHHU+p3JfH42t8s5aNxfgr6X8fr6g=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.3-0.20231020090841-5edec97ee393 h1:43kE03FW3NONfE6hXlghafS1d233dfc7grlFqd+15SA=
 | 
			
		||||
git.selly.red/Selly-Modules/natsio v1.0.3-0.20231020090841-5edec97ee393/go.mod h1:KNODhfeBqxRmHHQHHU+p3JfH42t8s5aNxfgr6X8fr6g=
 | 
			
		||||
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=
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,26 @@
 | 
			
		|||
package kiotviet
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	apiPathListBranches       = "/branches"
 | 
			
		||||
	apiPathListProductOnHands = "/productOnHands"
 | 
			
		||||
	apiPathListWebhook        = "/webhooks"
 | 
			
		||||
	apiPathRegisterWebhook    = "/webhooks"
 | 
			
		||||
	apiPathUnregisterWebhook  = "/webhooks/%d" // %s -> webhook id
 | 
			
		||||
 | 
			
		||||
	apiPathAuth = "/connect/token"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	baseURLProd      = "https://public.kiotapi.com"
 | 
			
		||||
	baseURLTokenProd = "https://id.kiotviet.vn"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	WebhookTypeCustomerUpdate = "customer.update"
 | 
			
		||||
	WebhookTypeCustomerDelete = "customer.delete"
 | 
			
		||||
	WebhookTypeProductUpdate  = "product.update"
 | 
			
		||||
	WebhookTypeProductDelete  = "product.delete"
 | 
			
		||||
	WebhookTypeStockUpdate    = "stock.update"
 | 
			
		||||
	WebhookTypeOrderUpdate    = "order.update"
 | 
			
		||||
	WebhookTypeInvoiceUpdate  = "invoice.update"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,9 @@
 | 
			
		|||
package kiotviet
 | 
			
		||||
 | 
			
		||||
// ENV ...
 | 
			
		||||
type ENV string
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// EnvStaging ENV = "STAGING"
 | 
			
		||||
	EnvProd ENV = "PROD"
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1 @@
 | 
			
		|||
package kiotviet
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,300 @@
 | 
			
		|||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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.Success); 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
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,63 @@
 | 
			
		|||
package kiotviet
 | 
			
		||||
 | 
			
		||||
type AuthReq struct {
 | 
			
		||||
	ClientID     string
 | 
			
		||||
	ClientSecret string
 | 
			
		||||
	GrantType    string
 | 
			
		||||
	Scopes       string
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductOnHandsReq struct {
 | 
			
		||||
	OrderBy          string `json:"orderBy,omitempty"`
 | 
			
		||||
	LastModifiedFrom string `json:"lastModifiedFrom,omitempty"`
 | 
			
		||||
	PageSize         int    `json:"pageSize,omitempty"`
 | 
			
		||||
	CurrentItem      int    `json:"currentItem,omitempty"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListBranchesReq struct {
 | 
			
		||||
	OrderBy          string `json:"orderBy,omitempty"`
 | 
			
		||||
	LastModifiedFrom string `json:"lastModifiedFrom,omitempty"`
 | 
			
		||||
	PageSize         int    `json:"pageSize,omitempty"`
 | 
			
		||||
	CurrentItem      int    `json:"currentItem,omitempty"`
 | 
			
		||||
	OrderDirection   string `json:"orderDirection,omitempty"`   // Asc/ Desc. Default Desc
 | 
			
		||||
	IncludeRemoveIDs string `json:"includeRemoveIds,omitempty"` // true/ false
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListWebhookReq struct {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookReq struct {
 | 
			
		||||
	Type     string `json:"Type"`
 | 
			
		||||
	Url      string `json:"Url"`
 | 
			
		||||
	IsActive bool   `json:"IsActive"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterWebhookReq struct {
 | 
			
		||||
	Webhook WebhookReq `json:"webhook"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnregisterWebhookReq struct {
 | 
			
		||||
	ID int
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookBody struct {
 | 
			
		||||
	ID            string                `json:"Id"`
 | 
			
		||||
	Attempt       int                   `json:"Attempt"`
 | 
			
		||||
	Notifications []WebhookNotification `json:"Notifications"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookNotification struct {
 | 
			
		||||
	Action string                   `json:"Action"`
 | 
			
		||||
	Data   []WebhookStockUpdateData `json:"Data"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type WebhookStockUpdateData struct {
 | 
			
		||||
	ProductID   int64  `json:"ProductId"`
 | 
			
		||||
	ProductCode string `json:"ProductCode"`
 | 
			
		||||
	ProductName string `json:"ProductName"`
 | 
			
		||||
	BranchID    int    `json:"BranchId"`
 | 
			
		||||
	BranchName  string `json:"BranchName"`
 | 
			
		||||
	Cost        int64  `json:"Cost"`
 | 
			
		||||
	OnHand      int    `json:"OnHand"`
 | 
			
		||||
	Reserved    int    `json:"Reserved"`
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,85 @@
 | 
			
		|||
package kiotviet
 | 
			
		||||
 | 
			
		||||
import "time"
 | 
			
		||||
 | 
			
		||||
type AuthRes struct {
 | 
			
		||||
	AccessToken string `json:"access_token"`
 | 
			
		||||
	ExpiresIn   int    `json:"expires_in"`
 | 
			
		||||
	TokenType   string `json:"token_type"`
 | 
			
		||||
	Scope       string `json:"scope"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListProductOnHandsRes struct {
 | 
			
		||||
	Total     int             `json:"total"`
 | 
			
		||||
	PageSize  int             `json:"pageSize"`
 | 
			
		||||
	Data      []ProductOnHand `json:"data"`
 | 
			
		||||
	Timestamp time.Time       `json:"timestamp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductOnHand struct {
 | 
			
		||||
	ID           int                      `json:"id"`
 | 
			
		||||
	Code         string                   `json:"code"`
 | 
			
		||||
	CreatedDate  string                   `json:"createdDate"`
 | 
			
		||||
	ModifiedDate string                   `json:"modifiedDate"`
 | 
			
		||||
	Inventories  []ProductOnHandInventory `json:"inventories"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ProductOnHandInventory struct {
 | 
			
		||||
	BranchID int `json:"branchId"`
 | 
			
		||||
	OnHand   int `json:"onHand"`
 | 
			
		||||
	Reserved int `json:"reserved"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListBranchesRes struct {
 | 
			
		||||
	Total     int       `json:"total"`
 | 
			
		||||
	PageSize  int       `json:"pageSize"`
 | 
			
		||||
	Data      []Branch  `json:"data"`
 | 
			
		||||
	Timestamp time.Time `json:"timestamp"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Branch struct {
 | 
			
		||||
	ID            int    `json:"id"`
 | 
			
		||||
	BranchName    string `json:"branchName"`
 | 
			
		||||
	Address       string `json:"address"`
 | 
			
		||||
	LocationName  string `json:"locationName"`
 | 
			
		||||
	ContactNumber string `json:"contactNumber"`
 | 
			
		||||
	RetailerID    int    `json:"retailerId"`
 | 
			
		||||
	CreatedDate   string `json:"createdDate"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RegisterWebhookRes struct {
 | 
			
		||||
	ID         int    `json:"id"`
 | 
			
		||||
	Type       string `json:"type"`
 | 
			
		||||
	Url        string `json:"url"`
 | 
			
		||||
	IsActive   bool   `json:"isActive"`
 | 
			
		||||
	RetailerID int    `json:"retailerId"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type UnregisterWebhookRes struct {
 | 
			
		||||
	Success bool
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ResponseError struct {
 | 
			
		||||
	ResponseStatus RError `json:"responseStatus"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type RError struct {
 | 
			
		||||
	ErrorCode string `json:"errorCode"`
 | 
			
		||||
	Message   string `json:"message"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type Webhook struct {
 | 
			
		||||
	Id           int       `json:"id"`
 | 
			
		||||
	Type         string    `json:"type"`
 | 
			
		||||
	Url          string    `json:"url"`
 | 
			
		||||
	IsActive     bool      `json:"isActive"`
 | 
			
		||||
	RetailerId   int       `json:"retailerId"`
 | 
			
		||||
	ModifiedDate time.Time `json:"modifiedDate"`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type ListWebhookRes struct {
 | 
			
		||||
	Total     int       `json:"total"`
 | 
			
		||||
	PageSize  int       `json:"pageSize"`
 | 
			
		||||
	Data      []Webhook `json:"data"`
 | 
			
		||||
	Timestamp time.Time `json:"timestamp"`
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue