v2.0: massive test data (104 products, 41 postings, 20 returns, 20 payouts, 25 txs, 3 companies)
Some checks failed
deploy / deploy (push) Failing after 2s
test / test (push) Failing after 1s

- Remove unused gin dependency from go.mod
- Remove credential logging from startup
- Remove dead parseOfferIDs function
- Add method check to GET /v1/product/list
- Complete all filter implementations (since, to, status, product_id, return_id, dir, analytics, page)
- CancelPosting now validates posting existence (404 for unknown)
- Implement MOCK_STOCKS_JSON file loading
- Add Phase 2 endpoints: v3/product/import, v1/product/info/description,
  v1/product/info/attributes, v2/category/tree, v3/category/attribute,
  v3/category/attribute/values
- Generate 104 products/stocks/prices across 3 companies:
  TechGiant (TG-0001..TG-0035), FashionLine (FL-0001..FL-0035), HomeStyle (HS-0001..HS-0034)
- 41 postings, 20 returns, 20 payouts, 25 transactions
- 31 tests (all PASS with race detector)
- Add Makefile
This commit is contained in:
Rinat
2026-07-17 14:38:53 +03:00
parent bb665d31bf
commit 50dc046369
9 changed files with 1644 additions and 374 deletions

View File

@ -6,9 +6,8 @@ import (
"time"
)
// PostingFBSListRequest - POST /v2/posting/fbs/list
type PostingFBSListRequest struct {
Dir string `json:"dir"` // "asc" or "desc"
Dir string `json:"dir"`
Filter struct {
Since string `json:"since"`
To string `json:"to"`
@ -23,26 +22,26 @@ type PostingFBSListRequest struct {
}
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"`
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"`
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) {
@ -66,7 +65,30 @@ func PostingFBSList(w http.ResponseWriter, r *http.Request) {
postings := GetPostingsFixtures()
// Filter by status if provided
if req.Filter.Since != "" {
sinceTs := parseTimeOrZero(req.Filter.Since)
filtered := make([]Posting, 0)
for _, p := range postings {
ts := parseTimeOrZero(p.CreatedAt)
if ts >= sinceTs {
filtered = append(filtered, p)
}
}
postings = filtered
}
if req.Filter.To != "" {
toTs := parseTimeOrZero(req.Filter.To)
filtered := make([]Posting, 0)
for _, p := range postings {
ts := parseTimeOrZero(p.CreatedAt)
if ts <= toTs {
filtered = append(filtered, p)
}
}
postings = filtered
}
if req.Filter.Status != "" {
filtered := make([]Posting, 0)
for _, p := range postings {
@ -77,7 +99,6 @@ func PostingFBSList(w http.ResponseWriter, r *http.Request) {
postings = filtered
}
// Filter by posting_number if provided
if len(req.Filter.PostingNumber) > 0 {
filtered := make([]Posting, 0)
for _, p := range postings {
@ -91,7 +112,22 @@ func PostingFBSList(w http.ResponseWriter, r *http.Request) {
postings = filtered
}
// Apply limit
if req.Dir == "asc" {
for i, j := 0, len(postings)-1; i < j; i, j = i+1, j-1 {
postings[i], postings[j] = postings[j], postings[i]
}
}
if req.With.AnalyticsData {
for i := range postings {
postings[i].AnalyticsData = map[string]any{
"commission": 5.0,
"delivery": 150.00,
"return": 0,
}
}
}
if len(postings) > req.Limit {
postings = postings[:req.Limit]
}
@ -103,7 +139,6 @@ func PostingFBSList(w http.ResponseWriter, r *http.Request) {
})
}
// PostingFBSGetRequest - POST /v2/posting/fbs/get
type PostingFBSGetRequest struct {
PostingNumber string `json:"posting_number"`
}
@ -134,14 +169,13 @@ func PostingFBSGet(w http.ResponseWriter, r *http.Request) {
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"`
Status string `json:"status"`
}
func CancelPosting(w http.ResponseWriter, r *http.Request) {
@ -161,6 +195,19 @@ func CancelPosting(w http.ResponseWriter, r *http.Request) {
return
}
postings := GetPostingsFixtures()
found := false
for _, p := range postings {
if p.PostingNumber == req.PostingNumber {
found = true
break
}
}
if !found {
writeError(w, 404, "posting not found")
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(CancelPostingResponse{
PostingNumber: req.PostingNumber,
@ -168,36 +215,34 @@ func CancelPosting(w http.ResponseWriter, r *http.Request) {
})
}
// Returns
type ReturnsListRequest struct {
Filter struct {
Since string `json:"since"`
To string `json:"to"`
Status string `json:"status"`
ReturnID int64 `json:"return_id"`
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"`
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"`
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) {
@ -214,6 +259,50 @@ func ReturnsList(w http.ResponseWriter, r *http.Request) {
returns := GetReturnsFixtures()
if req.Filter.Since != "" {
sinceTs := parseTimeOrZero(req.Filter.Since)
filtered := make([]Return, 0)
for _, ret := range returns {
ts := parseTimeOrZero(ret.CreatedAt)
if ts >= sinceTs {
filtered = append(filtered, ret)
}
}
returns = filtered
}
if req.Filter.To != "" {
toTs := parseTimeOrZero(req.Filter.To)
filtered := make([]Return, 0)
for _, ret := range returns {
ts := parseTimeOrZero(ret.CreatedAt)
if ts <= toTs {
filtered = append(filtered, ret)
}
}
returns = filtered
}
if req.Filter.Status != "" {
filtered := make([]Return, 0)
for _, ret := range returns {
if ret.Status == req.Filter.Status {
filtered = append(filtered, ret)
}
}
returns = filtered
}
if req.Filter.ReturnID > 0 {
filtered := make([]Return, 0)
for _, ret := range returns {
if ret.ReturnID == req.Filter.ReturnID {
filtered = append(filtered, ret)
}
}
returns = filtered
}
if req.Limit == 0 {
req.Limit = 100
}
@ -229,7 +318,14 @@ func ReturnsList(w http.ResponseWriter, r *http.Request) {
})
}
func parseTimeOrZero(s string) int64 {
t, err := time.Parse(time.RFC3339, s)
if err != nil {
return 0
}
return t.Unix()
}
func init() {
// Ensure timestamps are consistent
_ = time.RFC3339
}