mirror of
https://github.com/retailcrm/api-client-go.git
synced 2025-04-07 19:12:00 +00:00
Compare commits
No commits in common. "master" and "v2.1.3" have entirely different histories.
14 changed files with 307 additions and 2701 deletions
24
.github/workflows/ci.yml
vendored
24
.github/workflows/ci.yml
vendored
|
@ -20,10 +20,10 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
- name: Set up Go 1.23
|
- name: Set up Go 1.17
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '1.23'
|
go-version: '1.17'
|
||||||
- name: Get dependencies
|
- name: Get dependencies
|
||||||
run: |
|
run: |
|
||||||
go mod tidy
|
go mod tidy
|
||||||
|
@ -31,7 +31,7 @@ jobs:
|
||||||
- name: Lint code with golangci-lint
|
- name: Lint code with golangci-lint
|
||||||
uses: golangci/golangci-lint-action@v3
|
uses: golangci/golangci-lint-action@v3
|
||||||
with:
|
with:
|
||||||
version: v1.62.2
|
version: v1.45.2
|
||||||
only-new-issues: true
|
only-new-issues: true
|
||||||
skip-pkg-cache: true
|
skip-pkg-cache: true
|
||||||
args: --build-tags=testutils
|
args: --build-tags=testutils
|
||||||
|
@ -40,13 +40,13 @@ jobs:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: ['1.19', '1.20', '1.21', '1.22', '1.23', 'stable']
|
go-version: ['1.13', '1.14', '1.15', '1.16', '1.17']
|
||||||
include:
|
include:
|
||||||
- go-version: '1.23'
|
- go-version: '1.17'
|
||||||
coverage: 1
|
coverage: 1
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Go ${{ matrix.go-version }}
|
- name: Set up Go ${{ matrix.go-version }}
|
||||||
uses: actions/setup-go@v3
|
uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: ${{ matrix.go-version }}
|
go-version: ${{ matrix.go-version }}
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
|
@ -59,21 +59,17 @@ jobs:
|
||||||
env:
|
env:
|
||||||
COVERAGE: ${{ matrix.coverage }}
|
COVERAGE: ${{ matrix.coverage }}
|
||||||
if: env.COVERAGE != 1
|
if: env.COVERAGE != 1
|
||||||
run: |
|
run: go test -tags=testutils ./...
|
||||||
go install gotest.tools/gotestsum@latest
|
|
||||||
gotestsum --format testdox ./... -tags=testutils -v -cpu 2 -timeout 60s -race
|
|
||||||
- name: Tests with coverage
|
- name: Tests with coverage
|
||||||
env:
|
env:
|
||||||
COVERAGE: ${{ matrix.coverage }}
|
COVERAGE: ${{ matrix.coverage }}
|
||||||
if: env.COVERAGE == 1
|
if: env.COVERAGE == 1
|
||||||
run: |
|
run: |
|
||||||
go install gotest.tools/gotestsum@latest
|
go test -tags=testutils ./... -race -coverprofile=coverage.txt -covermode=atomic "$d"
|
||||||
gotestsum --format testdox ./... -tags=testutils -v -cpu 2 -timeout 60s -race -cover -coverprofile=coverage.txt -covermode=atomic "$d"
|
|
||||||
- name: Coverage
|
- name: Coverage
|
||||||
env:
|
env:
|
||||||
COVERAGE: ${{ matrix.coverage }}
|
COVERAGE: ${{ matrix.coverage }}
|
||||||
if: env.COVERAGE == 1
|
if: env.COVERAGE == 1
|
||||||
run: |
|
run: |
|
||||||
go install github.com/axw/gocov/gocov@latest
|
|
||||||
gocov convert ./coverage.txt | gocov report
|
|
||||||
bash <(curl -s https://codecov.io/bash)
|
bash <(curl -s https://codecov.io/bash)
|
||||||
|
rm coverage.txt
|
||||||
|
|
103
.golangci.yml
103
.golangci.yml
|
@ -1,70 +1,32 @@
|
||||||
run:
|
run:
|
||||||
skip-dirs-use-default: true
|
skip-dirs-use-default: true
|
||||||
allow-parallel-runners: true
|
allow-parallel-runners: true
|
||||||
|
skip-files:
|
||||||
issues:
|
|
||||||
exclude-files:
|
|
||||||
- testutils.go
|
- testutils.go
|
||||||
exclude-rules:
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- lll
|
|
||||||
- errcheck
|
|
||||||
- misspell
|
|
||||||
- ineffassign
|
|
||||||
- whitespace
|
|
||||||
- makezero
|
|
||||||
- errcheck
|
|
||||||
- funlen
|
|
||||||
- goconst
|
|
||||||
- gocognit
|
|
||||||
- gocyclo
|
|
||||||
- godot
|
|
||||||
- unused
|
|
||||||
- errchkjson
|
|
||||||
- varnamelen
|
|
||||||
exclude-use-default: true
|
|
||||||
exclude-case-sensitive: false
|
|
||||||
max-issues-per-linter: 0
|
|
||||||
max-same-issues: 0
|
|
||||||
fix: true
|
|
||||||
|
|
||||||
output:
|
output:
|
||||||
formats:
|
format: colored-line-number
|
||||||
- format: colored-line-number
|
|
||||||
sort-results: true
|
sort-results: true
|
||||||
|
|
||||||
# Linters below do not support go1.18 yet because of generics.
|
|
||||||
# See https://github.com/golangci/golangci-lint/issues/2649
|
|
||||||
# - bodyclose
|
|
||||||
# - sqlclosecheck
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
enable:
|
enable:
|
||||||
- asciicheck
|
- deadcode
|
||||||
- asasalint
|
|
||||||
- varnamelen
|
|
||||||
- reassign
|
|
||||||
- nilnil
|
|
||||||
- nilerr
|
|
||||||
- nakedret
|
|
||||||
- goprintffuncname
|
|
||||||
- typecheck
|
|
||||||
- errchkjson
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- gosimple
|
- gosimple
|
||||||
- govet
|
- govet
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- staticcheck
|
- staticcheck
|
||||||
|
- structcheck
|
||||||
- unused
|
- unused
|
||||||
- unparam
|
- unparam
|
||||||
|
- varcheck
|
||||||
|
- bodyclose
|
||||||
- dogsled
|
- dogsled
|
||||||
- dupl
|
- dupl
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
- exhaustive
|
||||||
- exportloopref
|
- exportloopref
|
||||||
- copyloopvar
|
|
||||||
- funlen
|
- funlen
|
||||||
- gocognit
|
- gocognit
|
||||||
- goconst
|
- goconst
|
||||||
|
@ -73,13 +35,16 @@ linters:
|
||||||
- godot
|
- godot
|
||||||
- goimports
|
- goimports
|
||||||
- revive
|
- revive
|
||||||
|
- gomnd
|
||||||
- gosec
|
- gosec
|
||||||
|
- ifshort
|
||||||
- lll
|
- lll
|
||||||
- makezero
|
- makezero
|
||||||
- misspell
|
- misspell
|
||||||
- nestif
|
- nestif
|
||||||
- prealloc
|
- prealloc
|
||||||
- predeclared
|
- predeclared
|
||||||
|
- sqlclosecheck
|
||||||
- unconvert
|
- unconvert
|
||||||
- whitespace
|
- whitespace
|
||||||
|
|
||||||
|
@ -90,7 +55,6 @@ linters-settings:
|
||||||
enable:
|
enable:
|
||||||
- assign
|
- assign
|
||||||
- atomic
|
- atomic
|
||||||
- atomicalign
|
|
||||||
- bools
|
- bools
|
||||||
- buildtag
|
- buildtag
|
||||||
- copylocks
|
- copylocks
|
||||||
|
@ -105,6 +69,7 @@ linters-settings:
|
||||||
- unmarshal
|
- unmarshal
|
||||||
- unreachable
|
- unreachable
|
||||||
- unsafeptr
|
- unsafeptr
|
||||||
|
- unused
|
||||||
settings:
|
settings:
|
||||||
printf:
|
printf:
|
||||||
funcs:
|
funcs:
|
||||||
|
@ -172,13 +137,11 @@ linters-settings:
|
||||||
threshold: 200
|
threshold: 200
|
||||||
errorlint:
|
errorlint:
|
||||||
errorf: true
|
errorf: true
|
||||||
asserts: false
|
|
||||||
comparison: false
|
|
||||||
exhaustive:
|
exhaustive:
|
||||||
check-generated: false
|
check-generated: false
|
||||||
default-signifies-exhaustive: false
|
default-signifies-exhaustive: false
|
||||||
funlen:
|
funlen:
|
||||||
lines: 90
|
lines: 60
|
||||||
statements: 40
|
statements: 40
|
||||||
gocognit:
|
gocognit:
|
||||||
min-complexity: 25
|
min-complexity: 25
|
||||||
|
@ -188,6 +151,8 @@ linters-settings:
|
||||||
local-prefixes: github.com/retailcrm/api-client-go/v2
|
local-prefixes: github.com/retailcrm/api-client-go/v2
|
||||||
lll:
|
lll:
|
||||||
line-length: 160
|
line-length: 160
|
||||||
|
maligned:
|
||||||
|
suggest-new: true
|
||||||
misspell:
|
misspell:
|
||||||
locale: US
|
locale: US
|
||||||
nestif:
|
nestif:
|
||||||
|
@ -195,19 +160,41 @@ linters-settings:
|
||||||
whitespace:
|
whitespace:
|
||||||
multi-if: false
|
multi-if: false
|
||||||
multi-func: false
|
multi-func: false
|
||||||
varnamelen:
|
|
||||||
max-distance: 10
|
issues:
|
||||||
ignore-map-index-ok: true
|
exclude-rules:
|
||||||
ignore-type-assert-ok: true
|
- path: _test\.go
|
||||||
ignore-chan-recv-ok: true
|
linters:
|
||||||
ignore-decls:
|
- gomnd
|
||||||
- t *testing.T
|
- lll
|
||||||
- e error
|
- bodyclose
|
||||||
- i int
|
- errcheck
|
||||||
|
- sqlclosecheck
|
||||||
|
- misspell
|
||||||
|
- ineffassign
|
||||||
|
- whitespace
|
||||||
|
- makezero
|
||||||
|
- maligned
|
||||||
|
- ifshort
|
||||||
|
- errcheck
|
||||||
|
- funlen
|
||||||
|
- goconst
|
||||||
|
- gocognit
|
||||||
|
- gocyclo
|
||||||
|
- godot
|
||||||
|
- gocritic
|
||||||
|
- gosec
|
||||||
|
- staticcheck
|
||||||
|
- unused
|
||||||
|
exclude-use-default: true
|
||||||
|
exclude-case-sensitive: false
|
||||||
|
max-issues-per-linter: 0
|
||||||
|
max-same-issues: 0
|
||||||
|
fix: true
|
||||||
|
|
||||||
severity:
|
severity:
|
||||||
default-severity: error
|
default-severity: error
|
||||||
case-sensitive: false
|
case-sensitive: false
|
||||||
|
|
||||||
service:
|
service:
|
||||||
golangci-lint-version: 1.62.x
|
golangci-lint-version: 1.36.x
|
||||||
|
|
899
client.go
899
client.go
|
@ -17,6 +17,10 @@ import (
|
||||||
"github.com/google/go-querystring/query"
|
"github.com/google/go-querystring/query"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// HTTPStatusUnknown can return for the method `/api/v5/customers/upload`, `/api/v5/customers-corporate/upload`,
|
||||||
|
// `/api/v5/orders/upload`.
|
||||||
|
const HTTPStatusUnknown = 460
|
||||||
|
|
||||||
// New initialize client.
|
// New initialize client.
|
||||||
func New(url string, key string) *Client {
|
func New(url string, key string) *Client {
|
||||||
return &Client{
|
return &Client{
|
||||||
|
@ -32,125 +36,6 @@ func (c *Client) WithLogger(logger BasicLogger) *Client {
|
||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// EnableRateLimiter activates rate limiting with specified retry attempts.
|
|
||||||
func (c *Client) EnableRateLimiter(maxAttempts uint) *Client {
|
|
||||||
c.mutex.Lock()
|
|
||||||
defer c.mutex.Unlock()
|
|
||||||
|
|
||||||
c.limiter = &RateLimiter{
|
|
||||||
maxAttempts: maxAttempts,
|
|
||||||
lastRequest: time.Now().Add(-time.Second), // Initialize to allow immediate first request.
|
|
||||||
}
|
|
||||||
|
|
||||||
return c
|
|
||||||
}
|
|
||||||
|
|
||||||
// applyRateLimit applies rate limiting before sending a request.
|
|
||||||
func (c *Client) applyRateLimit(uri string) {
|
|
||||||
if c.limiter == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.limiter.mutex.Lock()
|
|
||||||
defer c.limiter.mutex.Unlock()
|
|
||||||
|
|
||||||
var delay time.Duration
|
|
||||||
if strings.HasPrefix(uri, "/telephony") {
|
|
||||||
delay = telephonyDelay
|
|
||||||
} else {
|
|
||||||
delay = regularDelay
|
|
||||||
}
|
|
||||||
|
|
||||||
elapsed := time.Since(c.limiter.lastRequest)
|
|
||||||
if elapsed < delay {
|
|
||||||
time.Sleep(delay - elapsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
c.limiter.lastRequest = time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) executeWithRetryBytes(
|
|
||||||
uri string,
|
|
||||||
executeFunc func() (interface{}, int, error),
|
|
||||||
) ([]byte, int, error) {
|
|
||||||
res, status, err := c.executeWithRetry(uri, executeFunc)
|
|
||||||
if res == nil {
|
|
||||||
return nil, status, err
|
|
||||||
}
|
|
||||||
return res.([]byte), status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) executeWithRetryReadCloser(
|
|
||||||
uri string,
|
|
||||||
executeFunc func() (interface{}, int, error),
|
|
||||||
) (io.ReadCloser, int, error) {
|
|
||||||
res, status, err := c.executeWithRetry(uri, executeFunc)
|
|
||||||
if res == nil {
|
|
||||||
return nil, status, err
|
|
||||||
}
|
|
||||||
return res.(io.ReadCloser), status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// executeWithRetry executes a request with retry logic for rate limiting.
|
|
||||||
func (c *Client) executeWithRetry(
|
|
||||||
uri string,
|
|
||||||
executeFunc func() (interface{}, int, error),
|
|
||||||
) (interface{}, int, error) {
|
|
||||||
if c.limiter == nil {
|
|
||||||
return executeFunc()
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
res interface{}
|
|
||||||
statusCode int
|
|
||||||
err error
|
|
||||||
lastAttempt bool
|
|
||||||
attempt uint = 1
|
|
||||||
maxAttempts = c.limiter.maxAttempts
|
|
||||||
totalAttempts = "∞"
|
|
||||||
infinite = maxAttempts == 0
|
|
||||||
)
|
|
||||||
|
|
||||||
var baseDelay time.Duration
|
|
||||||
if strings.HasPrefix(uri, "/telephony") {
|
|
||||||
baseDelay = telephonyDelay
|
|
||||||
} else {
|
|
||||||
baseDelay = regularDelay
|
|
||||||
}
|
|
||||||
|
|
||||||
if !infinite {
|
|
||||||
totalAttempts = strconv.FormatUint(uint64(maxAttempts), 10)
|
|
||||||
}
|
|
||||||
|
|
||||||
for infinite || attempt <= maxAttempts {
|
|
||||||
c.applyRateLimit(uri)
|
|
||||||
res, statusCode, err = executeFunc()
|
|
||||||
lastAttempt = !infinite && attempt == maxAttempts
|
|
||||||
|
|
||||||
// If rate limited on final attempt, set error to ErrRateLimited. Return results otherwise.
|
|
||||||
if statusCode == http.StatusServiceUnavailable && lastAttempt {
|
|
||||||
return res, statusCode, ErrRateLimited
|
|
||||||
}
|
|
||||||
|
|
||||||
// If not rate limited or on final attempt, return result.
|
|
||||||
if statusCode != http.StatusServiceUnavailable || lastAttempt {
|
|
||||||
return res, statusCode, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate exponential backoff delay: baseDelay * 2^(attempt-1).
|
|
||||||
backoffDelay := baseDelay * (1 << (attempt - 1))
|
|
||||||
if c.Debug {
|
|
||||||
c.writeLog("API Error: rate limited (503), retrying in %v (attempt %d/%s)",
|
|
||||||
backoffDelay, attempt, totalAttempts)
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(backoffDelay)
|
|
||||||
attempt++
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, statusCode, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// writeLog writes to the log.
|
// writeLog writes to the log.
|
||||||
func (c *Client) writeLog(format string, v ...interface{}) {
|
func (c *Client) writeLog(format string, v ...interface{}) {
|
||||||
if c.logger != nil {
|
if c.logger != nil {
|
||||||
|
@ -163,6 +48,7 @@ func (c *Client) writeLog(format string, v ...interface{}) {
|
||||||
|
|
||||||
// GetRequest implements GET Request.
|
// GetRequest implements GET Request.
|
||||||
func (c *Client) GetRequest(urlWithParameters string, versioned ...bool) ([]byte, int, error) {
|
func (c *Client) GetRequest(urlWithParameters string, versioned ...bool) ([]byte, int, error) {
|
||||||
|
var res []byte
|
||||||
var prefix = "/api/v5"
|
var prefix = "/api/v5"
|
||||||
|
|
||||||
if len(versioned) > 0 {
|
if len(versioned) > 0 {
|
||||||
|
@ -171,49 +57,41 @@ func (c *Client) GetRequest(urlWithParameters string, versioned ...bool) ([]byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uri := urlWithParameters
|
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.URL, prefix, urlWithParameters), nil)
|
||||||
|
if err != nil {
|
||||||
|
return res, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
return c.executeWithRetryBytes(uri, func() (interface{}, int, error) {
|
req.Header.Set("X-API-KEY", c.Key)
|
||||||
var res []byte
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", fmt.Sprintf("%s%s%s", c.URL, prefix, urlWithParameters), nil)
|
if c.Debug {
|
||||||
if err != nil {
|
c.writeLog("API Request: %s %s", fmt.Sprintf("%s%s%s", c.URL, prefix, urlWithParameters), c.Key)
|
||||||
return res, 0, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("X-API-KEY", c.Key)
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return res, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if c.Debug {
|
if resp.StatusCode >= http.StatusInternalServerError {
|
||||||
c.writeLog("API Request: %s %s", fmt.Sprintf("%s%s%s", c.URL, prefix, urlWithParameters), c.Key)
|
return res, resp.StatusCode, CreateGenericAPIError(
|
||||||
}
|
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
res, err = buildRawResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, 0, err
|
return res, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusInternalServerError && resp.StatusCode != http.StatusServiceUnavailable {
|
if resp.StatusCode >= http.StatusBadRequest && resp.StatusCode < http.StatusInternalServerError {
|
||||||
return res, resp.StatusCode, CreateGenericAPIError(
|
return res, resp.StatusCode, CreateAPIError(res)
|
||||||
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res, err = buildRawResponse(resp)
|
if c.Debug {
|
||||||
if err != nil {
|
c.writeLog("API Response: %s", res)
|
||||||
return res, 0, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest &&
|
return res, resp.StatusCode, nil
|
||||||
resp.StatusCode < http.StatusInternalServerError &&
|
|
||||||
resp.StatusCode != http.StatusServiceUnavailable {
|
|
||||||
return res, resp.StatusCode, CreateAPIError(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Debug {
|
|
||||||
c.writeLog("API Response: %s", res)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, resp.StatusCode, nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PostRequest implements POST Request with generic body data.
|
// PostRequest implements POST Request with generic body data.
|
||||||
|
@ -222,7 +100,12 @@ func (c *Client) PostRequest(
|
||||||
postData interface{},
|
postData interface{},
|
||||||
contType ...string,
|
contType ...string,
|
||||||
) ([]byte, int, error) {
|
) ([]byte, int, error) {
|
||||||
var contentType string
|
var (
|
||||||
|
res []byte
|
||||||
|
contentType string
|
||||||
|
)
|
||||||
|
|
||||||
|
prefix := "/api/v5"
|
||||||
|
|
||||||
if len(contType) > 0 {
|
if len(contType) > 0 {
|
||||||
contentType = contType[0]
|
contentType = contType[0]
|
||||||
|
@ -230,55 +113,47 @@ func (c *Client) PostRequest(
|
||||||
contentType = "application/x-www-form-urlencoded"
|
contentType = "application/x-www-form-urlencoded"
|
||||||
}
|
}
|
||||||
|
|
||||||
prefix := "/api/v5"
|
reader, err := getReaderForPostData(postData)
|
||||||
|
if err != nil {
|
||||||
|
return res, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
return c.executeWithRetryBytes(uri, func() (interface{}, int, error) {
|
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s%s", c.URL, prefix, uri), reader)
|
||||||
var res []byte
|
if err != nil {
|
||||||
|
return res, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
reader, err := getReaderForPostData(postData)
|
req.Header.Set("Content-Type", contentType)
|
||||||
if err != nil {
|
req.Header.Set("X-API-KEY", c.Key)
|
||||||
return res, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s%s", c.URL, prefix, uri), reader)
|
if c.Debug {
|
||||||
if err != nil {
|
c.writeLog("API Request: %s %s", uri, c.Key)
|
||||||
return res, 0, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Content-Type", contentType)
|
resp, err := c.httpClient.Do(req)
|
||||||
req.Header.Set("X-API-KEY", c.Key)
|
if err != nil {
|
||||||
|
return res, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if c.Debug {
|
if resp.StatusCode >= http.StatusInternalServerError {
|
||||||
c.writeLog("API Request: %s %s", uri, c.Key)
|
return res, resp.StatusCode, CreateGenericAPIError(
|
||||||
}
|
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
res, err = buildRawResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return res, 0, err
|
return res, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusInternalServerError && resp.StatusCode != http.StatusServiceUnavailable {
|
if resp.StatusCode >= http.StatusBadRequest && resp.StatusCode < http.StatusInternalServerError {
|
||||||
return res, resp.StatusCode, CreateGenericAPIError(
|
return res, resp.StatusCode, CreateAPIError(res)
|
||||||
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
res, err = buildRawResponse(resp)
|
if c.Debug {
|
||||||
if err != nil {
|
c.writeLog("API Response: %s", res)
|
||||||
return res, 0, err
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest &&
|
return res, resp.StatusCode, nil
|
||||||
resp.StatusCode < http.StatusInternalServerError &&
|
|
||||||
resp.StatusCode != http.StatusServiceUnavailable {
|
|
||||||
return res, resp.StatusCode, CreateAPIError(res)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Debug {
|
|
||||||
c.writeLog("API Response: %s", res)
|
|
||||||
}
|
|
||||||
|
|
||||||
return res, resp.StatusCode, nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func getReaderForPostData(postData interface{}) (io.Reader, error) {
|
func getReaderForPostData(postData interface{}) (io.Reader, error) {
|
||||||
|
@ -1957,174 +1832,6 @@ func (c *Client) CorporateCustomerEdit(customer CorporateCustomer, by string, si
|
||||||
return resp, status, nil
|
return resp, status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearCart clears the current customer's shopping cart
|
|
||||||
//
|
|
||||||
// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-customer-interaction-site-cart-clear
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.ClearCart("site_id", retailcrm.SiteFilter{SiteBy: "id"},
|
|
||||||
// retailcrm.ClearCartRequest{
|
|
||||||
// ClearedAt: time.Now().String(),
|
|
||||||
// Customer: retailcrm.CartCustomer{
|
|
||||||
// ID: 1,
|
|
||||||
// ExternalID: "ext_id",
|
|
||||||
// Site: "site",
|
|
||||||
// BrowserID: "browser_id",
|
|
||||||
// GaClientID: "ga_client_id",
|
|
||||||
// },
|
|
||||||
// Order: retailcrm.ClearCartOrder{
|
|
||||||
// ID: 1,
|
|
||||||
// ExternalID: "ext_id",
|
|
||||||
// Number: "abc123",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
func (c *Client) ClearCart(site string, filter SiteFilter, req ClearCartRequest) (
|
|
||||||
SuccessfulResponse, int, error,
|
|
||||||
) {
|
|
||||||
var resp SuccessfulResponse
|
|
||||||
|
|
||||||
updateJSON, err := json.Marshal(&req)
|
|
||||||
if err != nil {
|
|
||||||
return SuccessfulResponse{}, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"cart": {string(updateJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
params, _ := query.Values(filter)
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest(fmt.Sprintf("/customer-interaction/%s/cart/clear?%s", site, params.Encode()), p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCart creates or overwrites shopping cart data
|
|
||||||
//
|
|
||||||
// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#post--api-v5-customer-interaction-site-cart-set
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.SetCart("site_id", retailcrm.SiteFilter{SiteBy: "id"},
|
|
||||||
// retailcrm.SetCartRequest{
|
|
||||||
// ExternalID: "ext_id",
|
|
||||||
// DroppedAt: time.Now().String(),
|
|
||||||
// Link: "link",
|
|
||||||
// Customer: retailcrm.CartCustomer{
|
|
||||||
// ID: 1,
|
|
||||||
// ExternalID: "ext_id",
|
|
||||||
// Site: "site",
|
|
||||||
// BrowserID: "browser_id",
|
|
||||||
// GaClientID: "ga_client_id",
|
|
||||||
// },
|
|
||||||
// Items: []retailcrm.SetCartItem{
|
|
||||||
// {
|
|
||||||
// Quantity: 1,
|
|
||||||
// Price: 1.0,
|
|
||||||
// Offer: retailcrm.SetCartOffer{
|
|
||||||
// ID: 1,
|
|
||||||
// ExternalID: "ext_id",
|
|
||||||
// XMLID: "xml_id",
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
func (c *Client) SetCart(site string, filter SiteFilter, req SetCartRequest) (
|
|
||||||
SuccessfulResponse, int, error,
|
|
||||||
) {
|
|
||||||
var resp SuccessfulResponse
|
|
||||||
|
|
||||||
updateJSON, err := json.Marshal(&req)
|
|
||||||
if err != nil {
|
|
||||||
return SuccessfulResponse{}, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"cart": {string(updateJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
params, _ := query.Values(filter)
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest(fmt.Sprintf("/customer-interaction/%s/cart/set?%s", site, params.Encode()), p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCart returns the current customer's shopping cart
|
|
||||||
//
|
|
||||||
// For more information see https://docs.retailcrm.ru/Developers/API/APIVersions/APIv5#get--api-v5-customer-interaction-site-cart-customerId
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.GetCart("site_id","customer_id",
|
|
||||||
// retailcrm.GetCartFilter{ SiteBy: "code", By: "externalId"})
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
func (c *Client) GetCart(site, customer string, filter GetCartFilter) (CartResponse, int, error) {
|
|
||||||
var resp CartResponse
|
|
||||||
|
|
||||||
params, _ := query.Values(filter)
|
|
||||||
|
|
||||||
data, status, err := c.GetRequest(fmt.Sprintf("/customer-interaction/%s/cart/%s?%s", site, customer, params.Encode()))
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliveryTracking updates tracking data
|
// DeliveryTracking updates tracking data
|
||||||
//
|
//
|
||||||
// For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#post--api-v5-delivery-generic-subcode-tracking
|
// For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#post--api-v5-delivery-generic-subcode-tracking
|
||||||
|
@ -2402,323 +2109,6 @@ func (c *Client) IntegrationModule(code string) (IntegrationModuleResponse, int,
|
||||||
return resp, status, nil
|
return resp, status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// LinksCreate creates a link
|
|
||||||
//
|
|
||||||
// For more information see https://www.simla.com/docs/Developers/API/APIVersions/APIv5#post--api-v5-orders-links-create
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.LinksCreate(retailcrm.SerializedOrderLink{
|
|
||||||
// Comment: "comment for link",
|
|
||||||
// Orders: []retailcrm.LinkedOrder{{ID: 10}, {ID: 12}},
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if data.Success == true {
|
|
||||||
// log.Println("Creating a link")
|
|
||||||
// }
|
|
||||||
func (c *Client) LinksCreate(link SerializedOrderLink, site ...string) (SuccessfulResponse, int, error) {
|
|
||||||
var resp SuccessfulResponse
|
|
||||||
|
|
||||||
linkJSON, err := json.Marshal(link)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"link": {string(linkJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
fillSite(&p, site)
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest("/orders/links/create", p)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientIdsUpload uploading of web analytics clientId
|
|
||||||
//
|
|
||||||
// For more information see https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-web-analytics-client-ids-upload
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.ClientIdsUpload([]retailcrm.ClientID{
|
|
||||||
// {
|
|
||||||
// Value: "value",
|
|
||||||
// Order: LinkedOrder{ID: 10, ExternalID: "externalID", Number: "number"},
|
|
||||||
// Customer: SerializedEntityCustomer{ID: 10, ExternalID: "externalID"},
|
|
||||||
// Site: "site",
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// Value: "value",
|
|
||||||
// Order: LinkedOrder{ID: 12, ExternalID: "externalID2", Number: "number2"},
|
|
||||||
// Customer: SerializedEntityCustomer{ID: 12, ExternalID: "externalID2"},
|
|
||||||
// Site: "site2",
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if data.Success == true {
|
|
||||||
// log.Println("Upload is successful")
|
|
||||||
// }
|
|
||||||
func (c *Client) ClientIdsUpload(clientIds []ClientID) (ClientIDResponse, int, error) {
|
|
||||||
var resp ClientIDResponse
|
|
||||||
clientIdsJSON, err := json.Marshal(&clientIds)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"clientIds": {string(clientIdsJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest("/web-analytics/client-ids/upload", p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SourcesUpload uploading of sources
|
|
||||||
//
|
|
||||||
// For more information see https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-web-analytics-sources-upload
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.SourcesUpload([]retailcrm.Source{
|
|
||||||
// {
|
|
||||||
// Source: "source",
|
|
||||||
// Medium: "medium",
|
|
||||||
// Campaign: "campaign",
|
|
||||||
// Keyword: "keyword",
|
|
||||||
// Content: "content",
|
|
||||||
// ClientID: "10",
|
|
||||||
// Order: LinkedOrder{ID: 10, ExternalID: "externalId", Number: "number"},
|
|
||||||
// Customer: SerializedEntityCustomer{ID: 10, ExternalID: "externalId"},
|
|
||||||
// Site: "site",
|
|
||||||
// },
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if data.Success == true {
|
|
||||||
// log.Println("Upload is successful!")
|
|
||||||
// }
|
|
||||||
func (c *Client) SourcesUpload(sources []Source) (SourcesResponse, int, error) {
|
|
||||||
var resp SourcesResponse
|
|
||||||
sourcesJSON, err := json.Marshal(&sources)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"sources": {string(sourcesJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest("/web-analytics/sources/upload", p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currencies returns a list of currencies
|
|
||||||
//
|
|
||||||
// For more information see https://docs.simla.com/Developers/API/APIVersions/APIv5#get--api-v5-reference-currencies
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.Currencies()
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// for _, value := range data.Currencies {
|
|
||||||
// log.Printf("%v\n", value)
|
|
||||||
// }
|
|
||||||
func (c *Client) Currencies() (CurrencyResponse, int, error) {
|
|
||||||
var resp CurrencyResponse
|
|
||||||
|
|
||||||
data, status, err := c.GetRequest("/reference/currencies")
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrenciesCreate create currency
|
|
||||||
//
|
|
||||||
// For more information see https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-reference-currencies-create
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.CurrenciesCreate(retailcrm.Currency{
|
|
||||||
// Code: "RUB",
|
|
||||||
// IsBase: true,
|
|
||||||
// IsAutoConvert: true,
|
|
||||||
// AutoConvertExtraPercent: 1,
|
|
||||||
// ManualConvertNominal: 1,
|
|
||||||
// ManualConvertValue: 1,
|
|
||||||
// })
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// if data.Success == true {
|
|
||||||
// log.Println("Create currency")
|
|
||||||
// }
|
|
||||||
func (c *Client) CurrenciesCreate(currency Currency) (CurrencyCreateResponse, int, error) {
|
|
||||||
var resp CurrencyCreateResponse
|
|
||||||
currencyJSON, err := json.Marshal(¤cy)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"currency": {string(currencyJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest("/reference/currencies/create", p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrenciesEdit edit an currency
|
|
||||||
//
|
|
||||||
// For more information see https://docs.simla.com/Developers/API/APIVersions/APIv5#post--api-v5-reference-currencies-id-edit
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
//
|
|
||||||
// var client = retailcrm.New("https://demo.url", "09jIJ")
|
|
||||||
//
|
|
||||||
// data, status, err := client.CurrenciesEdit(
|
|
||||||
// retailcrm.Currency{
|
|
||||||
// ID: 10,
|
|
||||||
// Code: "RUB",
|
|
||||||
// IsBase: true,
|
|
||||||
// IsAutoConvert: true,
|
|
||||||
// AutoConvertExtraPercent: 1,
|
|
||||||
// ManualConvertNominal: 1,
|
|
||||||
// ManualConvertValue: 1,
|
|
||||||
// },
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// if err != nil {
|
|
||||||
// if apiErr, ok := retailcrm.AsAPIError(err); ok {
|
|
||||||
// log.Fatalf("http status: %d, %s", status, apiErr.String())
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// log.Fatalf("http status: %d, error: %s", status, err)
|
|
||||||
// }
|
|
||||||
// if data.Success == true {
|
|
||||||
// log.Println("Currency was edit")
|
|
||||||
// }
|
|
||||||
func (c *Client) CurrenciesEdit(currency Currency) (SuccessfulResponse, int, error) {
|
|
||||||
var resp SuccessfulResponse
|
|
||||||
var uid = strconv.Itoa(currency.ID)
|
|
||||||
|
|
||||||
currencyJSON, err := json.Marshal(¤cy)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, http.StatusBadRequest, err
|
|
||||||
}
|
|
||||||
|
|
||||||
p := url.Values{
|
|
||||||
"currency": {string(currencyJSON)},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, status, err := c.PostRequest(fmt.Sprintf("/reference/currencies/%s/edit", uid), p)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
if err != nil {
|
|
||||||
return resp, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IntegrationModuleEdit integration module create/edit
|
// IntegrationModuleEdit integration module create/edit
|
||||||
//
|
//
|
||||||
// For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#get--api-v5-integration-modules-code
|
// For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#get--api-v5-integration-modules-code
|
||||||
|
@ -5260,7 +4650,7 @@ func (c *Client) StaticticsUpdate() (SuccessfulResponse, int, error) {
|
||||||
//
|
//
|
||||||
// data, status, err := client.Costs(CostsRequest{
|
// data, status, err := client.Costs(CostsRequest{
|
||||||
// Filter: CostsFilter{
|
// Filter: CostsFilter{
|
||||||
// IDs: []string{"1","2","3"},
|
// Ids: []string{"1","2","3"},
|
||||||
// MinSumm: "1000"
|
// MinSumm: "1000"
|
||||||
// },
|
// },
|
||||||
// })
|
// })
|
||||||
|
@ -7055,52 +6445,53 @@ func (c *Client) EditProductsGroup(by, id, site string, group ProductGroup) (Act
|
||||||
// log.Printf("%s", fileData)
|
// log.Printf("%s", fileData)
|
||||||
// }
|
// }
|
||||||
func (c *Client) GetOrderPlate(by, orderID, site string, plateID int) (io.ReadCloser, int, error) {
|
func (c *Client) GetOrderPlate(by, orderID, site string, plateID int) (io.ReadCloser, int, error) {
|
||||||
requestURL := fmt.Sprintf("%s/api/v5/orders/%s/plates/%d/print?%s", c.URL, orderID, plateID, url.Values{
|
p := url.Values{
|
||||||
"by": {checkBy(by)},
|
"by": {checkBy(by)},
|
||||||
"site": {site},
|
"site": {site},
|
||||||
}.Encode())
|
}
|
||||||
|
|
||||||
return c.executeWithRetryReadCloser(requestURL, func() (interface{}, int, error) {
|
requestURL := fmt.Sprintf("%s/api/v5/orders/%s/plates/%d/print?%s", c.URL, orderID, plateID, p.Encode())
|
||||||
req, err := http.NewRequest("GET", requestURL, nil)
|
req, err := http.NewRequest("GET", requestURL, nil)
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("X-API-KEY", c.Key)
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
if c.Debug {
|
req.Header.Set("X-API-KEY", c.Key)
|
||||||
c.writeLog("API Request: %s %s", requestURL, c.Key)
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
if c.Debug {
|
||||||
|
c.writeLog("API Request: %s %s", requestURL, c.Key)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusInternalServerError {
|
||||||
|
return nil, resp.StatusCode, CreateGenericAPIError(
|
||||||
|
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode >= http.StatusBadRequest && resp.StatusCode < http.StatusInternalServerError {
|
||||||
|
res, err := buildRawResponse(resp)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusInternalServerError && resp.StatusCode != http.StatusServiceUnavailable {
|
return nil, resp.StatusCode, CreateAPIError(res)
|
||||||
return nil, resp.StatusCode, CreateGenericAPIError(
|
}
|
||||||
fmt.Sprintf("HTTP request error. Status code: %d.", resp.StatusCode))
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode >= http.StatusBadRequest &&
|
reader := resp.Body
|
||||||
resp.StatusCode < http.StatusInternalServerError &&
|
err = reader.Close()
|
||||||
resp.StatusCode != http.StatusServiceUnavailable {
|
|
||||||
res, err := buildRawResponse(resp)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, resp.StatusCode, CreateAPIError(res)
|
return reader, resp.StatusCode, nil
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp.Body, resp.StatusCode, nil
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NotificationsSend send a notification
|
// NotificationsSend send a notification
|
||||||
|
@ -7140,85 +6531,3 @@ func (c *Client) NotificationsSend(req NotificationsSendRequest) (int, error) {
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) ListMGChannelTemplates(channelID, page, limit int) (MGChannelTemplatesResponse, int, error) {
|
|
||||||
var resp MGChannelTemplatesResponse
|
|
||||||
|
|
||||||
values := url.Values{
|
|
||||||
"page": {fmt.Sprintf("%d", page)},
|
|
||||||
"limit": {fmt.Sprintf("%d", limit)},
|
|
||||||
"channel_id": {fmt.Sprintf("%d", channelID)},
|
|
||||||
}
|
|
||||||
|
|
||||||
data, code, err := c.GetRequest(fmt.Sprintf("/reference/mg-channels/templates?%s", values.Encode()))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, code, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &resp)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return resp, code, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return resp, code, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) EditMGChannelTemplate(req EditMGChannelTemplateRequest) (int, error) {
|
|
||||||
templates, err := json.Marshal(req.Templates)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(templates) == "null" {
|
|
||||||
templates = []byte(`[]`)
|
|
||||||
}
|
|
||||||
|
|
||||||
removed, err := json.Marshal(req.Removed)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if string(removed) == "null" {
|
|
||||||
removed = []byte(`[]`)
|
|
||||||
}
|
|
||||||
|
|
||||||
values := url.Values{
|
|
||||||
"templates": {string(templates)},
|
|
||||||
"removed": {string(removed)},
|
|
||||||
}
|
|
||||||
|
|
||||||
_, code, err := c.PostRequest("/reference/mg-channels/templates/edit", values)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return code, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Client) StoreOffers(req OffersRequest) (StoreOffersResponse, int, error) {
|
|
||||||
var result StoreOffersResponse
|
|
||||||
|
|
||||||
filter, err := query.Values(req)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return StoreOffersResponse{}, 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, status, err := c.GetRequest(fmt.Sprintf("/store/offers?%s", filter.Encode()))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return StoreOffersResponse{}, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(resp, &result)
|
|
||||||
if err != nil {
|
|
||||||
return StoreOffersResponse{}, status, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, status, nil
|
|
||||||
}
|
|
||||||
|
|
1016
client_test.go
1016
client_test.go
File diff suppressed because it is too large
Load diff
2
error.go
2
error.go
|
@ -9,8 +9,6 @@ import (
|
||||||
|
|
||||||
var missingParameterMatcher = regexp.MustCompile(`^Parameter \'([\w\]\[\_\-]+)\' is missing$`)
|
var missingParameterMatcher = regexp.MustCompile(`^Parameter \'([\w\]\[\_\-]+)\' is missing$`)
|
||||||
var (
|
var (
|
||||||
// ErrRateLimited will be returned if request was rate limited.
|
|
||||||
ErrRateLimited = NewAPIError("rate limit exceeded")
|
|
||||||
// ErrMissingCredentials will be returned if no API key was provided to the API.
|
// ErrMissingCredentials will be returned if no API key was provided to the API.
|
||||||
ErrMissingCredentials = NewAPIError(`apiKey is missing`)
|
ErrMissingCredentials = NewAPIError(`apiKey is missing`)
|
||||||
// ErrInvalidCredentials will be returned if provided API key is invalid.
|
// ErrInvalidCredentials will be returned if provided API key is invalid.
|
||||||
|
|
40
filters.go
40
filters.go
|
@ -199,7 +199,6 @@ type OrdersFilter struct {
|
||||||
PaymentStatuses []string `url:"paymentStatuses,omitempty,brackets"`
|
PaymentStatuses []string `url:"paymentStatuses,omitempty,brackets"`
|
||||||
PaymentTypes []string `url:"paymentTypes,omitempty,brackets"`
|
PaymentTypes []string `url:"paymentTypes,omitempty,brackets"`
|
||||||
DeliveryTypes []string `url:"deliveryTypes,omitempty,brackets"`
|
DeliveryTypes []string `url:"deliveryTypes,omitempty,brackets"`
|
||||||
DeliveryServices []string `url:"deliveryServices,omitempty,brackets"`
|
|
||||||
OrderMethods []string `url:"orderMethods,omitempty,brackets"`
|
OrderMethods []string `url:"orderMethods,omitempty,brackets"`
|
||||||
ShipmentStores []string `url:"shipmentStores,omitempty,brackets"`
|
ShipmentStores []string `url:"shipmentStores,omitempty,brackets"`
|
||||||
Couriers []string `url:"couriers,omitempty,brackets"`
|
Couriers []string `url:"couriers,omitempty,brackets"`
|
||||||
|
@ -352,7 +351,6 @@ type ProductsFilter struct {
|
||||||
ExternalID string `url:"externalId,omitempty"`
|
ExternalID string `url:"externalId,omitempty"`
|
||||||
Manufacturer string `url:"manufacturer,omitempty"`
|
Manufacturer string `url:"manufacturer,omitempty"`
|
||||||
URL string `url:"url,omitempty"`
|
URL string `url:"url,omitempty"`
|
||||||
URLLike string `url:"urlLike,omitempty"`
|
|
||||||
PriceType string `url:"priceType,omitempty"`
|
PriceType string `url:"priceType,omitempty"`
|
||||||
OfferExternalID string `url:"offerExternalId,omitempty"`
|
OfferExternalID string `url:"offerExternalId,omitempty"`
|
||||||
Sites []string `url:"sites,omitempty,brackets"`
|
Sites []string `url:"sites,omitempty,brackets"`
|
||||||
|
@ -381,22 +379,22 @@ type ShipmentFilter struct {
|
||||||
|
|
||||||
// CostsFilter type.
|
// CostsFilter type.
|
||||||
type CostsFilter struct {
|
type CostsFilter struct {
|
||||||
MinSumm int `url:"minSumm,omitempty"`
|
MinSumm string `url:"minSumm,omitempty"`
|
||||||
MaxSumm int `url:"maxSumm,omitempty"`
|
MaxSumm string `url:"maxSumm,omitempty"`
|
||||||
OrderNumber string `url:"orderNumber,omitempty"`
|
OrderNumber string `url:"orderNumber,omitempty"`
|
||||||
Comment string `url:"orderNumber,omitempty"`
|
Comment string `url:"orderNumber,omitempty"`
|
||||||
IDs []int `url:"ids,omitempty,brackets"`
|
Ids []string `url:"ids,omitempty,brackets"`
|
||||||
Sites []string `url:"sites,omitempty,brackets"`
|
Sites []string `url:"sites,omitempty,brackets"`
|
||||||
CreatedBy []int `url:"createdBy,omitempty,brackets"`
|
CreatedBy []string `url:"createdBy,omitempty,brackets"`
|
||||||
CostGroups []string `url:"costGroups,omitempty,brackets"`
|
CostGroups []string `url:"costGroups,omitempty,brackets"`
|
||||||
CostItems []string `url:"costItems,omitempty,brackets"`
|
CostItems []string `url:"costItems,omitempty,brackets"`
|
||||||
Users []int `url:"users,omitempty,brackets"`
|
Users []string `url:"users,omitempty,brackets"`
|
||||||
DateFrom string `url:"dateFrom,omitempty"`
|
DateFrom string `url:"dateFrom,omitempty"`
|
||||||
DateTo string `url:"dateTo,omitempty"`
|
DateTo string `url:"dateTo,omitempty"`
|
||||||
CreatedAtFrom string `url:"createdAtFrom,omitempty"`
|
CreatedAtFrom string `url:"createdAtFrom,omitempty"`
|
||||||
CreatedAtTo string `url:"createdAtTo,omitempty"`
|
CreatedAtTo string `url:"createdAtTo,omitempty"`
|
||||||
OrderIDs []int `url:"orderIds,omitempty,brackets"`
|
OrderIds []string `url:"orderIds,omitempty,brackets"`
|
||||||
OrderExternalIDs []string `url:"orderExternalIds,omitempty,brackets"`
|
OrderExternalIds []string `url:"orderIds,omitempty,brackets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// FilesFilter type.
|
// FilesFilter type.
|
||||||
|
@ -450,8 +448,8 @@ type LoyaltyAccountAPIFilter struct {
|
||||||
ID string `url:"id,omitempty"`
|
ID string `url:"id,omitempty"`
|
||||||
Status string `url:"status,,omitempty"`
|
Status string `url:"status,,omitempty"`
|
||||||
Customer string `url:"customer,omitempty"`
|
Customer string `url:"customer,omitempty"`
|
||||||
MinOrderSum string `url:"minOrdersSum,omitempty"`
|
MinOrderSum string `url:"minOrderSum,omitempty"`
|
||||||
MaxOrderSum string `url:"maxOrdersSum,omitempty"`
|
MaxOrderSum string `url:"maxOrderSum,omitempty"`
|
||||||
MinAmount string `url:"minAmount,omitempty"`
|
MinAmount string `url:"minAmount,omitempty"`
|
||||||
MaxAmount string `url:"maxAmount,omitempty"`
|
MaxAmount string `url:"maxAmount,omitempty"`
|
||||||
PhoneNumber string `url:"phoneNumber,omitempty"`
|
PhoneNumber string `url:"phoneNumber,omitempty"`
|
||||||
|
@ -475,23 +473,3 @@ type LoyaltyAPIFilter struct {
|
||||||
Ids []int `url:"ids,omitempty,brackets"`
|
Ids []int `url:"ids,omitempty,brackets"`
|
||||||
Sites []string `url:"sites,omitempty,brackets"`
|
Sites []string `url:"sites,omitempty,brackets"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type OffersFilter struct {
|
|
||||||
Ids []int `url:"ids,omitempty,brackets"`
|
|
||||||
Active *int `url:"active,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SiteFilter struct {
|
|
||||||
// SiteBy contains information about what is betrayed site id or site code.
|
|
||||||
// id|code, default is code.
|
|
||||||
SiteBy string `url:"siteBy,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type GetCartFilter struct {
|
|
||||||
// SiteBy contains information about what is betrayed site id or site code.
|
|
||||||
// id|code, default is code.
|
|
||||||
SiteBy string `url:"siteBy,omitempty"`
|
|
||||||
// By contains information about what is betrayed: customer id or customer externalId.
|
|
||||||
// id|externalId, default is externalId.
|
|
||||||
By string `url:"by,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
|
@ -58,30 +58,6 @@ func (l *StringMap) UnmarshalJSON(data []byte) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *CustomFieldMap) UnmarshalJSON(data []byte) error {
|
|
||||||
var i interface{}
|
|
||||||
var items CustomFieldMap
|
|
||||||
if err := json.Unmarshal(data, &i); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch e := i.(type) {
|
|
||||||
case map[string]interface{}:
|
|
||||||
items = make(CustomFieldMap, len(e))
|
|
||||||
for idx, val := range e {
|
|
||||||
items[idx] = val
|
|
||||||
}
|
|
||||||
case []interface{}:
|
|
||||||
items = make(CustomFieldMap, len(e))
|
|
||||||
for idx, val := range e {
|
|
||||||
items[strconv.Itoa(idx)] = val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*l = items
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p *OrderPayments) UnmarshalJSON(data []byte) error {
|
func (p *OrderPayments) UnmarshalJSON(data []byte) error {
|
||||||
var i interface{}
|
var i interface{}
|
||||||
var m OrderPayments
|
var m OrderPayments
|
||||||
|
|
|
@ -44,7 +44,7 @@ func TestAPIErrorsList_UnmarshalJSON(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCustomFieldsList_UnmarshalJSON(t *testing.T) {
|
func TestCustomFieldsList_UnmarshalJSON(t *testing.T) {
|
||||||
var list CustomFieldMap
|
var list StringMap
|
||||||
|
|
||||||
require.NoError(t, json.Unmarshal([]byte(`["first", "second"]`), &list))
|
require.NoError(t, json.Unmarshal([]byte(`["first", "second"]`), &list))
|
||||||
assert.Len(t, list, 2)
|
assert.Len(t, list, 2)
|
||||||
|
@ -56,13 +56,6 @@ func TestCustomFieldsList_UnmarshalJSON(t *testing.T) {
|
||||||
assert.Equal(t, list["a"], "first")
|
assert.Equal(t, list["a"], "first")
|
||||||
assert.Equal(t, list["b"], "second")
|
assert.Equal(t, list["b"], "second")
|
||||||
|
|
||||||
require.NoError(t, json.Unmarshal([]byte(`{"a": ["first", "second"], "b": "second"}`), &list))
|
|
||||||
assert.Len(t, list, 2)
|
|
||||||
assert.Len(t, list["a"].([]interface{}), 2)
|
|
||||||
assert.Equal(t, list["a"].([]interface{})[0], "first")
|
|
||||||
assert.Equal(t, list["a"].([]interface{})[1], "second")
|
|
||||||
assert.Equal(t, list["b"], "second")
|
|
||||||
|
|
||||||
require.NoError(t, json.Unmarshal([]byte(`[]`), &list))
|
require.NoError(t, json.Unmarshal([]byte(`[]`), &list))
|
||||||
assert.Len(t, list, 0)
|
assert.Len(t, list, 0)
|
||||||
}
|
}
|
||||||
|
|
29
request.go
29
request.go
|
@ -194,22 +194,6 @@ type DeliveryShipmentsRequest struct {
|
||||||
Page int `url:"page,omitempty"`
|
Page int `url:"page,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClearCartRequest type.
|
|
||||||
type ClearCartRequest struct {
|
|
||||||
ClearedAt string `url:"clearedAt,omitempty"`
|
|
||||||
Customer CartCustomer `url:"customer,omitempty"`
|
|
||||||
Order ClearCartOrder `url:"order,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCartRequest type.
|
|
||||||
type SetCartRequest struct {
|
|
||||||
ExternalID string `url:"externalId,omitempty"`
|
|
||||||
DroppedAt string `url:"droppedAt,omitempty"`
|
|
||||||
Link string `url:"link,omitempty"`
|
|
||||||
Customer CartCustomer `url:"customer,omitempty"`
|
|
||||||
Items []SetCartItem `url:"items,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CostsRequest type.
|
// CostsRequest type.
|
||||||
type CostsRequest struct {
|
type CostsRequest struct {
|
||||||
Filter CostsFilter `url:"filter,omitempty"`
|
Filter CostsFilter `url:"filter,omitempty"`
|
||||||
|
@ -265,7 +249,7 @@ type AccountBonusOperationsRequest struct {
|
||||||
type LoyaltyBonusCreditRequest struct {
|
type LoyaltyBonusCreditRequest struct {
|
||||||
Amount float64 `url:"amount"`
|
Amount float64 `url:"amount"`
|
||||||
ActivationDate string `url:"activationDate,omitempty"`
|
ActivationDate string `url:"activationDate,omitempty"`
|
||||||
ExpiredDate string `url:"expireDate,omitempty"`
|
ExpiredDate string `url:"expiredDate,omitempty"`
|
||||||
Comment string `url:"comment,omitempty"`
|
Comment string `url:"comment,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -277,7 +261,7 @@ type LoyaltyBonusStatusDetailsRequest struct {
|
||||||
|
|
||||||
type LoyaltyAccountsRequest struct {
|
type LoyaltyAccountsRequest struct {
|
||||||
Limit int `url:"limit,omitempty"`
|
Limit int `url:"limit,omitempty"`
|
||||||
Page int `url:"page,omitempty"`
|
Page int `url:"limit,omitempty"`
|
||||||
Filter LoyaltyAccountAPIFilter `url:"filter,omitempty"`
|
Filter LoyaltyAccountAPIFilter `url:"filter,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,11 +284,6 @@ type NotificationsSendRequest struct {
|
||||||
UserIDs []string `json:"userIds,omitempty"`
|
UserIDs []string `json:"userIds,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EditMGChannelTemplateRequest struct {
|
|
||||||
Templates []MGChannelTemplate `json:"templates"`
|
|
||||||
Removed []int `json:"removed"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemURL returns system URL from the connection request without trailing slash.
|
// SystemURL returns system URL from the connection request without trailing slash.
|
||||||
func (r ConnectRequest) SystemURL() string {
|
func (r ConnectRequest) SystemURL() string {
|
||||||
if r.URL == "" {
|
if r.URL == "" {
|
||||||
|
@ -326,7 +305,3 @@ func (r ConnectRequest) Verify(secret string) bool {
|
||||||
}
|
}
|
||||||
return hmac.Equal([]byte(r.Token), []byte(hex.EncodeToString(mac.Sum(nil))))
|
return hmac.Equal([]byte(r.Token), []byte(hex.EncodeToString(mac.Sum(nil))))
|
||||||
}
|
}
|
||||||
|
|
||||||
type OffersRequest struct {
|
|
||||||
OffersFilter `url:"filter,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
46
response.go
46
response.go
|
@ -407,12 +407,6 @@ type ProductsPropertiesResponse struct {
|
||||||
Properties []Property `json:"properties,omitempty"`
|
Properties []Property `json:"properties,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CartResponse type.
|
|
||||||
type CartResponse struct {
|
|
||||||
SuccessfulResponse
|
|
||||||
Cart Cart `json:"cart"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeliveryShipmentsResponse type.
|
// DeliveryShipmentsResponse type.
|
||||||
type DeliveryShipmentsResponse struct {
|
type DeliveryShipmentsResponse struct {
|
||||||
Success bool `json:"success"`
|
Success bool `json:"success"`
|
||||||
|
@ -602,34 +596,6 @@ type AccountBonusOperationsResponse struct {
|
||||||
BonusOperations []BonusOperation `json:"bonusOperations,omitempty"`
|
BonusOperations []BonusOperation `json:"bonusOperations,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientIDResponse type.
|
|
||||||
type ClientIDResponse struct {
|
|
||||||
ErrorMsg string `json:"errorMsg,omitempty"`
|
|
||||||
Errors map[string]string `json:"errors,omitempty"`
|
|
||||||
FailedClientIds []ClientID `json:"failed_client_ids,omitempty"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SourcesResponse type.
|
|
||||||
type SourcesResponse struct {
|
|
||||||
ErrorMsg string `json:"errorMsg,omitempty"`
|
|
||||||
Errors map[string]string `json:"errors,omitempty"`
|
|
||||||
FailedSources []Source `json:"failed_sources,omitempty"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrencyResponse type.
|
|
||||||
type CurrencyResponse struct {
|
|
||||||
Currencies []Currency `json:"currencies,omitempty"`
|
|
||||||
Success bool `json:"success"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CurrencyCreateResponse type.
|
|
||||||
type CurrencyCreateResponse struct {
|
|
||||||
Success bool `json:"success"`
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoyaltyAccountResponse struct {
|
type LoyaltyAccountResponse struct {
|
||||||
SuccessfulResponse
|
SuccessfulResponse
|
||||||
LoyaltyAccount `json:"loyaltyAccount"`
|
LoyaltyAccount `json:"loyaltyAccount"`
|
||||||
|
@ -685,15 +651,3 @@ type ActionProductsGroupResponse struct {
|
||||||
SuccessfulResponse
|
SuccessfulResponse
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MGChannelTemplatesResponse struct {
|
|
||||||
Pagination *Pagination `json:"pagination"`
|
|
||||||
Templates []MGChannelTemplate `json:"templates"`
|
|
||||||
SuccessfulResponse
|
|
||||||
}
|
|
||||||
|
|
||||||
type StoreOffersResponse struct {
|
|
||||||
Pagination *Pagination `json:"pagination"`
|
|
||||||
SuccessfulResponse
|
|
||||||
Offers []Offer `json:"offers,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,30 +0,0 @@
|
||||||
package retailcrm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type SystemTime time.Time
|
|
||||||
|
|
||||||
const systemTimeLayout = "2006-01-02 15:04:05"
|
|
||||||
|
|
||||||
// UnmarshalJSON parses time.Time from system format.
|
|
||||||
func (st *SystemTime) UnmarshalJSON(b []byte) (err error) {
|
|
||||||
s := strings.Trim(string(b), `"`)
|
|
||||||
nt, err := time.Parse(systemTimeLayout, s)
|
|
||||||
*st = SystemTime(nt)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON will marshal time.Time to system format.
|
|
||||||
func (st SystemTime) MarshalJSON() ([]byte, error) {
|
|
||||||
return []byte(st.String()), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the time in the custom format.
|
|
||||||
func (st *SystemTime) String() string {
|
|
||||||
t := time.Time(*st)
|
|
||||||
return fmt.Sprintf("%q", t.Format(systemTimeLayout))
|
|
||||||
}
|
|
122
template.go
122
template.go
|
@ -1,122 +0,0 @@
|
||||||
package retailcrm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TemplateItemTypeText is a type for text chunk in template.
|
|
||||||
TemplateItemTypeText uint8 = iota
|
|
||||||
// TemplateItemTypeVar is a type for variable in template.
|
|
||||||
TemplateItemTypeVar
|
|
||||||
QuickReply ButtonType = "QUICK_REPLY"
|
|
||||||
PhoneNumber ButtonType = "PHONE_NUMBER"
|
|
||||||
URL ButtonType = "URL"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// TemplateVarCustom is a custom variable type.
|
|
||||||
TemplateVarCustom = "custom"
|
|
||||||
// TemplateVarName is a name variable type.
|
|
||||||
TemplateVarName = "name"
|
|
||||||
// TemplateVarFirstName is a first name variable type.
|
|
||||||
TemplateVarFirstName = "first_name"
|
|
||||||
// TemplateVarLastName is a last name variable type.
|
|
||||||
TemplateVarLastName = "last_name"
|
|
||||||
)
|
|
||||||
|
|
||||||
// templateVarAssoc for checking variable validity, only for internal use.
|
|
||||||
var templateVarAssoc = map[string]interface{}{
|
|
||||||
TemplateVarCustom: nil,
|
|
||||||
TemplateVarName: nil,
|
|
||||||
TemplateVarFirstName: nil,
|
|
||||||
TemplateVarLastName: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
type Text struct {
|
|
||||||
Parts []TextTemplateItem `json:"parts"`
|
|
||||||
Example []string `json:"example,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Media struct {
|
|
||||||
Example string `json:"example,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Header struct {
|
|
||||||
Text *Text `json:"text,omitempty"`
|
|
||||||
Document *Media `json:"document,omitempty"`
|
|
||||||
Image *Media `json:"image,omitempty"`
|
|
||||||
Video *Media `json:"video,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TemplateItemList []TextTemplateItem
|
|
||||||
|
|
||||||
// TextTemplateItem is a part of template.
|
|
||||||
type TextTemplateItem struct {
|
|
||||||
Text string
|
|
||||||
VarType string
|
|
||||||
Type uint8
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalJSON controls how TextTemplateItem will be marshaled into JSON.
|
|
||||||
func (t TextTemplateItem) MarshalJSON() ([]byte, error) {
|
|
||||||
switch t.Type {
|
|
||||||
case TemplateItemTypeText:
|
|
||||||
return json.Marshal(t.Text)
|
|
||||||
case TemplateItemTypeVar:
|
|
||||||
return json.Marshal(map[string]interface{}{
|
|
||||||
"var": t.VarType,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, errors.New("unknown TextTemplateItem type")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON will correctly unmarshal TextTemplateItem.
|
|
||||||
func (t *TextTemplateItem) UnmarshalJSON(b []byte) error {
|
|
||||||
var obj interface{}
|
|
||||||
err := json.Unmarshal(b, &obj)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
switch bodyPart := obj.(type) {
|
|
||||||
case string:
|
|
||||||
t.Type = TemplateItemTypeText
|
|
||||||
t.Text = bodyPart
|
|
||||||
case map[string]interface{}:
|
|
||||||
// {} case
|
|
||||||
if len(bodyPart) == 0 {
|
|
||||||
t.Type = TemplateItemTypeText
|
|
||||||
t.Text = "{}"
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if varTypeCurr, ok := bodyPart["var"].(string); ok {
|
|
||||||
if _, ok := templateVarAssoc[varTypeCurr]; !ok {
|
|
||||||
return fmt.Errorf("invalid placeholder var '%s'", varTypeCurr)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Type = TemplateItemTypeVar
|
|
||||||
t.VarType = varTypeCurr
|
|
||||||
} else {
|
|
||||||
return errors.New("invalid TextTemplateItem")
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
return errors.New("invalid TextTemplateItem")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type ButtonType string
|
|
||||||
|
|
||||||
type Button struct {
|
|
||||||
Type ButtonType `json:"type"`
|
|
||||||
URL string `json:"url,omitempty"`
|
|
||||||
Text string `json:"text,omitempty"`
|
|
||||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
|
||||||
Example []string `json:"example,omitempty"`
|
|
||||||
}
|
|
149
testutils.go
149
testutils.go
|
@ -85,7 +85,7 @@ func getLoyaltyAccountCreate() SerializedCreateLoyaltyAccount {
|
||||||
return SerializedCreateLoyaltyAccount{
|
return SerializedCreateLoyaltyAccount{
|
||||||
SerializedBaseLoyaltyAccount: SerializedBaseLoyaltyAccount{
|
SerializedBaseLoyaltyAccount: SerializedBaseLoyaltyAccount{
|
||||||
PhoneNumber: "89151005004",
|
PhoneNumber: "89151005004",
|
||||||
CustomFields: []interface{}{"dog"},
|
CustomFields: []string{"dog"},
|
||||||
},
|
},
|
||||||
Customer: SerializedEntityCustomer{
|
Customer: SerializedEntityCustomer{
|
||||||
ID: 123,
|
ID: 123,
|
||||||
|
@ -103,9 +103,7 @@ func getLoyaltyAccountCreateResponse() CreateLoyaltyAccountResponse {
|
||||||
LoyaltyLevel: LoyaltyLevel{},
|
LoyaltyLevel: LoyaltyLevel{},
|
||||||
CreatedAt: "2022-11-24 12:39:37",
|
CreatedAt: "2022-11-24 12:39:37",
|
||||||
ActivatedAt: "2022-11-24 12:39:37",
|
ActivatedAt: "2022-11-24 12:39:37",
|
||||||
CustomFields: map[string]interface{}{
|
CustomFields: []string{"dog"},
|
||||||
"animal": "dog",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,9 +118,7 @@ func getLoyaltyAccountEditResponse() EditLoyaltyAccountResponse {
|
||||||
LoyaltyLevel: LoyaltyLevel{},
|
LoyaltyLevel: LoyaltyLevel{},
|
||||||
CreatedAt: "2022-11-24 12:39:37",
|
CreatedAt: "2022-11-24 12:39:37",
|
||||||
ActivatedAt: "2022-11-24 12:39:37",
|
ActivatedAt: "2022-11-24 12:39:37",
|
||||||
CustomFields: map[string]interface{}{
|
CustomFields: []string{"dog"},
|
||||||
"animal": "dog",
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -138,7 +134,7 @@ func getLoyaltyAccountResponse() string {
|
||||||
},
|
},
|
||||||
"customer": {
|
"customer": {
|
||||||
"id": 123,
|
"id": 123,
|
||||||
"customFields": {},
|
"customFields": [],
|
||||||
"firstName": "Руслан1",
|
"firstName": "Руслан1",
|
||||||
"lastName": "Ефанов",
|
"lastName": "Ефанов",
|
||||||
"patronymic": ""
|
"patronymic": ""
|
||||||
|
@ -158,12 +154,7 @@ func getLoyaltyAccountResponse() string {
|
||||||
"createdAt": "2022-11-24 12:39:37",
|
"createdAt": "2022-11-24 12:39:37",
|
||||||
"activatedAt": "2022-11-24 12:39:37",
|
"activatedAt": "2022-11-24 12:39:37",
|
||||||
"status": "activated",
|
"status": "activated",
|
||||||
"customFields": {
|
"customFields": []
|
||||||
"custom_multiselect": ["test1", "test3"],
|
|
||||||
"custom_select": "test2",
|
|
||||||
"custom_integer": 456,
|
|
||||||
"custom_float": 8.43
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
@ -433,133 +424,3 @@ func getLoyaltyResponse() string {
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMGTemplatesResponse() string {
|
|
||||||
return `{
|
|
||||||
"success": true,
|
|
||||||
"pagination": {
|
|
||||||
"limit": 10,
|
|
||||||
"totalCount": 100,
|
|
||||||
"currentPage": 5,
|
|
||||||
"totalPageCount": 10
|
|
||||||
},
|
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"externalId": 0,
|
|
||||||
"channel": {
|
|
||||||
"allowedSendByPhone": false,
|
|
||||||
"id": 1,
|
|
||||||
"externalId": 1,
|
|
||||||
"type": "fbmessenger",
|
|
||||||
"active": true,
|
|
||||||
"name": "fbmessenger"
|
|
||||||
},
|
|
||||||
"code": "namespace#NAMEAAA#ru",
|
|
||||||
"name": "NAMEAAA",
|
|
||||||
"active": true,
|
|
||||||
"template": [
|
|
||||||
"Text_0",
|
|
||||||
{
|
|
||||||
"var": "custom"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"templateExample": ["Text_1"],
|
|
||||||
"namespace": "namespace_0",
|
|
||||||
"lang": "en",
|
|
||||||
"category": "test_0",
|
|
||||||
"header": {
|
|
||||||
"text": {
|
|
||||||
"parts": [
|
|
||||||
"JABAAA",
|
|
||||||
{
|
|
||||||
"var": "custom"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"example": [
|
|
||||||
"AAAAAA"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"image": {
|
|
||||||
"example": "https://example.com/file/123.png"
|
|
||||||
},
|
|
||||||
"document": {
|
|
||||||
"example": "https://example.com/file/123.pdf"
|
|
||||||
},
|
|
||||||
"video": {
|
|
||||||
"example": "https://example.com/file/123.mp4"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"footer": "footer_0",
|
|
||||||
"buttons": [
|
|
||||||
{
|
|
||||||
"type": "PHONE_NUMBER",
|
|
||||||
"text": "your-phone-button-text",
|
|
||||||
"phoneNumber": "+79895553535"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "QUICK_REPLY",
|
|
||||||
"text": "Yes"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "URL",
|
|
||||||
"url": "https://example.com/file/{{1}}",
|
|
||||||
"text": "button",
|
|
||||||
"example": [
|
|
||||||
"https://www.website.com/dynamic-url-example"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"verificationStatus": "APPROVED"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMGTemplatesForEdit() string {
|
|
||||||
return `[{"header":{"text":{"parts":["Hello,",{"var":"custom"}],"example":["Henry"]},"document":{"example":"https://example.com/file/123.pdf"},"image":{"example":"https://example.com/file/123.png"},"video":{"example":"https://example.com/file/123.mp4"}},"lang":"en","category":"test_0","code":"namespace#name_0#ru","name":"name_0","namespace":"namespace","footer":"footer_0","verificationStatus":"REJECTED","template":["Text_0",{"var":"custom"}],"buttons":[{"type":"PHONE_NUMBER","text":"your-phone-button-text","phoneNumber":"+79895553535"},{"type":"QUICK_REPLY","text":"Yes"},{"type":"URL","url":"https://example.com/file/{{1}}","text":"button","example":["https://www.website.com/dynamic-url-example"]}],"templateExample":["WIU"],"id":1,"externalId":10,"mgChannelId":110,"active":true}]`
|
|
||||||
}
|
|
||||||
|
|
||||||
func getStoreOfferResponse() string {
|
|
||||||
return `{
|
|
||||||
"success": true,
|
|
||||||
"pagination": {
|
|
||||||
"limit": 20,
|
|
||||||
"totalCount": 1,
|
|
||||||
"currentPage": 1,
|
|
||||||
"totalPageCount": 1
|
|
||||||
},
|
|
||||||
"offers": [
|
|
||||||
{
|
|
||||||
"images": [
|
|
||||||
"https://s3-s1.retailcrm.tech/ru-central1/retailcrm/dev-vega-d32aea7f9a5bc26eba6ad986077cea03/product/65a92fa0bb737-test.jpeg"
|
|
||||||
],
|
|
||||||
"id": 76,
|
|
||||||
"site": "main",
|
|
||||||
"name": "Название\nПеревод строки",
|
|
||||||
"article": "Артикул",
|
|
||||||
"product": {
|
|
||||||
"type": "product",
|
|
||||||
"catalogId": 2,
|
|
||||||
"id": 222
|
|
||||||
},
|
|
||||||
"prices": [
|
|
||||||
{
|
|
||||||
"priceType": "base",
|
|
||||||
"price": 10000,
|
|
||||||
"ordering": 991,
|
|
||||||
"currency": "RUB"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"purchasePrice": 10,
|
|
||||||
"quantity": 5,
|
|
||||||
"active": true,
|
|
||||||
"unit": {
|
|
||||||
"code": "pc",
|
|
||||||
"name": "Штука",
|
|
||||||
"sym": "шт."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}`
|
|
||||||
}
|
|
||||||
|
|
515
types.go
515
types.go
|
@ -5,28 +5,14 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ByID is "id" constant to use as `by` property in methods.
|
// ByID is "id" constant to use as `by` property in methods.
|
||||||
const ByID = "id"
|
const ByID = "id"
|
||||||
|
|
||||||
// ByExternalID is "externalId" constant to use as `by` property in methods.
|
// ByExternalId is "externalId" constant to use as `by` property in methods.
|
||||||
const ByExternalID = "externalId"
|
const ByExternalID = "externalId"
|
||||||
|
|
||||||
// RateLimiter configuration constants.
|
|
||||||
const (
|
|
||||||
regularPathRPS = 10 // API rate limit (requests per second).
|
|
||||||
telephonyPathRPS = 40 // Telephony API endpoints rate limit (requests per second).
|
|
||||||
regularDelay = time.Second / regularPathRPS // Delay between regular requests.
|
|
||||||
telephonyDelay = time.Second / telephonyPathRPS // Delay between telephony requests.
|
|
||||||
)
|
|
||||||
|
|
||||||
// HTTPStatusUnknown can return for the method `/api/v5/customers/upload`, `/api/v5/customers-corporate/upload`,
|
|
||||||
// `/api/v5/orders/upload`.
|
|
||||||
const HTTPStatusUnknown = 460
|
|
||||||
|
|
||||||
// Client type.
|
// Client type.
|
||||||
type Client struct {
|
type Client struct {
|
||||||
URL string
|
URL string
|
||||||
|
@ -34,15 +20,6 @@ type Client struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
httpClient *http.Client
|
httpClient *http.Client
|
||||||
logger BasicLogger
|
logger BasicLogger
|
||||||
limiter *RateLimiter
|
|
||||||
mutex sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// RateLimiter manages API request rates to prevent hitting rate limits.
|
|
||||||
type RateLimiter struct {
|
|
||||||
maxAttempts uint // Maximum number of retry attempts (0 = infinite).
|
|
||||||
lastRequest time.Time // Time of the last request.
|
|
||||||
mutex sync.Mutex
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pagination type.
|
// Pagination type.
|
||||||
|
@ -76,29 +53,22 @@ type Address struct {
|
||||||
Text string `json:"text,omitempty"`
|
Text string `json:"text,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GeoID type. Can be empty string.
|
|
||||||
type GeoID json.Number
|
|
||||||
|
|
||||||
// GeoHierarchyRow type.
|
// GeoHierarchyRow type.
|
||||||
type GeoHierarchyRow struct {
|
type GeoHierarchyRow struct {
|
||||||
Country string `json:"country,omitempty"`
|
Country string `json:"country,omitempty"`
|
||||||
Region string `json:"region,omitempty"`
|
Region string `json:"region,omitempty"`
|
||||||
RegionID GeoID `json:"regionId,omitempty"`
|
RegionID int `json:"regionId,omitempty"`
|
||||||
City string `json:"city,omitempty"`
|
City string `json:"city,omitempty"`
|
||||||
CityID GeoID `json:"cityId,omitempty"`
|
CityID int `json:"cityId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Source type.
|
// Source type.
|
||||||
type Source struct {
|
type Source struct {
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
Medium string `json:"medium,omitempty"`
|
Medium string `json:"medium,omitempty"`
|
||||||
Campaign string `json:"campaign,omitempty"`
|
Campaign string `json:"campaign,omitempty"`
|
||||||
Keyword string `json:"keyword,omitempty"`
|
Keyword string `json:"keyword,omitempty"`
|
||||||
Content string `json:"content,omitempty"`
|
Content string `json:"content,omitempty"`
|
||||||
ClientID string `json:"client_id,omitempty"`
|
|
||||||
Site string `json:"site,omitempty"`
|
|
||||||
Order LinkedOrder `json:"order,omitempty"`
|
|
||||||
Customer SerializedEntityCustomer `json:"customer,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Contragent type.
|
// Contragent type.
|
||||||
|
@ -152,41 +122,41 @@ Customer related types
|
||||||
|
|
||||||
// Customer type.
|
// Customer type.
|
||||||
type Customer struct {
|
type Customer struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
ExternalID string `json:"externalId,omitempty"`
|
||||||
FirstName string `json:"firstName,omitempty"`
|
FirstName string `json:"firstName,omitempty"`
|
||||||
LastName string `json:"lastName,omitempty"`
|
LastName string `json:"lastName,omitempty"`
|
||||||
Patronymic string `json:"patronymic,omitempty"`
|
Patronymic string `json:"patronymic,omitempty"`
|
||||||
Sex string `json:"sex,omitempty"`
|
Sex string `json:"sex,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
Phones []Phone `json:"phones,omitempty"`
|
Phones []Phone `json:"phones,omitempty"`
|
||||||
Address *Address `json:"address,omitempty"`
|
Address *Address `json:"address,omitempty"`
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Birthday string `json:"birthday,omitempty"`
|
Birthday string `json:"birthday,omitempty"`
|
||||||
ManagerID int `json:"managerId,omitempty"`
|
ManagerID int `json:"managerId,omitempty"`
|
||||||
Vip bool `json:"vip,omitempty"`
|
Vip bool `json:"vip,omitempty"`
|
||||||
Bad bool `json:"bad,omitempty"`
|
Bad bool `json:"bad,omitempty"`
|
||||||
Site string `json:"site,omitempty"`
|
Site string `json:"site,omitempty"`
|
||||||
Source *Source `json:"source,omitempty"`
|
Source *Source `json:"source,omitempty"`
|
||||||
Contragent *Contragent `json:"contragent,omitempty"`
|
Contragent *Contragent `json:"contragent,omitempty"`
|
||||||
PersonalDiscount float32 `json:"personalDiscount,omitempty"`
|
PersonalDiscount float32 `json:"personalDiscount,omitempty"`
|
||||||
CumulativeDiscount float32 `json:"cumulativeDiscount,omitempty"`
|
CumulativeDiscount float32 `json:"cumulativeDiscount,omitempty"`
|
||||||
DiscountCardNumber string `json:"discountCardNumber,omitempty"`
|
DiscountCardNumber string `json:"discountCardNumber,omitempty"`
|
||||||
EmailMarketingUnsubscribedAt string `json:"emailMarketingUnsubscribedAt,omitempty"`
|
EmailMarketingUnsubscribedAt string `json:"emailMarketingUnsubscribedAt,omitempty"`
|
||||||
AvgMarginSumm float32 `json:"avgMarginSumm,omitempty"`
|
AvgMarginSumm float32 `json:"avgMarginSumm,omitempty"`
|
||||||
MarginSumm float32 `json:"marginSumm,omitempty"`
|
MarginSumm float32 `json:"marginSumm,omitempty"`
|
||||||
TotalSumm float32 `json:"totalSumm,omitempty"`
|
TotalSumm float32 `json:"totalSumm,omitempty"`
|
||||||
AverageSumm float32 `json:"averageSumm,omitempty"`
|
AverageSumm float32 `json:"averageSumm,omitempty"`
|
||||||
OrdersCount int `json:"ordersCount,omitempty"`
|
OrdersCount int `json:"ordersCount,omitempty"`
|
||||||
CostSumm float32 `json:"costSumm,omitempty"`
|
CostSumm float32 `json:"costSumm,omitempty"`
|
||||||
MaturationTime int `json:"maturationTime,omitempty"`
|
MaturationTime int `json:"maturationTime,omitempty"`
|
||||||
FirstClientID string `json:"firstClientId,omitempty"`
|
FirstClientID string `json:"firstClientId,omitempty"`
|
||||||
LastClientID string `json:"lastClientId,omitempty"`
|
LastClientID string `json:"lastClientId,omitempty"`
|
||||||
BrowserID string `json:"browserId,omitempty"`
|
BrowserID string `json:"browserId,omitempty"`
|
||||||
MgCustomerID string `json:"mgCustomerId,omitempty"`
|
MgCustomerID string `json:"mgCustomerId,omitempty"`
|
||||||
PhotoURL string `json:"photoUrl,omitempty"`
|
PhotoURL string `json:"photoUrl,omitempty"`
|
||||||
CustomFields CustomFieldMap `json:"customFields,omitempty"`
|
CustomFields StringMap `json:"customFields,omitempty"`
|
||||||
Tags []Tag `json:"tags,omitempty"`
|
Tags []Tag `json:"tags,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CorporateCustomer type.
|
// CorporateCustomer type.
|
||||||
|
@ -197,7 +167,7 @@ type CorporateCustomer struct {
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Vip bool `json:"vip,omitempty"`
|
Vip bool `json:"vip,omitempty"`
|
||||||
Bad bool `json:"bad,omitempty"`
|
Bad bool `json:"bad,omitempty"`
|
||||||
CustomFields CustomFieldMap `json:"customFields,omitempty"`
|
CustomFields StringMap `json:"customFields,omitempty"`
|
||||||
PersonalDiscount float32 `json:"personalDiscount,omitempty"`
|
PersonalDiscount float32 `json:"personalDiscount,omitempty"`
|
||||||
DiscountCardNumber string `json:"discountCardNumber,omitempty"`
|
DiscountCardNumber string `json:"discountCardNumber,omitempty"`
|
||||||
ManagerID int `json:"managerId,omitempty"`
|
ManagerID int `json:"managerId,omitempty"`
|
||||||
|
@ -247,15 +217,6 @@ type CorporateCustomerContactCustomer struct {
|
||||||
Site string `json:"site,omitempty"`
|
Site string `json:"site,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CartCustomer type.
|
|
||||||
type CartCustomer struct {
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
|
||||||
Site string `json:"site,omitempty"`
|
|
||||||
BrowserID string `json:"browserId,omitempty"`
|
|
||||||
GaClientID string `json:"gaClientId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Company struct {
|
type Company struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
IsMain bool `json:"isMain,omitempty"`
|
IsMain bool `json:"isMain,omitempty"`
|
||||||
|
@ -267,7 +228,7 @@ type Company struct {
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Contragent *Contragent `json:"contragent,omitempty"`
|
Contragent *Contragent `json:"contragent,omitempty"`
|
||||||
Address *IdentifiersPair `json:"address,omitempty"`
|
Address *IdentifiersPair `json:"address,omitempty"`
|
||||||
CustomFields CustomFieldMap `json:"customFields,omitempty"`
|
CustomFields StringMap `json:"customFields,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// CorporateCustomerNote type.
|
// CorporateCustomerNote type.
|
||||||
|
@ -284,25 +245,15 @@ type Phone struct {
|
||||||
|
|
||||||
// CustomerHistoryRecord type.
|
// CustomerHistoryRecord type.
|
||||||
type CustomerHistoryRecord struct {
|
type CustomerHistoryRecord struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Created bool `json:"created,omitempty"`
|
Created bool `json:"created,omitempty"`
|
||||||
Deleted bool `json:"deleted,omitempty"`
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
Field string `json:"field,omitempty"`
|
Field string `json:"field,omitempty"`
|
||||||
OldValue interface{} `json:"oldValue,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
NewValue interface{} `json:"newValue,omitempty"`
|
APIKey *APIKey `json:"apiKey,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
Customer *Customer `json:"customer,omitempty"`
|
||||||
APIKey *APIKey `json:"apiKey,omitempty"`
|
|
||||||
Customer *Customer `json:"customer,omitempty"`
|
|
||||||
Address *CustomerAddressWithIsMain `json:"address,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CustomerAddressWithIsMain struct {
|
|
||||||
ID int `json:"id"`
|
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
IsMain bool `json:"isMain"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// CorporateCustomerHistoryRecord type.
|
// CorporateCustomerHistoryRecord type.
|
||||||
|
@ -313,8 +264,6 @@ type CorporateCustomerHistoryRecord struct {
|
||||||
Deleted bool `json:"deleted,omitempty"`
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
Field string `json:"field,omitempty"`
|
Field string `json:"field,omitempty"`
|
||||||
OldValue interface{} `json:"oldValue,omitempty"`
|
|
||||||
NewValue interface{} `json:"newValue,omitempty"`
|
|
||||||
User *User `json:"user,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
APIKey *APIKey `json:"apiKey,omitempty"`
|
APIKey *APIKey `json:"apiKey,omitempty"`
|
||||||
CorporateCustomer *CorporateCustomer `json:"corporateCustomer,omitempty"`
|
CorporateCustomer *CorporateCustomer `json:"corporateCustomer,omitempty"`
|
||||||
|
@ -326,7 +275,6 @@ Order related types
|
||||||
|
|
||||||
type OrderPayments map[string]OrderPayment
|
type OrderPayments map[string]OrderPayment
|
||||||
type StringMap map[string]string
|
type StringMap map[string]string
|
||||||
type CustomFieldMap map[string]interface{}
|
|
||||||
type Properties map[string]Property
|
type Properties map[string]Property
|
||||||
|
|
||||||
// Order type.
|
// Order type.
|
||||||
|
@ -378,61 +326,10 @@ type Order struct {
|
||||||
Delivery *OrderDelivery `json:"delivery,omitempty"`
|
Delivery *OrderDelivery `json:"delivery,omitempty"`
|
||||||
Marketplace *OrderMarketplace `json:"marketplace,omitempty"`
|
Marketplace *OrderMarketplace `json:"marketplace,omitempty"`
|
||||||
Items []OrderItem `json:"items,omitempty"`
|
Items []OrderItem `json:"items,omitempty"`
|
||||||
CustomFields CustomFieldMap `json:"customFields,omitempty"`
|
CustomFields StringMap `json:"customFields,omitempty"`
|
||||||
Payments OrderPayments `json:"payments,omitempty"`
|
Payments OrderPayments `json:"payments,omitempty"`
|
||||||
ApplyRound *bool `json:"applyRound,omitempty"`
|
ApplyRound *bool `json:"applyRound,omitempty"`
|
||||||
PrivilegeType string `json:"privilegeType,omitempty"`
|
PrivilegeType string `json:"privilegeType,omitempty"`
|
||||||
DialogID int `json:"dialogId,omitempty"`
|
|
||||||
Links []OrderLink `json:"links,omitempty"`
|
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// LinkedOrder type.
|
|
||||||
type LinkedOrder struct {
|
|
||||||
Number string `json:"number,omitempty"`
|
|
||||||
ExternalID string `json:"externalID,omitempty"`
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrderLink type.
|
|
||||||
type OrderLink struct {
|
|
||||||
Comment string `json:"comment,omitempty"`
|
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
|
||||||
Order LinkedOrder `json:"order,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SerializedOrderLink type.
|
|
||||||
type SerializedOrderLink struct {
|
|
||||||
Comment string `json:"comment,omitempty"`
|
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
|
||||||
Orders []LinkedOrder `json:"orders,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClearCartOrder type.
|
|
||||||
type ClearCartOrder struct {
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ExternalID string `json:"externalID,omitempty"`
|
|
||||||
Number string `json:"number,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ClientID type.
|
|
||||||
type ClientID struct {
|
|
||||||
Value string `json:"value"`
|
|
||||||
CreateAt string `json:"createAt,omitempty"`
|
|
||||||
Site string `json:"site,omitempty"`
|
|
||||||
Customer SerializedEntityCustomer `json:"customer,omitempty"`
|
|
||||||
Order LinkedOrder `json:"order,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Currency type.
|
|
||||||
type Currency struct {
|
|
||||||
Code string `json:"code,omitempty"`
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ManualConvertNominal int `json:"manualConvertNominal,omitempty"`
|
|
||||||
AutoConvertExtraPercent int `json:"autoConvertExtraPercent,omitempty"`
|
|
||||||
IsBase bool `json:"isBase,omitempty"`
|
|
||||||
IsAutoConvert bool `json:"isAutoConvert,omitempty"`
|
|
||||||
ManualConvertValue float32 `json:"manualConvertValue,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrdersStatus type.
|
// OrdersStatus type.
|
||||||
|
@ -485,59 +382,6 @@ type OrderDeliveryData struct {
|
||||||
AdditionalFields map[string]interface{}
|
AdditionalFields map[string]interface{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetCartItem type.
|
|
||||||
type SetCartItem struct {
|
|
||||||
Quantity float64 `json:"quantity,omitempty"`
|
|
||||||
Price float64 `json:"price,omitempty"`
|
|
||||||
Offer SetCartOffer `json:"offer,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCartOffer type.
|
|
||||||
type SetCartOffer struct {
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ExternalID string `json:"externalID,omitempty"`
|
|
||||||
XMLID string `json:"xmlId,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cart type.
|
|
||||||
type Cart struct {
|
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
|
||||||
DroppedAt string `json:"droppedAt,omitempty"`
|
|
||||||
ClearedAt string `json:"clearedAt,omitempty"`
|
|
||||||
Link string `json:"link,omitempty"`
|
|
||||||
Items []CartItem `json:"items,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CartItem type.
|
|
||||||
type CartItem struct {
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
Quantity float64 `json:"quantity,omitempty"`
|
|
||||||
Price float64 `json:"price,omitempty"`
|
|
||||||
Offer CartOffer `json:"offer,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CartOffer type.
|
|
||||||
type CartOffer struct {
|
|
||||||
DisplayName string `json:"displayName,omitempty"`
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
|
||||||
XMLID string `json:"xmlId,omitempty"`
|
|
||||||
Name string `json:"name,omitempty"`
|
|
||||||
Article string `json:"article,omitempty"`
|
|
||||||
VatRate string `json:"vatRate,omitempty"`
|
|
||||||
Properties StringMap `json:"properties,omitempty"`
|
|
||||||
Unit CartUnit `json:"unit,omitempty"`
|
|
||||||
Barcode string `json:"barcode,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CartUnit type.
|
|
||||||
type CartUnit struct {
|
|
||||||
Code string `json:"code"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Sym string `json:"sym"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalJSON method.
|
// UnmarshalJSON method.
|
||||||
func (v *OrderDeliveryData) UnmarshalJSON(b []byte) error {
|
func (v *OrderDeliveryData) UnmarshalJSON(b []byte) error {
|
||||||
var additionalData map[string]interface{}
|
var additionalData map[string]interface{}
|
||||||
|
@ -621,21 +465,15 @@ type OrderItem struct {
|
||||||
|
|
||||||
// OrdersHistoryRecord type.
|
// OrdersHistoryRecord type.
|
||||||
type OrdersHistoryRecord struct {
|
type OrdersHistoryRecord struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Created bool `json:"created,omitempty"`
|
Created bool `json:"created,omitempty"`
|
||||||
Deleted bool `json:"deleted,omitempty"`
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
Field string `json:"field,omitempty"`
|
Field string `json:"field,omitempty"`
|
||||||
OldValue interface{} `json:"oldValue,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
NewValue interface{} `json:"newValue,omitempty"`
|
APIKey *APIKey `json:"apiKey,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
Order *Order `json:"order,omitempty"`
|
||||||
APIKey *APIKey `json:"apiKey,omitempty"`
|
|
||||||
Order *Order `json:"order,omitempty"`
|
|
||||||
Ancestor *Order `json:"ancestor,omitempty"`
|
|
||||||
Item *OrderItem `json:"item,omitempty"`
|
|
||||||
Payment *Payment `json:"payment"`
|
|
||||||
CombinedTo *Order `json:"combinedTo,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pack type.
|
// Pack type.
|
||||||
|
@ -661,16 +499,14 @@ type PackItem struct {
|
||||||
|
|
||||||
// PacksHistoryRecord type.
|
// PacksHistoryRecord type.
|
||||||
type PacksHistoryRecord struct {
|
type PacksHistoryRecord struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Created bool `json:"created,omitempty"`
|
Created bool `json:"created,omitempty"`
|
||||||
Deleted bool `json:"deleted,omitempty"`
|
Deleted bool `json:"deleted,omitempty"`
|
||||||
Source string `json:"source,omitempty"`
|
Source string `json:"source,omitempty"`
|
||||||
Field string `json:"field,omitempty"`
|
Field string `json:"field,omitempty"`
|
||||||
OldValue interface{} `json:"oldValue,omitempty"`
|
User *User `json:"user,omitempty"`
|
||||||
NewValue interface{} `json:"newValue,omitempty"`
|
Pack *Pack `json:"pack,omitempty"`
|
||||||
User *User `json:"user,omitempty"`
|
|
||||||
Pack *Pack `json:"pack,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Offer type.
|
// Offer type.
|
||||||
|
@ -693,7 +529,6 @@ type Offer struct {
|
||||||
Prices []OfferPrice `json:"prices,omitempty"`
|
Prices []OfferPrice `json:"prices,omitempty"`
|
||||||
Images []string `json:"images,omitempty"`
|
Images []string `json:"images,omitempty"`
|
||||||
Unit *Unit `json:"unit,omitempty"`
|
Unit *Unit `json:"unit,omitempty"`
|
||||||
Product *Product `json:"product,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inventory type.
|
// Inventory type.
|
||||||
|
@ -723,7 +558,6 @@ type OfferPrice struct {
|
||||||
Price float32 `json:"price,omitempty"`
|
Price float32 `json:"price,omitempty"`
|
||||||
Ordering int `json:"ordering,omitempty"`
|
Ordering int `json:"ordering,omitempty"`
|
||||||
PriceType string `json:"priceType,omitempty"`
|
PriceType string `json:"priceType,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OfferPriceUpload type.
|
// OfferPriceUpload type.
|
||||||
|
@ -763,7 +597,6 @@ type User struct {
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
Active bool `json:"active,omitempty"`
|
Active bool `json:"active,omitempty"`
|
||||||
Online bool `json:"online,omitempty"`
|
Online bool `json:"online,omitempty"`
|
||||||
Position string `json:"position,omitempty"`
|
|
||||||
IsAdmin bool `json:"isAdmin,omitempty"`
|
IsAdmin bool `json:"isAdmin,omitempty"`
|
||||||
IsManager bool `json:"isManager,omitempty"`
|
IsManager bool `json:"isManager,omitempty"`
|
||||||
Email string `json:"email,omitempty"`
|
Email string `json:"email,omitempty"`
|
||||||
|
@ -872,16 +705,10 @@ type WorkTime struct {
|
||||||
LunchEndTime string `json:"lunch_end_time"`
|
LunchEndTime string `json:"lunch_end_time"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NonWorkingDays type.
|
|
||||||
type NonWorkingDays struct {
|
|
||||||
StartDate string `json:"start_date"`
|
|
||||||
EndDate string `json:"end_date"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SerializedBaseLoyaltyAccount struct {
|
type SerializedBaseLoyaltyAccount struct {
|
||||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||||
CardNumber string `json:"cardNumber,omitempty"`
|
CardNumber string `json:"cardNumber,omitempty"`
|
||||||
CustomFields []interface{} `json:"customFields,omitempty"`
|
CustomFields []string `json:"customFields,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SerializedCreateLoyaltyAccount struct {
|
type SerializedCreateLoyaltyAccount struct {
|
||||||
|
@ -893,29 +720,12 @@ type SerializedEditLoyaltyAccount struct {
|
||||||
SerializedBaseLoyaltyAccount
|
SerializedBaseLoyaltyAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChannelSetting struct {
|
|
||||||
Site string `json:"site"`
|
|
||||||
OrderType string `json:"order_type"`
|
|
||||||
OrderMethod string `json:"order_method"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MgOrderCreationSettings struct {
|
|
||||||
Channels map[int]ChannelSetting `json:"channels"`
|
|
||||||
Default ChannelSetting `json:"default"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MgSettings struct {
|
|
||||||
OrderCreation MgOrderCreationSettings `json:"order_creation"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Settings type. Contains retailCRM configuration.
|
// Settings type. Contains retailCRM configuration.
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
DefaultCurrency SettingsNode `json:"default_currency"`
|
DefaultCurrency SettingsNode `json:"default_currency"`
|
||||||
SystemLanguage SettingsNode `json:"system_language"`
|
SystemLanguage SettingsNode `json:"system_language"`
|
||||||
Timezone SettingsNode `json:"timezone"`
|
Timezone SettingsNode `json:"timezone"`
|
||||||
MgSettings MgSettings `json:"mg"`
|
WorkTimes []WorkTime `json:"work_times"`
|
||||||
WorkTimes []WorkTime `json:"work_times"`
|
|
||||||
NonWorkingDays []NonWorkingDays `json:"non_working_days"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -977,7 +787,6 @@ type DeliveryType struct {
|
||||||
DeliveryServices []string `json:"deliveryServices,omitempty"`
|
DeliveryServices []string `json:"deliveryServices,omitempty"`
|
||||||
PaymentTypes []string `json:"paymentTypes,omitempty"` // Deprecated, use DeliveryPaymentTypes
|
PaymentTypes []string `json:"paymentTypes,omitempty"` // Deprecated, use DeliveryPaymentTypes
|
||||||
DeliveryPaymentTypes []DeliveryPaymentType `json:"deliveryPaymentTypes,omitempty"`
|
DeliveryPaymentTypes []DeliveryPaymentType `json:"deliveryPaymentTypes,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type DeliveryPaymentType struct {
|
type DeliveryPaymentType struct {
|
||||||
|
@ -1008,8 +817,8 @@ type LegalEntity struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SerializedEntityCustomer struct {
|
type SerializedEntityCustomer struct {
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
ExternalID int `json:"externalId,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// OrderMethod type.
|
// OrderMethod type.
|
||||||
|
@ -1067,7 +876,6 @@ type PriceType struct {
|
||||||
Ordering int `json:"ordering,omitempty"`
|
Ordering int `json:"ordering,omitempty"`
|
||||||
Groups []string `json:"groups,omitempty"`
|
Groups []string `json:"groups,omitempty"`
|
||||||
Geo []GeoHierarchyRow `json:"geo,omitempty"`
|
Geo []GeoHierarchyRow `json:"geo,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProductStatus type.
|
// ProductStatus type.
|
||||||
|
@ -1121,7 +929,6 @@ type Site struct {
|
||||||
IsDemo bool `json:"isDemo,omitempty"`
|
IsDemo bool `json:"isDemo,omitempty"`
|
||||||
CatalogID string `json:"catalogId,omitempty"`
|
CatalogID string `json:"catalogId,omitempty"`
|
||||||
IsCatalogMainSite bool `json:"isCatalogMainSite,omitempty"`
|
IsCatalogMainSite bool `json:"isCatalogMainSite,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store type.
|
// Store type.
|
||||||
|
@ -1153,33 +960,24 @@ type ProductGroup struct {
|
||||||
|
|
||||||
// BaseProduct type.
|
// BaseProduct type.
|
||||||
type BaseProduct struct {
|
type BaseProduct struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
Type ProductType `json:"type,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
URL string `json:"url,omitempty"`
|
Article string `json:"article,omitempty"`
|
||||||
Article string `json:"article,omitempty"`
|
ExternalID string `json:"externalId,omitempty"`
|
||||||
ExternalID string `json:"externalId,omitempty"`
|
Manufacturer string `json:"manufacturer,omitempty"`
|
||||||
Manufacturer string `json:"manufacturer,omitempty"`
|
Description string `json:"description,omitempty"`
|
||||||
Description string `json:"description,omitempty"`
|
Popular bool `json:"popular,omitempty"`
|
||||||
Popular bool `json:"popular,omitempty"`
|
Stock bool `json:"stock,omitempty"`
|
||||||
Stock bool `json:"stock,omitempty"`
|
Novelty bool `json:"novelty,omitempty"`
|
||||||
Novelty bool `json:"novelty,omitempty"`
|
Recommended bool `json:"recommended,omitempty"`
|
||||||
Recommended bool `json:"recommended,omitempty"`
|
Active bool `json:"active,omitempty"`
|
||||||
Active bool `json:"active,omitempty"`
|
Markable bool `json:"markable,omitempty"`
|
||||||
Markable bool `json:"markable,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ProductType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
RegularProduct ProductType = "product"
|
|
||||||
ServiceProduct ProductType = "service"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Product type.
|
// Product type.
|
||||||
type Product struct {
|
type Product struct {
|
||||||
BaseProduct
|
BaseProduct
|
||||||
ID int `json:"id,omitempty"`
|
ID int `json:"id,omitempty"`
|
||||||
Type ProductType `json:"type"`
|
|
||||||
MaxPrice float32 `json:"maxPrice,omitempty"`
|
MaxPrice float32 `json:"maxPrice,omitempty"`
|
||||||
MinPrice float32 `json:"minPrice,omitempty"`
|
MinPrice float32 `json:"minPrice,omitempty"`
|
||||||
ImageURL string `json:"imageUrl,omitempty"`
|
ImageURL string `json:"imageUrl,omitempty"`
|
||||||
|
@ -1350,21 +1148,11 @@ type Action struct {
|
||||||
|
|
||||||
// MgTransport type.
|
// MgTransport type.
|
||||||
type MgTransport struct {
|
type MgTransport struct {
|
||||||
WebhookURL string `json:"webhookUrl,omitempty"`
|
WebhookURL string `json:"webhookUrl,omitempty"`
|
||||||
RefreshToken bool `json:"refreshToken,omitempty"`
|
|
||||||
Actions *MgTransportActions `json:"actions,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MgTransportActions struct {
|
|
||||||
Visits string `json:"visits,omitempty"`
|
|
||||||
Online string `json:"online,omitempty"`
|
|
||||||
ManualTemplatesSync string `json:"manualTemplatesSync,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MgBot type.
|
// MgBot type.
|
||||||
type MgBot struct {
|
type MgBot struct{}
|
||||||
RefreshToken bool `json:"refreshToken,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Cost related types
|
Cost related types
|
||||||
|
@ -1425,13 +1213,11 @@ type CustomFields struct {
|
||||||
InGroupActions bool `json:"inGroupActions,omitempty"`
|
InGroupActions bool `json:"inGroupActions,omitempty"`
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Entity string `json:"entity,omitempty"`
|
Entity string `json:"entity,omitempty"`
|
||||||
// Deprecated: Use DefaultTyped instead.
|
Default string `json:"default,omitempty"`
|
||||||
Default string `json:"default,omitempty"`
|
Ordering int `json:"ordering,omitempty"`
|
||||||
Ordering int `json:"ordering,omitempty"`
|
DisplayArea string `json:"displayArea,omitempty"`
|
||||||
DisplayArea string `json:"displayArea,omitempty"`
|
ViewMode string `json:"viewMode,omitempty"`
|
||||||
ViewMode string `json:"viewMode,omitempty"`
|
Dictionary string `json:"dictionary,omitempty"`
|
||||||
Dictionary string `json:"dictionary,omitempty"`
|
|
||||||
DefaultTyped interface{} `json:"default_typed,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1458,45 +1244,6 @@ type Activity struct {
|
||||||
Freeze bool `json:"freeze"`
|
Freeze bool `json:"freeze"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatCustomerOnline struct {
|
|
||||||
LastOnline SystemTime `json:"lastOnline"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatVisitsResponse struct {
|
|
||||||
UTM *ChatUTM `json:"utm,omitempty"`
|
|
||||||
Device ChatDevice `json:"device"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
City string `json:"city"`
|
|
||||||
LastVisit ChatLastVisit `json:"lastVisit"`
|
|
||||||
CountVisits uint `json:"countVisits"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatLastVisit struct {
|
|
||||||
CreatedAt SystemTime `json:"createdAt"`
|
|
||||||
EndedAt *SystemTime `json:"endedAt,omitempty"`
|
|
||||||
Source string `json:"source"`
|
|
||||||
Pages []ChatVisitedPage `json:"pages"`
|
|
||||||
Duration uint `json:"duration"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatVisitedPage struct {
|
|
||||||
DateTime SystemTime `json:"dateTime"`
|
|
||||||
Title string `json:"title,omitempty"`
|
|
||||||
URL string `json:"url"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatDevice struct {
|
|
||||||
Lang string `json:"lang"`
|
|
||||||
Browser string `json:"browser"`
|
|
||||||
OS string `json:"os"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ChatUTM struct {
|
|
||||||
Source string `json:"source"`
|
|
||||||
Medium string `json:"medium"`
|
|
||||||
Campaign string `json:"campaign"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tag struct.
|
// Tag struct.
|
||||||
type Tag struct {
|
type Tag struct {
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
|
@ -1556,22 +1303,22 @@ type DeliveryTypeInfo struct {
|
||||||
|
|
||||||
// LoyaltyAccount type.
|
// LoyaltyAccount type.
|
||||||
type LoyaltyAccount struct {
|
type LoyaltyAccount struct {
|
||||||
Active bool `json:"active"`
|
Active bool `json:"active"`
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||||
CardNumber string `json:"cardNumber,omitempty"`
|
CardNumber string `json:"cardNumber,omitempty"`
|
||||||
Amount float64 `json:"amount,omitempty"`
|
Amount float64 `json:"amount,omitempty"`
|
||||||
LoyaltyLevel LoyaltyLevel `json:"level,omitempty"`
|
LoyaltyLevel LoyaltyLevel `json:"level,omitempty"`
|
||||||
CreatedAt string `json:"createdAt,omitempty"`
|
CreatedAt string `json:"createdAt,omitempty"`
|
||||||
ActivatedAt string `json:"activatedAt,omitempty"`
|
ActivatedAt string `json:"activatedAt,omitempty"`
|
||||||
ConfirmedPhoneAt string `json:"confirmedPhoneAt,omitempty"`
|
ConfirmedPhoneAt string `json:"confirmedPhoneAt,omitempty"`
|
||||||
LastCheckID int `json:"lastCheckId,omitempty"`
|
LastCheckID int `json:"lastCheckId,omitempty"`
|
||||||
CustomFields CustomFieldMap `json:"customFields,omitempty"`
|
CustomFields []string `json:"customFields,omitempty"`
|
||||||
Loyalty Loyalty `json:"loyalty,omitempty"`
|
Loyalty Loyalty `json:"loyalty,omitempty"`
|
||||||
Customer Customer `json:"customer,omitempty"`
|
Customer Customer `json:"customer,omitempty"`
|
||||||
Status string `json:"status,omitempty"`
|
Status string `json:"status,omitempty"`
|
||||||
OrderSum float64 `json:"orderSum,omitempty"`
|
OrderSum float64 `json:"orderSum,omitempty"`
|
||||||
NextLevelSum float64 `json:"nextLevelSum,omitempty"`
|
NextLevelSum float64 `json:"nextLevelSum,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loyalty type.
|
// Loyalty type.
|
||||||
|
@ -1587,7 +1334,6 @@ type Loyalty struct {
|
||||||
ActivatedAt string `json:"activatedAt,omitempty"`
|
ActivatedAt string `json:"activatedAt,omitempty"`
|
||||||
DeactivatedAt string `json:"deactivatedAt,omitempty"`
|
DeactivatedAt string `json:"deactivatedAt,omitempty"`
|
||||||
BlockedAt string `json:"blockedAt,omitempty"`
|
BlockedAt string `json:"blockedAt,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LoyaltyLevel type.
|
// LoyaltyLevel type.
|
||||||
|
@ -1631,7 +1377,6 @@ type SerializedLoyaltyOrder struct {
|
||||||
Delivery Delivery `json:"delivery,omitempty"`
|
Delivery Delivery `json:"delivery,omitempty"`
|
||||||
Site string `json:"site,omitempty"`
|
Site string `json:"site,omitempty"`
|
||||||
Items []LoyaltyItems `json:"items,omitempty"`
|
Items []LoyaltyItems `json:"items,omitempty"`
|
||||||
Currency string `json:"currency,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type LoyaltyEventDiscount struct {
|
type LoyaltyEventDiscount struct {
|
||||||
|
@ -1689,31 +1434,3 @@ type ExternalID struct {
|
||||||
|
|
||||||
type UserGroupType string
|
type UserGroupType string
|
||||||
type NotificationType string
|
type NotificationType string
|
||||||
|
|
||||||
type MGChannel struct {
|
|
||||||
Type string `json:"type"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
ID int `json:"id"`
|
|
||||||
ExternalID int `json:"externalId"`
|
|
||||||
AllowedSendByPhone bool `json:"allowedSendByPhone"`
|
|
||||||
Active bool `json:"active"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type MGChannelTemplate struct {
|
|
||||||
Channel *MGChannel `json:"channel,omitempty"`
|
|
||||||
Header *Header `json:"header"`
|
|
||||||
Lang string `json:"lang"`
|
|
||||||
Category string `json:"category"`
|
|
||||||
Code string `json:"code,omitempty"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Namespace string `json:"namespace,omitempty"`
|
|
||||||
Footer string `json:"footer,omitempty"`
|
|
||||||
VerificationStatus string `json:"verificationStatus,omitempty"`
|
|
||||||
BodyTemplate TemplateItemList `json:"template"`
|
|
||||||
Buttons []Button `json:"buttons,omitempty"`
|
|
||||||
BodyTemplateExample []string `json:"templateExample"`
|
|
||||||
ID int `json:"id,omitempty"`
|
|
||||||
ExternalID int `json:"externalId,omitempty"`
|
|
||||||
MGChannelID int `json:"mgChannelId"`
|
|
||||||
Active bool `json:"active"`
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue