Files
bssapp/svc/routes/product_performance.go
T

230 lines
7.4 KiB
Go

package routes
import (
"bssapp-backend/queries"
"bssapp-backend/utils"
"context"
"database/sql"
"encoding/json"
"net/http"
"strconv"
"strings"
"time"
)
func GetProductPerformanceHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 60*time.Second)
defer cancel()
f := queries.ProductPerformanceFilters{
Search: strings.TrimSpace(r.URL.Query().Get("q")),
ProductCode: strings.TrimSpace(r.URL.Query().Get("product_code")),
MarketKey: strings.TrimSpace(r.URL.Query().Get("market_key")),
Kategori: strings.TrimSpace(r.URL.Query().Get("kategori")),
Seri: strings.TrimSpace(r.URL.Query().Get("seri")),
Bucket: strings.TrimSpace(r.URL.Query().Get("bucket")),
SortBy: strings.TrimSpace(r.URL.Query().Get("sort_by")),
Descending: boolQuery(r, "descending", true),
Limit: intQuery(r, "limit", 100),
Page: intQuery(r, "page", 1),
}
rows, total, err := queries.ListProductPerformance(ctx, pg, f)
if err != nil {
http.Error(w, "urun performans listesi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("X-Total-Count", strconv.Itoa(total))
_ = json.NewEncoder(w).Encode(map[string]any{
"rows": rows,
"total_count": total,
"page": f.Page,
"limit": f.Limit,
})
}
}
func GetProductPerformanceSalesDetailsHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second)
defer cancel()
rows, err := queries.ListProductPerformanceSalesDetails(
ctx,
pg,
strings.TrimSpace(r.URL.Query().Get("product_code")),
strings.TrimSpace(r.URL.Query().Get("color_code")),
strings.TrimSpace(r.URL.Query().Get("yaka_kodu")),
intQuery(r, "limit", 100),
)
if err != nil {
http.Error(w, "urun satis detayi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(rows)
}
}
func GetProductPerformanceStockSizesHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second)
defer cancel()
rows, err := queries.ListProductPerformanceStockSizes(
ctx,
strings.TrimSpace(r.URL.Query().Get("product_code")),
strings.TrimSpace(r.URL.Query().Get("color_code")),
strings.TrimSpace(r.URL.Query().Get("yaka_kodu")),
)
if err != nil {
http.Error(w, "urun beden stok detayi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(rows)
}
}
func GetProductPerformanceSummaryHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 30*time.Second)
defer cancel()
summary, err := queries.GetProductPerformanceSummary(ctx, pg)
if err != nil {
http.Error(w, "urun performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(summary)
}
}
func GetProductPerformanceMarketsHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 30*time.Second)
defer cancel()
rows, err := queries.ListProductPerformanceMarkets(ctx, pg, intQuery(r, "limit", 100))
if err != nil {
http.Error(w, "piyasa performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(rows)
}
}
func GetProductPerformanceCountriesHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 30*time.Second)
defer cancel()
rows, err := queries.ListProductPerformanceCountries(ctx, pg, intQuery(r, "limit", 100))
if err != nil {
http.Error(w, "ulke performans ozeti alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(rows)
}
}
func GetProductPerformanceCustomersHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
traceID := utils.TraceIDFromRequest(r)
ctx, cancel := context.WithTimeout(utils.ContextWithTraceID(r.Context(), traceID), 30*time.Second)
defer cancel()
rows, err := queries.ListProductPerformanceCustomers(
ctx,
pg,
strings.TrimSpace(r.URL.Query().Get("breakdown")),
intQuery(r, "limit", 100),
)
if err != nil {
http.Error(w, "musteri performans kirilimi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(rows)
}
}
type productPerformanceRefreshPayload struct {
Mode string `json:"mode"`
Stage string `json:"stage"`
ResumeAfter int `json:"resume_after"`
SkipDelete bool `json:"skip_delete"`
StartDate string `json:"start_date"`
EndDate string `json:"end_date"`
}
func PostProductPerformanceRefreshHandler(pg *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json; charset=utf-8")
var payload productPerformanceRefreshPayload
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
http.Error(w, "invalid payload", http.StatusBadRequest)
return
}
now := time.Now()
startDate := parseDateOrZero(payload.StartDate)
endDate := parseDateOrZero(payload.EndDate)
if endDate.IsZero() {
endDate = now
}
ctx, cancel := context.WithTimeout(r.Context(), 4*time.Hour)
defer cancel()
result, err := queries.RefreshProductPerformance(ctx, pg, queries.ProductPerformanceRefreshRequest{
Mode: payload.Mode,
Stage: payload.Stage,
ResumeAfter: payload.ResumeAfter,
SkipDelete: payload.SkipDelete,
StartDate: startDate,
EndDate: endDate,
})
if err != nil {
http.Error(w, "urun performans refresh hatasi: "+err.Error(), http.StatusInternalServerError)
return
}
_ = json.NewEncoder(w).Encode(result)
}
}
func intQuery(r *http.Request, key string, fallback int) int {
raw := strings.TrimSpace(r.URL.Query().Get(key))
if raw == "" {
return fallback
}
n, err := strconv.Atoi(raw)
if err != nil || n <= 0 {
return fallback
}
return n
}
func boolQuery(r *http.Request, key string, fallback bool) bool {
raw := strings.TrimSpace(strings.ToLower(r.URL.Query().Get(key)))
if raw == "" {
return fallback
}
return raw == "1" || raw == "true" || raw == "yes" || raw == "on"
}
func parseDateOrZero(raw string) time.Time {
raw = strings.TrimSpace(raw)
if raw == "" {
return time.Time{}
}
t, err := time.Parse("2006-01-02", raw)
if err != nil {
return time.Time{}
}
return t
}