Merge remote-tracking branch 'origin/master'
This commit is contained in:
712
svc/queries/pricing_parameters.go
Normal file
712
svc/queries/pricing_parameters.go
Normal file
@@ -0,0 +1,712 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/lib/pq"
|
||||
)
|
||||
|
||||
type PricingParameterSyncResult struct {
|
||||
Total int `json:"total"`
|
||||
Upserted int `json:"upserted"`
|
||||
Deactivated int `json:"deactivated"`
|
||||
}
|
||||
|
||||
type pricingParameterRow struct {
|
||||
AskiliYan string
|
||||
Kategori string
|
||||
UrunIlkGrubu string
|
||||
UrunAnaGrubu string
|
||||
UrunAltGrubu string
|
||||
Icerik string
|
||||
Marka string
|
||||
BrandCode string
|
||||
BrandGroupSec string
|
||||
}
|
||||
|
||||
type PricingParameterRuleRow struct {
|
||||
PricingParameterID int64 `json:"pricing_parameter_id"`
|
||||
ScopeKey string `json:"scope_key"`
|
||||
AskiliYan string `json:"askili_yan"`
|
||||
Kategori string `json:"kategori"`
|
||||
UrunIlkGrubu string `json:"urun_ilk_grubu"`
|
||||
UrunAnaGrubu string `json:"urun_ana_grubu"`
|
||||
UrunAltGrubu string `json:"urun_alt_grubu"`
|
||||
Icerik string `json:"icerik"`
|
||||
Marka string `json:"marka"`
|
||||
BrandCode string `json:"brand_code"`
|
||||
BrandGroupSec string `json:"brand_group"`
|
||||
HasRule bool `json:"has_rule"`
|
||||
Rule *PricingRuleRow `json:"rule"`
|
||||
}
|
||||
|
||||
// EnsurePricingParameterTables keeps the MSSQL-derived cascade cache close to
|
||||
// the pricing rules. Rows are retained when they disappear from MSSQL and
|
||||
// marked inactive so historical rule scopes remain understandable.
|
||||
func EnsurePricingParameterTables(pg *sql.DB) error {
|
||||
stmts := []string{
|
||||
`
|
||||
CREATE TABLE IF NOT EXISTS mk_urunpricingprmtr (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
askili_yan TEXT NOT NULL DEFAULT '',
|
||||
kategori TEXT NOT NULL DEFAULT '',
|
||||
urun_ilk_grubu TEXT NOT NULL DEFAULT '',
|
||||
urun_ana_grubu TEXT NOT NULL DEFAULT '',
|
||||
urun_alt_grubu TEXT NOT NULL DEFAULT '',
|
||||
icerik TEXT NOT NULL DEFAULT '',
|
||||
marka TEXT NOT NULL DEFAULT '',
|
||||
brand_code TEXT NOT NULL DEFAULT '',
|
||||
brand_group_sec TEXT NOT NULL DEFAULT '',
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
first_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
||||
scope_key TEXT GENERATED ALWAYS AS (
|
||||
md5(askili_yan || chr(31) || kategori || chr(31) || urun_ilk_grubu ||
|
||||
chr(31) || urun_ana_grubu || chr(31) || urun_alt_grubu || chr(31) ||
|
||||
icerik || chr(31) || marka || chr(31) || brand_code || chr(31) ||
|
||||
brand_group_sec)
|
||||
) STORED
|
||||
)`,
|
||||
`DROP INDEX IF EXISTS ux_mk_urunpricingprmtr_scope`,
|
||||
`
|
||||
DO $$
|
||||
BEGIN
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM information_schema.columns
|
||||
WHERE table_schema=current_schema()
|
||||
AND table_name='mk_urunpricingprmtr'
|
||||
AND column_name='karisim'
|
||||
) THEN
|
||||
DROP INDEX IF EXISTS ux_mk_urunpricingprmtr_active_scope;
|
||||
DROP INDEX IF EXISTS ix_mk_urunpricingprmtr_scope_history;
|
||||
ALTER TABLE mk_urunpricingprmtr DROP COLUMN IF EXISTS scope_key;
|
||||
ALTER TABLE mk_urunpricingprmtr DROP COLUMN karisim;
|
||||
END IF;
|
||||
END $$`,
|
||||
`
|
||||
ALTER TABLE mk_urunpricingprmtr
|
||||
ADD COLUMN IF NOT EXISTS scope_key TEXT GENERATED ALWAYS AS (
|
||||
md5(askili_yan || chr(31) || kategori || chr(31) || urun_ilk_grubu ||
|
||||
chr(31) || urun_ana_grubu || chr(31) || urun_alt_grubu || chr(31) ||
|
||||
icerik || chr(31) || marka || chr(31) || brand_code || chr(31) ||
|
||||
brand_group_sec)
|
||||
) STORED`,
|
||||
`
|
||||
WITH ranked AS (
|
||||
SELECT
|
||||
id,
|
||||
ROW_NUMBER() OVER (PARTITION BY scope_key ORDER BY last_seen_at DESC, id DESC) AS rn
|
||||
FROM mk_urunpricingprmtr
|
||||
WHERE is_active=TRUE
|
||||
)
|
||||
UPDATE mk_urunpricingprmtr p
|
||||
SET is_active=FALSE
|
||||
FROM ranked r
|
||||
WHERE p.id=r.id
|
||||
AND r.rn > 1`,
|
||||
`CREATE UNIQUE INDEX IF NOT EXISTS ux_mk_urunpricingprmtr_active_scope ON mk_urunpricingprmtr (scope_key) WHERE is_active = TRUE`,
|
||||
`CREATE INDEX IF NOT EXISTS ix_mk_urunpricingprmtr_scope_history ON mk_urunpricingprmtr (scope_key, last_seen_at DESC, id DESC)`,
|
||||
`CREATE INDEX IF NOT EXISTS ix_mk_urunpricingprmtr_active ON mk_urunpricingprmtr (is_active)`,
|
||||
`CREATE INDEX IF NOT EXISTS ix_mk_urunpricingprmtr_ilk_ana ON mk_urunpricingprmtr (urun_ilk_grubu, urun_ana_grubu) WHERE is_active = TRUE`,
|
||||
`CREATE INDEX IF NOT EXISTS ix_mk_urunpricingprmtr_brand ON mk_urunpricingprmtr (brand_code, brand_group_sec) WHERE is_active = TRUE`,
|
||||
`ALTER TABLE mk_pricing_rule ADD COLUMN IF NOT EXISTS pricing_parameter_id BIGINT REFERENCES mk_urunpricingprmtr(id) ON DELETE SET NULL`,
|
||||
`DROP INDEX IF EXISTS ux_mk_pricing_rule_parameter`,
|
||||
`CREATE INDEX IF NOT EXISTS ix_mk_pricing_rule_parameter_latest ON mk_pricing_rule (pricing_parameter_id, created_at DESC, updated_at DESC) WHERE pricing_parameter_id IS NOT NULL`,
|
||||
}
|
||||
for _, stmt := range stmts {
|
||||
if _, err := pg.Exec(stmt); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func FillPricingRuleScopeFromParameter(ctx context.Context, tx *sql.Tx, item *PricingRuleSaveItem) error {
|
||||
if item == nil || item.PricingParameterID <= 0 {
|
||||
return nil
|
||||
}
|
||||
var p pricingParameterRow
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
SELECT
|
||||
askili_yan, kategori, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||||
icerik, marka, brand_code, brand_group_sec
|
||||
FROM mk_urunpricingprmtr
|
||||
WHERE id=$1 AND is_active=TRUE
|
||||
`, item.PricingParameterID).Scan(
|
||||
&p.AskiliYan,
|
||||
&p.Kategori,
|
||||
&p.UrunIlkGrubu,
|
||||
&p.UrunAnaGrubu,
|
||||
&p.UrunAltGrubu,
|
||||
&p.Icerik,
|
||||
&p.Marka,
|
||||
&p.BrandCode,
|
||||
&p.BrandGroupSec,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
item.AskiliYan = pricingParameterScopeValue(p.AskiliYan)
|
||||
item.Kategori = pricingParameterScopeValue(p.Kategori)
|
||||
item.UrunIlkGrubu = pricingParameterScopeValue(p.UrunIlkGrubu)
|
||||
item.UrunAnaGrubu = pricingParameterScopeValue(p.UrunAnaGrubu)
|
||||
item.UrunAltGrubu = pricingParameterScopeValue(p.UrunAltGrubu)
|
||||
item.Icerik = pricingParameterScopeValue(p.Icerik)
|
||||
item.Karisim = nil
|
||||
item.Marka = pricingParameterScopeValue(p.Marka)
|
||||
item.BrandCode = pricingParameterScopeValue(p.BrandCode)
|
||||
item.BrandGroupSec = pricingParameterScopeValue(p.BrandGroupSec)
|
||||
return nil
|
||||
}
|
||||
|
||||
func VersionPricingParameterForRule(ctx context.Context, tx *sql.Tx, pricingParameterID int64) (int64, error) {
|
||||
if pricingParameterID <= 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var p pricingParameterRow
|
||||
var scopeKey string
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
SELECT
|
||||
askili_yan, kategori, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||||
icerik, marka, brand_code, brand_group_sec, scope_key
|
||||
FROM mk_urunpricingprmtr
|
||||
WHERE id=$1
|
||||
AND is_active=TRUE
|
||||
`, pricingParameterID).Scan(
|
||||
&p.AskiliYan,
|
||||
&p.Kategori,
|
||||
&p.UrunIlkGrubu,
|
||||
&p.UrunAnaGrubu,
|
||||
&p.UrunAltGrubu,
|
||||
&p.Icerik,
|
||||
&p.Marka,
|
||||
&p.BrandCode,
|
||||
&p.BrandGroupSec,
|
||||
&scopeKey,
|
||||
); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE mk_urunpricingprmtr
|
||||
SET is_active=FALSE,
|
||||
last_seen_at=now()
|
||||
WHERE scope_key=$1
|
||||
AND is_active=TRUE
|
||||
`, scopeKey); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var newID int64
|
||||
if err := tx.QueryRowContext(ctx, `
|
||||
INSERT INTO mk_urunpricingprmtr (
|
||||
askili_yan, kategori, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||||
icerik, marka, brand_code, brand_group_sec,
|
||||
is_active, first_seen_at, last_seen_at
|
||||
)
|
||||
VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,TRUE,now(),now())
|
||||
RETURNING id
|
||||
`,
|
||||
p.AskiliYan,
|
||||
p.Kategori,
|
||||
p.UrunIlkGrubu,
|
||||
p.UrunAnaGrubu,
|
||||
p.UrunAltGrubu,
|
||||
p.Icerik,
|
||||
p.Marka,
|
||||
p.BrandCode,
|
||||
p.BrandGroupSec,
|
||||
).Scan(&newID); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return newID, nil
|
||||
}
|
||||
|
||||
func pricingParameterScopeValue(value string) []string {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return nil
|
||||
}
|
||||
return []string{value}
|
||||
}
|
||||
|
||||
func SyncPricingParametersFromMSSQL(ctx context.Context, mssql *sql.DB, pg *sql.DB) (PricingParameterSyncResult, error) {
|
||||
out := PricingParameterSyncResult{}
|
||||
startedAt := time.Now()
|
||||
if mssql == nil || pg == nil {
|
||||
return out, sql.ErrConnDone
|
||||
}
|
||||
if err := EnsurePricingRuleTables(pg); err != nil {
|
||||
return out, err
|
||||
}
|
||||
if err := EnsurePricingParameterTables(pg); err != nil {
|
||||
return out, err
|
||||
}
|
||||
if err := EnsureBrandClassificationTables(pg); err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
rows, err := mssql.QueryContext(ctx, `
|
||||
SELECT DISTINCT
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt45Desc)), '') AS AskiliYan,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt44Desc)), '') AS Kategori,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt42Desc)), '') AS UrunIlkGrubu,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt01Desc)), '') AS UrunAnaGrubu,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt02Desc)), '') AS UrunAltGrubu,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt41Desc)), '') AS Icerik,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt10Desc)), '') AS Marka,
|
||||
COALESCE(LTRIM(RTRIM(ProductAtt10)), '') AS BrandCode
|
||||
FROM ProductFilterWithDescription('TR')
|
||||
WHERE ProductAtt42 IN ('SERI', 'AKSESUAR')
|
||||
AND IsBlocked = 0
|
||||
AND LEN(LTRIM(RTRIM(ProductCode))) = 13;
|
||||
`)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
src := make([]pricingParameterRow, 0, 4096)
|
||||
for rows.Next() {
|
||||
var item pricingParameterRow
|
||||
if err := rows.Scan(
|
||||
&item.AskiliYan,
|
||||
&item.Kategori,
|
||||
&item.UrunIlkGrubu,
|
||||
&item.UrunAnaGrubu,
|
||||
&item.UrunAltGrubu,
|
||||
&item.Icerik,
|
||||
&item.Marka,
|
||||
&item.BrandCode,
|
||||
); err != nil {
|
||||
return out, err
|
||||
}
|
||||
item = trimPricingParameterRow(item)
|
||||
src = append(src, item)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.Total = len(src)
|
||||
log.Printf("Pricing parameter sync source loaded: rows=%d duration=%s", out.Total, time.Since(startedAt))
|
||||
|
||||
groupByBrand, err := pricingParameterBrandGroups(ctx, pg)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
tx, err := pg.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
defer tx.Rollback()
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
CREATE TEMP TABLE tmp_urunpricingprmtr_sync (
|
||||
askili_yan TEXT NOT NULL,
|
||||
kategori TEXT NOT NULL,
|
||||
urun_ilk_grubu TEXT NOT NULL,
|
||||
urun_ana_grubu TEXT NOT NULL,
|
||||
urun_alt_grubu TEXT NOT NULL,
|
||||
icerik TEXT NOT NULL,
|
||||
marka TEXT NOT NULL,
|
||||
brand_code TEXT NOT NULL,
|
||||
brand_group_sec TEXT NOT NULL,
|
||||
scope_key TEXT NOT NULL PRIMARY KEY
|
||||
) ON COMMIT DROP
|
||||
`); err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
copyStmt, err := tx.PrepareContext(ctx, pq.CopyIn(
|
||||
"tmp_urunpricingprmtr_sync",
|
||||
"askili_yan",
|
||||
"kategori",
|
||||
"urun_ilk_grubu",
|
||||
"urun_ana_grubu",
|
||||
"urun_alt_grubu",
|
||||
"icerik",
|
||||
"marka",
|
||||
"brand_code",
|
||||
"brand_group_sec",
|
||||
"scope_key",
|
||||
))
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
seenScopeKeys := make(map[string]struct{}, len(src))
|
||||
for _, item := range src {
|
||||
item.BrandGroupSec = groupByBrand[item.BrandCode]
|
||||
scopeKey := pricingParameterScopeKey(item)
|
||||
if _, exists := seenScopeKeys[scopeKey]; exists {
|
||||
continue
|
||||
}
|
||||
seenScopeKeys[scopeKey] = struct{}{}
|
||||
if _, err := copyStmt.ExecContext(ctx,
|
||||
item.AskiliYan,
|
||||
item.Kategori,
|
||||
item.UrunIlkGrubu,
|
||||
item.UrunAnaGrubu,
|
||||
item.UrunAltGrubu,
|
||||
item.Icerik,
|
||||
item.Marka,
|
||||
item.BrandCode,
|
||||
item.BrandGroupSec,
|
||||
scopeKey,
|
||||
); err != nil {
|
||||
_ = copyStmt.Close()
|
||||
return out, err
|
||||
}
|
||||
}
|
||||
if _, err := copyStmt.ExecContext(ctx); err != nil {
|
||||
_ = copyStmt.Close()
|
||||
return out, err
|
||||
}
|
||||
if err := copyStmt.Close(); err != nil {
|
||||
return out, err
|
||||
}
|
||||
out.Upserted = len(seenScopeKeys)
|
||||
log.Printf("Pricing parameter sync copy loaded: rows=%d duration=%s", out.Upserted, time.Since(startedAt))
|
||||
|
||||
res, err := tx.ExecContext(ctx, `
|
||||
UPDATE mk_urunpricingprmtr p
|
||||
SET is_active=FALSE
|
||||
WHERE p.is_active=TRUE
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM tmp_urunpricingprmtr_sync t
|
||||
WHERE t.scope_key=p.scope_key
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
if n, err := res.RowsAffected(); err == nil {
|
||||
out.Deactivated = int(n)
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `
|
||||
UPDATE mk_urunpricingprmtr p
|
||||
SET last_seen_at=now()
|
||||
FROM tmp_urunpricingprmtr_sync t
|
||||
WHERE p.scope_key=t.scope_key
|
||||
AND p.is_active=TRUE
|
||||
`); err != nil {
|
||||
return out, err
|
||||
}
|
||||
|
||||
insertResult, err := tx.ExecContext(ctx, `
|
||||
INSERT INTO mk_urunpricingprmtr (
|
||||
askili_yan, kategori, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||||
icerik, marka, brand_code, brand_group_sec,
|
||||
is_active, first_seen_at, last_seen_at
|
||||
)
|
||||
SELECT
|
||||
askili_yan, kategori, urun_ilk_grubu, urun_ana_grubu, urun_alt_grubu,
|
||||
icerik, marka, brand_code, brand_group_sec,
|
||||
TRUE, now(), now()
|
||||
FROM tmp_urunpricingprmtr_sync t
|
||||
WHERE NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM mk_urunpricingprmtr p
|
||||
WHERE p.scope_key=t.scope_key
|
||||
AND p.is_active=TRUE
|
||||
)
|
||||
`)
|
||||
if err != nil {
|
||||
return out, err
|
||||
}
|
||||
if n, err := insertResult.RowsAffected(); err == nil {
|
||||
out.Upserted = int(n)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return out, err
|
||||
}
|
||||
log.Printf("Pricing parameter sync committed: rows=%d duration=%s", out.Upserted, time.Since(startedAt))
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func pricingParameterScopeKey(item pricingParameterRow) string {
|
||||
parts := []string{
|
||||
item.AskiliYan,
|
||||
item.Kategori,
|
||||
item.UrunIlkGrubu,
|
||||
item.UrunAnaGrubu,
|
||||
item.UrunAltGrubu,
|
||||
item.Icerik,
|
||||
item.Marka,
|
||||
item.BrandCode,
|
||||
item.BrandGroupSec,
|
||||
}
|
||||
sum := md5.Sum([]byte(strings.Join(parts, string(rune(31)))))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func trimPricingParameterRow(item pricingParameterRow) pricingParameterRow {
|
||||
item.AskiliYan = strings.TrimSpace(item.AskiliYan)
|
||||
item.Kategori = strings.TrimSpace(item.Kategori)
|
||||
item.UrunIlkGrubu = strings.TrimSpace(item.UrunIlkGrubu)
|
||||
item.UrunAnaGrubu = strings.TrimSpace(item.UrunAnaGrubu)
|
||||
item.UrunAltGrubu = strings.TrimSpace(item.UrunAltGrubu)
|
||||
item.Icerik = strings.TrimSpace(item.Icerik)
|
||||
item.Marka = strings.TrimSpace(item.Marka)
|
||||
item.BrandCode = strings.TrimSpace(item.BrandCode)
|
||||
item.BrandGroupSec = strings.TrimSpace(item.BrandGroupSec)
|
||||
return item
|
||||
}
|
||||
|
||||
func pricingParameterBrandGroups(ctx context.Context, pg *sql.DB) (map[string]string, error) {
|
||||
rows, err := pg.QueryContext(ctx, `
|
||||
SELECT m.brand_code, g.title
|
||||
FROM mk_brandgrpmatch m
|
||||
JOIN mk_brandgrp g ON g.id = m.grp_id
|
||||
`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := make(map[string]string, 1024)
|
||||
for rows.Next() {
|
||||
var code, group string
|
||||
if err := rows.Scan(&code, &group); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out[strings.TrimSpace(code)] = strings.TrimSpace(group)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func ListPricingParameterDistinctOptions(ctx context.Context, pg *sql.DB, field string, f PricingRuleOptionFilters, limit int) ([]string, error) {
|
||||
field = strings.TrimSpace(field)
|
||||
if limit <= 0 {
|
||||
limit = 500
|
||||
}
|
||||
fieldMap := map[string]string{
|
||||
"askili_yan": "askili_yan",
|
||||
"kategori": "kategori",
|
||||
"urun_ilk_grubu": "urun_ilk_grubu",
|
||||
"urun_ana_grubu": "urun_ana_grubu",
|
||||
"urun_alt_grubu": "urun_alt_grubu",
|
||||
"icerik": "icerik",
|
||||
"marka": "marka",
|
||||
"brand_code": "brand_code",
|
||||
"brand_group": "brand_group_sec",
|
||||
}
|
||||
target, ok := fieldMap[field]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid field")
|
||||
}
|
||||
|
||||
type filter struct {
|
||||
Field string
|
||||
Values []string
|
||||
}
|
||||
filters := []filter{
|
||||
{"askili_yan", f.AskiliYan},
|
||||
{"kategori", f.Kategori},
|
||||
{"urun_ilk_grubu", f.UrunIlkGrubu},
|
||||
{"urun_ana_grubu", f.UrunAnaGrubu},
|
||||
{"urun_alt_grubu", f.UrunAltGrubu},
|
||||
{"icerik", f.Icerik},
|
||||
{"marka", f.Marka},
|
||||
{"brand_code", f.BrandCode},
|
||||
{"brand_group", f.BrandGroupSec},
|
||||
}
|
||||
|
||||
args := make([]any, 0, len(filters)+1)
|
||||
where := []string{"is_active=TRUE", target + " <> ''"}
|
||||
for _, item := range filters {
|
||||
if item.Field == field {
|
||||
continue
|
||||
}
|
||||
values := normalizeTextList(item.Values)
|
||||
if len(values) == 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, pq.Array(values))
|
||||
where = append(where, fieldMap[item.Field]+fmt.Sprintf(" = ANY($%d::text[])", len(args)))
|
||||
}
|
||||
args = append(args, limit)
|
||||
|
||||
rows, err := pg.QueryContext(ctx, `
|
||||
SELECT DISTINCT `+target+`
|
||||
FROM mk_urunpricingprmtr
|
||||
WHERE `+strings.Join(where, " AND ")+`
|
||||
ORDER BY `+target+`
|
||||
LIMIT $`+fmt.Sprint(len(args))+`
|
||||
`, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := make([]string, 0, limit)
|
||||
for rows.Next() {
|
||||
var value string
|
||||
if err := rows.Scan(&value); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
value = strings.TrimSpace(value)
|
||||
if value != "" {
|
||||
out = append(out, value)
|
||||
}
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func ListPricingParameterRules(ctx context.Context, pg *sql.DB, f PricingRuleOptionFilters) ([]PricingParameterRuleRow, error) {
|
||||
where, args := pricingParameterFilterSQL(f)
|
||||
|
||||
rows, err := pg.QueryContext(ctx, `
|
||||
SELECT
|
||||
p.id,
|
||||
p.scope_key,
|
||||
p.askili_yan,
|
||||
p.kategori,
|
||||
p.urun_ilk_grubu,
|
||||
p.urun_ana_grubu,
|
||||
p.urun_alt_grubu,
|
||||
p.icerik,
|
||||
p.marka,
|
||||
p.brand_code,
|
||||
p.brand_group_sec,
|
||||
COALESCE(r.id::text, ''),
|
||||
COALESCE(r.is_active, TRUE),
|
||||
|
||||
COALESCE(tx.base_mult, 0)::float8,
|
||||
COALESCE(tx.m1, 0)::float8,
|
||||
COALESCE(tx.m2, 0)::float8,
|
||||
COALESCE(tx.m3, 0)::float8,
|
||||
COALESCE(tx.m4, 0)::float8,
|
||||
COALESCE(tx.m5, 0)::float8,
|
||||
COALESCE(tx.m6, 0)::float8,
|
||||
COALESCE(tr.step, 0)::float8,
|
||||
|
||||
COALESCE(ux.base_mult, 0)::float8,
|
||||
COALESCE(ux.m1, 0)::float8,
|
||||
COALESCE(ux.m2, 0)::float8,
|
||||
COALESCE(ux.m3, 0)::float8,
|
||||
COALESCE(ux.m4, 0)::float8,
|
||||
COALESCE(ux.m5, 0)::float8,
|
||||
COALESCE(ux.m6, 0)::float8,
|
||||
COALESCE(ur.step, 0)::float8,
|
||||
|
||||
COALESCE(ex.base_mult, 0)::float8,
|
||||
COALESCE(ex.m1, 0)::float8,
|
||||
COALESCE(ex.m2, 0)::float8,
|
||||
COALESCE(ex.m3, 0)::float8,
|
||||
COALESCE(ex.m4, 0)::float8,
|
||||
COALESCE(ex.m5, 0)::float8,
|
||||
COALESCE(ex.m6, 0)::float8,
|
||||
COALESCE(er.step, 0)::float8
|
||||
FROM mk_urunpricingprmtr p
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT latest_rule.*
|
||||
FROM mk_pricing_rule latest_rule
|
||||
WHERE latest_rule.pricing_parameter_id = p.id
|
||||
ORDER BY latest_rule.created_at DESC, latest_rule.updated_at DESC, latest_rule.id DESC
|
||||
LIMIT 1
|
||||
) r ON TRUE
|
||||
LEFT JOIN mk_pricex tx ON tx.rule_id = r.id AND tx.currency='TRY'
|
||||
LEFT JOIN mk_pricex ux ON ux.rule_id = r.id AND ux.currency='USD'
|
||||
LEFT JOIN mk_pricex ex ON ex.rule_id = r.id AND ex.currency='EUR'
|
||||
LEFT JOIN mk_priceroll tr ON tr.rule_id = r.id AND tr.currency='TRY'
|
||||
LEFT JOIN mk_priceroll ur ON ur.rule_id = r.id AND ur.currency='USD'
|
||||
LEFT JOIN mk_priceroll er ON er.rule_id = r.id AND er.currency='EUR'
|
||||
WHERE `+strings.Join(where, " AND ")+`
|
||||
ORDER BY
|
||||
p.urun_ilk_grubu,
|
||||
p.urun_ana_grubu,
|
||||
p.urun_alt_grubu,
|
||||
p.marka,
|
||||
p.brand_code,
|
||||
p.id
|
||||
`, args...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
out := make([]PricingParameterRuleRow, 0, 1024)
|
||||
for rows.Next() {
|
||||
var item PricingParameterRuleRow
|
||||
rule := PricingRuleRow{}
|
||||
if err := rows.Scan(
|
||||
&item.PricingParameterID,
|
||||
&item.ScopeKey,
|
||||
&item.AskiliYan,
|
||||
&item.Kategori,
|
||||
&item.UrunIlkGrubu,
|
||||
&item.UrunAnaGrubu,
|
||||
&item.UrunAltGrubu,
|
||||
&item.Icerik,
|
||||
&item.Marka,
|
||||
&item.BrandCode,
|
||||
&item.BrandGroupSec,
|
||||
&rule.ID,
|
||||
&rule.IsActive,
|
||||
&rule.TryBase, &rule.Try1, &rule.Try2, &rule.Try3, &rule.Try4, &rule.Try5, &rule.Try6, &rule.TryStep,
|
||||
&rule.UsdBase, &rule.Usd1, &rule.Usd2, &rule.Usd3, &rule.Usd4, &rule.Usd5, &rule.Usd6, &rule.UsdStep,
|
||||
&rule.EurBase, &rule.Eur1, &rule.Eur2, &rule.Eur3, &rule.Eur4, &rule.Eur5, &rule.Eur6, &rule.EurStep,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rule.PricingParameterID = item.PricingParameterID
|
||||
rule.AskiliYan = pricingParameterScopeValue(item.AskiliYan)
|
||||
rule.Kategori = pricingParameterScopeValue(item.Kategori)
|
||||
rule.UrunIlkGrubu = pricingParameterScopeValue(item.UrunIlkGrubu)
|
||||
rule.UrunAnaGrubu = pricingParameterScopeValue(item.UrunAnaGrubu)
|
||||
rule.UrunAltGrubu = pricingParameterScopeValue(item.UrunAltGrubu)
|
||||
rule.Icerik = pricingParameterScopeValue(item.Icerik)
|
||||
rule.Karisim = nil
|
||||
rule.Marka = pricingParameterScopeValue(item.Marka)
|
||||
rule.BrandCode = pricingParameterScopeValue(item.BrandCode)
|
||||
rule.BrandGroupSec = pricingParameterScopeValue(item.BrandGroupSec)
|
||||
item.HasRule = strings.TrimSpace(rule.ID) != ""
|
||||
if item.HasRule {
|
||||
item.Rule = &rule
|
||||
}
|
||||
out = append(out, item)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
|
||||
func pricingParameterFilterSQL(f PricingRuleOptionFilters) ([]string, []any) {
|
||||
type filter struct {
|
||||
Column string
|
||||
Values []string
|
||||
}
|
||||
filters := []filter{
|
||||
{"p.askili_yan", f.AskiliYan},
|
||||
{"p.kategori", f.Kategori},
|
||||
{"p.urun_ilk_grubu", f.UrunIlkGrubu},
|
||||
{"p.urun_ana_grubu", f.UrunAnaGrubu},
|
||||
{"p.urun_alt_grubu", f.UrunAltGrubu},
|
||||
{"p.icerik", f.Icerik},
|
||||
{"p.marka", f.Marka},
|
||||
{"p.brand_code", f.BrandCode},
|
||||
{"p.brand_group_sec", f.BrandGroupSec},
|
||||
}
|
||||
where := []string{"p.is_active=TRUE"}
|
||||
args := make([]any, 0, len(filters))
|
||||
for _, item := range filters {
|
||||
values := normalizeTextList(item.Values)
|
||||
if len(values) == 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, pq.Array(values))
|
||||
where = append(where, item.Column+fmt.Sprintf(" = ANY($%d::text[])", len(args)))
|
||||
}
|
||||
return where, args
|
||||
}
|
||||
Reference in New Issue
Block a user