Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83fd8cf825 | ||
|
|
ebbc21b618 | ||
|
|
f53b573d62 | ||
|
|
eb0ce6feb6 | ||
|
|
9a41bb1196 | ||
|
|
e76b9f3961 | ||
|
|
add4202b3e |
38
README.md
38
README.md
@@ -11,6 +11,7 @@ Read full [documentation](https://docs.ozon.ru/api/seller/en/#tag/Introduction)
|
||||
You can check [list of supported endpoints](ENDPOINTS.md)
|
||||
|
||||
## How to start
|
||||
### API
|
||||
Get Client-Id and Api-Key in your seller profile [here](https://seller.ozon.ru/app/settings/api-keys?locale=en)
|
||||
|
||||
Just add dependency to your project and you're ready to go.
|
||||
@@ -49,6 +50,43 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### Notifications
|
||||
Ozon can send push-notifications to your REST server. There is an implementation of REST server that handles notifications in this library.
|
||||
|
||||
[Official documentation](https://docs.ozon.ru/api/seller/en/#tag/push_intro)
|
||||
|
||||
How to use:
|
||||
```Golang
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/diphantxm/ozon-api-client/ozon/notifications"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create server
|
||||
port := 5000
|
||||
server := notifications.NewNotificationServer(port)
|
||||
|
||||
// Register handlers passing message type and handler itself
|
||||
server.Register(notifications.ChatClosedType, func(req interface{}) error {
|
||||
notification := req.(*notifications.ChatClosed)
|
||||
|
||||
// Do something with the notification here...
|
||||
log.Printf("chat %s has been closed\n", notification.ChatId)
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
// Run server
|
||||
if err := server.Run(); err != nil {
|
||||
log.Printf("error while running notification server: %s", err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Contribution
|
||||
If you need some endpoints ASAP, create an issue and list all the endpoints. I will add them to library soon.
|
||||
|
||||
|
||||
19
ozon/notifications/enums.go
Normal file
19
ozon/notifications/enums.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package notifications
|
||||
|
||||
type MessageType string
|
||||
|
||||
const (
|
||||
PingType MessageType = "TYPE_PING"
|
||||
NewPostingType MessageType = "TYPE_NEW_POSTING"
|
||||
PostingCancelledType MessageType = "TYPE_POSTING_CANCELLED"
|
||||
StateChangedType MessageType = "TYPE_STATE_CHANGED"
|
||||
CutoffDateChangedType MessageType = "TYPE_CUTOFF_DATE_CHANGED"
|
||||
DeliveryDateChangedType MessageType = "TYPE_DELIVERY_DATE_CHANGED"
|
||||
CreateOrUpdateType MessageType = "TYPE_CREATE_OR_UPDATE_ITEM"
|
||||
PriceIndexChangedType MessageType = "TYPE_PRICE_INDEX_CHANGED"
|
||||
StocksChangedType MessageType = "TYPE_STOCKS_CHANGED"
|
||||
NewMessageType MessageType = "TYPE_NEW_MESSAGE"
|
||||
UpdateMessageType MessageType = "TYPE_UPDATE_MESSAGE"
|
||||
MessageReadType MessageType = "TYPE_MESSAGE_READ"
|
||||
ChatClosedType MessageType = "TYPE_CHAT_CLOSED"
|
||||
)
|
||||
165
ozon/notifications/server.go
Normal file
165
ozon/notifications/server.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Handler func(req interface{}) error
|
||||
|
||||
type NotificationServer struct {
|
||||
port int
|
||||
handlers map[MessageType]Handler
|
||||
}
|
||||
|
||||
func NewNotificationServer(port int) *NotificationServer {
|
||||
return &NotificationServer{
|
||||
port: port,
|
||||
handlers: map[MessageType]Handler{},
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) Run() error {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", ns.handler)
|
||||
server := http.Server{
|
||||
Addr: fmt.Sprintf("0.0.0.0:%d", ns.port),
|
||||
Handler: mux,
|
||||
}
|
||||
return server.ListenAndServe()
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) handler(rw http.ResponseWriter, httpReq *http.Request) {
|
||||
mt := &Common{}
|
||||
content, err := ioutil.ReadAll(httpReq.Body)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
ns.error(rw, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
if err := json.Unmarshal(content, mt); err != nil {
|
||||
log.Print(err)
|
||||
ns.error(rw, http.StatusBadRequest, err)
|
||||
return
|
||||
}
|
||||
|
||||
if mt.MessageType == PingType {
|
||||
resp := pingResponse{
|
||||
Version: "1.0",
|
||||
Name: "Ozon Seller API",
|
||||
Time: time.Now(),
|
||||
}
|
||||
respJson, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
ns.error(rw, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write(respJson)
|
||||
return
|
||||
}
|
||||
|
||||
req, err := ns.unmarshal(mt.MessageType, content)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
ns.result(rw, false)
|
||||
//ns.error(rw, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
h, ok := ns.handlers[mt.MessageType]
|
||||
if !ok {
|
||||
ns.result(rw, true)
|
||||
log.Printf("handler for %s is not registered", mt.MessageType)
|
||||
return
|
||||
}
|
||||
if err := h(req); err != nil {
|
||||
log.Print(err)
|
||||
ns.result(rw, false)
|
||||
//ns.error(rw, http.StatusInternalServerError, err)
|
||||
return
|
||||
}
|
||||
|
||||
ns.result(rw, true)
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) Register(mt MessageType, handler func(req interface{}) error) {
|
||||
ns.handlers[mt] = handler
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) unmarshal(messageType MessageType, content []byte) (interface{}, error) {
|
||||
switch messageType {
|
||||
case NewPostingType:
|
||||
v := &NewPosting{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case PostingCancelledType:
|
||||
v := &PostingCancelled{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case StateChangedType:
|
||||
v := &StateChanged{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case CutoffDateChangedType:
|
||||
v := &CutoffDateChanged{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case DeliveryDateChangedType:
|
||||
v := &DeliveryDateChanged{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case CreateOrUpdateType:
|
||||
v := &CreateOrUpdateItem{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case PriceIndexChangedType:
|
||||
v := &PriceIndexChanged{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case StocksChangedType:
|
||||
v := &StocksChanged{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case NewMessageType:
|
||||
v := &NewMessage{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case UpdateMessageType:
|
||||
v := &UpdateMessage{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case MessageReadType:
|
||||
v := &MessageRead{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
case ChatClosedType:
|
||||
v := &ChatClosed{}
|
||||
err := json.Unmarshal(content, v)
|
||||
return v, err
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported type: %s", messageType)
|
||||
}
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) error(rw http.ResponseWriter, statusCode int, err error) {
|
||||
errResp := errorResponse{
|
||||
Data: errorData{
|
||||
Code: fmt.Sprintf("%d", statusCode),
|
||||
Message: err.Error(),
|
||||
},
|
||||
}
|
||||
errJson, _ := json.Marshal(errResp)
|
||||
rw.WriteHeader(statusCode)
|
||||
rw.Write(errJson)
|
||||
}
|
||||
|
||||
func (ns *NotificationServer) result(rw http.ResponseWriter, res bool) {
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
rw.Write([]byte(fmt.Sprintf(`{"result": %t}`, res)))
|
||||
}
|
||||
133
ozon/notifications/server_test.go
Normal file
133
ozon/notifications/server_test.go
Normal file
@@ -0,0 +1,133 @@
|
||||
package notifications
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestNotificationServer(t *testing.T) {
|
||||
testCases := []struct {
|
||||
request string
|
||||
response string
|
||||
}{
|
||||
// PING
|
||||
{
|
||||
`{
|
||||
"message_type": "TYPE_PING",
|
||||
"time": "2019-08-24T14:15:22Z"
|
||||
}`,
|
||||
`{
|
||||
"version": "1.0",
|
||||
"name": "Ozon Seller API"
|
||||
}`,
|
||||
},
|
||||
// REGISTERED HANDLER
|
||||
{
|
||||
`{
|
||||
"message_type": "TYPE_CHAT_CLOSED",
|
||||
"chat_id": "b646d975-0c9c-4872-9f41-8b1e57181063",
|
||||
"chat_type": "Buyer_Seller",
|
||||
"user": {
|
||||
"id": "115568",
|
||||
"type": "Сustomer"
|
||||
},
|
||||
"seller_id": "7"
|
||||
}`,
|
||||
`{
|
||||
"result": true
|
||||
}`,
|
||||
},
|
||||
// UNREGISTERED HANDLER
|
||||
{
|
||||
`{
|
||||
"message_type": "TYPE_MESSAGE_READ",
|
||||
"chat_id": "b646d975-0c9c-4872-9f41-8b1e57181063",
|
||||
"chat_type": "Buyer_Seller",
|
||||
"message_id": "3000000000817031942",
|
||||
"created_at": "2022-07-18T20:58:04.528Z",
|
||||
"user": {
|
||||
"id": "115568",
|
||||
"type": "Сustomer"
|
||||
},
|
||||
"last_read_message_id": "3000000000817031942",
|
||||
"seller_id": "7"
|
||||
}`,
|
||||
`{
|
||||
"result": true
|
||||
}`,
|
||||
},
|
||||
}
|
||||
|
||||
port := getFreePort()
|
||||
|
||||
client := http.Client{}
|
||||
server := NewNotificationServer(port)
|
||||
server.Register(ChatClosedType, func(req interface{}) error {
|
||||
_, ok := req.(*ChatClosed)
|
||||
if !ok {
|
||||
return fmt.Errorf("req is not of ChatClosed type")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
go func() {
|
||||
if err := server.Run(); err != nil {
|
||||
t.Fatalf("notification server is down: %s", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// TODO: get rid of it
|
||||
// Needed to make sure server is running
|
||||
time.Sleep(3 * time.Second)
|
||||
|
||||
for _, testCase := range testCases {
|
||||
httpResp, err := client.Post(fmt.Sprintf("http://0.0.0.0:%d/", port), "application/json", strings.NewReader(testCase.request))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
gotJson, err := ioutil.ReadAll(httpResp.Body)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
|
||||
expected := map[string]interface{}{}
|
||||
got := map[string]interface{}{}
|
||||
err = json.Unmarshal(gotJson, &got)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
err = json.Unmarshal([]byte(testCase.response), &expected)
|
||||
|
||||
if err := compare(expected, got); err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func compare(expected map[string]interface{}, got map[string]interface{}) error {
|
||||
for k, v := range expected {
|
||||
if gotValue, ok := got[k]; !ok {
|
||||
return fmt.Errorf("key %s is expected to present", k)
|
||||
} else if !reflect.DeepEqual(gotValue, v) {
|
||||
return fmt.Errorf("key %s is not equal, got: %v, want: %v", k, gotValue, v)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func getFreePort() int {
|
||||
listener, _ := net.Listen("tcp", ":0")
|
||||
defer listener.Close()
|
||||
|
||||
return listener.Addr().(*net.TCPAddr).Port
|
||||
}
|
||||
327
ozon/notifications/types.go
Normal file
327
ozon/notifications/types.go
Normal file
@@ -0,0 +1,327 @@
|
||||
package notifications
|
||||
|
||||
import "time"
|
||||
|
||||
// Checking if the service is ready at initial connection and periodically after it
|
||||
type pingRequest struct {
|
||||
Common
|
||||
|
||||
// Date and time when the notification was sent in UTC format
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
type pingResponse struct {
|
||||
// Application version
|
||||
Version string `json:"version"`
|
||||
|
||||
// Application name
|
||||
Name string `json:"name"`
|
||||
|
||||
// Date and time when notification processing started in UTC format
|
||||
Time time.Time `json:"time"`
|
||||
}
|
||||
|
||||
type Common struct {
|
||||
MessageType MessageType `json:"message_type"`
|
||||
}
|
||||
|
||||
// New shipment
|
||||
type NewPosting struct {
|
||||
Common
|
||||
|
||||
// Shipment number
|
||||
PostingNumber string `json:"posting_number"`
|
||||
|
||||
// Products information
|
||||
Products []Product `json:"products"`
|
||||
|
||||
// Date and time when the shipment processing started in the UTC format
|
||||
InProccessAt time.Time `json:"in_process_at"`
|
||||
|
||||
// Warehouse identifier where the products for this shipment are stored
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
type Product struct {
|
||||
// Product SKU
|
||||
SKU int64 `json:"sku"`
|
||||
|
||||
// Product quantity
|
||||
Quantity int64 `json:"quantity"`
|
||||
}
|
||||
|
||||
// Shipment cancellation
|
||||
type PostingCancelled struct {
|
||||
Common
|
||||
|
||||
// Shipment number
|
||||
PostingNumber string `json:"posting_number"`
|
||||
|
||||
// Products information
|
||||
Products []Product `json:"products"`
|
||||
|
||||
// Previous shipment status
|
||||
OldState string `json:"old_state"`
|
||||
|
||||
// New shipment status: posting_canceled—canceled
|
||||
NewState string `json:"new_state"`
|
||||
|
||||
// Date and time when the shipment status was changed in UTC format
|
||||
ChangedStateDate time.Time `json:"changed_state_date"`
|
||||
|
||||
// Information about cancellation reason
|
||||
Reason Reason `json:"reason"`
|
||||
|
||||
// Warehouse identifier where the products for this shipment are stored
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
type Reason struct {
|
||||
// Cancellation reason identifier
|
||||
Id int64 `json:"id"`
|
||||
|
||||
// Cancellation reason
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
// Shipment status change
|
||||
type StateChanged struct {
|
||||
Common
|
||||
|
||||
// Shipment number
|
||||
PostingNumber string `json:"posting_number"`
|
||||
|
||||
// New shipment status
|
||||
NewState string `json:"new_state"`
|
||||
|
||||
// Date and time when the shipment status was changed in UTC format
|
||||
ChangedStateDate time.Time `json:"chagned_state_date"`
|
||||
|
||||
// Warehouse identifier where the products for this shipment are stored
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
// Shipment shipping date change
|
||||
type CutoffDateChanged struct {
|
||||
Common
|
||||
|
||||
// Shipment number
|
||||
PostingNumber string `json:"posting_number"`
|
||||
|
||||
// New shipping date and time in UTC format
|
||||
NewCutoffDate time.Time `json:"new_cutoff_date"`
|
||||
|
||||
// Previous shipping date and time in UTC format
|
||||
OldCutoffDate time.Time `json:"old_cutoff_date"`
|
||||
|
||||
// Warehouse identifier where the products for this shipment are stored
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
// Shipment delivery date change
|
||||
type DeliveryDateChanged struct {
|
||||
Common
|
||||
|
||||
// Shipment number
|
||||
PostingNumber string `json:"posting_number"`
|
||||
|
||||
// New delivery start date and time in UTC format
|
||||
NewDeliveryDateBegin time.Time `json:"new_delivery_date_begin"`
|
||||
|
||||
// New delivery end date and time in UTC format
|
||||
NewDeliveryDateEnd time.Time `json:"new_delivery_date_end"`
|
||||
|
||||
// Previous delivery start date and time in UTC format
|
||||
OldDeliveryDateBegin time.Time `json:"old_delivery_date_begin"`
|
||||
|
||||
// Previous delivery end date and time in UTC format
|
||||
OldDeliveryDateEnd time.Time `json:"old_delivery_date_end"`
|
||||
|
||||
// Warehouse identifier where the products for this shipment are stored
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
// Product creation and update or processing error
|
||||
type CreateOrUpdateItem struct {
|
||||
Common
|
||||
|
||||
// Product identifier in the seller's system
|
||||
OfferId string `json:"offer_id"`
|
||||
|
||||
// Product identifier
|
||||
ProductId int64 `json:"product_id"`
|
||||
|
||||
// An indication that errors occurred during the product creation or update
|
||||
IsError bool `json:"is_error"`
|
||||
|
||||
// Update date and time
|
||||
ChangedAt time.Time `json:"changed_at"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
// Product price index change
|
||||
type PriceIndexChanged struct {
|
||||
Common
|
||||
|
||||
// Date and time of price index change
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// Product SKU
|
||||
SKU int64 `json:"sku"`
|
||||
|
||||
// Product identifier
|
||||
ProductId int64 `json:"product_id"`
|
||||
|
||||
// Price index
|
||||
PriceIndex int64 `json:"price_index"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
// Stock change at the seller's warehouse
|
||||
type StocksChanged struct {
|
||||
Common
|
||||
|
||||
// Array with products data
|
||||
Items []Item `json:"items"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
type Item struct {
|
||||
// Update date and time
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// Product SKU when working under the FBS or rFBS schemes
|
||||
SKU int64 `json:"sku"`
|
||||
|
||||
// Product identifier
|
||||
ProductId int64 `json:"product_id"`
|
||||
|
||||
// Array with product stocks data
|
||||
Stocks []Stock `json:"stocks"`
|
||||
}
|
||||
|
||||
type Stock struct {
|
||||
// Warehouse identifier
|
||||
WarehouseId int64 `json:"warehouse_id"`
|
||||
|
||||
// Total product stocks at the warehouse
|
||||
Present int64 `json:"present"`
|
||||
|
||||
// Number of reserved products at the warehouse
|
||||
Reserved int64 `json:"reserved"`
|
||||
}
|
||||
|
||||
// New message in chat
|
||||
type NewMessage struct {
|
||||
Common
|
||||
|
||||
// Chat identifier
|
||||
ChatId string `json:"chat_id"`
|
||||
|
||||
// Chat type
|
||||
ChatType string `json:"chat_type"`
|
||||
|
||||
// Message identifier
|
||||
MessageId string `json:"message_id"`
|
||||
|
||||
// Message creation date
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
|
||||
// Information about message sender
|
||||
User User `json:"user"`
|
||||
|
||||
// Array with message content in Markdown format
|
||||
Data []string `json:"data"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
// Sender identifier
|
||||
Id string `json:"id"`
|
||||
|
||||
// Sender type
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// Message in chat has changed
|
||||
type UpdateMessage struct {
|
||||
NewMessage
|
||||
|
||||
// Message update date
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Customer or support read your message
|
||||
type MessageRead struct {
|
||||
NewMessage
|
||||
|
||||
// Last read message identifier
|
||||
LastReadMessageId string `json:"last_read_message_id"`
|
||||
}
|
||||
|
||||
// Chat is closed
|
||||
type ChatClosed struct {
|
||||
Common
|
||||
|
||||
// Chat identifier
|
||||
ChatId string `json:"chat_id"`
|
||||
|
||||
// Chat type
|
||||
ChatType string `json:"chat_type"`
|
||||
|
||||
// Information about the user who closed the chat
|
||||
User User `json:"user"`
|
||||
|
||||
// User identifier
|
||||
Id string `json:"id"`
|
||||
|
||||
// User type
|
||||
Type string `json:"type"`
|
||||
|
||||
// Seller identifier
|
||||
SellerId string `json:"seller_id"`
|
||||
}
|
||||
|
||||
type Response struct {
|
||||
// Notification is received
|
||||
Result bool `json:"result"`
|
||||
}
|
||||
|
||||
type errorResponse struct {
|
||||
// Information about the error
|
||||
Data errorData `json:"error"`
|
||||
}
|
||||
|
||||
type errorData struct {
|
||||
// Error code
|
||||
Code string `json:"code"`
|
||||
|
||||
// Detailed error description
|
||||
Message string `json:"message"`
|
||||
|
||||
// Additional information
|
||||
Details string `json:"details"`
|
||||
}
|
||||
@@ -1912,6 +1912,9 @@ type GetProductPriceInfoResult struct {
|
||||
}
|
||||
|
||||
type GetPRoductPriceInfoResultItem struct {
|
||||
// Maximum acquiring fee
|
||||
Acquiring int32 `json:"acquiring"`
|
||||
|
||||
// Commissions information
|
||||
Commissions GetProductPriceInfoResultItemCommission `json:"commissions"`
|
||||
|
||||
@@ -1970,10 +1973,10 @@ type GetProductPriceInfoResultItemCommission struct {
|
||||
// Pipeline from (FBS)
|
||||
FBSPipelineFrom float64 `json:"fbs_direct_flow_trans_min_amount"`
|
||||
|
||||
// Shipment processing fee to (FBS)
|
||||
// Minimal shipment processing fee (FBS) — 0 rubles
|
||||
FBSShipmentProcessingToFee float64 `json:"fbs_first_mile_min_amount"`
|
||||
|
||||
// Shipment processing fee from (FBS)
|
||||
// Maximal shipment processing fee (FBS) — 25 rubles
|
||||
FBSShipmentProcessingFromFee float64 `json:"Shipment processing fee from (FBS)"`
|
||||
|
||||
// Return and cancellation fees, shipment processing (FBS)
|
||||
@@ -1985,7 +1988,13 @@ type GetProductPriceInfoResultItemCommission struct {
|
||||
// Return and cancellation fees, pipeline from (FBS)
|
||||
FBSReturnCancellationFromFees float64 `json:"fbs_return_flow_trans_min_amount"`
|
||||
|
||||
// Sales commission percentage (FBO and FBS)
|
||||
// Sales commission percentage (FBO)
|
||||
SalesCommissionFBORate float64 `json:"sales_percent_fbo"`
|
||||
|
||||
// Sales commission percentage (FBS)
|
||||
SalesCommissionFBSRate float64 `json:"sales_percent_fbs"`
|
||||
|
||||
// Larger sales commission percentage among FBO and FBS
|
||||
SalesCommissionRate float64 `json:"sales_percent"`
|
||||
}
|
||||
|
||||
|
||||
@@ -2240,6 +2240,7 @@ func TestGetProductPriceInfo(t *testing.T) {
|
||||
"result": {
|
||||
"items": [
|
||||
{
|
||||
"acquiring": 0,
|
||||
"product_id": 243686911,
|
||||
"offer_id": "356792",
|
||||
"price": {
|
||||
@@ -2255,9 +2256,28 @@ func TestGetProductPriceInfo(t *testing.T) {
|
||||
"marketing_seller_price": "",
|
||||
"auto_action_enabled": true
|
||||
},
|
||||
"price_index": "0.00",
|
||||
"price_indexes": {
|
||||
"external_index_data": {
|
||||
"minimal_price": "string",
|
||||
"minimal_price_currency": "string",
|
||||
"price_index_value": 0
|
||||
},
|
||||
"ozon_index_data": {
|
||||
"minimal_price": "string",
|
||||
"minimal_price_currency": "string",
|
||||
"price_index_value": 0
|
||||
},
|
||||
"price_index": "WITHOUT_INDEX",
|
||||
"self_marketplaces_index_data": {
|
||||
"minimal_price": "string",
|
||||
"minimal_price_currency": "string",
|
||||
"price_index_value": 0
|
||||
}
|
||||
},
|
||||
"commissions": {
|
||||
"sales_percent": 15,
|
||||
"sales_percent_fbo": 15,
|
||||
"sales_percent_fbs": 0,
|
||||
"fbo_fulfillment_amount": 0,
|
||||
"fbo_direct_flow_trans_min_amount": 31,
|
||||
"fbo_direct_flow_trans_max_amount": 46.5,
|
||||
@@ -2266,7 +2286,7 @@ func TestGetProductPriceInfo(t *testing.T) {
|
||||
"fbo_return_flow_trans_min_amount": 21.7,
|
||||
"fbo_return_flow_trans_max_amount": 21.7,
|
||||
"fbs_first_mile_min_amount": 0,
|
||||
"fbs_first_mile_max_amount": 0,
|
||||
"fbs_first_mile_max_amount": 25,
|
||||
"fbs_direct_flow_trans_min_amount": 41,
|
||||
"fbs_direct_flow_trans_max_amount": 61.5,
|
||||
"fbs_deliv_to_customer_amount": 60,
|
||||
|
||||
Reference in New Issue
Block a user