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