101 lines
3.8 KiB
Go
101 lines
3.8 KiB
Go
package catalog
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/billing"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
// EnsureCategoryAttributeLinks removes orphan category_attributes rows (missing
|
|
// category or attribute) without wiping taxonomy or valid links. Returns orphans
|
|
// removed and remaining link count.
|
|
func EnsureCategoryAttributeLinks(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (orphansRemoved int, links int, err error) {
|
|
if pool == nil {
|
|
return 0, 0, fmt.Errorf("nil pool")
|
|
}
|
|
ct, err := pool.Exec(ctx, `
|
|
DELETE FROM category_attributes ca
|
|
WHERE ca.company_id = $1
|
|
AND (
|
|
NOT EXISTS (
|
|
SELECT 1 FROM categories c
|
|
WHERE c.company_id = ca.company_id AND c.unique_id = ca.category_unique_id
|
|
)
|
|
OR NOT EXISTS (
|
|
SELECT 1 FROM attributes a
|
|
WHERE a.id = ca.attribute_id AND a.company_id = ca.company_id
|
|
)
|
|
)`, companyID)
|
|
if err != nil {
|
|
return 0, 0, fmt.Errorf("purge orphan category_attributes: %w", err)
|
|
}
|
|
orphansRemoved = int(ct.RowsAffected())
|
|
if err := pool.QueryRow(ctx, `
|
|
SELECT count(*)::int FROM category_attributes WHERE company_id = $1`, companyID).Scan(&links); err != nil {
|
|
return orphansRemoved, 0, err
|
|
}
|
|
return orphansRemoved, links, nil
|
|
}
|
|
|
|
// RepairCompanyCategoryEnhancePrompts is the company-scoped variant of
|
|
// RepairA1DemoCategoryEnhancePrompts: loads wp_product_categories.sql when
|
|
// available (upload bytes, SEED_A1_WP_CATEGORIES / Downloads), else
|
|
// a1-category-prompts.json, splits legacy combined overlays into role sections,
|
|
// and force-applies WP dump matches. Falls back to CategoryEnhanceUserTemplate.
|
|
// Idempotent when unchanged.
|
|
func RepairCompanyCategoryEnhancePrompts(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID) (updated, alreadyOK, emptySkipped int, err error) {
|
|
res, err := RepairCompanyCategoryEnhancePromptsWithOptions(ctx, pool, companyID, RepairA1DemoOptions{})
|
|
if err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
return res.Updated, res.AlreadyOK, res.EmptySkipped, nil
|
|
}
|
|
|
|
// RepairCompanyCategoryEnhancePromptsWithOptions applies category enhance prompt
|
|
// repair for one company. Pass WPCategoriesSQL to force-apply an uploaded dump
|
|
// (Admin Sync A1); empty opts keep auto-detect fallback.
|
|
func RepairCompanyCategoryEnhancePromptsWithOptions(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID, opts RepairA1DemoOptions) (RepairCategoryEnhancePromptsResult, error) {
|
|
out := RepairCategoryEnhancePromptsResult{
|
|
ByCompany: map[string]int{},
|
|
}
|
|
if pool == nil {
|
|
return out, fmt.Errorf("nil pool")
|
|
}
|
|
if len(opts.WPCategoriesSQL) > 0 {
|
|
if _, _, err := LoadWPCategoryPromptOverlaysFromBytes(opts.WPCategoriesSQL); err != nil {
|
|
return out, fmt.Errorf("wp_product_categories upload: %w", err)
|
|
}
|
|
}
|
|
seedByNorm, seedByUID, seedMeta := resolveCategoryPromptOverlays(opts)
|
|
out.SeedPath = seedMeta.Path
|
|
out.WPCategoriesPath = seedMeta.WPPath
|
|
out.SeedEntries = seedMeta.Entries
|
|
forceFromSeed := seedMeta.ForceFromSeed
|
|
if opts.ForceFromSeed != nil {
|
|
forceFromSeed = *opts.ForceFromSeed
|
|
}
|
|
if _, err := repairCompanyCategoryEnhancePrompts(ctx, pool, companyID, companyID.String(), seedByNorm, seedByUID, false, forceFromSeed, &out); err != nil {
|
|
return out, err
|
|
}
|
|
return out, nil
|
|
}
|
|
|
|
// ResolvePlatformDemoCompanyID finds the Platform Demo sandbox (never A1 cohort).
|
|
func ResolvePlatformDemoCompanyID(ctx context.Context, pool *pgxpool.Pool) (uuid.UUID, error) {
|
|
var id uuid.UUID
|
|
err := pool.QueryRow(ctx, `
|
|
SELECT c.id
|
|
FROM companies c
|
|
WHERE c.name = $1
|
|
AND COALESCE(c.legacy_company_id, '') <> $2
|
|
ORDER BY c.created_at ASC
|
|
LIMIT 1`, platformDemoCompanyName, billing.A1LegacyCompanyID).Scan(&id)
|
|
if err != nil {
|
|
return uuid.Nil, fmt.Errorf("platform demo company not found: %w", err)
|
|
}
|
|
return id, nil
|
|
}
|