This commit is contained in:
2026-08-16 16:57:36 +02:00
parent 96f8c1115c
commit 532d439c41
106 changed files with 10147 additions and 494 deletions
+33 -12
View File
@@ -260,7 +260,7 @@ func enrichCategoryPrompts(ctx context.Context, pool *pgxpool.Pool, companyID uu
}
primary := company.LoadLanguage(ctx, pool, companyID)
item["prompts"] = prompts
item["prompt"] = company.PromptForLanguage(prompts, primary)
item["prompt"] = company.PromptForLanguage(prompts, primary, primary)
item["has_prompt"] = company.HasAnyPrompt(prompts)
return item, nil
}
@@ -668,8 +668,11 @@ func processedProductsCountFromSQL(needsRawJoin bool) string {
// Enrichment coverage SQL predicates (alias p = processed_products, r = raw_products).
const (
processedHasNameSQL = `(COALESCE(NULLIF(p.processed_name, ''), NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '') <> '')`
processedHasDescriptionSQL = `(COALESCE(NULLIF(p.processed_description, ''), NULLIF(p.description, ''), NULLIF(r.mapped_data->>'description', ''), '') <> '')`
// Prefer processed_* so dashboard product fields match V1 process items for the same EAN.
processedPreferredNameSQL = `COALESCE(NULLIF(p.processed_name, ''), NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '')`
processedPreferredDescriptionSQL = `COALESCE(NULLIF(p.processed_description, ''), NULLIF(p.description, ''), NULLIF(r.mapped_data->>'description', ''), '')`
processedHasNameSQL = `(` + processedPreferredNameSQL + ` <> '')`
processedHasDescriptionSQL = `(` + processedPreferredDescriptionSQL + ` <> '')`
processedHasCategorySQL = `(COALESCE(NULLIF(p.category, ''), '') <> '' AND lower(p.category) <> 'none')`
// Resolve display name / canonical unique_id when products store unique_id, UUID id, or name.
processedCategoryResolveJoin = `
@@ -1093,7 +1096,7 @@ func (s *Service) ListProcessedProducts(ctx context.Context, companyID uuid.UUID
func(ctx context.Context) ([]map[string]any, error) {
rows, err := s.Pool.Query(ctx, fmt.Sprintf(`
SELECT p.id, p.product_id,
COALESCE(NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '') AS name,
`+processedPreferredNameSQL+` AS name,
COALESCE(NULLIF(p.processed_name, ''), '') AS processed_name,
p.category,
COALESCE(cat.name, NULLIF(BTRIM(p.category), '')) AS category_name,
@@ -1102,9 +1105,9 @@ func (s *Service) ListProcessedProducts(ctx context.Context, companyID uuid.UUID
f.name AS feed_name,
f.last_synced_at AS feed_last_synced_at,
r.updated_at AS raw_updated_at,
(COALESCE(NULLIF(p.processed_name, ''), NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '') <> '') AS has_name,
(`+processedPreferredNameSQL+` <> '') AS has_name,
(COALESCE(NULLIF(p.processed_name, ''), '') <> '') AS has_processed_name,
(COALESCE(NULLIF(p.processed_description, ''), NULLIF(p.description, ''), NULLIF(r.mapped_data->>'description', ''), '') <> '') AS has_description,
(`+processedPreferredDescriptionSQL+` <> '') AS has_description,
(COALESCE(NULLIF(p.processed_description, ''), '') <> '') AS has_processed_description,
(COALESCE(NULLIF(p.category, ''), '') <> '' AND lower(p.category) <> 'none') AS has_category,
`+processedHasAttributesSQL+` AS has_attributes,
@@ -1120,7 +1123,7 @@ func (s *Service) ListProcessedProducts(ctx context.Context, companyID uuid.UUID
return nil, err
}
defer rows.Close()
return scanMaps(rows, []string{
items, err := scanMaps(rows, []string{
"id", "product_id", "name", "processed_name", "category", "category_name", "category_unique_id",
"status", "raw_product_id", "feed_id", "gtin",
"feed_name", "feed_last_synced_at", "raw_updated_at",
@@ -1128,6 +1131,15 @@ func (s *Service) ListProcessedProducts(ctx context.Context, companyID uuid.UUID
"has_eprel",
"created_at", "updated_at",
})
if err != nil {
return nil, err
}
for _, item := range items {
if name, ok := item["name"].(string); ok && strings.TrimSpace(name) != "" {
item["title"] = name
}
}
return items, nil
},
)
}
@@ -1172,12 +1184,12 @@ func (s *Service) ListProcessedProductsDetailed(ctx context.Context, companyID u
func(ctx context.Context) ([]map[string]any, error) {
rows, err := s.Pool.Query(ctx, fmt.Sprintf(`
SELECT p.id, p.product_id,
COALESCE(NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '') AS name,
`+processedPreferredNameSQL+` AS name,
p.category,
COALESCE(cat.name, NULLIF(BTRIM(p.category), '')) AS category_name,
COALESCE(cat.unique_id, NULLIF(BTRIM(p.category), '')) AS category_unique_id,
p.status, p.raw_product_id, p.feed_id, r.gtin,
COALESCE(NULLIF(p.description, ''), NULLIF(r.mapped_data->>'description', ''), '') AS description,
`+processedPreferredDescriptionSQL+` AS description,
p.processed_name, p.processed_description,
COALESCE(p.meta_title, ''), COALESCE(p.meta_description, ''),
p.attributes, p.processed_attributes, r.mapped_data,
@@ -1190,7 +1202,7 @@ func (s *Service) ListProcessedProductsDetailed(ctx context.Context, companyID u
return nil, err
}
defer rows.Close()
return scanMaps(rows, []string{
items, err := scanMaps(rows, []string{
"id", "product_id", "name", "category", "category_name", "category_unique_id",
"status", "raw_product_id", "feed_id", "gtin",
"description", "processed_name", "processed_description",
@@ -1198,6 +1210,13 @@ func (s *Service) ListProcessedProductsDetailed(ctx context.Context, companyID u
"attributes", "processed_attributes", "mapped_data",
"created_at", "updated_at",
})
if err != nil {
return nil, err
}
for _, item := range items {
alignProductFieldsWithV1(item)
}
return items, nil
},
)
}
@@ -1205,11 +1224,11 @@ func (s *Service) ListProcessedProductsDetailed(ctx context.Context, companyID u
func (s *Service) GetProcessedProduct(ctx context.Context, companyID, id uuid.UUID) (map[string]any, error) {
row := s.Pool.QueryRow(ctx, `
SELECT p.id, p.product_id,
COALESCE(NULLIF(p.name, ''), NULLIF(r.mapped_data->>'name', ''), NULLIF(r.mapped_data->>'title', ''), '') AS name,
`+processedPreferredNameSQL+` AS name,
p.category,
COALESCE(cat.name, NULLIF(BTRIM(p.category), '')) AS category_name,
COALESCE(cat.unique_id, NULLIF(BTRIM(p.category), '')) AS category_unique_id,
COALESCE(NULLIF(p.description, ''), NULLIF(r.mapped_data->>'description', ''), '') AS description,
`+processedPreferredDescriptionSQL+` AS description,
p.processed_name, p.processed_description,
p.status, p.attributes, p.processed_attributes, r.gtin, r.mapped_data,
COALESCE(p.feed_id, r.feed_id) AS feed_id,
@@ -1241,6 +1260,7 @@ func (s *Service) GetProcessedProduct(ctx context.Context, companyID, id uuid.UU
return nil, err
}
linkFeedSpecificationsIntoProduct(item)
alignProductFieldsWithV1(item)
primary := company.LoadLanguage(ctx, s.Pool, companyID)
item["content_language"] = primary
item["content_languages"] = company.LoadContentLanguages(ctx, s.Pool, companyID)
@@ -1303,6 +1323,7 @@ func (s *Service) GetRawProduct(ctx context.Context, companyID, id uuid.UUID) (m
return nil, err
}
linkFeedSpecificationsIntoProduct(item)
alignProductFieldsWithV1(item)
primary := company.LoadLanguage(ctx, s.Pool, companyID)
item["content_language"] = primary
item["content_languages"] = company.LoadContentLanguages(ctx, s.Pool, companyID)