v2.0: massive test data (104 products, 41 postings, 20 returns, 20 payouts, 25 txs, 3 companies)
- 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:
@ -6,33 +6,32 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// FinanceTransactionListRequest - POST /v1/finance/transaction/list
|
||||
type FinanceTransactionListRequest struct {
|
||||
Filter struct {
|
||||
Since string `json:"since"`
|
||||
To string `json:"to"`
|
||||
TransactionType string `json:"transaction_type"`
|
||||
Since string `json:"since"`
|
||||
To string `json:"to"`
|
||||
TransactionType string `json:"transaction_type"`
|
||||
PostingNumber []string `json:"posting_number"`
|
||||
} `json:"filter"`
|
||||
Limit int `json:"limit"`
|
||||
}
|
||||
|
||||
type Transaction struct {
|
||||
TransactionType string `json:"transaction_type"`
|
||||
Amount float64 `json:"amount"`
|
||||
CurrencyCode string `json:"currency_code"`
|
||||
PostingNumber string `json:"posting_number,omitempty"`
|
||||
OrderID int64 `json:"order_id,omitempty"`
|
||||
Items []TransactionItem `json:"items,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
TransactionType string `json:"transaction_type"`
|
||||
Amount float64 `json:"amount"`
|
||||
CurrencyCode string `json:"currency_code"`
|
||||
PostingNumber string `json:"posting_number,omitempty"`
|
||||
OrderID int64 `json:"order_id,omitempty"`
|
||||
Items []TransactionItem `json:"items,omitempty"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
}
|
||||
|
||||
type TransactionItem struct {
|
||||
Type string `json:"type"`
|
||||
Amount float64 `json:"amount"`
|
||||
Quantity int `json:"quantity,omitempty"`
|
||||
ProductID int64 `json:"product_id,omitempty"`
|
||||
OfferID string `json:"offer_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Amount float64 `json:"amount"`
|
||||
Quantity int `json:"quantity,omitempty"`
|
||||
ProductID int64 `json:"product_id,omitempty"`
|
||||
OfferID string `json:"offer_id,omitempty"`
|
||||
}
|
||||
|
||||
func FinanceTransactionList(w http.ResponseWriter, r *http.Request) {
|
||||
@ -49,6 +48,53 @@ func FinanceTransactionList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
transactions := GetTransactionsFixtures()
|
||||
|
||||
if req.Filter.Since != "" {
|
||||
sinceTs := parseTimeOrZero(req.Filter.Since)
|
||||
filtered := make([]Transaction, 0)
|
||||
for _, t := range transactions {
|
||||
ts := parseTimeOrZero(t.CreatedAt)
|
||||
if ts >= sinceTs {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
transactions = filtered
|
||||
}
|
||||
|
||||
if req.Filter.To != "" {
|
||||
toTs := parseTimeOrZero(req.Filter.To)
|
||||
filtered := make([]Transaction, 0)
|
||||
for _, t := range transactions {
|
||||
ts := parseTimeOrZero(t.CreatedAt)
|
||||
if ts <= toTs {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
transactions = filtered
|
||||
}
|
||||
|
||||
if req.Filter.TransactionType != "" {
|
||||
filtered := make([]Transaction, 0)
|
||||
for _, t := range transactions {
|
||||
if t.TransactionType == req.Filter.TransactionType {
|
||||
filtered = append(filtered, t)
|
||||
}
|
||||
}
|
||||
transactions = filtered
|
||||
}
|
||||
|
||||
if len(req.Filter.PostingNumber) > 0 {
|
||||
filtered := make([]Transaction, 0)
|
||||
for _, t := range transactions {
|
||||
for _, num := range req.Filter.PostingNumber {
|
||||
if t.PostingNumber == num {
|
||||
filtered = append(filtered, t)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
transactions = filtered
|
||||
}
|
||||
|
||||
if req.Limit == 0 {
|
||||
req.Limit = 100
|
||||
}
|
||||
@ -60,11 +106,10 @@ func FinanceTransactionList(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"transactions": transactions,
|
||||
"total": len(transactions),
|
||||
"total": len(transactions),
|
||||
})
|
||||
}
|
||||
|
||||
// FinancePayoutListRequest - POST /v1/finance/payout/list
|
||||
type FinancePayoutListRequest struct {
|
||||
Filter struct {
|
||||
Since string `json:"since"`
|
||||
@ -74,13 +119,13 @@ type FinancePayoutListRequest struct {
|
||||
}
|
||||
|
||||
type Payout struct {
|
||||
PayoutID int64 `json:"payout_id"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Amount float64 `json:"amount"`
|
||||
CurrencyCode string `json:"currency_code"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
OperationsCount int `json:"operations_count"`
|
||||
PayoutID int64 `json:"payout_id"`
|
||||
Type string `json:"type"`
|
||||
Status string `json:"status"`
|
||||
Amount float64 `json:"amount"`
|
||||
CurrencyCode string `json:"currency_code"`
|
||||
CreatedAt string `json:"created_at"`
|
||||
OperationsCount int `json:"operations_count"`
|
||||
}
|
||||
|
||||
func FinancePayoutList(w http.ResponseWriter, r *http.Request) {
|
||||
@ -97,6 +142,30 @@ func FinancePayoutList(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
payouts := GetPayoutsFixtures()
|
||||
|
||||
if req.Filter.Since != "" {
|
||||
sinceTs := parseTimeOrZero(req.Filter.Since)
|
||||
filtered := make([]Payout, 0)
|
||||
for _, p := range payouts {
|
||||
ts := parseTimeOrZero(p.CreatedAt)
|
||||
if ts >= sinceTs {
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
}
|
||||
payouts = filtered
|
||||
}
|
||||
|
||||
if req.Filter.To != "" {
|
||||
toTs := parseTimeOrZero(req.Filter.To)
|
||||
filtered := make([]Payout, 0)
|
||||
for _, p := range payouts {
|
||||
ts := parseTimeOrZero(p.CreatedAt)
|
||||
if ts <= toTs {
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
}
|
||||
payouts = filtered
|
||||
}
|
||||
|
||||
if req.Limit == 0 {
|
||||
req.Limit = 100
|
||||
}
|
||||
@ -112,11 +181,10 @@ func FinancePayoutList(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
// AnalyticsDataRequest - POST /v1/analytics/data
|
||||
type AnalyticsDataRequest struct {
|
||||
DateFrom string `json:"date_from"`
|
||||
DateTo string `json:"date_to"`
|
||||
Metrics []string `json:"metrics"`
|
||||
DateFrom string `json:"date_from"`
|
||||
DateTo string `json:"date_to"`
|
||||
Metrics []string `json:"metrics"`
|
||||
Dimension []string `json:"dimension"`
|
||||
}
|
||||
|
||||
@ -126,34 +194,44 @@ func AnalyticsData(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var req AnalyticsDataRequest
|
||||
_ = json.NewDecoder(r.Body).Decode(&req)
|
||||
|
||||
results := []map[string]any{
|
||||
{
|
||||
"date": time.Now().Format("2006-01-02"),
|
||||
"orders_count": 42,
|
||||
"revenue": 125000.50,
|
||||
"avg_order": 2976.20,
|
||||
},
|
||||
}
|
||||
if req.DateFrom != "" {
|
||||
results[0]["date_from"] = req.DateFrom
|
||||
}
|
||||
if req.DateTo != "" {
|
||||
results[0]["date_to"] = req.DateTo
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]any{
|
||||
"data": []map[string]any{
|
||||
{
|
||||
"date": time.Now().Format("2006-01-02"),
|
||||
"orders_count": 42,
|
||||
"revenue": 125000.50,
|
||||
"avg_order": 2976.20,
|
||||
},
|
||||
},
|
||||
"data": results,
|
||||
"total": 1,
|
||||
})
|
||||
}
|
||||
|
||||
// TurnoverStocksRequest - POST /v1/analytics/turnover/stocks
|
||||
type TurnoverStocksRequest struct {
|
||||
Date string `json:"date"`
|
||||
SKU []string `json:"sku"`
|
||||
Date string `json:"date"`
|
||||
SKU []string `json:"sku"`
|
||||
}
|
||||
|
||||
type TurnoverStocksResponse struct {
|
||||
Items []struct {
|
||||
SKU string `json:"sku"`
|
||||
ProductID int64 `json:"product_id"`
|
||||
OnHand int `json:"orders_count_canceled"`
|
||||
Reserved int `json:"reserved"`
|
||||
InWayToCustomer int `json:"in_way_to_customer"`
|
||||
InWayFromCustomer int `json:"in_way_from_customer"`
|
||||
SKU string `json:"sku"`
|
||||
ProductID int64 `json:"product_id"`
|
||||
OnHand int `json:"orders_count_canceled"`
|
||||
Reserved int `json:"reserved"`
|
||||
InWayToCustomer int `json:"in_way_to_customer"`
|
||||
InWayFromCustomer int `json:"in_way_from_customer"`
|
||||
} `json:"items"`
|
||||
}
|
||||
|
||||
@ -163,15 +241,22 @@ func TurnoverStocks(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var req TurnoverStocksRequest
|
||||
_ = json.NewDecoder(r.Body).Decode(&req)
|
||||
|
||||
if len(req.SKU) > 0 {
|
||||
_ = req.SKU
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(TurnoverStocksResponse{
|
||||
Items: []struct {
|
||||
SKU string `json:"sku"`
|
||||
ProductID int64 `json:"product_id"`
|
||||
OnHand int `json:"orders_count_canceled"`
|
||||
Reserved int `json:"reserved"`
|
||||
InWayToCustomer int `json:"in_way_to_customer"`
|
||||
InWayFromCustomer int `json:"in_way_from_customer"`
|
||||
SKU string `json:"sku"`
|
||||
ProductID int64 `json:"product_id"`
|
||||
OnHand int `json:"orders_count_canceled"`
|
||||
Reserved int `json:"reserved"`
|
||||
InWayToCustomer int `json:"in_way_to_customer"`
|
||||
InWayFromCustomer int `json:"in_way_from_customer"`
|
||||
}{
|
||||
{SKU: "TEST-SKU-001", ProductID: 99001234001, OnHand: 150, Reserved: 0, InWayToCustomer: 10, InWayFromCustomer: 2},
|
||||
{SKU: "TEST-SKU-002", ProductID: 99001234002, OnHand: 75, Reserved: 5, InWayToCustomer: 15, InWayFromCustomer: 1},
|
||||
|
||||
Reference in New Issue
Block a user