lang
This commit is contained in:
@@ -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}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user