94 lines
3.2 KiB
Go
94 lines
3.2 KiB
Go
package processing
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"strings"
|
||
|
|
|
||
|
|
"github.com/google/uuid"
|
||
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
||
|
|
)
|
||
|
|
|
||
|
|
// SyncCompanyA1Opts controls admin Sync A1 (dump category backfill + Fix hygiene).
|
||
|
|
// Default is backfill-categories + hygiene — never a full wipe/reimport.
|
||
|
|
type SyncCompanyA1Opts struct {
|
||
|
|
FixCompanyCatalogOpts
|
||
|
|
// MySQLDumpPath is an explicit dump path; empty triggers auto-detect
|
||
|
|
// (SEED_A1_MYSQL_DUMP + MySQLDumpCandidates).
|
||
|
|
MySQLDumpPath string
|
||
|
|
// SkipDumpBackfill skips dump scan even when a dump is found.
|
||
|
|
SkipDumpBackfill bool
|
||
|
|
}
|
||
|
|
|
||
|
|
// SyncCompanyA1Result combines dump category backfill with FixCompanyCatalogResult.
|
||
|
|
type SyncCompanyA1Result struct {
|
||
|
|
FixCompanyCatalogResult
|
||
|
|
|
||
|
|
DumpFound bool `json:"dump_found"`
|
||
|
|
DumpPath string `json:"dump_path,omitempty"`
|
||
|
|
DumpSkippedReason string `json:"dump_skipped_reason,omitempty"`
|
||
|
|
DumpPairs int `json:"dump_pairs"`
|
||
|
|
DumpMappedUpdated int64 `json:"dump_mapped_updated"`
|
||
|
|
DumpProcessedUpdated int64 `json:"dump_processed_updated"`
|
||
|
|
PurgedOtherRaw int64 `json:"purged_other_raw"`
|
||
|
|
PurgedOtherPP int64 `json:"purged_other_pp"`
|
||
|
|
// DumpStatus is a short label for flash UI ({dump_status}).
|
||
|
|
DumpStatus string `json:"dump_status"`
|
||
|
|
}
|
||
|
|
|
||
|
|
// SyncCompanyA1 runs dump→category backfill when a MySQL dump is available, then
|
||
|
|
// FixCompanyCatalog hygiene. Does not wipe or reimport the catalog.
|
||
|
|
func SyncCompanyA1(ctx context.Context, pool *pgxpool.Pool, companyID uuid.UUID, companyName string, a1Cohort bool, opts SyncCompanyA1Opts) (SyncCompanyA1Result, error) {
|
||
|
|
out := SyncCompanyA1Result{
|
||
|
|
FixCompanyCatalogResult: FixCompanyCatalogResult{
|
||
|
|
CompanyID: companyID,
|
||
|
|
CompanyName: companyName,
|
||
|
|
A1Cohort: a1Cohort,
|
||
|
|
},
|
||
|
|
DumpStatus: "skipped",
|
||
|
|
}
|
||
|
|
if pool == nil {
|
||
|
|
return out, fmt.Errorf("nil pool")
|
||
|
|
}
|
||
|
|
|
||
|
|
dumpPath := strings.TrimSpace(opts.MySQLDumpPath)
|
||
|
|
if !opts.SkipDumpBackfill {
|
||
|
|
resolved := ResolveMySQLDumpPath(dumpPath)
|
||
|
|
if resolved != "" {
|
||
|
|
out.DumpFound = true
|
||
|
|
out.DumpPath = resolved
|
||
|
|
dumpRes, err := BackfillCategoriesFromMySQLDump(ctx, pool, companyID, resolved)
|
||
|
|
if err != nil {
|
||
|
|
return out, fmt.Errorf("dump category backfill: %w", err)
|
||
|
|
}
|
||
|
|
out.DumpPairs = dumpRes.DumpPairs
|
||
|
|
out.DumpMappedUpdated = dumpRes.MappedUpdated
|
||
|
|
out.DumpProcessedUpdated = dumpRes.ProcessedUpdated
|
||
|
|
out.DumpStatus = "ok"
|
||
|
|
|
||
|
|
rawN, ppN, err := PurgeA1FixtureEANsFromOtherTenants(ctx, pool, companyID)
|
||
|
|
if err != nil {
|
||
|
|
return out, fmt.Errorf("purge fixture eans: %w", err)
|
||
|
|
}
|
||
|
|
out.PurgedOtherRaw = rawN
|
||
|
|
out.PurgedOtherPP = ppN
|
||
|
|
} else if dumpPath != "" {
|
||
|
|
out.DumpSkippedReason = fmt.Sprintf("mysql dump not found at %q and no auto-detect match", dumpPath)
|
||
|
|
out.DumpStatus = "missing"
|
||
|
|
} else {
|
||
|
|
out.DumpSkippedReason = "no MySQL dump (set SEED_A1_MYSQL_DUMP or place descrybe_new.sql in scripts/seed or ~/Downloads); continuing with DB hygiene only"
|
||
|
|
out.DumpStatus = "missing"
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
out.DumpSkippedReason = "dump backfill skipped by request"
|
||
|
|
out.DumpStatus = "skipped"
|
||
|
|
}
|
||
|
|
|
||
|
|
fixRes, err := FixCompanyCatalog(ctx, pool, companyID, companyName, a1Cohort, opts.FixCompanyCatalogOpts)
|
||
|
|
if err != nil {
|
||
|
|
return out, err
|
||
|
|
}
|
||
|
|
out.FixCompanyCatalogResult = fixRes
|
||
|
|
return out, nil
|
||
|
|
}
|