diff --git a/README.md b/README.md index 9c883b2..80a4baf 100644 --- a/README.md +++ b/README.md @@ -3,12 +3,10 @@ This library provides convenient access to the eWarehousing Solutions API from applications written in the Go language. - ## Documentation https://api.docs.ewarehousing-solutions.com/ - ## Installation ``` @@ -19,13 +17,20 @@ go get -u github.com/ewarehousing-solutions/ewhs-api-go - Go 19+ - ## Usage ```go -... +config := ewhs.NewConfig("username", "password", "wms_code", "customer_code") +client, err := ewhs.NewClient(nil, config) +if err != nil { +log.Fatal(err) +} ``` +## Support + +[www.ewarehousing-solutions.nl](https://ewarehousing-solutions.nl/) — info@ewarehousing-solutions.nl + +## Credits -# Support -[www.ewarehousing-solutions.nl](https://ewarehousing-solutions.nl/) — info@ewarehousing-solutions.nl \ No newline at end of file +This package is heavily based on [https://github.com/VictorAvelar/mollie-api-go](VictorAvelar/mollie-api-go). \ No newline at end of file diff --git a/ewhs/articles.go b/ewhs/articles.go index 0d0856b..5506fb6 100644 --- a/ewhs/articles.go +++ b/ewhs/articles.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -35,8 +36,8 @@ type ArticleListOptions struct { Direction string `url:"direction,omitempty"` } -func (as *ArticlesService) List(opts *ArticleListOptions) (list *[]Article, res *Response, err error) { - res, err = as.client.get("wms/articles/", opts) +func (as *ArticlesService) List(ctx context.Context, opts *ArticleListOptions) (list *[]Article, res *Response, err error) { + res, err = as.client.get(ctx, "wms/articles/", opts) if err != nil { return } @@ -48,8 +49,8 @@ func (as *ArticlesService) List(opts *ArticleListOptions) (list *[]Article, res return } -func (as *ArticlesService) Get(articleID string) (article *Article, res *Response, err error) { - res, err = as.client.get(fmt.Sprintf("wms/articles/%s/", articleID), nil) +func (as *ArticlesService) Get(ctx context.Context, articleID string) (article *Article, res *Response, err error) { + res, err = as.client.get(ctx, fmt.Sprintf("wms/articles/%s/", articleID), nil) if err != nil { return } @@ -61,8 +62,8 @@ func (as *ArticlesService) Get(articleID string) (article *Article, res *Respons return } -func (as *ArticlesService) Create(art Article) (article *Article, res *Response, err error) { - res, err = as.client.post("wms/articles/", art, nil) +func (as *ArticlesService) Create(ctx context.Context, art Article) (article *Article, res *Response, err error) { + res, err = as.client.post(ctx, "wms/articles/", art, nil) if err != nil { return @@ -75,8 +76,8 @@ func (as *ArticlesService) Create(art Article) (article *Article, res *Response, return } -func (as *ArticlesService) Update(articleID string, art Article) (article *Article, res *Response, err error) { - res, err = as.client.patch(fmt.Sprintf("wms/articles/%s/", articleID), art, nil) +func (as *ArticlesService) Update(ctx context.Context, articleID string, art Article) (article *Article, res *Response, err error) { + res, err = as.client.patch(ctx, fmt.Sprintf("wms/articles/%s/", articleID), art, nil) if err != nil { return diff --git a/ewhs/auth.go b/ewhs/auth.go new file mode 100644 index 0000000..68af182 --- /dev/null +++ b/ewhs/auth.go @@ -0,0 +1,8 @@ +package ewhs + +type AuthToken struct { + Token string `json:"token,omitempty"` + Iat int `json:"iat,omitempty"` + Exp int `json:"exp,omitempty"` + RefreshToken string `json:"refresh_token,omitempty"` +} diff --git a/ewhs/auth_test.go b/ewhs/auth_test.go new file mode 100644 index 0000000..448d1ee --- /dev/null +++ b/ewhs/auth_test.go @@ -0,0 +1,77 @@ +package ewhs + +import ( + "context" + "fmt" + "github.com/ewarehousing-solutions/ewhs-api-go/test/testdata" + "github.com/stretchr/testify/suite" + "net/http" + "testing" +) + +type authServiceSuite struct{ suite.Suite } + +func (as *authServiceSuite) TestAuthService_Authorize() { + type args struct { + ctx context.Context + } + cases := []struct { + name string + args args + wantErr bool + err error + pre func() + handler http.HandlerFunc + }{ + { + "authorize works as expected.", + args{ + context.Background(), + }, + false, + nil, + noPre, + func(w http.ResponseWriter, r *http.Request) { + testHeader(as.T(), r, CustomerCodeHeader, "test_customer") + testHeader(as.T(), r, WmsCodeHeader, "test_wms") + testMethod(as.T(), r, "POST") + + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(testdata.CreateAuthTokenResponse)) + }, + }, + { + "wrong login credentials gives an error.", + args{ + context.Background(), + }, + true, + fmt.Errorf("401 - 401 Unauthorized"), + noPre, + unauthorizedHandler, + }, + } + + for _, c := range cases { + setup() + defer teardown() + + as.T().Run(c.name, func(t *testing.T) { + c.pre() + tMux.HandleFunc("/wms/auth/login/", c.handler) + + _, err := tClient.authorize(c.args.ctx) + if c.wantErr { + as.NotNil(err) + as.EqualError(err, c.err.Error()) + } else { + as.Nil(err) + as.NotNil(tClient.authToken) + } + }) + } +} + +func TestAuthService(t *testing.T) { + suite.Run(t, new(authServiceSuite)) +} diff --git a/ewhs/config.go b/ewhs/config.go index 8ab3893..d9a22cf 100644 --- a/ewhs/config.go +++ b/ewhs/config.go @@ -1,8 +1,17 @@ package ewhs type Config struct { + Username string + Password string + WmsCode string + CustomerCode string } -func NewConfig() *Config { - return &Config{} +func NewConfig(username string, password string, wmsCode string, customerCode string) *Config { + return &Config{ + Username: username, + Password: password, + WmsCode: wmsCode, + CustomerCode: customerCode, + } } diff --git a/ewhs/errors.go b/ewhs/errors.go new file mode 100644 index 0000000..4c95445 --- /dev/null +++ b/ewhs/errors.go @@ -0,0 +1,19 @@ +package ewhs + +import "fmt" + +// BaseError contains the general error structure +// returned by mollie. +type BaseError struct { + Status int `json:"status,omitempty"` + Title string `json:"title,omitempty"` + Detail string `json:"detail,omitempty"` +} + +// Error interface compliance. +func (be *BaseError) Error() string { + //str := fmt.Sprintf("%d - %s: %s", be.Status, be.Title, be.Detail) + str := fmt.Sprintf("%d - %s", be.Status, be.Title) + + return str +} diff --git a/ewhs/ewhs.go b/ewhs/ewhs.go index d09da7a..c25528a 100644 --- a/ewhs/ewhs.go +++ b/ewhs/ewhs.go @@ -2,25 +2,41 @@ package ewhs import ( "bytes" + "context" "encoding/json" + "errors" "fmt" "github.com/google/go-querystring/query" "io" "net/http" "net/url" + "runtime" + "strings" + "time" ) const ( BaseURL string = "https://eu.middleware.ewarehousing-solutions.com" RequestContentType string = "application/json" + AuthHeader string = "Authorization" + CustomerCodeHeader string = "X-Customer-Code" + WmsCodeHeader string = "X-Wms-Code" +) + +var ( + errEmptyAuthKey = errors.New("you must provide a non-empty authentication key") + errBadBaseURL = errors.New("malformed base url, it must contain a trailing slash") ) // Client represents a client. type Client struct { - client *http.Client - baseURL *url.URL - common service - config *Config + BaseURL *url.URL + client *http.Client + userAgent string + common service + config *Config + + authToken string // Services Articles *ArticlesService @@ -37,13 +53,13 @@ type service struct { client *Client } -func (c *Client) get(uri string, options interface{}) (res *Response, err error) { +func (c *Client) get(ctx context.Context, uri string, options interface{}) (res *Response, err error) { if options != nil { v, _ := query.Values(options) uri = fmt.Sprintf("%s?%s", uri, v.Encode()) } - req, err := c.NewRequest(http.MethodGet, uri, nil) + req, err := c.NewRequest(ctx, http.MethodGet, uri, nil) if err != nil { return } @@ -51,13 +67,13 @@ func (c *Client) get(uri string, options interface{}) (res *Response, err error) return c.Do(req) } -func (c *Client) post(uri string, body interface{}, options interface{}) (res *Response, err error) { +func (c *Client) post(ctx context.Context, uri string, body interface{}, options interface{}) (res *Response, err error) { if options != nil { v, _ := query.Values(options) uri = fmt.Sprintf("%s?%s", uri, v.Encode()) } - req, err := c.NewRequest(http.MethodPost, uri, body) + req, err := c.NewRequest(ctx, http.MethodPost, uri, body) if err != nil { return } @@ -65,13 +81,13 @@ func (c *Client) post(uri string, body interface{}, options interface{}) (res *R return c.Do(req) } -func (c *Client) patch(uri string, body interface{}, options interface{}) (res *Response, err error) { +func (c *Client) patch(ctx context.Context, uri string, body interface{}, options interface{}) (res *Response, err error) { if options != nil { v, _ := query.Values(options) uri = fmt.Sprintf("%s?%s", uri, v.Encode()) } - req, err := c.NewRequest(http.MethodPatch, uri, body) + req, err := c.NewRequest(ctx, http.MethodPatch, uri, body) if err != nil { return } @@ -79,13 +95,13 @@ func (c *Client) patch(uri string, body interface{}, options interface{}) (res * return c.Do(req) } -func (c *Client) delete(uri string, options interface{}) (res *Response, err error) { +func (c *Client) delete(ctx context.Context, uri string, options interface{}) (res *Response, err error) { if options != nil { v, _ := query.Values(options) uri = fmt.Sprintf("%s?%s", uri, v.Encode()) } - req, err := c.NewRequest(http.MethodDelete, uri, nil) + req, err := c.NewRequest(ctx, http.MethodDelete, uri, nil) if err != nil { return } @@ -93,8 +109,46 @@ func (c *Client) delete(uri string, options interface{}) (res *Response, err err return c.Do(req) } -func (c *Client) NewRequest(method string, uri string, body interface{}) (req *http.Request, err error) { - u, err := c.baseURL.Parse(uri) +// Authorize fetches a new access token based on login credentials +func (c *Client) authorize(ctx context.Context) (res *Response, err error) { + req, err := c.NewRequest(ctx, http.MethodPost, "wms/auth/login/", nil) + if err != nil { + return + } + + res, err = c.Do(req) + + if err != nil { + return + } + + authToken := AuthToken{} + + if err = json.Unmarshal(res.content, &authToken); err != nil { + return + } + + c.authToken = authToken.Token + + return res, nil +} + +func (c *Client) WithAuthToken(k string) error { + if k == "" { + return errEmptyAuthKey + } + + c.authToken = strings.TrimSpace(k) + + return nil +} + +func (c *Client) NewRequest(ctx context.Context, method string, uri string, body interface{}) (req *http.Request, err error) { + if !strings.HasSuffix(c.BaseURL.Path, "/") { + return nil, errBadBaseURL + } + + u, err := c.BaseURL.Parse(uri) if err != nil { return nil, err } @@ -110,13 +164,36 @@ func (c *Client) NewRequest(method string, uri string, body interface{}) (req *h } } - req, err = http.NewRequest(method, u.String(), buf) + if ctx == nil { + ctx = context.Background() + } + + req, err = http.NewRequestWithContext(ctx, method, u.String(), buf) if err != nil { return nil, err } - req.Header.Set("Content-Type", RequestContentType) req.Header.Set("Accept", RequestContentType) + req.Header.Set("Content-Type", RequestContentType) + + if c.config != nil { + req.Header.Set(CustomerCodeHeader, c.config.CustomerCode) + req.Header.Set(WmsCodeHeader, c.config.WmsCode) + } + + // TODO: allow expand headers + //if ctx.Value("Expand") != nil { + //} + + // if no auth token is found -> authorize first + if c.authToken == "" && uri != "wms/auth/login/" { + _, err := c.authorize(ctx) + if err != nil { + return nil, err + } + } + + req.Header.Add(AuthHeader, strings.Join([]string{"Bearer", c.authToken}, " ")) return req, nil } @@ -144,20 +221,23 @@ func (c *Client) Do(req *http.Request) (*Response, error) { return response, nil } -func NewClient(baseClient *http.Client, c *Config) Client { +func NewClient(baseClient *http.Client, c *Config) (ewhs *Client, err error) { if baseClient == nil { baseClient = http.DefaultClient + { + baseClient.Timeout = 30 * time.Second + } } u, _ := url.Parse(BaseURL) - ewhs := Client{ - baseURL: u, + ewhs = &Client{ + BaseURL: u, client: baseClient, config: c, } - ewhs.common.client = &ewhs + ewhs.common.client = ewhs // services for resources ewhs.Articles = (*ArticlesService)(&ewhs.common) @@ -169,29 +249,30 @@ func NewClient(baseClient *http.Client, c *Config) Client { ewhs.Variants = (*VariantsService)(&ewhs.common) ewhs.Webhooks = (*WebhooksService)(&ewhs.common) - return ewhs -} - -/* -Error reports details on a failed API request. -*/ -type Error struct { - Code int `json:"code"` - Message string `json:"message"` - Response *Response `json:"response"` -} + ewhs.userAgent = strings.Join([]string{ + runtime.GOOS, + runtime.GOARCH, + runtime.Version(), + }, ";") -// Error function complies with the error interface -func (e *Error) Error() string { - return fmt.Sprintf("response failed with status %v", e.Message) + return ewhs, nil } -func newError(r *Response) *Error { - var e Error - e.Response = r - e.Code = r.StatusCode - e.Message = r.Status - return &e +func newError(rsp *Response) error { + merr := &BaseError{} + + //if rsp.ContentLength > 0 { + // err := json.Unmarshal(rsp.content, merr) + // if err != nil { + // return err + // } + //} else { + merr.Status = rsp.StatusCode + merr.Title = rsp.Status + merr.Detail = string(rsp.content) + //} + + return merr } type Response struct { diff --git a/ewhs/ewhs_test.go b/ewhs/ewhs_test.go new file mode 100644 index 0000000..9eaa5fc --- /dev/null +++ b/ewhs/ewhs_test.go @@ -0,0 +1,190 @@ +package ewhs + +import ( + "github.com/ewarehousing-solutions/ewhs-api-go/test/testdata" + "github.com/stretchr/testify/assert" + "io" + "net/http" + "net/http/httptest" + "net/url" + "strings" + "testing" + "time" +) + +var ( + tMux *http.ServeMux + tServer *httptest.Server + tClient *Client + tConf *Config +) + +var ( + noPre = func() {} + crashSrv = func() { + u, _ := url.Parse(tServer.URL) + tClient.BaseURL = u + } +) + +func setup() { + tMux = http.NewServeMux() + tServer = httptest.NewServer(tMux) + + tConf = NewConfig("test_username", "test_password", "test_wms", "test_customer") + tClient, _ = NewClient(nil, tConf) + + u, _ := url.Parse(tServer.URL + "/") + tClient.BaseURL = u +} + +func teardown() { + tServer.Close() +} + +func testMethod(t *testing.T, r *http.Request, want string) { + if got := r.Method; got != want { + t.Errorf("Request method: %v, want %v", got, want) + } +} + +func testHeader(t *testing.T, r *http.Request, header string, want string) { + if got := r.Header.Get(header); got != want { + t.Errorf("Header.Get(%q) returned %q, want %q", header, got, want) + } +} + +func testQuery(t *testing.T, r *http.Request, want string) { + if r.URL.Query().Encode() != want { + t.Errorf("Query().Encode() retuned unexpected values, want: %q, got %q", want, r.URL.Query().Encode()) + } +} + +func unauthorizedHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusUnauthorized) + w.Write([]byte(testdata.WrongCredentialsResponse)) +} + +func errorHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + w.Write([]byte(testdata.InternalServerErrorResponse)) +} + +func encodingHandler(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + _, _ = w.Write([]byte(`{hello: [{},]}`)) +} + +// <----- .Testing helpers -----> + +func TestNewClient(t *testing.T) { + var c = http.DefaultClient + { + c.Timeout = 25 * time.Second + } + + tests := []struct { + name string + client *http.Client + }{ + { + "nil returns a valid client", + nil, + }, + { + "a passed client is decorated", + c, + }, + } + + conf := NewConfig("test_username", "test_password", "test_wms", "test_customer") + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewClient(tt.client, conf) + assert.Nil(t, err) + }) + } +} + +func TestCheckResponse(t *testing.T) { + res1 := &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(strings.NewReader("not found ok")), + } + + res2 := &http.Response{ + StatusCode: http.StatusOK, + Status: http.StatusText(http.StatusOK), + Body: io.NopCloser(strings.NewReader("success ok")), + } + + res3 := &http.Response{ + StatusCode: http.StatusNotFound, + Status: http.StatusText(http.StatusNotFound), + Body: io.NopCloser(strings.NewReader("")), + } + + tests := []struct { + name string + code string + arg *Response + }{ + { + "not found response", + "Not Found", + &Response{Response: res1}, + }, + { + "successful response", + "", + &Response{Response: res2}, + }, + { + "success with empty body", + "", + &Response{Response: res3}, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := CheckResponse(tt.arg); err != nil { + if !strings.Contains(err.Error(), tt.code) { + t.Error(err) + } + } + }) + } +} + +func TestClient_Authorize(t *testing.T) { + var c = http.DefaultClient + { + c.Timeout = 25 * time.Second + } + + tests := []struct { + name string + client *http.Client + }{ + { + "nil returns a valid client", + nil, + }, + { + "a passed client is decorated", + c, + }, + } + + conf := NewConfig("test_username", "test_password", "test_wms", "test_customer") + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := NewClient(tt.client, conf) + assert.Nil(t, err) + }) + } +} diff --git a/ewhs/inbounds.go b/ewhs/inbounds.go index 77a11a3..6babcc9 100644 --- a/ewhs/inbounds.go +++ b/ewhs/inbounds.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -30,8 +31,8 @@ type InboundListOptions struct { Direction string `url:"direction,omitempty"` } -func (is *InboundsService) List(opts *InboundListOptions) (list *[]Inbound, res *Response, err error) { - res, err = is.client.get("wms/inbounds/", opts) +func (is *InboundsService) List(ctx context.Context, opts *InboundListOptions) (list *[]Inbound, res *Response, err error) { + res, err = is.client.get(ctx, "wms/inbounds/", opts) if err != nil { return } @@ -43,8 +44,8 @@ func (is *InboundsService) List(opts *InboundListOptions) (list *[]Inbound, res return } -func (is *InboundsService) Get(inboundID string) (inbound *Inbound, res *Response, err error) { - res, err = is.client.get(fmt.Sprintf("wms/inbounds/%s/", inboundID), nil) +func (is *InboundsService) Get(ctx context.Context, inboundID string) (inbound *Inbound, res *Response, err error) { + res, err = is.client.get(ctx, fmt.Sprintf("wms/inbounds/%s/", inboundID), nil) if err != nil { return } @@ -56,8 +57,8 @@ func (is *InboundsService) Get(inboundID string) (inbound *Inbound, res *Respons return } -func (is *InboundsService) Create(inb Inbound) (inbound *Inbound, res *Response, err error) { - res, err = is.client.post("wms/inbounds/", inb, nil) +func (is *InboundsService) Create(ctx context.Context, inb Inbound) (inbound *Inbound, res *Response, err error) { + res, err = is.client.post(ctx, "wms/inbounds/", inb, nil) if err != nil { return @@ -70,8 +71,8 @@ func (is *InboundsService) Create(inb Inbound) (inbound *Inbound, res *Response, return } -func (is *InboundsService) Update(inboundID string, inb Inbound) (inbound *Inbound, res *Response, err error) { - res, err = is.client.patch(fmt.Sprintf("wms/inbounds/%s/", inboundID), inb, nil) +func (is *InboundsService) Update(ctx context.Context, inboundID string, inb Inbound) (inbound *Inbound, res *Response, err error) { + res, err = is.client.patch(ctx, fmt.Sprintf("wms/inbounds/%s/", inboundID), inb, nil) if err != nil { return @@ -84,8 +85,8 @@ func (is *InboundsService) Update(inboundID string, inb Inbound) (inbound *Inbou return } -func (is *InboundsService) Cancel(inboundID string) (inbound *Inbound, res *Response, err error) { - res, err = is.client.patch(fmt.Sprintf("wms/inbounds/%s/cancel", inboundID), nil, nil) +func (is *InboundsService) Cancel(ctx context.Context, inboundID string) (inbound *Inbound, res *Response, err error) { + res, err = is.client.patch(ctx, fmt.Sprintf("wms/inbounds/%s/cancel", inboundID), nil, nil) if err != nil { return } diff --git a/ewhs/orders.go b/ewhs/orders.go index f3d4f41..1cc8ade 100644 --- a/ewhs/orders.go +++ b/ewhs/orders.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -43,7 +44,7 @@ type ShippingAddress struct { AddressedTo string `json:"addressed_to,omitempty"` PhoneNumber string `json:"phone_number,omitempty"` MobileNumber string `json:"mobile_number,omitempty"` - StreetNumber int `json:"street_number,omitempty"` + StreetNumber string `json:"street_number,omitempty"` StreetNumberAddition string `json:"street_number_addition,omitempty"` } @@ -58,8 +59,8 @@ type OrderListOptions struct { Direction string `url:"direction,omitempty"` } -func (os *OrdersService) List(opts *OrderListOptions) (list *[]Order, res *Response, err error) { - res, err = os.client.get("wms/orders/", opts) +func (os *OrdersService) List(ctx context.Context, opts *OrderListOptions) (list *[]Order, res *Response, err error) { + res, err = os.client.get(ctx, "wms/orders/", opts) if err != nil { return } @@ -71,8 +72,8 @@ func (os *OrdersService) List(opts *OrderListOptions) (list *[]Order, res *Respo return } -func (os *OrdersService) Get(orderID string) (order *Order, res *Response, err error) { - res, err = os.client.get(fmt.Sprintf("wms/orders/%s/", orderID), nil) +func (os *OrdersService) Get(ctx context.Context, orderID string) (order *Order, res *Response, err error) { + res, err = os.client.get(ctx, fmt.Sprintf("wms/orders/%s/", orderID), nil) if err != nil { return } @@ -84,8 +85,8 @@ func (os *OrdersService) Get(orderID string) (order *Order, res *Response, err e return } -func (os *OrdersService) Create(ord Order) (order *Order, res *Response, err error) { - res, err = os.client.post("wms/orders/", ord, nil) +func (os *OrdersService) Create(ctx context.Context, ord Order) (order *Order, res *Response, err error) { + res, err = os.client.post(ctx, "wms/orders/", ord, nil) if err != nil { return @@ -98,8 +99,8 @@ func (os *OrdersService) Create(ord Order) (order *Order, res *Response, err err return } -func (os *OrdersService) Update(orderID string, ord Order) (order *Order, res *Response, err error) { - res, err = os.client.patch(fmt.Sprintf("wms/orders/%s/", orderID), ord, nil) +func (os *OrdersService) Update(ctx context.Context, orderID string, ord Order) (order *Order, res *Response, err error) { + res, err = os.client.patch(ctx, fmt.Sprintf("wms/orders/%s/", orderID), ord, nil) if err != nil { return @@ -112,8 +113,8 @@ func (os *OrdersService) Update(orderID string, ord Order) (order *Order, res *R return } -func (os *OrdersService) Cancel(orderID string) (order *Order, res *Response, err error) { - res, err = os.client.patch(fmt.Sprintf("wms/orders/%s/cancel", orderID), nil, nil) +func (os *OrdersService) Cancel(ctx context.Context, orderID string) (order *Order, res *Response, err error) { + res, err = os.client.patch(ctx, fmt.Sprintf("wms/orders/%s/cancel", orderID), nil, nil) if err != nil { return } diff --git a/ewhs/orders_test.go b/ewhs/orders_test.go index d6c8274..0eaf579 100644 --- a/ewhs/orders_test.go +++ b/ewhs/orders_test.go @@ -1 +1,241 @@ package ewhs + +import ( + "context" + "fmt" + "github.com/ewarehousing-solutions/ewhs-api-go/test/testdata" + "github.com/stretchr/testify/suite" + "net/http" + "testing" +) + +type ordersServiceSuite struct{ suite.Suite } + +func (os *ordersServiceSuite) TestOrdersService_Get() { + type args struct { + ctx context.Context + order string + } + cases := []struct { + name string + args args + wantErr bool + err error + pre func() + handler http.HandlerFunc + }{ + { + "get orders works as expected.", + args{ + context.Background(), + "c9165f93-8301-4aaa-9f64-27f191c0c778", + }, + false, + nil, + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + func(w http.ResponseWriter, r *http.Request) { + testHeader(os.T(), r, AuthHeader, "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + testHeader(os.T(), r, CustomerCodeHeader, "test_customer") + testHeader(os.T(), r, WmsCodeHeader, "test_wms") + testMethod(os.T(), r, "GET") + + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + _, _ = w.Write([]byte(testdata.GetOrderResponse)) + }, + }, + { + "get orders works as expected.", + args{ + context.Background(), + "c9165f93-8301-4aaa-9f64-27f191c0c778", + }, + false, + nil, + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + func(w http.ResponseWriter, r *http.Request) { + testHeader(os.T(), r, AuthHeader, "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + testMethod(os.T(), r, "GET") + + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + _, _ = w.Write([]byte(testdata.GetOrderResponse)) + }, + }, + { + "get orders, an error is returned from the server", + args{ + context.Background(), + "c9165f93-8301-4aaa-9f64-27f191c0c778", + }, + true, + fmt.Errorf("500 - 500 Internal Server Error"), + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + errorHandler, + }, + { + "get orders, an error occurs when parsing json", + args{ + context.Background(), + "c9165f93-8301-4aaa-9f64-27f191c0c778", + }, + true, + fmt.Errorf("invalid character 'h' looking for beginning of object key string"), + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + encodingHandler, + }, + { + "get orders, invalid url when building request", + args{ + context.Background(), + "c9165f93-8301-4aaa-9f64-27f191c0c778", + }, + true, + errBadBaseURL, + crashSrv, + errorHandler, + }, + } + + for _, c := range cases { + setup() + defer teardown() + + os.T().Run(c.name, func(t *testing.T) { + c.pre() + tMux.HandleFunc(fmt.Sprintf("/wms/orders/%s/", c.args.order), c.handler) + + m, res, err := tClient.Orders.Get(c.args.ctx, c.args.order) + if c.wantErr { + os.NotNil(err) + os.EqualError(err, c.err.Error()) + } else { + os.Nil(err) + os.IsType(&Order{}, m) + os.IsType(&http.Response{}, res.Response) + } + }) + } +} + +func (os *ordersServiceSuite) TestOrdersService_Create() { + type args struct { + ctx context.Context + order Order + } + cases := []struct { + name string + args args + wantErr bool + err error + pre func() + handler http.HandlerFunc + }{ + { + "create orders works as expected.", + args{ + context.Background(), + Order{ + ShippingAddress: ShippingAddress{}, + }, + }, + false, + nil, + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + func(w http.ResponseWriter, r *http.Request) { + testHeader(os.T(), r, AuthHeader, "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + testHeader(os.T(), r, CustomerCodeHeader, "test_customer") + testHeader(os.T(), r, WmsCodeHeader, "test_wms") + testMethod(os.T(), r, "POST") + + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + _, _ = w.Write([]byte(testdata.GetOrderResponse)) + }, + }, + { + "create orders works as expected.", + args{ + context.Background(), + Order{}, + }, + false, + nil, + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + func(w http.ResponseWriter, r *http.Request) { + testHeader(os.T(), r, AuthHeader, "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + testMethod(os.T(), r, "POST") + + if _, ok := r.Header[AuthHeader]; !ok { + w.WriteHeader(http.StatusUnauthorized) + } + _, _ = w.Write([]byte(testdata.GetOrderResponse)) + }, + }, + { + "create orders, an error is returned from the server", + args{ + context.Background(), + Order{}, + }, + true, + fmt.Errorf("500 - 500 Internal Server Error"), + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + errorHandler, + }, + { + "create orders, an error occurs when parsing json", + args{ + context.Background(), + Order{}, + }, + true, + fmt.Errorf("invalid character 'h' looking for beginning of object key string"), + func() { + tClient.WithAuthToken("eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9") + }, + encodingHandler, + }, + } + + for _, c := range cases { + setup() + defer teardown() + + os.T().Run(c.name, func(t *testing.T) { + c.pre() + tMux.HandleFunc("/wms/orders/", c.handler) + + m, res, err := tClient.Orders.Create(c.args.ctx, c.args.order) + if c.wantErr { + os.NotNil(err) + os.EqualError(err, c.err.Error()) + } else { + os.Nil(err) + os.IsType(&Order{}, m) + os.IsType(&http.Response{}, res.Response) + } + }) + } +} + +func TestOrdersService(t *testing.T) { + suite.Run(t, new(ordersServiceSuite)) +} diff --git a/ewhs/shipments.go b/ewhs/shipments.go index 8c8b1e6..6bca6d2 100644 --- a/ewhs/shipments.go +++ b/ewhs/shipments.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" "time" @@ -25,8 +26,8 @@ type ShipmentListOptions struct { Direction string `url:"direction,omitempty"` } -func (ss *ShipmentsService) List(opts *ShipmentListOptions) (list *[]Shipment, res *Response, err error) { - res, err = ss.client.get("wms/shipments/", opts) +func (ss *ShipmentsService) List(ctx context.Context, opts *ShipmentListOptions) (list *[]Shipment, res *Response, err error) { + res, err = ss.client.get(ctx, "wms/shipments/", opts) if err != nil { return } @@ -38,8 +39,8 @@ func (ss *ShipmentsService) List(opts *ShipmentListOptions) (list *[]Shipment, r return } -func (ss *ShipmentsService) Get(shipmentID string) (shipment *Shipment, res *Response, err error) { - res, err = ss.client.get(fmt.Sprintf("wms/shipments/%s/", shipmentID), nil) +func (ss *ShipmentsService) Get(ctx context.Context, shipmentID string) (shipment *Shipment, res *Response, err error) { + res, err = ss.client.get(ctx, fmt.Sprintf("wms/shipments/%s/", shipmentID), nil) if err != nil { return } diff --git a/ewhs/shippingmethods.go b/ewhs/shippingmethods.go index 7c0f60b..d740133 100644 --- a/ewhs/shippingmethods.go +++ b/ewhs/shippingmethods.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -23,8 +24,8 @@ type ShippingMethodListOptions struct { Direction string `url:"direction,omitempty"` } -func (ss *ShippingMethodsService) List(opts *ShippingMethodListOptions) (list *[]ShippingMethod, res *Response, err error) { - res, err = ss.client.get("wms/shippingmethods/", opts) +func (ss *ShippingMethodsService) List(ctx context.Context, opts *ShippingMethodListOptions) (list *[]ShippingMethod, res *Response, err error) { + res, err = ss.client.get(ctx, "wms/shippingmethods/", opts) if err != nil { return } @@ -36,8 +37,8 @@ func (ss *ShippingMethodsService) List(opts *ShippingMethodListOptions) (list *[ return } -func (ss *ShippingMethodsService) Get(shippingMethodID string) (shippingMethod *ShippingMethod, res *Response, err error) { - res, err = ss.client.get(fmt.Sprintf("wms/shippingmethods/%s/", shippingMethodID), nil) +func (ss *ShippingMethodsService) Get(ctx context.Context, shippingMethodID string) (shippingMethod *ShippingMethod, res *Response, err error) { + res, err = ss.client.get(ctx, fmt.Sprintf("wms/shippingmethods/%s/", shippingMethodID), nil) if err != nil { return } diff --git a/ewhs/stock.go b/ewhs/stock.go index dd92088..7cfc9c7 100644 --- a/ewhs/stock.go +++ b/ewhs/stock.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "time" ) @@ -34,8 +35,8 @@ type StockListOptions struct { Direction string `url:"direction,omitempty"` } -func (ss *StockService) List(opts *StockListOptions) (list *[]Stock, res *Response, err error) { - res, err = ss.client.get("wms/stock/", opts) +func (ss *StockService) List(ctx context.Context, opts *StockListOptions) (list *[]Stock, res *Response, err error) { + res, err = ss.client.get(ctx, "wms/stock/", opts) if err != nil { return } diff --git a/ewhs/variants.go b/ewhs/variants.go index a486894..e83de48 100644 --- a/ewhs/variants.go +++ b/ewhs/variants.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -32,8 +33,8 @@ type VariantListOptions struct { Direction string `url:"direction,omitempty"` } -func (vs *VariantsService) List(opts *VariantListOptions) (list *[]Variant, res *Response, err error) { - res, err = vs.client.get("wms/variants/", opts) +func (vs *VariantsService) List(ctx context.Context, opts *VariantListOptions) (list *[]Variant, res *Response, err error) { + res, err = vs.client.get(ctx, "wms/variants/", opts) if err != nil { return } @@ -45,8 +46,8 @@ func (vs *VariantsService) List(opts *VariantListOptions) (list *[]Variant, res return } -func (vs *VariantsService) Get(variantID string) (variant *Variant, res *Response, err error) { - res, err = vs.client.get(fmt.Sprintf("wms/variants/%s/", variantID), nil) +func (vs *VariantsService) Get(ctx context.Context, variantID string) (variant *Variant, res *Response, err error) { + res, err = vs.client.get(ctx, fmt.Sprintf("wms/variants/%s/", variantID), nil) if err != nil { return } @@ -58,8 +59,8 @@ func (vs *VariantsService) Get(variantID string) (variant *Variant, res *Respons return } -func (vs *VariantsService) Create(ord Order) (order *Order, res *Response, err error) { - res, err = vs.client.post("wms/variants/", ord, nil) +func (vs *VariantsService) Create(ctx context.Context, ord Order) (order *Order, res *Response, err error) { + res, err = vs.client.post(ctx, "wms/variants/", ord, nil) if err != nil { return @@ -72,8 +73,8 @@ func (vs *VariantsService) Create(ord Order) (order *Order, res *Response, err e return } -func (vs *VariantsService) Update(variantID string, vr Variant) (variant *Variant, res *Response, err error) { - res, err = vs.client.patch(fmt.Sprintf("wms/variants/%s/", variantID), vr, nil) +func (vs *VariantsService) Update(ctx context.Context, variantID string, vr Variant) (variant *Variant, res *Response, err error) { + res, err = vs.client.patch(ctx, fmt.Sprintf("wms/variants/%s/", variantID), vr, nil) if err != nil { return diff --git a/ewhs/webhooks.go b/ewhs/webhooks.go index 3b64d1c..1b93069 100644 --- a/ewhs/webhooks.go +++ b/ewhs/webhooks.go @@ -1,6 +1,7 @@ package ewhs import ( + "context" "encoding/json" "fmt" ) @@ -14,8 +15,8 @@ type Webhook struct { HashSecret string `json:"hash_secret,omitempty"` } -func (ws *WebhooksService) List() (list *[]Webhook, res *Response, err error) { - res, err = ws.client.get("wms/webhooks/", nil) +func (ws *WebhooksService) List(ctx context.Context) (list *[]Webhook, res *Response, err error) { + res, err = ws.client.get(ctx, "wms/webhooks/", nil) if err != nil { return } @@ -27,8 +28,8 @@ func (ws *WebhooksService) List() (list *[]Webhook, res *Response, err error) { return } -func (ws *WebhooksService) Get(webhookID string) (webhook *Webhook, res *Response, err error) { - res, err = ws.client.get(fmt.Sprintf("webhooks/%s/", webhookID), nil) +func (ws *WebhooksService) Get(ctx context.Context, webhookID string) (webhook *Webhook, res *Response, err error) { + res, err = ws.client.get(ctx, fmt.Sprintf("webhooks/%s/", webhookID), nil) if err != nil { return } @@ -40,8 +41,8 @@ func (ws *WebhooksService) Get(webhookID string) (webhook *Webhook, res *Respons return } -func (ws *WebhooksService) Create(wh Webhook) (webhook *Webhook, res *Response, err error) { - res, err = ws.client.post("webhooks/", wh, nil) +func (ws *WebhooksService) Create(ctx context.Context, wh Webhook) (webhook *Webhook, res *Response, err error) { + res, err = ws.client.post(ctx, "webhooks/", wh, nil) if err != nil { return @@ -54,8 +55,8 @@ func (ws *WebhooksService) Create(wh Webhook) (webhook *Webhook, res *Response, return } -func (ws *WebhooksService) Update(webhookID string, wh Webhook) (webhook *Webhook, res *Response, err error) { - res, err = ws.client.patch(fmt.Sprintf("webhooks/%s/", webhookID), wh, nil) +func (ws *WebhooksService) Update(ctx context.Context, webhookID string, wh Webhook) (webhook *Webhook, res *Response, err error) { + res, err = ws.client.patch(ctx, fmt.Sprintf("webhooks/%s/", webhookID), wh, nil) if err != nil { return @@ -68,8 +69,8 @@ func (ws *WebhooksService) Update(webhookID string, wh Webhook) (webhook *Webhoo return } -func (os *OrdersService) Delete(webhookID string) (webhook *Webhook, res *Response, err error) { - res, err = os.client.delete(fmt.Sprintf("webhooks/%s/", webhookID), nil) +func (os *OrdersService) Delete(ctx context.Context, webhookID string) (webhook *Webhook, res *Response, err error) { + res, err = os.client.delete(ctx, fmt.Sprintf("webhooks/%s/", webhookID), nil) if err != nil { return } diff --git a/go.mod b/go.mod index 15a51d5..ce48051 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,10 @@ module github.com/ewarehousing-solutions/ewhs-api-go go 1.19 -require github.com/google/go-querystring v1.1.0 // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/google/go-querystring v1.1.0 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/stretchr/testify v1.8.1 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 4974eb1..40e7780 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,20 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/test/testdata/auth.go b/test/testdata/auth.go new file mode 100644 index 0000000..7db0186 --- /dev/null +++ b/test/testdata/auth.go @@ -0,0 +1,13 @@ +package testdata + +const CreateAuthTokenResponse = `{ +"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJpYXQiOjE2Njc4OTc2MDgsImV4cCI6MTY2NzkwMTIwOCwicm9sZXMiOlsiUk9MRV9XRUIiLCJST0xFX01JRERMRVdBUkVfQkFUQ0hfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9TSElQUElOR01FVEhPRFNfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9NT0RJRklDQVRJT05TX1JFQUQiLCJST0xFX01JRERMRVdBUkVfQVJUSUNMRVNfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9BUlRJQ0xFU19DUkVBVEUiLCJST0xFX01JRERMRVdBUkVfQVJUSUNMRVNfVVBEQVRFIiwiUk9MRV9NSURETEVXQVJFX0lOQk9VTkRTX1JFQUQiLCJST0xFX01JRERMRVdBUkVfSU5CT1VORFNfQ1JFQVRFIiwiUk9MRV9NSURETEVXQVJFX0lOQk9VTkRTX1VQREFURSIsIlJPTEVfTUlERExFV0FSRV9JTkJPVU5EU19DQU5DRUwiLCJST0xFX01JRERMRVdBUkVfT1JERVJTX1JFQUQiLCJST0xFX01JRERMRVdBUkVfT1JERVJTX0NSRUFURSIsIlJPTEVfTUlERExFV0FSRV9PUkRFUlNfVVBEQVRFIiwiUk9MRV9NSURETEVXQVJFX09SREVSU19DQU5DRUwiLCJST0xFX01JRERMRVdBUkVfT1JERVJTX0RPQ1VNRU5UU19SRUFEIiwiUk9MRV9NSURETEVXQVJFX09SREVSU19ET0NVTUVOVFNfQ1JFQVRFIiwiUk9MRV9NSURETEVXQVJFX09SREVSU19ET0NVTUVOVFNfVVBEQVRFIiwiUk9MRV9NSURETEVXQVJFX09SREVSU19ET0NVTUVOVFNfREVMRVRFIiwiUk9MRV9NSURETEVXQVJFX0RPQ1VNRU5UU19ERUxFVEUiLCJST0xFX01JRERMRVdBUkVfU0hJUE1FTlRTX1JFQUQiLCJST0xFX01JRERMRVdBUkVfU1RPQ0tfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9DVVNUT01FUlNfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9FWFBPUlRfUkVBRCIsIlJPTEVfTUlERExFV0FSRV9FWFBPUlRfQ1JFQVRFIiwiUk9MRV9NSURETEVXQVJFX0VYUE9SVF9CSUxMSU5HX0NSRUFURSIsIlJPTEVfTUlERExFV0FSRV9FWFBPUlRfRklOQU5DSUFMX0NSRUFURSIsIlJPTEVfTUlERExFV0FSRV9FWFBPUlRfRE9XTkxPQUQiLCJST0xFX01JRERMRVdBUkVfQUxMR1JPVVBTIiwiUk9MRV9NSURETEVXQVJFX01PRElGSUNBVElPTlNfQ1JFQVRFIiwiUk9MRV9NSURETEVXQVJFX01PRElGSUNBVElPTlNfVVBEQVRFIiwiUk9MRV9NSURETEVXQVJFX01PRElGSUNBVElPTlNfQVBQUk9WRSIsIlJPTEVfTUlERExFV0FSRV9NT0RJRklDQVRJT05TX0RJU0FQUFJPVkUiLCJST0xFX1VTRVIiXSwidXNlcm5hbWUiOiJtYXJrbm90aXZlYXBpIiwidXNlcl9pZCI6IjkxMDc4NDBiLTg0YjYtNDgxMy05NWViLWFmODE1YjAyNGY4YiIsInVzZXJfdHlwZSI6ImFwaSIsImN1c3RvbWVyX2lkcyI6WyJiZTYyYzI3ZS0yYWFjLTRhYzEtOTAyZS1mNzcwZDY0ZjhkY2UiLCI2ZTYyM2RhYy0wNzliLTRiNTgtYjVkNS01MmE0ZWZhOWRlMWIiLCJiOTczMDY4MS0zMGFlLTRlYzAtODU2NC01MmVjMGU3Y2MyMjAiLCI4YWMxNTlmNi1mNDcxLTQwN2UtOGU5ZC1iZDNlMTgzNDY2ODMiLCIyMjE5MDNkOC0yMGQyLTRiNzItOTgyNy0yMjZmZTMxNDFjNDUiLCJhODgzOTY3Ny01NGQzLTQ4MDUtODc4ZC0zMjU5MGQ0NDVkY2QiLCI2NGYxNGQ2Mi0zYzRjLTQzYjgtODM1My00YjFjZTJmZmExY2EiLCJkYjdhZjIwMC1iZTY1LTRjMTItYTY3ZS1hNDkxNGJkOTJiMmYiLCIwZTU0M2M5OS1mMzcxLTQyYzgtODM4OS1lMzM1NDUzZmRkMTAiLCI3MjM5YTM3My1hYzhjLTRjOWUtOWI3OC05OTRhY2UzMTIyMjciLCI4OTY3MTBhZi1hMzhkLTRmNDAtOWM3Ni1kNzc2YmYwY2VmN2EiLCI1ZTExZTExYi05ZWI1LTQ5OWItYjJiYy1jMmZiZWNiNzQwNGQiXSwicmVxdWVzdF9pcCI6IjEwLjAuMC4zNiJ9.KHdQRVLArCKPxm27j9HPMwN7D0-W5VANV-GTsoEQkfNDIVwhzQJn3rRmG6titW4AQNp6u1Ti2nccxM7nHQTjChif711krMS9IUryLGWUta-Utmg8kn0kFBgnBBOleU2mlfyXeViwlgC9FPhd9QouzeDX-uTPn_RfBqt1SxY0EDbXsY0abqmYgaGqkUPTHom67qm7l-GpKtcAEOWrxdw5DG2uD-P0tEUL738IIsycasPk538uruTrnCSbOXMf6VnPDFGOumfZrGl9UzAzXjEMdWvyLs4ukHIxKWVPoYfsBrG40l2ovNnYfm6acI000RcHY1bV6DcHEqHUpGpbrk3gI_bI4KEPZGkkmJKMckv9JhbA-tq8oGDSYYJeRq8M76L-3mjNWixYSn0_2QLmmWQT0tYiFHs8vBRAhPTcypDP-DuwMKzlLP2KgdbFHf6tSGVa-Lip4ae2DmKUifToUaAveZ1PEP_GTUZQ7SaGEQiUnMBSpudrp2VOB8NbYLFaWtfjdzPpAHmEMFPJMxbne-33mV4RINuxR4PbSlzfCvEPXVE2-6af1us1hkZC2wW_ZQfAti_Ay6_i5Dx-Ttwhy4lxRmA0XznITfPT4Fv3L-gS6nK5eU9_x6egDT55a4Q9U-TgMX011umBLmSNZWcBFo-Y-C6bwYjG76qVl8plm0p0cmA", +"iat": 1667897608, +"exp": 1667901208, +"refresh_token": "f5e7fca6863fd6c2694af2cf72178741a04441548a94c47ab337076cdab15db77bcddc539926d5ebcb6ed35ebee9f11c01fcd6a5e382d632bdac7b36cca83805" +}` + +const WrongCredentialsResponse = `{ +"code": 401, +"message": "Invalid credentials." +}` diff --git a/test/testdata/errors.go b/test/testdata/errors.go new file mode 100644 index 0000000..17baa0a --- /dev/null +++ b/test/testdata/errors.go @@ -0,0 +1,6 @@ +package testdata + +const InternalServerErrorResponse = `{ + "title": "Internal Server Error", + "detail": "An internal server error occurred while processing your request.", +}` diff --git a/test/testdata/orders.go b/test/testdata/orders.go new file mode 100644 index 0000000..81ec26d --- /dev/null +++ b/test/testdata/orders.go @@ -0,0 +1,139 @@ +package testdata + +const GetOrderResponse = `{ + "id": "c9165f93-8301-4aaa-9f64-27f191c0c778", + "created_at": "2022-02-11T09:32:12+00:00", + "customer": "be62c27e-2aac-4ac1-902e-f770d64f8dce", + "external_reference": "1644571933", + "reference": "ORD00000003029", + "status": "created", + "business_to_business": true, + "applied_business_rules": null, + "partial_delivery": false, + "language": null, + "note": "Testorder", + "customer_note": "Pleaserushthisorder", + "shipping_method": null, + "shipping_address": { + "addressed_to": "eWarehousing Solutions", + "contact_person": null, + "street": "Nijverheidsweg", + "street2": null, + "street_number": "27", + "street_number_addition": null, + "zipcode": "3331MB", + "city": "Zwijndrecht", + "country": "NL", + "state": "ZH", + "phone_number": "0102202863", + "mobile_number": null, + "fax_number": null, + "email_address": null + }, + "order_lines": [ + { + "variant": { + "id": "87557e7a-4f4d-44eb-bbf1-c9d83df90099", + "article_code": "default_variant_b_id", + "name": "default_variant_b_id", + "description": null, + "ean": "default_variant_b_id", + "sku": "default_variant_b_id", + "hs_tariff_code": null, + "height": null, + "depth": null, + "width": null, + "weight": null, + "expirable": false, + "country_of_origin": null, + "using_serial_numbers": false, + "value": 0 + }, + "quantity": 7, + "description": "Voorbeeldproduct-B" + }, + { + "variant": { + "id": "1e19da60-4d2b-4c15-8f4e-8978f6113c00", + "article_code": "default_variant_a_id", + "name": "default_variant_a_id", + "description": null, + "ean": "default_variant_a_id", + "sku": "default_variant_a_id", + "hs_tariff_code": null, + "height": null, + "depth": null, + "width": null, + "weight": null, + "expirable": false, + "country_of_origin": null, + "using_serial_numbers": false, + "value": 0 + }, + "quantity": 15, + "description": "Voorbeeldproduct-A" + } + ] +}` + +const CreateOrderRequest = `{ + "external_reference": "1667553171", + "shipping_contactperson": "John Doe", + "requested_delivery_date": "2022-10-15", + "customer_note": "Please take care", + "shipping_email": "john.doe@comcast.net", + "shipping_method": "a299249a-b2cd-4666-a6e5-77d3e1156a22", + "note": "Quisque ornare tortor at risus", + "documents": [ + { + "shipping_label": false, + "title": "my_label", + "quantity": 1, + "orderPrice": 213, + "file": "JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nD2OywoCMQxF9/mKu3YRk7bptDAIDuh+oOAP+AAXgrOZ37etjmSTe3ISIljpDYGwwrKxRwrKGcsNlx1e31mt5UFTIYucMFiqcrlif1ZobP0do6g48eIPKE+ydk6aM0roJG/RegwcNhDr5tChd+z+miTJnWqoT/3oUabOToVmmvEBy5IoCgplbmRzdHJlYW0KZW5kb2JqCgozIDAgb2JqCjEzNAplbmRvYmoKCjUgMCBvYmoKPDwvTGVuZ3RoIDYgMCBSL0ZpbHRlci9GbGF0ZURlY29kZS9MZW5ndGgxIDIzMTY0Pj4Kc3RyZWFtCnic7Xx5fFvVlf+59z0tdrzIu7xFz1G8Kl7i2HEWE8vxQlI3iRM71A6ksSwrsYptKZYUE9omYStgloZhaSlMMbTsbSPLAZwEGgNlusxQ0mHa0k4Z8muhlJb8ynQoZVpi/b736nkjgWlnfn/8Pp9fpNx3zz33bPecc899T4oVHA55KIEOkUJO96DLvyQxM5WI/omIpbr3BbU/3J61FPBpItOa3f49g1948t/vI4rLIzL8dM/A/t3vn77ZSpT0LlH8e/0eV98jn3k0mSj7bchY2Q/EpdNXm4hyIIOW9g8Gr+gyrq3EeAPGVQM+t+uw5VrQ51yBcc6g6wr/DywvGAHegbE25Br0bFR/ezPGR4kq6/y+QPCnVBYl2ijka/5hjz95S8kmok8kEFl8wDG8xQtjZhRjrqgGo8kcF7+I/r98GY5TnmwPU55aRIhb9PWZNu2Nvi7mRM9/C2flx5r+itA36KeshGk0wf5MWfQ+y2bLaSOp9CdkyxE6S3dSOnXSXSyVllImbaeNTAWNg25m90T3Rd+ii+jv6IHoU+zq6GOY/yL9A70PC/5NZVRHm0G/nTz0lvIGdUe/Qma6nhbRWtrGMslFP8H7j7DhdrqDvs0+F30fWtPpasirp0ZqjD4b/YDK6Gb1sOGVuCfoNjrBjFF31EuLaQmNckf0J9HXqIi66Wv0DdjkYFPqBiqgy+k6+jLLVv4B0J30dZpmCXyn0mQ4CU0b6RIaohEapcfoByyVtRteMbwT/Wz0TTJSGpXAJi+9xWrZJv6gmhBdF/05XUrH6HtYr3hPqZeqDxsunW6I/n30Ocqgp1g8e5o9a6g23Hr2quj90W8hI4toOTyyGXp66Rp6lr5P/05/4AejB2kDdUDzCyyfaawIHv8Jz+YH+AHlZarAanfC2hDdR2FE5DidoGfgm3+l0/QGS2e57BOsl93G/sATeB9/SblHOar8i8rUR+FvOxXCR0F6kJ7Efn6RXmIGyK9i7ewzzMe+xP6eneZh/jb/k2pWr1H/op41FE2fnv5LdHP0j2SlHPokXUkH4duv0QQdpR/Sj+kP9B/0HrOwVayf3c/C7DR7m8fxJXwL9/O7+IP8m8pm5TblWbVWXa9err6o/tzwBcNNJpdp+oOHpm+f/ub0j6JPRX+E3EmC/CJqhUevQlY8SCfpZUj/Gb1KvxT5A/lr2Q72aWgJsBvYHeyb7AX2I/ZbrJLkewlfy5uh1ceH4aer+e38Dmh/Ce9T/Of8Vf47/kfFoCxRVip7lfuVsDKpnFJ+rVrUIrVCXa5uUXeoUUSm2nCxocPwiOFxw3OGd4z1xj6j3/gb09Wma83/dLbs7L9N03T/dHh6ArlrRiZdCU98lR5A3h9FDH4Aj/4QFp+mdxGFHFbAimH3atbK2tgm9il2GfOwq9n17O/Yl9k97AH2LawAa+Am2O7gjbyDu7iHX8uv57fwo3gf59/nP+Gv8DOwPEuxKw5lubJR2aFcqgxhDUHlgHItPHub8pjykvKy8qbyG+UMopalLlZD6pXq3erD6lH1R4ZPGgbxfsBw0jBl+JHhA8MHRm7MMeYZK42fMT5i/KXJaFppajfdaPoX03+Y/SyPlcFybX614NnYg4v5YzxdPcjOAJHPVErGyh2IQwd2xX9QgzKNuCSJediWwbPVNMFpdKph8AfZCaplL9BBI1dQidXTFGG/4KfV5/lF9GPWw7LVh5Uhww94AT2OanSYP81PsPV0lNfzS/i9CrE32CP0BvL9CrqDXc4C9Dg7w9awz7M6dpD+hWcqHexaqo8+wFUWxzaydwgW0FVqH33646sgW02/oLemv6omqp9DfZqkuxDRb9Br7FH6MzNE30Z1U1CNXKgyNyPfryNR9XZinx3EfsxGBRkwvkRHxYliqjOuU6+kd+g/6S3DcWTUelTSN6e96lfVX0XrouXYYdhl9Aj2XT9djB3zBrLkGYzF6DLs9HjUkmrs6nbaQX30eVS926Lh6L3Ra6L7oz76R/D+mS1jf2Zj2BGT4Kin7+H9RfoZuwn78OL/3ikw3UdT9FtmZYWsGvvhjGGf4bDhMcNRw7cNLxqXw9vX0j3I6F8im+OxAjf9iH5Lf2JmxCabllEN7F0F27togHcrz1ATyyE/9mwJ6vh6fSUBSLka3rsX+/kZ7I13UCcuo2/TK4yzLKzIDf1myGmDn3eB+iFE8Bo2AUwfqnYZ/Q7rTmKreBD6nJB0F6rWFGz6Bf0a3o5Ku5ahLjSzSyDrT/Qp6oOGldTOxhGBJ2k1Kmuz8k/w91JmofVsCfs6+HqwQ5Mon1YbfsU4LZveHF3FvcozOGOiwI/h9Mqli9heWJGMdZylDLaFaqe3wYaXiZyNnc6GdRfVr12zelVdbc2K6uVVlRXlyxxlpSXFRYVL7UsKNNvi/LzcnGxrVmZGelpqiiU5KTFhUXyc2WQ0qApntKzF3tqjhYt6wmqRfcOGcjG2u4BwzUP0hDWgWhfShLUeSaYtpHSCcveHKJ0xSucsJbNo9VRfvkxrsWvhF5vt2iTbsbUL8C3N9m4tfEbCmyR8WMKJgAsKwKC1WPubtTDr0VrCrfv6R1t6miFufFF8k73JE1++jMbjFwFcBCicZfePs6x1TAI8q2XNOCdzIowK59ibW8LZ9mZhQVgpbHH1hdu3drU05xYUdJcvC7Mmt703TPb14WSHJKEmqSZsbAqbpBrNK1ZDN2njy6ZGb560UG+PI6HP3ue6rCusuLqFjhQH9DaHs6583To3hPDUpq7r58/mKqMtVq8mhqOj12vhqa1d82cLxLW7GzLAywtbe0ZbofpmOLGtQ4M2fl13V5hdB5WaWIlYVWx9HnuLwPR8RgvH2dfb+0c/04PQ5IyGadv+gkhOjvNY9DTltGijnV32gnBDrr3b1Zw3nk6j2/ZPZDu17IUz5cvGLSkxx44nJetAQuJ8wDM7JyFJLqC2bbOeZcIi+0YkRFhza7Cky441rRIXzyoada8CGV7dDFzhPkTEG45r6hm1rBF4wR82FFrs2ugfCRlgP/P2QoxLxxgLLX8kAYo8mU01zM/AYYcjXFYmUsTUhJjCxnVyXFu+bN8kX2n3WzR0cB+1w7eu7jWVcH9BgQjwTZNO6sUgfGhrV2ysUW9uhJyVju4w7xEzUzMzGdvFzKGZmVn2Hjsy+ah8EMgIm4tm/yVbMtNa+teEWebHTHti820d9ratO7q0ltEe3bdtnQtGsflVs3M6FE5r6lJyuQ7xXEXOIikvmyUWg66EsFqIf0aZ1H1hBUkpEUxrDVt6NsSu3fEFBR/JM2kyz2OajL4juGQ3x6ZbGV7jWDheu2C8wLqEUQX2qkW8rXPH6Gj8grlWFKDR0Va71jraM+qajB7qtWsW++gx/jB/eNTf0jMT0Mno8Ztyw603d2MR/WwNkpXT+nE7u2HruJPd0LGj65gFT283dHZFOONNPeu7x5dirusYbkWcEstnsWKkiRG1MSR6hJvlVO4xJ9EhOatKhBy7JxlJnHkGx8g9yWM4i8ThVY7bFBF8A9449U20/ihn00bTJG9wppFBnVYo3qROM8o2Gw3TXHmaFVEcbnatZHVY3qs/W7/Z8m79prP11ADY8gEuy6sKUgpSCnFhuIH4QFOmPnAa6C+kqVPQhScYMrjwnGUhGx10rigxlMRfnOVRPQmGsqzVWRsyuzP7Mw2rs1bmXp97t+GuRQZbSiEjnpZamGwxZxcfMTHTZHRqIm5RDUy82Zl2qIBpBVUFvCAlVSPNUmXhlkl+04S2vMPqgGk7hW2bLDv3vufYu+mMNLJB2kg797KdaQXVWZmZqRnpuBfE217AUlZU163jtTVFRcVF9jt4/lM9V032lNft3nRN79fPvsxKXv1c3YZd9fUDHeueMBzPK3pu+s0fPnHNmLutzKY+90FtUuolLzz22JO7U5PEs/ct0d+oHbivy6R7nVmfStmTcpdBiTNmG+t5fUobb0t5k5uSJ3nQmaIuyqT4jPT0+DhjWnpRRgZNslJnUqZTW1pzJJNFM1lmjhWLdmYuWVpz2Dpm5X7rO1b+eyuzxi8qijOLqWTQjpnZO2Zmzs5qqJdr3zvsEKvfjNUPO95D23Sm3iIjVW+BFxrOCC+wnQW1RqN9SVFRLaKWnpm5onrlSgEqm9c84738sU+ybNu2hg3DZSz7vu29n37sLj42bT3tWbsl9Dqb+svPxToP4H73y+o6KmZrj1EpjNmZEt9gMBoTMoyZCTVKjbnGWmNv5i3mFmuzPUFTKks74npKD5XeV/p148OmhxKeMD6REC49VXq6NIlKK0vbMXGy9LVSY6kzJ6+mAeNDctJgKlBNOfmZcFkk3lQgPLdYNVlSUopz8/KKiuMZGZMtRakpzh21PSnMl8JSJnmrMzkntyg/DzhfHuvJY3nAHS1EdBl8HCEqFsmUHNcgeudK2F0M0mJnI1o92tLimmLnmotqKotfKn6tWEkuthUfKlaoWCuuKo4Wq8XZJb+K+Vq4OPZCtp2Bl9/budeBRHtv707RwefS6+LdcKbhDEtJXU1oy6vYsGPvToTBkVaQsXJFdWbWSnnNzEAIapCDS4xGCRbNgAeYctPU7ruqWh+4LPRASf70m/nFW9f2V0y/ubhhZWN/+fSbatFtj3Zu396567LmL5/t5ru+WlG/4aa7pjlvvWfHstZr7z77AWKWNL1V3YbcTGM1R1NLDCxtMnraaU1IrjFnJibXmMTFKC6GTOC4cI4tZ00NgqomLkoyWjilGdU0rioKg9vTeizMMsmOOFMXJSdWJpWQllGV0ZOhvJPBMoR/lxTViN6Zmre4JiMrK0ddrTit2TUHFaZMsmJnHJcjVD8xSsXTiTNvZY1GVagW2enfGYs52LHpbDau+Gc9u7nF0/xrh2Pv8CbLu69Tw5mdlQ3StSx1dYr0a+pqAKYki9joDibjsrMtbOloC69BxY+oFjoefYdY9J1xBc/veHXjRDlGhuhvnEmJKQ1plrRsXFKtDQacIRMYiD6CcUxWd1pBWloBMyUp9iXFxWLL1CUxx/T7zD59Y1Nh06cOtm/dnL2+tvfT2WrR2ST+hw/4sZ29Fy1J+UVioFvUwDvxLPg+amAy7rdHnIVGw7H0Y1blYgPbY/iJgaemFCYmJVGupRAuSSZz5jlVL9OWX5Xfk+/PP5RvyLckayzmLFH48hYWvtm6J6pe6urKudq3IqVAQ/HLSDeKymfP5nLj14i6dyf7V5a07cBjvV/a/JnvP/vAkX1Nn95QO2Y4nlnw6pHrJ70pGWd/qj433VPR29jenxiPbPoS1nMt1hNHw84Gs0E1GgpNmrnKfNL8mlmtNB82c7OZFFWsJ47MpgbjFjyKb1Nw8vAcbVHVIr5IjZu/iPj5i0D9eg8ABnPL2LkXvWKw1GM1WEhGgWxfUs6cXcv7zt5rOP7+9IPvn71NVCcrHP5rw8uowpPO6pUqK1M1i5bSrR6yGszqSSvPyEzh6amZKUlpyWRJSmNk4elx5uRFbNeiKAwTZSbeyFKSY4VYVh2c13jYFomPkr2iwbzF3G5WzCWWypRdKTxlkqnOxKS0Ip6+i8YypzJ5JkL3ZFxCTWZ21hXHuJfk0hx76zeJ0/KDnfXv7sx+naxYm1gVWgMuq6uT8UJ5EMUhbUVtjSgLWSZRBDIyVmTYURLs1ntX3x26IlDUtO6i2n/+5+k371WL2r9wbcfS71hWb2179YOnlI0i126Hsd9AbMTZPnKM4rAPG1DnnHHtcfxQXDhuKu5U3O/jDLa4nriDcWNAGBSjCQe/kkzMSafwxKjQTtwiGA1GkxrPTUVMFXs5rmBpjZpt1o8ah34LIAOEJcjQyOhgAcOONJjL0G5n2dNvsmz1SaZOf/CXT6hFOEDYPAs7xBaccpYK+wztBn7IEDZMGU4Zfm8w2Aw9hoOGMSAMMAY3JVwpYjRjCWWr51ii614R02s4/udWeKMRZ3Ixzqp0ymNfO0aW6PvO1kWr7477SuJdlkcMD8efiDuROJljNqezDfxiY2v8lsWPJD5pfDLnu/HfS/hJ/CsJ75v+lJiYl5yX4czNr8lwJqXUJGeczHgpQ5GFLnlxg+yTstDzW5wJyUmp7Uk9STzJmspEFmTn1rAVqcLsiXytRvZLSmO9ozzWW/Nk70xOSq4ZE/flFpi9KzUVmTehLkq1igxcushEBawyo2BLEkvKqVy8a7Fv8X2L1cXJBWYnirY5O9/bGPPGpjNy+2w68y6KwBkUOWe61VmS3mB1Lk7GJdeCS15KgyxqDWdlEUyFEaBIFcaASPagE31khhTnnSyEkoEwgeNMzGeJLjwRF79ODhsLGhwk6F93oCjvlOqTnPBSklCaJNQnOeEskkJRnBwOHKP1uAtD8HbupZ0OhiPHrhUX1VpoRTUpBfL+JE0chiZjFv8zs65868j0767zsvSXz7BU41mncrVr/Y5i5YpLLquvZ2xb5Vfuf+K2V5kZ1fm70898/qYNbODKg01NAfkxmPiI79d7nvlx/8ldyfV/NGeb5adDD/yqfu5Tf5reavwyqgdDbWMzH58RmdZNb6amuQ/UPvQBU4IRKMN36Q71V3SLKZ8OqAFK4qtx53sJ3Qncl/hjZMX4dtEw1wielfQ4s7H/5JN8UtGUIeV/qw1qyPBZXXoClSANxIsjISppO+65Nlt82AgCu0u9ksTduzRYXhXJFy9HiuTCnaEOK9TFLDqsUjrr12EDWdnndNgI+A4dNtF32Dd02ExF3K/DcTTK79LhePU5RdPhRdRr+qUOJ9Buc7MOJxqPmh/T4SS6LPnTs347mHxch+E2y2od5qRa1umwQsss63VYpXjLkA4bKMFyhQ4bAV+rwybqtRzWYTOlWf6gw3HUkmLQ4XjuSvmEDi+i5WmPz35btiLtFzqcqOxIT9bhJKrI8sISpgqvJ2V9SYdVysl6UMIG4OOzTuqwSplZ35ewEXhj1ms6rFJq1hsSNom4ZP1JhxGLrKiEzcAnWNN0WCWr1SbhOBFfa50OI77ZtToMOdkNOoz4Zl+sw5CZfZ8OI77ZEzqM+Gb/ow4jvtm/0mHEN+dhHUZ8c17UYcQ391M6jPhq2TqM+Gqf1WHEV/tfOoz4Ft8p4Xjhq+J/12H4qji2xkXAp5Zk67BKi0scEk4QaynZqMOwv2SrhJNE5pd4dFilvJKQhC1Szm06LOR8TcJpwuclz+owfF7yXQmnC3tKfqbDsKfkTQlnAJ9eynRYJa00Q8KZgr60VodBX9ok4WxJv1OHBf1eCeeKHCi9TYeRA6X3SDhf2FM6rsOwp/QpCdsk/fd1WNC/LOGlIgdK39Jh5EDpHyVcJvxTlqjD8E9ZzM5yUQnKSnVYnYHN0v+zMOwvk/ljlusq26rDAr9LwAkx+v06LPDXS1jGpex+HRZ6H6VO2k9+8tBucpEbvUaPonVSv4Q3kY+G0II6lYaK6aNhwOLqAt4rKTRgBsBfAahZ4l3/Q0mVs5Zp1IGZAQrN0gSA24g+pm85rca7isp1qFpiG8ExgH4bePbAhqDk2gZ5AbRh2odrH6iGMe8C5Xqpo+8cO9fMo9FmqdbQJVJKYNbqFdBahbeGKr8JWDdmfZj3wbNBKj2vlI+SMUdbPs+uznn4b0nPCr/1QcYg+mG6HDih7b/vcw1YD7zlhU1BaZvwkYaxoAnqUrcjHhq1S36NiqS+Tbhuge7d0vcu0As+D6QKb49ITiGt4jw2xeLsg15hkx+0+z+SyiPzS9CNSKv2zOr16tlbLqPso17d6s1ypl960QVrls3aPixnvDJTO3ANSatjEYll1SrkUpO0JCi9POO3Ydiigcql52Iso7zS930yw0TODUld8+Pu1mW5pG2Cc1BKFHb3Q/+glBjzviatdkl9bj0asRlhdUCPh0uuMca3fzb+Xj3b/XoEPdI3AZmNsdXNRMil2x+S2jSpYb5VM5EXvhHjESm7f142CFqflBXTPYOPeTuoe8StZ2rgHLogZHqkV7zoY7LdOiYkPS0yai6nfXLnDkuPDkh+YamI56DONaPBLfn36Vq9+kpj+1FImPPCblAKaTHsnF+9und9+kq8kj4kR3NRDcgsHZDWnT8nZmprYHYtYm5QypuTIerF5bq1Lt3/bln1NH2XzvisT+reI7ExfrHDvHoM++W+8+s54sNV7Oh9urdjEuaqvUvGKpYdmvShW1+/V0ZtQNL45d6LZeOQ5IytZH52e2czS+z8K/TIDEprRG7u0/dWrO4MzNoxKEdz2Rv80IkU+ND63LqOXikhJD3dtyA3PbQX+BnPitx2z65wt8xtTebAFdK3AZl3wdl6Eou6sD2234N61YjtpoCeZXPVMzY7KCPioislf8xqIdctZ+cyLaa9T3rLL3fJ/tlVzOgekjVTzLukJ4Z1HWIPxbwYlPwzFs9I98scGpR1c8a2Cnn2BTG3BmdqJeSKd4Wkml9hK2R1GgRFv9xLA4AGAQ3JCHnkKEC7ZA7EIl4xS/l/V8OIzJgYrWeels2o9J0491vRmpB5At4CrDgBWnH9pMS3ANOBq8jNi3EStOC9SWI7KRFPU6J1ymwKnCfXtFl8bJ/EPOrXfT6Xo3/dKTYXmZmKPBPnXjm7H/ShWZ3u2doWy+e582h+tYxVjrk6Gtu/Xr1mBvQ9vUdK8czWRLFbu3VtYnfv02tp7+xpFNMZ/BjPzNTOkdnq5NF3nGc2p4dl/Qjq+3m3no/n89fMLhQe88yTMreLz9XXp5+AIgN7ZWWMWd2rR2ZIl3y+CBXLVS30VKwin5sV52qeqW2iirnkvagLWgd0bwf0GvJRuoX3twMzV2f3nxMLj36XMf+eK1a9XdIiv/SsV7/T+Wtirum5ODSvts3oFZWkT3raO+8UGZ53r7xslnp4Xt7Ond0f7ylh3aCUP5NXvgXyRmT8L5fRnH8fOlMf5yh9oI3doYakx4X8/tn1xOyan92DekWN+T+2q/x6fsxV3oU59HErmsuPjXLt50Zu5t5LnDke/Q4ttprY/Z5bRnXoQzEY/pC/5yQH5N1qSN71x86hffLeaITm313919GfkTes3/959Wee893FnRvHmLfm7ljdUua5+3gmYq4P+Xr332TtnJfP1bDwvF9okUe/iw3i7JmRIJ5PGin2JFCCe/gaqsPzl4brcozK8XxVI5+yxKcj26lNp6zC7HLM1OhwHZ7G6iTXSqrFs4BoQvrfdtb990/GmbnKD3lv9jzs3O/37Ha5PdqjWme/R9vkG/IFgdKafMN+37Ar6PUNaf4Bd4XW7Aq6/guiSiFM6/ANhAQmoG0cAt/y1aurynGprtAaBwa0bd49/cGAts0T8Azv8/Q1DntdA+t9A30zMtdIjCZQay7xDAeE6BUVVVVaySave9gX8O0Ols6RzKeQ2HIpq1PCj2idw64+z6Br+HLNt/tjLdeGPXu8gaBn2NOneYe0IEi3d2jtrqBWpHVu0rbs3l2huYb6NM9AwDPSD7KKWUlYs2/PsMvfv38+yqM1D7tGvEN7BK8X7i3Xtvl6IXqz193vG3AFlgnpw16316V1uEJDfVgIXLWqusk3FPQMCtuG92sBF7wIR3l3a32egHfP0DIttnY3qFxeTA76hj1af2jQNQTzNXe/a9jlxjIw8LoDWIdrSMPcfrF+L9zuxwI9bk8g4IM6sSAX5Ifc/ZpXFyUWHxryaCPeYL90w6DP1ye4BQyzgzDEDacGZnDBEc9Q0OsBtRtAaHh/hSY97dvnGXYh3sFhjys4iCnB4A4h5gGhTMTRMyxN2B0aGAAobYX6QR+UeIf6QoGgXGoguH/AM98TIlsDQotneNA7JCmGfZdDrAv2u0NQFAtgn9e1xyfmR/rhc63fM+CHR3zaHu8+jySQae/SBuAObdAD3w153SB3+f0euHHI7YGSmLu9wlma5wosZtAzsF/D2gLInQEhY9A7IN0b1DdSQNfnBkevRwsFkFLSm569IWFsyC38r+32YcmQiEUFgyJPsPRhD+IeRGogTAG4TKYnhoOuPa4rvUMQ7Qm6l8WcBvY+b8A/4NovVAjuIc9IwO/ywzSQ9MHEoDcgBAty/7Bv0CelVfQHg/41lZUjIyMVg3rCVrh9g5X9wcGBysGg+NuSysHALpdYeIVA/pUMI54BYD2SZfOWzo2tG5saOzdu2axtadU+ubGpZXNHi9Z48baWlk0tmzsT4xPjO/vh1hmvCReLmMBQrCAoPXqeLSYXIxJZrLl3v7bfFxKcbpFt8LPcR7G0RHLIHEV8sf2GQO7aM+zxiEys0LrB1u9CGvh6xTYCZ3CBMSI7R0Q6eRA4j/D0sMcdRJx3w49zdokQ+vZ4JIkM8SwfQoPs7Q0FIRpm+rCj5i2oODBjFBJ51hWzzCLbtH2ugZCrFxnmCiBD5nNXaNuHZM7un1kF1qRXLqS3Swv4PW4vis65K9fgxSGZbYLX1dfnFTmBrByWVXmZQA9L38rd/SGjBryDXrEgKJF0I77hywOxJJX5KJG+ERTUUO+AN9Av9EBWzN2DSFTYj1D592ux5NU9tFCR9MfG3XOLE9Vrb8gTkGpQ99ye4SF9BcO63ZI40O8LDfRhD+3zekZi5eqc5Qs6RNKDCtA3V+Jm1wizZGF1B+diLBbm0q3efX6x0uRZBn3f64KgxxVcIwi2dzTiEChZVVNXqtUtX1VeVVNVFRe3vQ3IquXLa2pwrVtRp9WtrF1duzox/iN23cduRjGq1M2T+xCPqx79Jknc6sz/mGXhTJBCLBG3Bm8toJnD7qaFH3NrOqZV/9Bj/oyOU25QnlG+o5zEdXz+/AL8ha8NLnxtcOFrgwtfG1z42uDC1wYXvja48LXBha8NLnxtcOFrgwtfG1z42uDC1wYXvjb4f/hrg9nPD7z0UZ8sxGY+iT6WrT6JCS2gPXf2Ylk1AguoZnCt9BbGl9N7oH8LuIWfOiycm+GZub/ynVfi3OwlEppPE8NskKN98vOOhfMLZ9r10zckn/18clfOpz7f/HxP+T7Shz7Vpq5T16pN6kp1lepUL1Lb1NXzqc8733neT3TmsK3nrCeGaRMjthw08+fmsG36venlH7J4Hp6l0C8VO7Jk3vws7q/Nm7/SN3+1vI/LK/3/y1O0mH5K53l9mzqVr1AyY2SLTilfnrCkVzsnlbsnktOqnY0W5U5qR+MUVjbRFBonn3IbHUTjIG+LlC+vPiaAifikagvobyIN7RCaQmO4Mjl2ogn6mybSMoX4ayLJKZLvs5GqmhgwYbFWtzemK1cQUzzKENnJphxAvxi9G30++l6lD5VC2OmcSLZUH4K+BpA3KBkoQzalUcmkavTNSg7lSrJQJCmmJxQpKatujFeaFKskSVYSUY9silkxRapt2glF/NmwU7lhIm6RsO+GiCWj+hnlOsVE6aA6BKosW/IzSjxVoomVdE7EJVYfbkxQOrHMTrjFpoj/rH+fvDqVoQgEQV+LkkeZmLtcyacM9K3K4kiGbeqEcrsk+zshBfrWRcwrRDeRmFQ91RiniL8HCCu3wuO3Sm2HJ4pWVVNjkVJCVYr4EwlNOQjooPjP4soooFGEaRShGUVoRmHFKBkR+RsxcyNoKpUrya+M0GG0+wCrEJkRgQePSWBpSfUxJVuxwhOWE/AdAzZnIi5JWGaNpKZJMutEQlJ1wzNKgLagcRgfnMiyVvtOKGVyKcsmrLmCwR+JS4DrsmKxAGOmiMEzSp6yWHoiX3og3GjDmFGyYiPGf8BPCe/wl/mPRXzFT/rI/h/1/kW9/2Gsj07xUxPQ4pzk/yz60415/A0I28VfpfsAcX6CP4+jxsZ/zieFFfxn/Bg1oH8F4z70x9CvQH88UvA92ySfnEAH2++JJGaKxfLnI45KHbAV6kBWrg6kZlY3FvLn+LOUBxE/Rb8U/bN8ipagP4nein6KB+l76J/gtbQW/VG9/w5/WuQ0f4o/iTPTxiciScKEcMQkuiMRo+i+FaHYqL3S9jT/Fn+cckD6zUhRDrCPTBQttSWfgDzGH+TBSL4ttTGe38+62LsgGqNXRE+p/IFInRByOPK0ZjvGD/PDTmuds9BZ7nxIqSqsKq96SNEKtXKtTntIa7TwW8kA52HD8ptwxfnMkT1oTrTD/MaIWhduPIs1iXVxOoTrmIR6cPVLiHC1zM6+I6EGfh1tQeOQcQDtINohtKtIxfVKtM+ifQ7t8xITRAuhjaB8+MHhB4cfHH7J4QeHHxx+cPglh19qD6EJjh5w9ICjBxw9kqMHHD3g6AFHj+QQ9vaAo0dytIOjHRzt4GiXHO3gaAdHOzjaJUc7ONrB0S45nOBwgsMJDqfkcILDCQ4nOJySwwkOJzickqMKHFXgqAJHleSoAkcVOKrAUSU5qsBRBY4qyaGBQwOHBg5Ncmjg0MChgUOTHBo4NHBoksMCDgs4LOCwSA4LOCzgsIDDIjksMj4hNMFxGhynwXEaHKclx2lwnAbHaXCclhynwXEaHKf5yLhyqvEFsJwCyymwnJIsp8ByCiynwHJKspwCyymwnNKXHpTO4EibA2gH0Q6hCd4p8E6Bdwq8U5J3SqZXCE3whsERBkcYHGHJEQZHGBxhcIQlRxgcYXCEJccYOMbAMQaOMckxBo4xcIyBY0xyjMnEDaEJjr89Kf/m0PCrWJcZhys/xEplf5Delv0BekX2n6dx2X+OHpL9Z+lq2V9JdbIfoSLZQ57sg2Qzs4itLrkxEyVgC9ouNB/afWhH0E6imST0EtpraFFe61yiJpu2mO4zHTGdNBmOmE6beLJxi/E+4xHjSaPhiPG0kWuNuTxR1lGUFvqivB7E9fdoOERwbZBQA6+B3hrU2Vq8a3iNM+WM9vsy9lIZO1nGjpSxL5axxjh+MVNlpcOdPofhrMuZULTO9gpaXVHxOlSmW598O8sWKVppm2RPx7pSpwP922jjaA+hXY1Wh1aNVo5WiGaTuDLQdzmX6CKfRitGK0DThArKzMTdTWqK2XmMJ7KHJl5IpDihp7gEfCcixVXoJiPFW9A9FSnutTXGsSepWNwGsScQucfRH4nYXsf0N2PdNyK2E+geidhq0O2MFFeguzRS/KKtMZFtJ5sqWDv1vgPrFv22iO0SkG2N2ErROSLFRYK6DIoKMVvKuuh19IU619KYJnvEthbdkohttaA2U7EIPDNSuTTPgCZ6ZQIG/f4Y61KZc5HtjO1229tg/x0ci/T4mTaponupcJJd4oy3PV3+VRA32iKN8YIe58O43odF/4TtocIbbfdAFit80na3rcJ2a/mkGehbYPeNUkXEdrU2yR93ptkO2apswfLXbQHbJ2wu2zbbzkLgI7bLbE8LM6mbdfHHn7S1Q+BGrKIwYru4cFKa2Grbb3Paim2rtaeFf2lVTG5d+dPCA1Qd074M/i0rnBQ5vr1ukqU4y0zvmA6bLjWtN6012U1LTItN+aZ0c6rZYk4yJ5jjzWaz0ayauZnM6eLnHRzizyvTjeKv18moiqsqYQsXVx77S1POzJw+QeE0pY23daxnbeEpN7X1auH3OuyTLH7rjrDBvp6FU9uorXN9eJWjbdIU3Rauc7SFTe2Xdo0zdms3sGF+wySjzq5JFhWo63LFD1GNM7rultxjxFj2dbd0d5M1c1+DtSF1Xcrq1ubzXHr0q2PuZZ0P5ofvauvoCj+W3x2uFkA0v7stfJX4mapjPJkntjQf40mi6+46pvp5css2gVf9zd0ge12SIZuTQEbFogOZeT1pggz1ZL0gQ4xidEVgB12B6EAXn0hFkq4oPlHSqUzQjb+itTSPa5qkKSR6RdK8UkjzaJAx4G0eLyqSVHaNdQkq1mXXpGGlUpDNBpJymyTBk5tNCrIxqSxcOUdSqJPUzpLUSl0Km6OxxWjSS2Zo0ktA4/gfvjzrHWxieejA8+KXv3rsLR60nvBN+/qt4UO9mjZ+IKT/JFhRT6+7X/QuTzhk9zSHD9ibtfHlz59n+nkxvdzePE7Pt3R2jT/v9DRHljuXt9hdzd0TDfVdjQt03Tirq6v+PMLqhbAuoauh8TzTjWK6QehqFLoaha4GZ4PU1eIVed/eNW6m9eJ3QWQ/wRfFI4d7cgu612da/OtEQh9bW2A9kHtcJfYILXJ0hxPs68OJaGKqvLG8UUxhn4mpJPHzbvqU9cDagtzj7BF9ygJ0in09zbiWBFFbuHZrW7igY0eXSJWw03X+mAXES05bqcXbjH8YB2XDez4lBc77Cp7vFQqFAuIScuApuS1c1tEWXrkVlphMUNXT3A1cxQxOUSRuPC6uZTI6hUkHjGBBoU5ADiZ+I8AZj6cuEx8zjpm4eFQITuTkV/uewQl+EA3PcXwkUimfl/nIxJJC8fwSnKisjfV4PhV9JKegWvwUQR1YRV8Y650p5QAOFx4uP1w3VjhWPlZnFD+08BCQtofEURqpfEihoCMw4wiAwW6K/XQB9N0fycuXiscE4HB0OwLyN17ow6526L8jA6fPOjagSw1I8cGZgMTwAYoRxyYdoRmmkM4iJ0OSRSr8P1jbNhMKZW5kc3RyZWFtCmVuZG9iagoKNiAwIG9iagoxMDgyNQplbmRvYmoKCjcgMCBvYmoKPDwvVHlwZS9Gb250RGVzY3JpcHRvci9Gb250TmFtZS9CQUFBQUErQXJpYWwtQm9sZE1UCi9GbGFncyA0Ci9Gb250QkJveFstNjI3IC0zNzYgMjAwMCAxMDExXS9JdGFsaWNBbmdsZSAwCi9Bc2NlbnQgOTA1Ci9EZXNjZW50IDIxMQovQ2FwSGVpZ2h0IDEwMTAKL1N0ZW1WIDgwCi9Gb250RmlsZTIgNSAwIFI+PgplbmRvYmoKCjggMCBvYmoKPDwvTGVuZ3RoIDI3Mi9GaWx0ZXIvRmxhdGVEZWNvZGU+PgpzdHJlYW0KeJxdkc9uhCAQxu88BcftYQNadbuJMdm62cRD/6S2D6AwWpKKBPHg2xcG2yY9QH7DzDf5ZmB1c220cuzVzqIFRwelpYVlXq0A2sOoNElSKpVwe4S3mDpDmNe22+JgavQwlyVhbz63OLvRw0XOPdwR9mIlWKVHevioWx+3qzFfMIF2lJOqohIG3+epM8/dBAxVx0b6tHLb0Uv+Ct43AzTFOIlWxCxhMZ0A2+kRSMl5RcvbrSKg5b9cskv6QXx21pcmvpTzLKs8p8inPPA9cnENnMX3c+AcOeWBC+Qc+RT7FIEfohb5HBm1l8h14MfIOZrc3QS7YZ8/a6BitdavAJeOs4eplYbffzGzCSo83zuVhO0KZW5kc3RyZWFtCmVuZG9iagoKOSAwIG9iago8PC9UeXBlL0ZvbnQvU3VidHlwZS9UcnVlVHlwZS9CYXNlRm9udC9CQUFBQUErQXJpYWwtQm9sZE1UCi9GaXJzdENoYXIgMAovTGFzdENoYXIgMTEKL1dpZHRoc1s3NTAgNzIyIDYxMCA4ODkgNTU2IDI3NyA2NjYgNjEwIDMzMyAyNzcgMjc3IDU1NiBdCi9Gb250RGVzY3JpcHRvciA3IDAgUgovVG9Vbmljb2RlIDggMCBSCj4+CmVuZG9iagoKMTAgMCBvYmoKPDwKL0YxIDkgMCBSCj4+CmVuZG9iagoKMTEgMCBvYmoKPDwvRm9udCAxMCAwIFIKL1Byb2NTZXRbL1BERi9UZXh0XT4+CmVuZG9iagoKMSAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDQgMCBSL1Jlc291cmNlcyAxMSAwIFIvTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwvUy9UcmFuc3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0kgdHJ1ZT4+L0NvbnRlbnRzIDIgMCBSPj4KZW5kb2JqCgoxMiAwIG9iago8PC9Db3VudCAxL0ZpcnN0IDEzIDAgUi9MYXN0IDEzIDAgUgo+PgplbmRvYmoKCjEzIDAgb2JqCjw8L1RpdGxlPEZFRkYwMDQ0MDA3NTAwNkQwMDZEMDA3OTAwMjAwMDUwMDA0NDAwNDYwMDIwMDA2NjAwNjkwMDZDMDA2NT4KL0Rlc3RbMSAwIFIvWFlaIDU2LjcgNzczLjMgMF0vUGFyZW50IDEyIDAgUj4+CmVuZG9iagoKNCAwIG9iago8PC9UeXBlL1BhZ2VzCi9SZXNvdXJjZXMgMTEgMCBSCi9NZWRpYUJveFsgMCAwIDU5NSA4NDIgXQovS2lkc1sgMSAwIFIgXQovQ291bnQgMT4+CmVuZG9iagoKMTQgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDQgMCBSCi9PdXRsaW5lcyAxMiAwIFIKPj4KZW5kb2JqCgoxNSAwIG9iago8PC9BdXRob3I8RkVGRjAwNDUwMDc2MDA2MTAwNkUwMDY3MDA2NTAwNkMwMDZGMDA3MzAwMjAwMDU2MDA2QzAwNjEwMDYzMDA2ODAwNkYwMDY3MDA2OTAwNjEwMDZFMDA2RTAwNjkwMDczPgovQ3JlYXRvcjxGRUZGMDA1NzAwNzIwMDY5MDA3NDAwNjUwMDcyPgovUHJvZHVjZXI8RkVGRjAwNEYwMDcwMDA2NTAwNkUwMDRGMDA2NjAwNjYwMDY5MDA2MzAwNjUwMDJFMDA2RjAwNzIwMDY3MDAyMDAwMzIwMDJFMDAzMT4KL0NyZWF0aW9uRGF0ZShEOjIwMDcwMjIzMTc1NjM3KzAyJzAwJyk+PgplbmRvYmoKCnhyZWYKMCAxNgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMTE5OTcgMDAwMDAgbiAKMDAwMDAwMDAxOSAwMDAwMCBuIAowMDAwMDAwMjI0IDAwMDAwIG4gCjAwMDAwMTIzMzAgMDAwMDAgbiAKMDAwMDAwMDI0NCAwMDAwMCBuIAowMDAwMDExMTU0IDAwMDAwIG4gCjAwMDAwMTExNzYgMDAwMDAgbiAKMDAwMDAxMTM2OCAwMDAwMCBuIAowMDAwMDExNzA5IDAwMDAwIG4gCjAwMDAwMTE5MTAgMDAwMDAgbiAKMDAwMDAxMTk0MyAwMDAwMCBuIAowMDAwMDEyMTQwIDAwMDAwIG4gCjAwMDAwMTIxOTYgMDAwMDAgbiAKMDAwMDAxMjQyOSAwMDAwMCBuIAowMDAwMDEyNDk0IDAwMDAwIG4gCnRyYWlsZXIKPDwvU2l6ZSAxNi9Sb290IDE0IDAgUgovSW5mbyAxNSAwIFIKL0lEIFsgPEY3RDc3QjNEMjJCOUY5MjgyOUQ0OUZGNUQ3OEI4RjI4Pgo8RjdENzdCM0QyMkI5RjkyODI5RDQ5RkY1RDc4QjhGMjg+IF0KPj4Kc3RhcnR4cmVmCjEyNzg3CiUlRU9GCg==" + } + ], + "order_lines": [ + { + "price": 0.0, + "quantity": 3, + "description": "green_jacket_test", + "article_code": "green_jacket" + } + ], + "shipping_address": { + "city": "Heinenoord", + "state": "ZH", + "street": "Nijverheidsweg", + "country": "NL", + "street2": "", + "zipcode": "3331MB", + "fax_number": "", + "addressed_to": "eWarehousing Solutions", + "phone_number": "0102202863", + "mobile_number": "", + "street_number": 27, + "street_number_addition": "" + } +}` + +const CreateOrderResponse = `{ + "id": "d00add08-b559-4b5f-b1aa-06b1db9834b0", + "created_at": "2022-11-08T08:53:48+00:00", + "requested_delivery_date": "2018-11-19T00:00:00+00:00", + "customer": "be62c27e-2aac-4ac1-902e-f770d64f8dce", + "external_reference": "1667553171", + "reference": "ORD00000004850", + "status": "created", + "business_to_business": true, + "applied_business_rules": true, + "partial_delivery": false, + "language": null, + "note": "Quisque ornare tortor at risus", + "customer_note": "Please take care", + "order_amount": null, + "assured_amount": null, + "inco_terms": null, + "shipping_method": null, + "currency": null +}`