716 lines
20 KiB
Go
716 lines
20 KiB
Go
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(NULLIF(tr.wholesale_step, 0), tr.step, 0)::float8,
|
|
COALESCE(NULLIF(tr.retail_step, 0), 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(NULLIF(ur.wholesale_step, 0), ur.step, 0)::float8,
|
|
COALESCE(NULLIF(ur.retail_step, 0), 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(NULLIF(er.wholesale_step, 0), er.step, 0)::float8,
|
|
COALESCE(NULLIF(er.retail_step, 0), 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.TryWholesaleStep, &rule.TryRetailStep,
|
|
&rule.UsdBase, &rule.Usd1, &rule.Usd2, &rule.Usd3, &rule.Usd4, &rule.Usd5, &rule.Usd6, &rule.UsdWholesaleStep, &rule.UsdRetailStep,
|
|
&rule.EurBase, &rule.Eur1, &rule.Eur2, &rule.Eur3, &rule.Eur4, &rule.Eur5, &rule.Eur6, &rule.EurWholesaleStep, &rule.EurRetailStep,
|
|
); 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
|
|
}
|