This commit is contained in:
2026-05-12 05:08:39 +02:00
parent ee054955b9
commit c99065496b
28 changed files with 2045 additions and 120 deletions
+260
View File
@@ -55,6 +55,32 @@ type CategoryProductCard struct {
EAN13 string
}
type MenuItem struct {
ID int64
ParentID int64
Name string
Slug string
Depth int
URL string `gorm:"-"`
Children []MenuItem `gorm:"-"`
}
type LocaleOption struct {
ID int64
CurrencyID int64 `gorm:"column:currency_id"`
Label string
Code string
Meta string
URL string `gorm:"-"`
}
type HeaderLocaleData struct {
CurrentLanguage LocaleOption
CurrentCountry LocaleOption
Languages []LocaleOption
Countries []LocaleOption
}
type Service struct {
db *gorm.DB
prefix string
@@ -239,3 +265,237 @@ func (s *Service) ResolveLanguageID(ctx context.Context, req *http.Request, fall
}
return row.ID
}
func (s *Service) GetCategoryMenu(ctx context.Context, languageID int64, shopID int64) ([]MenuItem, error) {
rootCategoryID, err := s.rootCategoryID(ctx)
if err != nil {
return nil, err
}
query := fmt.Sprintf(`
WITH RECURSIVE category_tree AS (
SELECT c.id_category AS id,
c.id_parent AS parent_id,
cl.name AS name,
cl.link_rewrite AS slug,
0 AS depth
FROM %scategory c
JOIN %scategory_shop cs ON cs.id_category = c.id_category
JOIN %scategory_lang cl ON cl.id_category = c.id_category
WHERE c.id_parent = ?
AND c.active = 1
AND cs.id_shop = ?
AND cl.id_lang = ?
UNION ALL
SELECT c.id_category AS id,
c.id_parent AS parent_id,
cl.name AS name,
cl.link_rewrite AS slug,
tree.depth + 1 AS depth
FROM %scategory c
JOIN %scategory_shop cs ON cs.id_category = c.id_category
JOIN %scategory_lang cl ON cl.id_category = c.id_category
JOIN category_tree tree ON tree.id = c.id_parent
WHERE c.active = 1
AND cs.id_shop = ?
AND cl.id_lang = ?
)
SELECT id, parent_id, name, slug, depth
FROM category_tree
ORDER BY depth ASC, parent_id ASC, name ASC
`, s.prefix, s.prefix, s.prefix, s.prefix, s.prefix, s.prefix)
var flat []MenuItem
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(query), rootCategoryID, shopID, languageID, shopID, languageID).Scan(&flat).Error; err != nil {
return nil, err
}
if len(flat) == 0 {
return nil, nil
}
nodes := make(map[int64]MenuItem, len(flat))
childrenByParent := make(map[int64][]int64, len(flat))
for i := range flat {
item := flat[i]
nodes[item.ID] = item
childrenByParent[item.ParentID] = append(childrenByParent[item.ParentID], item.ID)
}
rootIDs := childrenByParent[rootCategoryID]
roots := make([]MenuItem, 0, len(rootIDs))
for _, id := range rootIDs {
if item, ok := buildMenuTree(id, nodes, childrenByParent); ok {
roots = append(roots, item)
}
}
return roots, nil
}
func (s *Service) GetHeaderLocale(ctx context.Context, languageID int64, currencyID int64, countryISO string) (HeaderLocaleData, error) {
var locale HeaderLocaleData
defaultCurrencyID, err := s.defaultCurrencyID(ctx)
if err != nil {
return HeaderLocaleData{}, err
}
languageQuery := fmt.Sprintf(`
SELECT id_lang AS id,
name AS label,
UPPER(iso_code) AS code,
COALESCE(NULLIF(language_code, ''), UPPER(iso_code)) AS meta
FROM %slang
WHERE active = 1
ORDER BY id_lang ASC
`, s.prefix)
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(languageQuery)).Scan(&locale.Languages).Error; err != nil {
return HeaderLocaleData{}, err
}
hasCountryCurrency, err := s.columnExists(ctx, s.prefix+"country", "id_currency")
if err != nil {
return HeaderLocaleData{}, err
}
var countryQuery string
var countryArgs []any
if hasCountryCurrency {
countryQuery = fmt.Sprintf(`
SELECT c.id_country AS id,
COALESCE(c.id_currency, ?) AS currency_id,
cl.name AS label,
UPPER(c.iso_code) AS code,
TRIM(CONCAT(COALESCE(UPPER(cur.iso_code), ''), ' ', COALESCE(cur.sign, ''))) AS meta
FROM %scountry c
JOIN %scountry_lang cl ON cl.id_country = c.id_country
LEFT JOIN %scurrency cur ON cur.id_currency = c.id_currency
WHERE c.active = 1
AND cl.id_lang = ?
ORDER BY cl.name ASC
`, s.prefix, s.prefix, s.prefix)
countryArgs = []any{defaultCurrencyID, languageID}
} else {
countryQuery = fmt.Sprintf(`
SELECT c.id_country AS id,
? AS currency_id,
cl.name AS label,
UPPER(c.iso_code) AS code,
UPPER(c.iso_code) AS meta
FROM %scountry c
JOIN %scountry_lang cl ON cl.id_country = c.id_country
WHERE c.active = 1
AND cl.id_lang = ?
ORDER BY cl.name ASC
`, s.prefix, s.prefix)
countryArgs = []any{defaultCurrencyID, languageID}
}
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(countryQuery), countryArgs...).Scan(&locale.Countries).Error; err != nil {
return HeaderLocaleData{}, err
}
locale.CurrentLanguage = pickLocaleOptionByID(locale.Languages, languageID)
locale.CurrentCountry = pickLocaleOptionByCode(locale.Countries, countryISO)
return locale, nil
}
func (s *Service) rootCategoryID(ctx context.Context) (int64, error) {
var row struct {
Value string `gorm:"column:value"`
}
query := fmt.Sprintf("SELECT value FROM %sconfiguration WHERE name = 'PS_ROOT_CATEGORY' LIMIT 1", s.prefix)
if err := s.db.WithContext(ctx).Raw(query).Scan(&row).Error; err != nil {
return 0, err
}
id := parseInt64(row.Value)
if id == 0 {
return 1, nil
}
return id, nil
}
func (s *Service) defaultCurrencyID(ctx context.Context) (int64, error) {
var row struct {
Value string `gorm:"column:value"`
}
query := fmt.Sprintf("SELECT value FROM %sconfiguration WHERE name = 'PS_CURRENCY_DEFAULT' LIMIT 1", s.prefix)
if err := s.db.WithContext(ctx).Raw(query).Scan(&row).Error; err != nil {
return 0, err
}
id := parseInt64(row.Value)
if id == 0 {
return 1, nil
}
return id, nil
}
func (s *Service) columnExists(ctx context.Context, tableName string, columnName string) (bool, error) {
var count int64
query := `
SELECT COUNT(*)
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = ?
AND column_name = ?
`
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(query), tableName, columnName).Scan(&count).Error; err != nil {
return false, err
}
return count > 0, nil
}
func parseInt64(value string) int64 {
var n int64
for _, r := range value {
if r < '0' || r > '9' {
return 0
}
n = n*10 + int64(r-'0')
}
return n
}
func buildMenuTree(id int64, nodes map[int64]MenuItem, childrenByParent map[int64][]int64) (MenuItem, bool) {
item, ok := nodes[id]
if !ok {
return MenuItem{}, false
}
childIDs := childrenByParent[id]
if len(childIDs) == 0 {
return item, true
}
item.Children = make([]MenuItem, 0, len(childIDs))
for _, childID := range childIDs {
child, ok := buildMenuTree(childID, nodes, childrenByParent)
if ok {
item.Children = append(item.Children, child)
}
}
return item, true
}
func pickLocaleOptionByID(options []LocaleOption, id int64) LocaleOption {
for _, option := range options {
if option.ID == id && id != 0 {
return option
}
}
if len(options) > 0 {
return options[0]
}
return LocaleOption{}
}
func pickLocaleOptionByCode(options []LocaleOption, code string) LocaleOption {
code = strings.ToUpper(strings.TrimSpace(code))
for _, option := range options {
if option.Code == code && code != "" {
return option
}
}
if len(options) > 0 {
return options[0]
}
if code == "" {
return LocaleOption{}
}
return LocaleOption{Code: code, Label: code, Meta: code}
}
+1 -1
View File
@@ -13,7 +13,7 @@ import (
"regexp"
"strings"
pscookie "prestaproxy/internal/prestashop/cookie"
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
)
type Config struct {
+1 -1
View File
@@ -10,7 +10,7 @@ import (
"strings"
"time"
pscookie "prestaproxy/internal/prestashop/cookie"
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
"gorm.io/gorm"
)