add new API methods & new parameters

This commit is contained in:
Pavel 2023-09-06 15:44:19 +03:00 committed by GitHub
commit c2a33378b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 823 additions and 9 deletions

1
api-client-go Submodule

@ -0,0 +1 @@
Subproject commit 5c6d2ebead217f5916767a9a542117fa496c677b

317
client.go
View File

@ -2109,6 +2109,323 @@ func (c *Client) IntegrationModule(code string) (IntegrationModuleResponse, int,
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(&currency)
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(&currency)
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
//
// For more information see http://www.simla.com/docs/Developers/API/APIVersions/APIv5#get--api-v5-integration-modules-code

View File

@ -1988,6 +1988,419 @@ func TestClient_OrdersOrders_Fail(t *testing.T) {
}
}
func TestClient_LinksCreate(t *testing.T) {
c := client()
orders := []LinkedOrder{{ID: 10}, {ID: 12}}
link := SerializedOrderLink{
Comment: "comment",
Orders: orders,
}
linkJSON, _ := json.Marshal(link)
p := url.Values{
"link": {string(linkJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/links/create").
BodyString(p.Encode()).
Reply(201).
BodyString(`{"success": true}`)
data, status, err := c.LinksCreate(link)
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
}
func TestClient_LinksCreate_Fail(t *testing.T) {
c := client()
orders := []LinkedOrder{{ID: 10}}
link := SerializedOrderLink{
Comment: "comment",
Orders: orders,
}
linkJSON, _ := json.Marshal(link)
p := url.Values{
"link": {string(linkJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/links/create").
BodyString(p.Encode()).
Reply(400).
BodyString(`{"errorMsg": "Errors in the entity format", errors: [orders: "This collection should contain 2 elements or more."}`)
data, _, err := c.LinksCreate(link)
if err == nil {
t.Error("Error must be return")
}
if data.Success != false {
t.Error(successFail)
}
}
func TestClient_ClientIdsUpload(t *testing.T) {
c := client()
clientIds := []ClientID{
{
Value: "value",
Order: LinkedOrder{ID: 10, ExternalID: "externalID", Number: "number"},
Customer: SerializedEntityCustomer{ID: 10, ExternalID: "externalID"},
Site: "site",
},
{
Value: "value2",
Order: LinkedOrder{ID: 12, ExternalID: "externalID2", Number: "number2"},
Customer: SerializedEntityCustomer{ID: 12, ExternalID: "externalID2"},
Site: "site2",
},
}
clientIdsJSON, _ := json.Marshal(&clientIds)
p := url.Values{
"clientIds": {string(clientIdsJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/web-analytics/client-ids/upload").
BodyString(p.Encode()).
Reply(201).
BodyString(`{"success": true}`)
data, status, err := c.ClientIdsUpload(clientIds)
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
}
func TestClient_ClientIdsUpload_Fail(t *testing.T) {
c := client()
clientIds := []ClientID{
{
Value: "value",
Order: LinkedOrder{ID: 10},
Customer: SerializedEntityCustomer{},
},
}
clientIdsJSON, _ := json.Marshal(&clientIds)
p := url.Values{
"clientIds": {string(clientIdsJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/web-analytics/client-ids/upload").
BodyString(p.Encode()).
Reply(400).
BodyString(`
{
"errorMsg": "ClientIds are loaded with errors",
"errors": [0: "customer: Set one of the following fields: id, externalId"]
}
`)
data, _, err := c.ClientIdsUpload(clientIds)
if err == nil {
t.Error("Error must be return")
}
if data.Success != false {
t.Error(successFail)
}
}
func TestClient_SourcesUpload(t *testing.T) {
c := client()
sources := []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",
},
}
sourcesJSON, _ := json.Marshal(&sources)
p := url.Values{
"sources": {string(sourcesJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/web-analytics/sources/upload").
BodyString(p.Encode()).
Reply(201).
BodyString(`{"success": true}`)
data, status, err := c.SourcesUpload(sources)
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
}
func TestClient_SourcesUpload_Fail(t *testing.T) {
c := client()
sources := []Source{
{
Source: "source",
Medium: "medium",
Campaign: "campaign",
Keyword: "keyword",
Content: "content",
ClientID: "12",
Order: LinkedOrder{ID: 10, ExternalID: "externalId", Number: "number"},
Customer: SerializedEntityCustomer{},
Site: "site",
},
}
sourcesJSON, _ := json.Marshal(&sources)
p := url.Values{
"sources": {string(sourcesJSON)},
}
gock.New(crmURL).
Post("/web-analytics/sources/upload").
BodyString(p.Encode()).
Reply(400).
BodyString(`
{
"errorMsg": "ClientIds are loaded with errors",
"errors": [0: "customer: Set one of the following fields: id, externalId"]
}
`)
data, _, err := c.SourcesUpload(sources)
if err == nil {
t.Error("Error must be return")
}
if data.Success != false {
t.Error(successFail)
}
}
func TestClient_Currencies(t *testing.T) {
c := client()
defer gock.Off()
gock.New(crmURL).
Get("/reference/currencies").
Reply(200).
BodyString(`
{
"success": true,
"currencies": [
{
"id": 10,
"code": "code",
"isBase": true,
"isAutoConvert": true,
"autoConvertExtraPercent": 1,
"manualConvertNominal": 1,
"manualConvertValue": 1.5
},
{
"id": 12,
"code": "code2",
"isBase": false,
"isAutoConvert": false,
"autoConvertExtra_percent": 2,
"manualConvertNominal": 5,
"manualConvertValue": 60.25
}
]
}`)
resp := CurrencyResponse{
Success: true,
Currencies: []Currency{
{
ID: 10,
Code: "code",
IsBase: true,
IsAutoConvert: true,
AutoConvertExtraPercent: 1,
ManualConvertNominal: 1,
ManualConvertValue: 1.5,
},
{
ID: 12,
Code: "code2",
IsBase: false,
IsAutoConvert: false,
AutoConvertExtraPercent: 0,
ManualConvertNominal: 5,
ManualConvertValue: 60.25,
},
},
}
data, status, err := c.Currencies()
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
assert.Equal(t, resp, data)
}
func TestClient_CurrenciesCreate(t *testing.T) {
c := client()
currency := Currency{
ID: 10,
Code: "RUB",
IsBase: true,
IsAutoConvert: true,
AutoConvertExtraPercent: 1,
ManualConvertNominal: 1,
ManualConvertValue: 1.5,
}
currencyJSON, _ := json.Marshal(&currency)
p := url.Values{
"currency": {string(currencyJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post("/reference/currencies/create").
BodyString(p.Encode()).
Reply(201).
BodyString(`{"success": true, "id": 10}`)
data, status, err := c.CurrenciesCreate(currency)
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
assert.Equal(t, currency.ID, data.ID)
}
func TestClient_CurrenciesEdit(t *testing.T) {
c := client()
currency := Currency{
ID: 10,
Code: "code",
IsBase: true,
IsAutoConvert: true,
AutoConvertExtraPercent: 1,
ManualConvertNominal: 1,
ManualConvertValue: 1.5,
}
var uid = strconv.Itoa(currency.ID)
currencyJSON, _ := json.Marshal(&currency)
p := url.Values{
"currency": {string(currencyJSON)},
}
defer gock.Off()
gock.New(crmURL).
Post(fmt.Sprintf("/reference/currencies/%s/edit", uid)).
BodyString(p.Encode()).
Reply(200).
BodyString(`{"success": true}`)
data, status, err := c.CurrenciesEdit(currency)
if err != nil {
t.Errorf("%v", err)
}
if status >= http.StatusBadRequest {
t.Errorf("%v", err)
}
if data.Success != true {
t.Errorf("%v", err)
}
}
func TestClient_OrderChange(t *testing.T) {
c := client()

View File

@ -199,6 +199,7 @@ type OrdersFilter struct {
PaymentStatuses []string `url:"paymentStatuses,omitempty,brackets"`
PaymentTypes []string `url:"paymentTypes,omitempty,brackets"`
DeliveryTypes []string `url:"deliveryTypes,omitempty,brackets"`
DeliveryServices []string `url:"deliveryServices,omitempty,brackets"`
OrderMethods []string `url:"orderMethods,omitempty,brackets"`
ShipmentStores []string `url:"shipmentStores,omitempty,brackets"`
Couriers []string `url:"couriers,omitempty,brackets"`
@ -448,8 +449,8 @@ type LoyaltyAccountAPIFilter struct {
ID string `url:"id,omitempty"`
Status string `url:"status,,omitempty"`
Customer string `url:"customer,omitempty"`
MinOrderSum string `url:"minOrderSum,omitempty"`
MaxOrderSum string `url:"maxOrderSum,omitempty"`
MinOrderSum string `url:"minOrdersSum,omitempty"`
MaxOrderSum string `url:"maxOrdersSum,omitempty"`
MinAmount string `url:"minAmount,omitempty"`
MaxAmount string `url:"maxAmount,omitempty"`
PhoneNumber string `url:"phoneNumber,omitempty"`

View File

@ -596,6 +596,34 @@ type AccountBonusOperationsResponse struct {
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 {
SuccessfulResponse
LoyaltyAccount `json:"loyaltyAccount"`

View File

@ -64,11 +64,15 @@ type GeoHierarchyRow struct {
// Source type.
type Source struct {
Source string `json:"source,omitempty"`
Medium string `json:"medium,omitempty"`
Campaign string `json:"campaign,omitempty"`
Keyword string `json:"keyword,omitempty"`
Content string `json:"content,omitempty"`
Source string `json:"source,omitempty"`
Medium string `json:"medium,omitempty"`
Campaign string `json:"campaign,omitempty"`
Keyword string `json:"keyword,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.
@ -344,6 +348,49 @@ type Order struct {
ApplyRound *bool `json:"applyRound,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"`
}
// 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.
@ -580,6 +627,7 @@ type OfferPrice struct {
Price float32 `json:"price,omitempty"`
Ordering int `json:"ordering,omitempty"`
PriceType string `json:"priceType,omitempty"`
Currency string `json:"currency,omitempty"`
}
// OfferPriceUpload type.
@ -619,6 +667,7 @@ type User struct {
CreatedAt string `json:"createdAt,omitempty"`
Active bool `json:"active,omitempty"`
Online bool `json:"online,omitempty"`
Position string `json:"position,omitempty"`
IsAdmin bool `json:"isAdmin,omitempty"`
IsManager bool `json:"isManager,omitempty"`
Email string `json:"email,omitempty"`
@ -832,6 +881,7 @@ type DeliveryType struct {
DeliveryServices []string `json:"deliveryServices,omitempty"`
PaymentTypes []string `json:"paymentTypes,omitempty"` // Deprecated, use DeliveryPaymentTypes
DeliveryPaymentTypes []DeliveryPaymentType `json:"deliveryPaymentTypes,omitempty"`
Currency string `json:"currency,omitempty"`
}
type DeliveryPaymentType struct {
@ -862,8 +912,8 @@ type LegalEntity struct {
}
type SerializedEntityCustomer struct {
ID int `json:"id,omitempty"`
ExternalID int `json:"externalId,omitempty"`
ID int `json:"id,omitempty"`
ExternalID string `json:"externalId,omitempty"`
}
// OrderMethod type.
@ -921,6 +971,7 @@ type PriceType struct {
Ordering int `json:"ordering,omitempty"`
Groups []string `json:"groups,omitempty"`
Geo []GeoHierarchyRow `json:"geo,omitempty"`
Currency string `json:"currency,omitempty"`
}
// ProductStatus type.
@ -974,6 +1025,7 @@ type Site struct {
IsDemo bool `json:"isDemo,omitempty"`
CatalogID string `json:"catalogId,omitempty"`
IsCatalogMainSite bool `json:"isCatalogMainSite,omitempty"`
Currency string `json:"currency,omitempty"`
}
// Store type.
@ -1381,6 +1433,7 @@ type Loyalty struct {
ActivatedAt string `json:"activatedAt,omitempty"`
DeactivatedAt string `json:"deactivatedAt,omitempty"`
BlockedAt string `json:"blockedAt,omitempty"`
Currency string `json:"currency,omitempty"`
}
// LoyaltyLevel type.
@ -1424,6 +1477,7 @@ type SerializedLoyaltyOrder struct {
Delivery Delivery `json:"delivery,omitempty"`
Site string `json:"site,omitempty"`
Items []LoyaltyItems `json:"items,omitempty"`
Currency string `json:"currency,omitempty"`
}
type LoyaltyEventDiscount struct {