- 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
264 lines
7.0 KiB
Go
264 lines
7.0 KiB
Go
package handlers
|
||
|
||
import (
|
||
"encoding/json"
|
||
"net/http"
|
||
)
|
||
|
||
type CategoryTreeRequest struct {
|
||
Language string `json:"language"`
|
||
}
|
||
|
||
type CategoryTreeNode struct {
|
||
CategoryID int64 `json:"category_id"`
|
||
Title string `json:"title"`
|
||
Children []CategoryTreeNode `json:"children"`
|
||
}
|
||
|
||
type CategoryTreeResponse struct {
|
||
Result []CategoryTreeNode `json:"result"`
|
||
}
|
||
|
||
func CategoryTree(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method != http.MethodPost {
|
||
http.Error(w, "method not allowed", 405)
|
||
return
|
||
}
|
||
|
||
var req CategoryTreeRequest
|
||
_ = json.NewDecoder(r.Body).Decode(&req)
|
||
|
||
w.Header().Set("Content-Type", "application/json")
|
||
json.NewEncoder(w).Encode(CategoryTreeResponse{
|
||
Result: []CategoryTreeNode{
|
||
{
|
||
CategoryID: 17000000,
|
||
Title: "Электроника",
|
||
Children: []CategoryTreeNode{
|
||
{CategoryID: 17000001, Title: "Смартфоны и гаджеты", Children: []CategoryTreeNode{
|
||
{CategoryID: 17036136, Title: "Смартфоны"},
|
||
{CategoryID: 17036137, Title: "Планшеты"},
|
||
}},
|
||
{CategoryID: 17000002, Title: "Ноутбуки и компьютеры"},
|
||
},
|
||
},
|
||
{
|
||
CategoryID: 17010000,
|
||
Title: "Одежда",
|
||
Children: []CategoryTreeNode{
|
||
{CategoryID: 17010001, Title: "Мужская одежда"},
|
||
{CategoryID: 17010002, Title: "Женская одежда"},
|
||
},
|
||
},
|
||
{
|
||
CategoryID: 17020000,
|
||
Title: "Дом и сад",
|
||
Children: []CategoryTreeNode{
|
||
{CategoryID: 17020001, Title: "Мебель"},
|
||
{CategoryID: 17020002, Title: "Освещение"},
|
||
},
|
||
},
|
||
},
|
||
})
|
||
}
|
||
|
||
type CategoryAttributeRequest struct {
|
||
AttributeType string `json:"attribute_type"`
|
||
CategoryID []int64 `json:"category_id"`
|
||
Language string `json:"language"`
|
||
}
|
||
|
||
type CategoryAttribute struct {
|
||
ID int64 `json:"id"`
|
||
Name string `json:"name"`
|
||
Description string `json:"description"`
|
||
Type string `json:"type"`
|
||
IsCollection bool `json:"is_collection"`
|
||
IsRequired bool `json:"is_required"`
|
||
GroupID int64 `json:"group_id"`
|
||
GroupName string `json:"group_name"`
|
||
DictionaryID int64 `json:"dictionary_id"`
|
||
}
|
||
|
||
type CategoryAttributesResponse struct {
|
||
Result []CategoryAttribute `json:"result"`
|
||
}
|
||
|
||
func CategoryAttributes(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method != http.MethodPost {
|
||
http.Error(w, "method not allowed", 405)
|
||
return
|
||
}
|
||
|
||
var req CategoryAttributeRequest
|
||
_ = json.NewDecoder(r.Body).Decode(&req)
|
||
|
||
w.Header().Set("Content-Type", "application/json")
|
||
json.NewEncoder(w).Encode(CategoryAttributesResponse{
|
||
Result: []CategoryAttribute{
|
||
{
|
||
ID: 8229,
|
||
Name: "Название модели",
|
||
Description: "Название модели товара",
|
||
Type: "String",
|
||
IsCollection: false,
|
||
IsRequired: true,
|
||
GroupID: 1,
|
||
GroupName: "Основные характеристики",
|
||
DictionaryID: 0,
|
||
},
|
||
{
|
||
ID: 85,
|
||
Name: "Бренд",
|
||
Description: "Производитель товара",
|
||
Type: "String",
|
||
IsCollection: false,
|
||
IsRequired: true,
|
||
GroupID: 1,
|
||
GroupName: "Основные характеристики",
|
||
DictionaryID: 0,
|
||
},
|
||
{
|
||
ID: 9044,
|
||
Name: "Цвет товара",
|
||
Description: "Основной цвет",
|
||
Type: "String",
|
||
IsCollection: false,
|
||
IsRequired: false,
|
||
GroupID: 2,
|
||
GroupName: "Внешний вид",
|
||
DictionaryID: 0,
|
||
},
|
||
{
|
||
ID: 4416,
|
||
Name: "Гарантия",
|
||
Description: "Срок гарантии в месяцах",
|
||
Type: "Number",
|
||
IsCollection: false,
|
||
IsRequired: false,
|
||
GroupID: 3,
|
||
GroupName: "Гарантия и сервис",
|
||
DictionaryID: 0,
|
||
},
|
||
{
|
||
ID: 4074,
|
||
Name: "Комплектация",
|
||
Description: "Что входит в комплект поставки",
|
||
Type: "String",
|
||
IsCollection: true,
|
||
IsRequired: false,
|
||
GroupID: 4,
|
||
GroupName: "Комплектация",
|
||
DictionaryID: 0,
|
||
},
|
||
{
|
||
ID: 5076,
|
||
Name: "Вес с упаковкой",
|
||
Description: "Вес товара в упаковке, г",
|
||
Type: "Number",
|
||
IsCollection: false,
|
||
IsRequired: false,
|
||
GroupID: 5,
|
||
GroupName: "Упаковка и габариты",
|
||
DictionaryID: 0,
|
||
},
|
||
},
|
||
})
|
||
}
|
||
|
||
type CategoryAttributeValuesRequest struct {
|
||
AttributeID int64 `json:"attribute_id"`
|
||
CategoryID int64 `json:"category_id"`
|
||
Language string `json:"language"`
|
||
}
|
||
|
||
type CategoryAttributeValue struct {
|
||
ID int64 `json:"id"`
|
||
Value string `json:"value"`
|
||
Info string `json:"info,omitempty"`
|
||
}
|
||
|
||
type CategoryAttributeValuesResponse struct {
|
||
Result []CategoryAttributeValue `json:"result"`
|
||
}
|
||
|
||
func CategoryAttributeValues(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method != http.MethodPost {
|
||
http.Error(w, "method not allowed", 405)
|
||
return
|
||
}
|
||
|
||
var req CategoryAttributeValuesRequest
|
||
_ = json.NewDecoder(r.Body).Decode(&req)
|
||
|
||
w.Header().Set("Content-Type", "application/json")
|
||
json.NewEncoder(w).Encode(CategoryAttributeValuesResponse{
|
||
Result: []CategoryAttributeValue{
|
||
{ID: 1, Value: "Apple", Info: "Apple Inc."},
|
||
{ID: 2, Value: "Samsung", Info: "Samsung Electronics"},
|
||
{ID: 3, Value: "Xiaomi", Info: "Xiaomi Corporation"},
|
||
{ID: 4, Value: "Huawei", Info: "Huawei Technologies"},
|
||
},
|
||
})
|
||
}
|
||
|
||
type ProductAttributesRequest struct {
|
||
Filter struct {
|
||
OfferIDs []string `json:"offer_id"`
|
||
ProductIDs []int64 `json:"product_id"`
|
||
} `json:"filter"`
|
||
}
|
||
|
||
type ProductAttributeValue struct {
|
||
AttributeID int64 `json:"attribute_id"`
|
||
Value string `json:"value"`
|
||
}
|
||
|
||
type ProductAttributesResult struct {
|
||
OfferID string `json:"offer_id"`
|
||
ProductID int64 `json:"product_id"`
|
||
Attributes []ProductAttributeValue `json:"attributes"`
|
||
}
|
||
|
||
type ProductAttributesResponse struct {
|
||
Result []ProductAttributesResult `json:"result"`
|
||
}
|
||
|
||
func ProductAttributes(w http.ResponseWriter, r *http.Request) {
|
||
if r.Method != http.MethodPost {
|
||
http.Error(w, "method not allowed", 405)
|
||
return
|
||
}
|
||
|
||
var req ProductAttributesRequest
|
||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||
writeError(w, 400, "invalid json")
|
||
return
|
||
}
|
||
|
||
allProducts := GetProductsFixtures()
|
||
results := make([]ProductAttributesResult, 0)
|
||
|
||
for _, oid := range req.Filter.OfferIDs {
|
||
for _, p := range allProducts {
|
||
if p.OfferID == oid {
|
||
results = append(results, ProductAttributesResult{
|
||
OfferID: p.OfferID,
|
||
ProductID: p.ProductID,
|
||
Attributes: []ProductAttributeValue{
|
||
{AttributeID: 8229, Value: p.Name},
|
||
{AttributeID: 85, Value: "Test Brand"},
|
||
{AttributeID: 9044, Value: "Черный"},
|
||
},
|
||
})
|
||
break
|
||
}
|
||
}
|
||
}
|
||
|
||
w.Header().Set("Content-Type", "application/json")
|
||
json.NewEncoder(w).Encode(ProductAttributesResponse{
|
||
Result: results,
|
||
})
|
||
}
|