Initial commit: ozon-mock Go server
- Mock Ozon Seller API endpoints - Products, Postings, Finance, Returns, Analytics - JSON fixtures for testing - Docker support - Gitea Actions CI/CD
This commit is contained in:
235
internal/handlers/postings.go
Normal file
235
internal/handlers/postings.go
Normal file
@ -0,0 +1,235 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// PostingFBSListRequest - POST /v2/posting/fbs/list
|
||||
type PostingFBSListRequest struct {
|
||||
Dir string `json:"dir"` // "asc" or "desc"
|
||||
Filter struct {
|
||||
Since string `json:"since"`
|
||||
To string `json:"to"`
|
||||
Status string `json:"status"`
|
||||
PostingNumber []string `json:"posting_number"`
|
||||
DeliveryMethod int `json:"delivery_method"`
|
||||
} `json:"filter"`
|
||||
Limit int `json:"limit"`
|
||||
With struct {
|
||||
AnalyticsData bool `json:"analytics_data"`
|
||||
} `json:"with"`
|
||||
}
|
||||
|
||||
type PostingItem struct {
|
||||
ProductID int64 `json:"product_id"`
|
||||
OfferID string `json:"offer_id"`
|
||||
Name string `json:"name"`
|
||||
Quantity int `json:"quantity"`
|
||||
Price float64 `json:"price"`
|
||||
ItemsCount int `json:"items_count"`
|
||||
}
|
||||
|
||||
type Posting struct {
|
||||
PostingNumber string `json:"posting_number"`
|
||||
OrderID int64 `json:"order_id"`
|
||||
OrderNumber string `json:"order_number"`
|
||||
Status string `json:"status"`
|
||||
Products []PostingItem `json:"products"`
|
||||
AnalyticsData any `json:"analytics_data,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
Warehouses []int64 `json:"warehouses"`
|
||||
WarehouseID int64 `json:"warehouse_id"`
|
||||
OrderType string `json:"order_type"`
|
||||
}
|
||||
|
||||
func PostingFBSList(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", 405)
|
||||
return
|
||||
}
|
||||
|
||||
var req PostingFBSListRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, 400, "invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
if req.Limit == 0 {
|
||||
req.Limit = 100
|
||||
}
|
||||
if req.Limit > 1000 {
|
||||
req.Limit = 1000
|
||||
}
|
||||
|
||||
postings := GetPostingsFixtures()
|
||||
|
||||
// Filter by status if provided
|
||||
if req.Filter.Status != "" {
|
||||
filtered := make([]Posting, 0)
|
||||
for _, p := range postings {
|
||||
if p.Status == req.Filter.Status {
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
}
|
||||
postings = filtered
|
||||
}
|
||||
|
||||
// Filter by posting_number if provided
|
||||
if len(req.Filter.PostingNumber) > 0 {
|
||||
filtered := make([]Posting, 0)
|
||||
for _, p := range postings {
|
||||
for _, num := range req.Filter.PostingNumber {
|
||||
if p.PostingNumber == num {
|
||||
filtered = append(filtered, p)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
postings = filtered
|
||||
}
|
||||
|
||||
// Apply limit
|
||||
if len(postings) > req.Limit {
|
||||
postings = postings[:req.Limit]
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"postings": postings,
|
||||
"total": len(postings),
|
||||
})
|
||||
}
|
||||
|
||||
// PostingFBSGetRequest - POST /v2/posting/fbs/get
|
||||
type PostingFBSGetRequest struct {
|
||||
PostingNumber string `json:"posting_number"`
|
||||
}
|
||||
|
||||
func PostingFBSGet(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", 405)
|
||||
return
|
||||
}
|
||||
|
||||
var req PostingFBSGetRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, 400, "invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
postings := GetPostingsFixtures()
|
||||
for _, p := range postings {
|
||||
if p.PostingNumber == req.PostingNumber {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"posting": p,
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
writeError(w, 404, "posting not found")
|
||||
}
|
||||
|
||||
// CancelPostingRequest - POST /v1/posting/fbs/cancel
|
||||
type CancelPostingRequest struct {
|
||||
PostingNumber string `json:"posting_number"`
|
||||
}
|
||||
|
||||
type CancelPostingResponse struct {
|
||||
PostingNumber string `json:"posting_number"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func CancelPosting(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", 405)
|
||||
return
|
||||
}
|
||||
|
||||
var req CancelPostingRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, 400, "invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
if req.PostingNumber == "" {
|
||||
writeError(w, 400, "posting_number is required")
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(CancelPostingResponse{
|
||||
PostingNumber: req.PostingNumber,
|
||||
Status: "cancelled",
|
||||
})
|
||||
}
|
||||
|
||||
// Returns
|
||||
|
||||
type ReturnsListRequest struct {
|
||||
Filter struct {
|
||||
Since string `json:"since"`
|
||||
To string `json:"to"`
|
||||
Status string `json:"status"`
|
||||
ReturnID int64 `json:"return_id"`
|
||||
} `json:"filter"`
|
||||
Limit int `json:"limit"`
|
||||
}
|
||||
|
||||
type ReturnItem struct {
|
||||
ProductID int64 `json:"product_id"`
|
||||
OfferID string `json:"offer_id"`
|
||||
Name string `json:"name"`
|
||||
Quantity int `json:"quantity"`
|
||||
IsOptional bool `json:"is_optional"`
|
||||
}
|
||||
|
||||
type Return struct {
|
||||
ReturnID int64 `json:"return_id"`
|
||||
PostingNumber string `json:"posting_number"`
|
||||
Status string `json:"status"`
|
||||
Reason string `json:"reason"`
|
||||
ReasonID int64 `json:"reason_id"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
RejectedAt string `json:"rejected_at,omitempty"`
|
||||
DeliveredAt string `json:"delivered_at,omitempty"`
|
||||
Items []ReturnItem `json:"items"`
|
||||
}
|
||||
|
||||
func ReturnsList(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "method not allowed", 405)
|
||||
return
|
||||
}
|
||||
|
||||
var req ReturnsListRequest
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
writeError(w, 400, "invalid json")
|
||||
return
|
||||
}
|
||||
|
||||
returns := GetReturnsFixtures()
|
||||
|
||||
if req.Limit == 0 {
|
||||
req.Limit = 100
|
||||
}
|
||||
|
||||
if len(returns) > req.Limit {
|
||||
returns = returns[:req.Limit]
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"result": returns,
|
||||
"total": len(returns),
|
||||
})
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Ensure timestamps are consistent
|
||||
_ = time.RFC3339
|
||||
}
|
||||
Reference in New Issue
Block a user