diff --git a/go.mod b/go.mod index 7c32cb8..cfef896 100644 --- a/go.mod +++ b/go.mod @@ -14,6 +14,7 @@ require ( github.com/elastic/go-licenser v0.4.1 // indirect github.com/elastic/go-sysinfo v1.1.1 // indirect github.com/elastic/go-windows v1.0.1 // indirect + github.com/go-resty/resty/v2 v2.7.0 // indirect github.com/golang/snappy v0.0.3 // indirect github.com/jcchavezs/porto v0.4.0 // indirect github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 // indirect @@ -34,6 +35,7 @@ require ( golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect golang.org/x/mod v0.5.1 // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/sys v0.0.0-20211102192858-4dd72447c267 // indirect golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect diff --git a/go.sum b/go.sum index dbbf8f5..05ef62d 100644 --- a/go.sum +++ b/go.sum @@ -17,6 +17,8 @@ github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6 github.com/elastic/go-windows v1.0.0/go.mod h1:TsU0Nrp7/y3+VwE82FoZF8gC/XFg/Elz6CcloAxnPgU= github.com/elastic/go-windows v1.0.1 h1:AlYZOldA+UJ0/2nBuqWdo90GFCgG9xuyw9SYzGUtJm0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= +github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY= +github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I= github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= @@ -142,6 +144,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= diff --git a/partnerapi/jtexpress/const.go b/partnerapi/jtexpress/const.go new file mode 100644 index 0000000..84d467f --- /dev/null +++ b/partnerapi/jtexpress/const.go @@ -0,0 +1,20 @@ +package jtexpress + +const ( + apiHostProd = "" + apiHostDev = "https://test.jtexpress.vn" + + apiPathEstimateFee = "/yuenan-interface-web/jtpos/inquiry!freight.action" + apiPathCreateOrder = "/yuenan-interface-web/order/orderAction!createOrder.action" + apiPathCancelOrder = "/yuenan-interface-web/order/orderAction!createOrder.action" + apiPathTrackingOrder = "" +) + +const ( + statusSuccess = "true" +) + +const ( + msgTypeEstimateFee = "FREIGHTQUERY" + msgTypeCreateOrder = "ORDERCREATE" +) diff --git a/partnerapi/jtexpress/jtexpress.go b/partnerapi/jtexpress/jtexpress.go new file mode 100644 index 0000000..2c9cbbb --- /dev/null +++ b/partnerapi/jtexpress/jtexpress.go @@ -0,0 +1,111 @@ +package jtexpress + +import ( + "crypto/md5" + "fmt" + "io" + + "github.com/go-resty/resty/v2" + + "git.selly.red/Selly-Modules/3pl/util/pjson" +) + +func New(degestKey, companyID string, isProd, debug bool) *Client { + host := apiHostDev + if isProd { + host = apiHostProd + } + c := &Client{ + DigestKey: degestKey, + EccompanyID: companyID, + IsProduction: isProd, + Debug: debug, + host: host, + httpClient: resty.New().SetDebug(debug), + } + return c +} + +type Client struct { + DigestKey string + EccompanyID string + IsProduction bool + Debug bool + host string + httpClient *resty.Client +} + +func (c *Client) EstimateFee(req *EstimateFeeReq) (*EstimateFeeItemRes, error) { + path := c.host + apiPathEstimateFee + data := pjson.ToJSONString(req) + resp, err := c.httpClient.R(). + SetFormData(map[string]string{ + "logistics_interface": data, + "data_digest": c.getDigest(data), + "msg_type": msgTypeEstimateFee, + "eccompanyid": c.EccompanyID, + }). + SetResult(&EstimateFeeRes{}). + Post(path) + if err != nil { + return nil, fmt.Errorf("jtepxress: request %s, err %v", path, err) + } + res := resp.Result().(*EstimateFeeRes) + if len(res.ResponseItems) == 0 { + return nil, fmt.Errorf("jtepxress: estimate fee empty response") + } + return res.ResponseItems[0], nil +} + +func (c *Client) CancelOrder(req *CancelOrderReq) (*CancelOrderRes, error) { + path := c.host + apiPathCancelOrder + data := pjson.ToJSONString(req) + resp, err := c.httpClient.R(). + SetFormData(map[string]string{ + "logistics_interface": data, + "data_digest": c.getDigest(data), + "msg_type": msgTypeEstimateFee, + "eccompanyid": c.EccompanyID, + }). + SetResult(&CancelOrderRes{}). + Post(path) + if err != nil { + return nil, fmt.Errorf("jtepxress: request %s, err %v", path, err) + } + res := resp.Result().(*CancelOrderRes) + if len(res.ResponseItems) == 0 { + return nil, fmt.Errorf("jtepxress: cancel order empty response") + } + // return res.ResponseItems[0], nil + return nil, err +} + +func (c *Client) CreateOrder(req *CreateOrderReq) (*CreateOrderItemRes, error) { + path := c.host + apiPathCreateOrder + data := pjson.ToJSONString(req) + resp, err := c.httpClient.R(). + SetFormData(map[string]string{ + "logistics_interface": data, + "data_digest": c.getDigest(data), + "msg_type": msgTypeCreateOrder, + "eccompanyid": c.EccompanyID, + }). + SetResult(&CreateOrderRes{}). + Post(path) + if err != nil { + return nil, fmt.Errorf("jtepxress: request %s, err %v", path, err) + } + res := resp.Result().(*CreateOrderRes) + if len(res.ResponseItems) == 0 { + return nil, fmt.Errorf("jtepxress: create order empty response") + } + return res.ResponseItems[0], nil +} + +func (c *Client) getDigest(data string) string { + s := data + c.DigestKey + h := md5.New() + + io.WriteString(h, s) + return fmt.Sprintf("%x", h.Sum(nil)) +} diff --git a/partnerapi/jtexpress/model_request.go b/partnerapi/jtexpress/model_request.go new file mode 100644 index 0000000..daddc0d --- /dev/null +++ b/partnerapi/jtexpress/model_request.go @@ -0,0 +1,75 @@ +package jtexpress + +type EstimateFeeLocation struct { + Prov string `json:"prov"` + City string `json:"city"` + Area string `json:"area"` +} + +type EstimateFeeReq struct { + SelfAddress int `json:"selfAddress"` + ProductType string `json:"producttype"` + CusName string `json:"cusname"` + GoodsValue string `json:"goodsvalue"` + ItemsValue string `json:"itemsvalue"` + Weight string `json:"weight"` + Sender EstimateFeeLocation `json:"sender"` + Receiver EstimateFeeLocation `json:"receiver"` + Decs string `json:"decs"` + FeeType string `json:"feetype"` +} + +type CreateOrderReq struct { + Customerid string `json:"customerid"` + Txlogisticid string `json:"txlogisticid"` + Ordertype int `json:"ordertype"` + Servicetype int `json:"servicetype"` + SelfAddress int `json:"selfAddress"` + Special string `json:"special"` + Partsign string `json:"partsign"` + Sender CreateOrderLocation `json:"sender"` + Receiver CreateOrderLocation `json:"receiver"` + Createordertime string `json:"createordertime"` + Sendstarttime string `json:"sendstarttime"` + Sendendtime string `json:"sendendtime"` + Paytype string `json:"paytype"` + Itemsvalue string `json:"itemsvalue"` + Goodsvalue string `json:"goodsvalue"` + IsInsured string `json:"isInsured"` + Items []OrderItem `json:"items"` + Weight string `json:"weight"` + Volume string `json:"volume"` + Remark string `json:"remark"` +} + +type CreateOrderLocation struct { + Name string `json:"name"` + Phone string `json:"phone"` + Mobile string `json:"mobile"` + Prov string `json:"prov"` + City string `json:"city"` + Area string `json:"area"` + Address string `json:"address"` +} + +type OrderItem struct { + Itemname string `json:"itemname"` + EnglishName string `json:"englishName"` + Number string `json:"number"` + Itemvalue string `json:"itemvalue"` + Desc string `json:"desc"` +} + +type CancelOrderReq struct { + Eccompanyid string `json:"eccompanyid"` + Customerid string `json:"customerid"` + Logisticproviderid string `json:"logisticproviderid"` + Fieldlist []CancelOrderFieldList `json:"fieldlist"` +} + +type CancelOrderFieldList struct { + Txlogisticid string `json:"txlogisticid"` + Fieldname string `json:"fieldname"` + Fieldvalue string `json:"fieldvalue"` + Remark string `json:"remark"` +} diff --git a/partnerapi/jtexpress/model_response.go b/partnerapi/jtexpress/model_response.go new file mode 100644 index 0000000..04b359a --- /dev/null +++ b/partnerapi/jtexpress/model_response.go @@ -0,0 +1,43 @@ +package jtexpress + +type EstimateFeeItemRes struct { + ProductType string `json:"producttype"` + Price string `json:"price"` + CodFee string `json:"codfee"` + InsuranceFee string `json:"insurancefee"` + DiscountFee string `json:"discountFee"` + Success string `json:"success"` + Reason string `json:"reason"` +} + +type EstimateFeeRes struct { + LogisticProviderID string `json:"logisticproviderid"` + ResponseItems []*EstimateFeeItemRes `json:"responseitems"` +} + +type CreateOrderRes struct { + LogisticProviderID string `json:"logisticproviderid"` + ResponseItems []*CreateOrderItemRes `json:"responseitems"` +} + +type CreateOrderItemRes struct { + Billcode string `json:"billcode"` + CodFee string `json:"codFee"` + Code string `json:"code"` + DiscountFee string `json:"discountFee"` + DispatchSite string `json:"dispatchSite"` + InquiryFee string `json:"inquiryFee"` + Insurancefee string `json:"insurancefee"` + Reason string `json:"reason"` + Reportnewurl string `json:"reportnewurl"` + Reporturl string `json:"reporturl"` + ReporturlJT string `json:"reporturlJT"` + Success string `json:"success"` + Transport string `json:"transport"` + Txlogisticid string `json:"txlogisticid"` +} + +type CancelOrderRes struct { + LogisticProviderID string `json:"logisticproviderid"` + ResponseItems []*CreateOrderItemRes `json:"responseitems"` +}