mirror of
https://github.com/retailcrm/api-client-go.git
synced 2024-11-21 20:36:03 +03:00
files upload support
This commit is contained in:
parent
ddf8ee7cef
commit
2f06836bd4
262
v5/client.go
262
v5/client.go
@ -1,8 +1,10 @@
|
||||
package v5
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
@ -12,6 +14,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/retailcrm/api-client-go/errs"
|
||||
)
|
||||
|
||||
@ -73,23 +76,46 @@ func (c *Client) GetRequest(urlWithParameters string, versioned ...bool) ([]byte
|
||||
return res, resp.StatusCode, failure
|
||||
}
|
||||
|
||||
// PostRequest implements POST Request
|
||||
func (c *Client) PostRequest(url string, postParams url.Values) ([]byte, int, *errs.Failure) {
|
||||
var res []byte
|
||||
var prefix = "/api/v5"
|
||||
// PostRequest implements POST Request with generic body data
|
||||
func (c *Client) PostRequest(uri string, postData interface{}, contType ...string) ([]byte, int, *errs.Failure) {
|
||||
var (
|
||||
res []byte
|
||||
contentType string
|
||||
reader io.Reader
|
||||
)
|
||||
|
||||
prefix := "/api/v5"
|
||||
failure := &errs.Failure{}
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s%s", c.URL, prefix, url), strings.NewReader(postParams.Encode()))
|
||||
if len(contType) > 0 {
|
||||
contentType = contType[0]
|
||||
} else {
|
||||
contentType = "application/x-www-form-urlencoded"
|
||||
}
|
||||
|
||||
switch postData.(type) {
|
||||
case url.Values:
|
||||
reader = strings.NewReader(postData.(url.Values).Encode())
|
||||
default:
|
||||
if i, ok := postData.(io.Reader); ok {
|
||||
reader = i
|
||||
} else {
|
||||
failure.SetRuntimeError(errors.New("postData should be url.Values or implement io.Reader"))
|
||||
return []byte{}, 0, failure
|
||||
}
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("POST", fmt.Sprintf("%s%s%s", c.URL, prefix, uri), reader)
|
||||
if err != nil {
|
||||
failure.SetRuntimeError(err)
|
||||
return res, 0, failure
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.Header.Set("Content-Type", contentType)
|
||||
req.Header.Set("X-API-KEY", c.Key)
|
||||
|
||||
if c.Debug {
|
||||
log.Printf("API Request: %s %s %s", url, c.Key, postParams.Encode())
|
||||
log.Printf("API Request: %s %s", uri, c.Key)
|
||||
}
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
@ -3941,6 +3967,228 @@ func (c *Client) CostEdit(id int, cost CostRecord, site ...string) (CreateRespon
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// Files returns files list
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// data, status, err := client.Files(FilesRequest{
|
||||
// Filter: FilesFilter{
|
||||
// Filename: "image.jpeg",
|
||||
// },
|
||||
// })
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
func (c *Client) Files(files FilesRequest) (FilesResponse, int, *errs.Failure) {
|
||||
var resp FilesResponse
|
||||
|
||||
params, _ := query.Values(files)
|
||||
|
||||
data, status, err := c.GetRequest(fmt.Sprintf("/files?%s", params.Encode()))
|
||||
|
||||
if err != nil && err.Error() != "" {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &resp)
|
||||
|
||||
if resp.Success == false {
|
||||
buildErr(data, err)
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// FileUpload uploads file to retailCRM
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// file, err := os.Open("file.jpg")
|
||||
// if err != nil {
|
||||
// fmt.Print(err)
|
||||
// }
|
||||
//
|
||||
// data, status, err := client.FileUpload(file)
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
func (c *Client) FileUpload(reader io.Reader) (FileUploadResponse, int, *errs.Failure) {
|
||||
var resp FileUploadResponse
|
||||
|
||||
data, status, err := c.PostRequest(fmt.Sprintf("/files/upload?apiKey=%s", c.Key), reader, "application/octet-stream")
|
||||
|
||||
if err != nil && err.Error() != "" {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &resp)
|
||||
|
||||
if resp.Success == false {
|
||||
buildErr(data, err)
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// File returns a file info
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// data, status, err := client.File(112)
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
//
|
||||
// if data.Success == true {
|
||||
// fmt.Printf("%v\n", data.File)
|
||||
// }
|
||||
func (c *Client) File(id int) (FileResponse, int, *errs.Failure) {
|
||||
var resp FileResponse
|
||||
|
||||
data, status, err := c.GetRequest(fmt.Sprintf("/files/%d", id))
|
||||
if err.Error() != "" {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &resp)
|
||||
|
||||
if resp.Success == false {
|
||||
buildErr(data, err)
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// FileDelete removes file from retailCRM
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// data, status, err := client.FileDelete(123)
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
func (c *Client) FileDelete(id int) (SuccessfulResponse, int, *errs.Failure) {
|
||||
var resp SuccessfulResponse
|
||||
|
||||
data, status, err := c.PostRequest(fmt.Sprintf("/files/%d/delete", id), strings.NewReader(""))
|
||||
|
||||
if err != nil && err.Error() != "" {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &resp)
|
||||
|
||||
if resp.Success == false {
|
||||
buildErr(data, err)
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// FileDownload downloads file from retailCRM
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// fileData, status, err := client.FileDownload(123)
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
func (c *Client) FileDownload(id int) (io.ReadCloser, int, *errs.Failure) {
|
||||
data, status, err := c.GetRequest(fmt.Sprintf("/files/%d/download", id))
|
||||
if status != http.StatusOK {
|
||||
return nil, status, err
|
||||
}
|
||||
|
||||
closer := ioutil.NopCloser(bytes.NewReader(data))
|
||||
return closer, status, nil
|
||||
}
|
||||
|
||||
// FileEdit edits file name and relations with orders and customers in retailCRM
|
||||
//
|
||||
// For more information see https://help.retailcrm.pro/Developers/ApiVersion5#get--api-v5-files
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// var client = v5.New("https://demo.url", "09jIJ")
|
||||
//
|
||||
// data, status, err := client.FileEdit(123, File{Filename: "image2.jpg"})
|
||||
//
|
||||
// if err.Error() != "" {
|
||||
// fmt.Printf("%v", err.RuntimeErr)
|
||||
// }
|
||||
//
|
||||
// if status >= http.StatusBadRequest {
|
||||
// fmt.Printf("%v", err.ApiErr())
|
||||
// }
|
||||
func (c *Client) FileEdit(id int, file File) (FileResponse, int, *errs.Failure) {
|
||||
var resp FileResponse
|
||||
|
||||
req, _ := json.Marshal(file)
|
||||
data, status, err := c.PostRequest(fmt.Sprintf("/files/%d/edit", id), bytes.NewReader(req))
|
||||
|
||||
if err != nil && err.Error() != "" {
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
json.Unmarshal(data, &resp)
|
||||
|
||||
if resp.Success == false {
|
||||
buildErr(data, err)
|
||||
return resp, status, err
|
||||
}
|
||||
|
||||
return resp, status, nil
|
||||
}
|
||||
|
||||
// CustomFields returns list of custom fields
|
||||
//
|
||||
// For more information see http://www.retailcrm.pro/docs/Developers/ApiVersion5#get--api-v5-custom-fields
|
||||
|
@ -3,12 +3,14 @@ package v5
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -4750,6 +4752,297 @@ func TestClient_CostsUpload_Fail(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_Files(t *testing.T) {
|
||||
c := client()
|
||||
fileID := 14925
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Get("/files").
|
||||
MatchParam("filter[ids][]", strconv.Itoa(fileID)).
|
||||
MatchParam("limit", "20").
|
||||
MatchParam("page", "1").
|
||||
Reply(200).
|
||||
BodyString(`{
|
||||
"success": true,
|
||||
"pagination": {
|
||||
"limit": 20,
|
||||
"totalCount": 0,
|
||||
"currentPage": 1,
|
||||
"totalPageCount": 0
|
||||
},
|
||||
"files": []
|
||||
}`)
|
||||
|
||||
_, status, err := c.Files(FilesRequest{
|
||||
Limit: 20,
|
||||
Page: 1,
|
||||
Filter: FilesFilter{
|
||||
Ids: []int{fileID},
|
||||
},
|
||||
})
|
||||
|
||||
if status != 200 {
|
||||
t.Errorf("%v %v", err.Error(), err.ApiError())
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FileUpload(t *testing.T) {
|
||||
c := client()
|
||||
file := strings.NewReader(`test file contents`)
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Post("/files/upload").
|
||||
Reply(200).
|
||||
BodyString(`{"success": true, "file": {"id": 1}}`)
|
||||
|
||||
data, status, err := c.FileUpload(file)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if data.Success != true {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if data.File.ID != 1 {
|
||||
t.Error("invalid file id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FileUploadFail(t *testing.T) {
|
||||
c := client()
|
||||
file := strings.NewReader(`test file contents`)
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Post("/files/upload").
|
||||
Reply(400).
|
||||
BodyString(`{"success": false, "errorMsg": "error"}`)
|
||||
|
||||
_, status, err := c.FileUpload(file)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusBadRequest {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusBadRequest, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_File(t *testing.T) {
|
||||
c := client()
|
||||
invalidFile := 20
|
||||
fileResponse := &FileResponse{
|
||||
Success: true,
|
||||
File: &File{
|
||||
ID: 19,
|
||||
Filename: "image.jpg",
|
||||
Type: "image/jpeg",
|
||||
CreatedAt: time.Now().String(),
|
||||
Size: 10000,
|
||||
Attachment: nil,
|
||||
},
|
||||
}
|
||||
respData, errr := json.Marshal(fileResponse)
|
||||
if errr != nil {
|
||||
t.Errorf("%v", errr.Error())
|
||||
}
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Get(fmt.Sprintf("/files/%d", fileResponse.File.ID)).
|
||||
Reply(200).
|
||||
BodyString(string(respData))
|
||||
|
||||
gock.New(crmURL).
|
||||
Get(fmt.Sprintf("/files/%d", invalidFile)).
|
||||
Reply(404).
|
||||
BodyString(`{"success": false, "errorMsg": "Not Found"}`)
|
||||
|
||||
s, status, err := c.File(fileResponse.File.ID)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if s.Success != true {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if s.File.ID != fileResponse.File.ID {
|
||||
t.Error("invalid response data")
|
||||
}
|
||||
|
||||
s, status, err = c.File(invalidFile)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusNotFound {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusNotFound, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FileDelete(t *testing.T) {
|
||||
c := client()
|
||||
successful := 19
|
||||
badRequest := 20
|
||||
notFound := 21
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Post(fmt.Sprintf("/files/%d/delete", successful)).
|
||||
Reply(200).
|
||||
BodyString(`{"success": true}`)
|
||||
|
||||
gock.New(crmURL).
|
||||
Post(fmt.Sprintf("/files/%d/delete", badRequest)).
|
||||
Reply(400).
|
||||
BodyString(`{"success": false, "errorMsg": "Error"}`)
|
||||
|
||||
gock.New(crmURL).
|
||||
Post(fmt.Sprintf("/files/%d/delete", notFound)).
|
||||
Reply(404).
|
||||
BodyString(`{"success": false, "errorMsg": "Not Found"}`)
|
||||
|
||||
data, status, err := c.FileDelete(successful)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if data.Success != true {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
data, status, err = c.FileDelete(badRequest)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusBadRequest {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusBadRequest, status)
|
||||
}
|
||||
|
||||
data, status, err = c.FileDelete(notFound)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusNotFound {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusNotFound, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FileDownload(t *testing.T) {
|
||||
c := client()
|
||||
successful := 19
|
||||
fail := 20
|
||||
fileData := "file data"
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Get(fmt.Sprintf("/files/%d/download", successful)).
|
||||
Reply(200).
|
||||
BodyString(fileData)
|
||||
|
||||
gock.New(crmURL).
|
||||
Get(fmt.Sprintf("/files/%d/download", fail)).
|
||||
Reply(400).
|
||||
BodyString("")
|
||||
|
||||
data, status, err := c.FileDownload(successful)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
fetchedByte, errr := ioutil.ReadAll(data)
|
||||
if errr != nil {
|
||||
t.Error(errr)
|
||||
}
|
||||
|
||||
fetched := string(fetchedByte)
|
||||
if fetched != fileData {
|
||||
t.Error("file data mismatch")
|
||||
}
|
||||
|
||||
data, status, err = c.FileDownload(fail)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusBadRequest {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusBadRequest, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_FileEdit(t *testing.T) {
|
||||
c := client()
|
||||
successful := 19
|
||||
fail := 20
|
||||
resp := FileResponse{
|
||||
Success: true,
|
||||
File: &File{Filename: "image.jpg"},
|
||||
}
|
||||
respData, _ := json.Marshal(resp)
|
||||
|
||||
defer gock.Off()
|
||||
|
||||
gock.New(crmURL).
|
||||
Post(fmt.Sprintf("/files/%d/edit", successful)).
|
||||
Reply(200).
|
||||
BodyString(string(respData))
|
||||
|
||||
gock.New(crmURL).
|
||||
Post(fmt.Sprintf("/files/%d/edit", fail)).
|
||||
Reply(404).
|
||||
BodyString(`{"success": false, "errorMsg": "Not Found"}`)
|
||||
|
||||
data, status, err := c.FileEdit(successful, *resp.File)
|
||||
if err.Error() != "" {
|
||||
t.Errorf("%v", err.Error())
|
||||
}
|
||||
|
||||
if status != http.StatusOK {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if data.Success != true {
|
||||
t.Errorf("%v", err.ApiError())
|
||||
}
|
||||
|
||||
if data.File.Filename != resp.File.Filename {
|
||||
t.Errorf("filename should be `%s`, got `%s` instead", resp.File.Filename, data.File.Filename)
|
||||
}
|
||||
|
||||
data, status, err = c.FileEdit(fail, *resp.File)
|
||||
if status != http.StatusNotFound {
|
||||
t.Errorf("status should be `%d`, got `%d` instead", http.StatusNotFound, status)
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_CustomFields(t *testing.T) {
|
||||
c := client()
|
||||
|
||||
|
@ -318,6 +318,23 @@ type CostsFilter struct {
|
||||
OrderExternalIds []string `url:"orderIds,omitempty,brackets"`
|
||||
}
|
||||
|
||||
// FilesFilter type
|
||||
type FilesFilter struct {
|
||||
Ids []int `url:"ids,omitempty,brackets"`
|
||||
OrderIds []int `url:"orderIds,omitempty,brackets"`
|
||||
OrderExternalIds []string `url:"orderExternalIds,omitempty,brackets"`
|
||||
CustomerIds []int `url:"customerIds,omitempty,brackets"`
|
||||
CustomerExternalIds []string `url:"customerExternalIds,omitempty,brackets"`
|
||||
CreatedAtFrom string `url:"createdAtFrom,omitempty"`
|
||||
CreatedAtTo string `url:"createdAtTo,omitempty"`
|
||||
SizeFrom int `url:"sizeFrom,omitempty"`
|
||||
SizeTo int `url:"sizeTo,omitempty"`
|
||||
Type []string `url:"type,omitempty,brackets"`
|
||||
Filename string `url:"filename,omitempty"`
|
||||
IsAttached string `url:"isAttached,omitempty"`
|
||||
Sites []string `url:"sites,omitempty,brackets"`
|
||||
}
|
||||
|
||||
// CustomFieldsFilter type
|
||||
type CustomFieldsFilter struct {
|
||||
Name string `url:"name,omitempty"`
|
||||
|
@ -150,6 +150,13 @@ type CostsRequest struct {
|
||||
Page int `url:"page,omitempty"`
|
||||
}
|
||||
|
||||
// FilesRequest type
|
||||
type FilesRequest struct {
|
||||
Filter FilesFilter `url:"filter,omitempty"`
|
||||
Limit int `url:"limit,omitempty"`
|
||||
Page int `url:"page,omitempty"`
|
||||
}
|
||||
|
||||
// CustomFieldsRequest type
|
||||
type CustomFieldsRequest struct {
|
||||
Filter CustomFieldsFilter `url:"filter,omitempty"`
|
||||
|
@ -367,6 +367,25 @@ type CostResponse struct {
|
||||
Cost *Cost `json:"cost,omitempty,brackets"`
|
||||
}
|
||||
|
||||
// FilesResponse type
|
||||
type FilesResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Pagination *Pagination `json:"pagination,omitempty"`
|
||||
Files []File `json:"files,omitempty,brackets"`
|
||||
}
|
||||
|
||||
// FileUpload response
|
||||
type FileUploadResponse struct {
|
||||
Success bool `json:"success"`
|
||||
File *File `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
// FileResponse type
|
||||
type FileResponse struct {
|
||||
Success bool `json:"success"`
|
||||
File *File `json:"file,omitempty"`
|
||||
}
|
||||
|
||||
// CustomFieldsResponse type
|
||||
type CustomFieldsResponse struct {
|
||||
Success bool `json:"success"`
|
||||
@ -401,6 +420,6 @@ type CustomFieldResponse struct {
|
||||
|
||||
// UnitsResponse type
|
||||
type UnitsResponse struct {
|
||||
Success bool `json:"success"`
|
||||
Units *[]Unit `json:"units,omitempty,brackets"`
|
||||
Success bool `json:"success"`
|
||||
Units *[]Unit `json:"units,omitempty,brackets"`
|
||||
}
|
||||
|
16
v5/types.go
16
v5/types.go
@ -923,6 +923,22 @@ type Cost struct {
|
||||
Sites []string `json:"sites,omitempty,brackets"`
|
||||
}
|
||||
|
||||
// File type
|
||||
type File struct {
|
||||
ID int `json:"id,omitempty"`
|
||||
Filename string `json:"filename,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
CreatedAt string `json:"createdAt,omitempty"`
|
||||
Size int `json:"size,omitempty"`
|
||||
Attachment []Attachment `json:"attachment,omitempty"`
|
||||
}
|
||||
|
||||
// Attachment type
|
||||
type Attachment struct {
|
||||
Customer *Customer `json:"customer,omitempty"`
|
||||
Order *Order `json:"order,omitempty"`
|
||||
}
|
||||
|
||||
// CustomFields type
|
||||
type CustomFields struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
|
Loading…
Reference in New Issue
Block a user