diff --git a/constant/natsio.go b/constant/natsio.go deleted file mode 100644 index d730e74..0000000 --- a/constant/natsio.go +++ /dev/null @@ -1,9 +0,0 @@ -package constant - -const natsCommunicationPrefix = "communication_" - -const ( - NatsCommunicationSubjectRequestHTTP = natsCommunicationPrefix + "request_http" - NatsCommunicationSubjectResponseHTTP = natsCommunicationPrefix + "response_http" - NatsCommunicationSubjectWebhookTNC = natsCommunicationPrefix + "webhook_tnc" -) diff --git a/go.mod b/go.mod index aed1d01..98b1f93 100644 --- a/go.mod +++ b/go.mod @@ -36,3 +36,5 @@ require ( golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 // indirect howett.net/plist v0.0.0-20181124034731-591f970eefbb // indirect ) + +//replace github.com/Selly-Modules/natsio => /Users/sinh/Documents/dev/selly-module/natsio diff --git a/partnerapi/globalcare/globale_care.go b/partnerapi/globalcare/globale_care.go index 56ed5fd..41f7ef7 100644 --- a/partnerapi/globalcare/globale_care.go +++ b/partnerapi/globalcare/globale_care.go @@ -1,17 +1,21 @@ package globalcare import ( + "crypto" + "crypto/rand" "crypto/rsa" + "crypto/sha256" + "errors" "fmt" "net/http" "github.com/Selly-Modules/logger" "github.com/Selly-Modules/natsio" "github.com/Selly-Modules/natsio/model" + "github.com/Selly-Modules/natsio/subject" "github.com/nats-io/nats.go" "github.com/thoas/go-funk" - "github.com/Selly-Modules/3pl/constant" "github.com/Selly-Modules/3pl/util/base64" "github.com/Selly-Modules/3pl/util/pjson" ) @@ -27,7 +31,7 @@ type Client struct { // NewClient generate Client // using privateKey to decrypt data from Global Care // using publicKey to encrypt data before send to Global Care -func NewClient(env ENV, privateKey, publicKey string) (*Client, error) { +func NewClient(env ENV, privateKey, publicKey string, natsClient natsio.Server) (*Client, error) { validENVs := []ENV{EnvProd, EnvDev, EnvStaging} if !funk.Contains(validENVs, env) { return nil, fmt.Errorf("globalcare.NewClient - invalid_env: %s", env) @@ -43,11 +47,13 @@ func NewClient(env ENV, privateKey, publicKey string) (*Client, error) { return &Client{ privateKey: privKey, publicKey: pubKey, + env: env, + natsClient: natsClient, }, nil } // CreateOrder ... -func (c *Client) CreateOrder(p CreateOrderPayload) (*CommonResponse, error) { +func (c *Client) CreateOrder(p CreateOrderPayload) (*CreateOrderResponseDecoded, error) { url := c.getBaseURL() + apiPathCreateOrder data := createOrderData{ ProductCode: productCodeDefault, @@ -58,9 +64,14 @@ func (c *Client) CreateOrder(p CreateOrderPayload) (*CommonResponse, error) { InsuredInfo: p.InsuredInfo, } + dataString := base64.Encode(pjson.ToBytes(data)) + sign, err := c.signData(dataString) + if err != nil { + return nil, fmt.Errorf("globalcare.Client.CreateOrder - sign_err %v", err) + } body := CommonRequestBody{ - Signature: "", // TODO:implement - Data: base64.Encode(pjson.ToBytes(data)), + Signature: sign, + Data: dataString, } natsPayload := model.CommunicationRequestHttp{ ResponseImmediately: true, @@ -70,7 +81,7 @@ func (c *Client) CreateOrder(p CreateOrderPayload) (*CommonResponse, error) { Data: pjson.ToJSONString(body), }, } - msg, err := c.requestNats(constant.NatsCommunicationSubjectRequestHTTP, natsPayload) + msg, err := c.requestNats(subject.Communication.RequestHTTP, natsPayload) if err != nil { logger.Error("globalcare.Client.CreateOrder", logger.LogData{ "err": err.Error(), @@ -85,12 +96,30 @@ func (c *Client) CreateOrder(p CreateOrderPayload) (*CommonResponse, error) { if err = pjson.Unmarshal(msg.Data, &r); err != nil { return nil, err } - err = r.ParseResponseData(&res) - return &res, err + if err = r.ParseResponseData(&res); err != nil { + return nil, err + } + if r.Response == nil { + return nil, fmt.Errorf("globalcare.Client.CreateOrder create_order_empty_response") + } + + if r.Response.StatusCode >= http.StatusBadRequest { + info, err := res.DecodeError() + if err != nil { + return nil, err + } + return nil, errors.New(info.Message) + } + info, err := res.DecodeCreateOrderSuccess() + if err != nil { + return nil, err + } + + return &info, err } // GetOrder ... -func (c *Client) GetOrder(orderCode string) (*CommonResponse, error) { +func (c *Client) GetOrder(orderCode string) (*GetOrderResponseDecoded, error) { url := c.getBaseURL() + fmt.Sprintf(apiPathGetOrder, orderCode) natsPayload := model.CommunicationRequestHttp{ ResponseImmediately: true, @@ -99,7 +128,7 @@ func (c *Client) GetOrder(orderCode string) (*CommonResponse, error) { Method: http.MethodGet, }, } - msg, err := c.requestNats(constant.NatsCommunicationSubjectRequestHTTP, natsPayload) + msg, err := c.requestNats(subject.Communication.RequestHTTP, natsPayload) if err != nil { logger.Error("globalcare.Client.GetOrder", logger.LogData{ "err": err.Error(), @@ -114,8 +143,25 @@ func (c *Client) GetOrder(orderCode string) (*CommonResponse, error) { if err = pjson.Unmarshal(msg.Data, &r); err != nil { return nil, err } - err = r.ParseResponseData(&res) - return &res, err + if err = r.ParseResponseData(&res); err != nil { + return nil, err + } + if r.Response == nil { + return nil, fmt.Errorf("globalcare.Client.GetOrder get_order_empty_response") + } + + if r.Response.StatusCode >= http.StatusBadRequest { + info, err := res.DecodeError() + if err != nil { + return nil, err + } + return nil, errors.New(info.Message) + } + info, err := res.DecodeGetOrderSuccess() + if err != nil { + return nil, err + } + return &info, err } func (c *Client) requestNats(subject string, data interface{}) (*nats.Msg, error) { @@ -126,3 +172,18 @@ func (c *Client) requestNats(subject string, data interface{}) (*nats.Msg, error func (c *Client) getBaseURL() string { return baseURLENVMapping[c.env] } + +func (c *Client) signData(s string) (string, error) { + msgHash := sha256.New() + _, err := msgHash.Write([]byte(s)) + if err != nil { + return "", err + } + msgHashSum := msgHash.Sum(nil) + signature, err := rsa.SignPKCS1v15(rand.Reader, c.privateKey, crypto.SHA256, msgHashSum) + if err != nil { + return "", err + } + + return base64.Encode(signature), nil +} diff --git a/partnerapi/globalcare/model_response.go b/partnerapi/globalcare/model_response.go index ae17dff..8bf04b1 100644 --- a/partnerapi/globalcare/model_response.go +++ b/partnerapi/globalcare/model_response.go @@ -1,8 +1,87 @@ package globalcare +import "encoding/json" + // CommonResponse ... type CommonResponse struct { - StatusCode int `json:"statusCode"` - Message string `json:"message"` - Result interface{} `json:"result"` + Data string `json:"data"` + Signature string `json:"signature"` +} + +// DecodeCreateOrderSuccess ... +func (r *CommonResponse) DecodeCreateOrderSuccess() (res CreateOrderResponseDecoded, err error) { + err = r.Decode(res) + return res, err +} + +// DecodeGetOrderSuccess ... +func (r *CommonResponse) DecodeGetOrderSuccess() (res GetOrderResponseDecoded, err error) { + err = r.Decode(res) + return res, err +} + +// DecodeError ... +func (r *CommonResponse) DecodeError() (res ResponseError, err error) { + err = r.Decode(res) + return res, err +} + +// Decode ... +func (r *CommonResponse) Decode(resultPointer interface{}) error { + return json.Unmarshal([]byte(r.Data), resultPointer) +} + +// CreateOrderResponseDecoded ... +type CreateOrderResponseDecoded struct { + StatusCode int `json:"statusCode"` + Result CreateOrderResult `json:"result"` +} + +// CreateOrderResult ... +type CreateOrderResult struct { + OrderCode string `json:"orderCode"` + PaymentLink string `json:"paymentLink"` + Fees int `json:"fees"` + StatusId int `json:"statusId"` +} + +// ResponseError ... +type ResponseError struct { + StatusCode int `json:"statusCode"` + Message string `json:"message"` +} + +// GetOrderResponseDecoded ... +type GetOrderResponseDecoded struct { + StatusCode int `json:"statusCode"` + Result GetOrderResult `json:"result"` +} + +// GetOrderResult ... +type GetOrderResult struct { + ProviderTitle string `json:"providerTitle"` + BeginDate string `json:"beginDate"` + EndDate string `json:"endDate"` + Amount string `json:"amount"` + CertLink string `json:"certLink"` + StatusId int `json:"statusId"` + StatusTitle string `json:"statusTitle"` + Buyer BuyerInfo `json:"buyer"` + InsuredInfo InsuranceInfo `json:"insuredInfo"` +} + +// InsuranceInfo ... +type InsuranceInfo struct { + TypeId int `json:"typeId"` + TypeName string `json:"typeName"` + CarOccupantAccidentInsurance int `json:"carOccupantAccidentInsurance"` +} + +// BuyerInfo ... +type BuyerInfo struct { + BuyerName string `json:"buyerName"` + BuyerPrivateId interface{} `json:"buyerPrivateId"` + BuyerPhone string `json:"buyerPhone"` + BuyerAddress string `json:"buyerAddress"` + BuyerEmail string `json:"buyerEmail"` } diff --git a/partnerapi/tnc/tnc.go b/partnerapi/tnc/tnc.go index a9a5971..0d0b867 100644 --- a/partnerapi/tnc/tnc.go +++ b/partnerapi/tnc/tnc.go @@ -9,9 +9,9 @@ import ( "github.com/Selly-Modules/logger" "github.com/Selly-Modules/natsio" "github.com/Selly-Modules/natsio/model" + "github.com/Selly-Modules/natsio/subject" "github.com/nats-io/nats.go" - "github.com/Selly-Modules/3pl/constant" "github.com/Selly-Modules/3pl/util/pjson" ) @@ -288,7 +288,7 @@ func (c *Client) getRequestHeader() map[string]string { } func (c *Client) requestHttpViaNats(data model.CommunicationRequestHttp) (*nats.Msg, error) { - s := constant.NatsCommunicationSubjectRequestHTTP + s := subject.Communication.RequestHTTP b := pjson.ToBytes(data) return c.natsClient.Request(s, b) }