This commit is contained in:
2026-08-13 23:43:53 +02:00
parent 322c70e5cf
commit 841a05572e
2 changed files with 37 additions and 3 deletions
+31 -2
View File
@@ -90,7 +90,8 @@ func main() {
log.Fatal(err)
}
billingSvc := &billing.Service{Pool: pg}
if err := billingSvc.ProvisionFreePlan(ctx, companyID); err != nil {
planNote, err := ensureFreePlan(ctx, pg, billingSvc, companyID)
if err != nil {
log.Fatalf("provision Free plan: %v", err)
}
companyAction := "existing"
@@ -98,7 +99,7 @@ func main() {
companyAction = "created"
}
fmt.Printf(" company: %s (%s) [%s]\n", companyName, companyID, companyAction)
fmt.Println(" plan: Free (provisioned)")
fmt.Printf(" plan: %s\n", planNote)
fmt.Println()
fmt.Println("Sign in on the web app (company is selected on login). Platform panel: /admin.")
}
@@ -311,3 +312,31 @@ func ensureAdminCompany(ctx context.Context, pg *pgxpool.Pool, userID uuid.UUID,
}
return companyID, companyName, true, nil
}
// ensureFreePlan assigns Free when missing. Syncs company_plans id sequence first —
// cutover/import DBs often leave BIGSERIAL behind MAX(id), which surfaces as
// duplicate key on company_plans_pkey during INSERT.
func ensureFreePlan(ctx context.Context, pg *pgxpool.Pool, billingSvc *billing.Service, companyID uuid.UUID) (string, error) {
if err := billingSvc.EnsureDefaultPlans(ctx); err != nil {
return "", err
}
if _, err := pg.Exec(ctx, `
SELECT setval(
pg_get_serial_sequence('company_plans', 'id'),
GREATEST(1, (SELECT COALESCE(MAX(id), 1) FROM company_plans))
)`); err != nil {
return "", fmt.Errorf("sync company_plans sequence: %w", err)
}
assigned, err := billingSvc.AssignPlanByNameIfMissing(ctx, companyID, "Free")
if err != nil {
// Race / still-stuck sequence: if an active plan exists, treat as OK.
if has, hasErr := billingSvc.HasActivePlan(ctx, companyID); hasErr == nil && has {
return "already active (assign skipped after error)", nil
}
return "", err
}
if assigned {
return "Free (assigned)", nil
}
return "already active (unchanged)", nil
}