Merge remote-tracking branch 'origin/master'
This commit is contained in:
163
svc/routes/pricing_rules.go
Normal file
163
svc/routes/pricing_rules.go
Normal file
@@ -0,0 +1,163 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/queries"
|
||||
"bssapp-backend/utils"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Step-1/2 scope (distinct+cascade) comes from the PostgreSQL parameter cache.
|
||||
// For now we implement:
|
||||
// - Postgres tables (bootstrap)
|
||||
// - List/Save rules (bulk)
|
||||
// - Options endpoint for cascade (mk_urunpricingprmtr)
|
||||
|
||||
type PricingRuleBulkSavePayload struct {
|
||||
Items []queries.PricingRuleSaveItem `json:"items"`
|
||||
}
|
||||
|
||||
func GetPricingRulesHandler(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 := utils.ContextWithTraceID(r.Context(), traceID)
|
||||
|
||||
rows, err := queries.ListPricingRules(ctx, pg)
|
||||
if err != nil {
|
||||
http.Error(w, "pricing rules list error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(rows)
|
||||
}
|
||||
}
|
||||
|
||||
// Very small “bulk upsert” for step-1/2: we only need to persist the multipliers+roundings for now.
|
||||
// Rules are identified by UUID; new rows can be created via empty id (server generates).
|
||||
func SavePricingRulesBulkHandler(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 PricingRuleBulkSavePayload
|
||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||
http.Error(w, "invalid payload", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
traceID := utils.TraceIDFromRequest(r)
|
||||
ctx := utils.ContextWithTraceID(r.Context(), traceID)
|
||||
|
||||
tx, err := pg.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
http.Error(w, "pg transaction start error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
updated := 0
|
||||
for _, it := range payload.Items {
|
||||
// Zero means that no rounding rule has been configured yet.
|
||||
if it.TryStep < 0 || it.UsdStep < 0 || it.EurStep < 0 {
|
||||
http.Error(w, "invalid rounding step", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
id, err := queries.UpsertPricingRule(ctx, tx, it)
|
||||
if err != nil {
|
||||
http.Error(w, "pricing rule save error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
if id != "" {
|
||||
updated++
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
http.Error(w, "pg transaction commit error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{"success": true, "updated": updated})
|
||||
}
|
||||
}
|
||||
|
||||
func GetPricingRuleOptionsHandler(pg *sql.DB) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
field := strings.TrimSpace(r.URL.Query().Get("field"))
|
||||
if field == "" {
|
||||
http.Error(w, "missing field", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
limit := 500
|
||||
if raw := strings.TrimSpace(r.URL.Query().Get("limit")); raw != "" {
|
||||
if n, err := strconv.Atoi(raw); err == nil && n > 0 && n <= 5000 {
|
||||
limit = n
|
||||
}
|
||||
}
|
||||
|
||||
f := pricingRuleFiltersFromRequest(r)
|
||||
|
||||
traceID := utils.TraceIDFromRequest(r)
|
||||
ctx := utils.ContextWithTraceID(r.Context(), traceID)
|
||||
|
||||
opts, err := queries.ListPricingParameterDistinctOptions(ctx, pg, field, f, limit)
|
||||
if err != nil {
|
||||
http.Error(w, "options lookup error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
_ = json.NewEncoder(w).Encode(map[string]any{
|
||||
"field": field,
|
||||
"options": opts,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func GetPricingParameterRulesHandler(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 := utils.ContextWithTraceID(r.Context(), traceID)
|
||||
rows, err := queries.ListPricingParameterRules(ctx, pg, pricingRuleFiltersFromRequest(r))
|
||||
if err != nil {
|
||||
http.Error(w, "pricing parameter rules list error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
_ = json.NewEncoder(w).Encode(rows)
|
||||
}
|
||||
}
|
||||
|
||||
func pricingRuleFiltersFromRequest(r *http.Request) queries.PricingRuleOptionFilters {
|
||||
return queries.PricingRuleOptionFilters{
|
||||
AskiliYan: splitCSV(r.URL.Query().Get("askili_yan")),
|
||||
Kategori: splitCSV(r.URL.Query().Get("kategori")),
|
||||
UrunIlkGrubu: splitCSV(r.URL.Query().Get("urun_ilk_grubu")),
|
||||
UrunAnaGrubu: splitCSV(r.URL.Query().Get("urun_ana_grubu")),
|
||||
UrunAltGrubu: splitCSV(r.URL.Query().Get("urun_alt_grubu")),
|
||||
Icerik: splitCSV(r.URL.Query().Get("icerik")),
|
||||
Marka: splitCSV(r.URL.Query().Get("marka")),
|
||||
BrandCode: splitCSV(r.URL.Query().Get("brand_code")),
|
||||
BrandGroupSec: splitCSV(r.URL.Query().Get("brand_group")),
|
||||
}
|
||||
}
|
||||
|
||||
func splitCSV(raw string) []string {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(raw, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, p := range parts {
|
||||
p = strings.TrimSpace(p)
|
||||
if p != "" {
|
||||
out = append(out, p)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user