Idempotent provisioning, service soft-delete, Plans page redesign, doc updates
Part A: Fix duplicate Service creation on provisioning retry - All 4 provisioning services use Service::firstOrCreate() keyed on subscription_id+service_type to prevent duplicates on queue retries - HandleSubscriptionCreated sends notification before provisioning, no longer re-throws on failure - RetryProvisioningCommand simplified to reuse existing Service records Part B: Plans/Pricing page complete redesign - Service type tabs (VPS, Dedicated, Web Hosting, MySQL) - Billing cycle segmented toggle (monthly/quarterly/semi-annual/annual) - Feature icons per service type, Popular/Best Value badges - Stock indicators, effective monthly price calculations Part C: Admin service soft-delete/archive - Service model uses SoftDeletes trait - Admin can archive and restore services - Show archived toggle on services list - Migration adds deleted_at column Docs: Updated TASKS.md, CLAUDE.md, PROJECT_DEVELOPMENT.md, MEMORY.md - Phase 3 marked complete, test counts updated (252 passing) - SupportPal references replaced with standalone ticket system - Frontend design skill background rule added - Closed GitHub issues #3, #6, #7, #8, #9 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -99,9 +99,16 @@ class BillingController extends Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Create setup intent for adding new cards
|
||||
if (! $user->hasStripeId()) {
|
||||
$user->createAsStripeCustomer();
|
||||
}
|
||||
|
||||
return Inertia::render('Billing/PaymentMethods', [
|
||||
'paymentMethods' => $paymentMethods,
|
||||
'defaultPaymentMethod' => $defaultPaymentMethod,
|
||||
'intent' => $user->createSetupIntent(),
|
||||
'stripeKey' => config('cashier.key'),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -147,7 +154,13 @@ class BillingController extends Controller
|
||||
$user = $request->user();
|
||||
|
||||
$renewals = $user->subscriptions()
|
||||
->with('plan')
|
||||
->select([
|
||||
'subscriptions.*',
|
||||
'plans.name as plan_name',
|
||||
'plans.price as plan_price',
|
||||
'plans.billing_cycle as plan_billing_cycle',
|
||||
])
|
||||
->leftJoin('plans', 'subscriptions.plan_id', '=', 'plans.id')
|
||||
->whereIn('stripe_status', ['active', 'trialing'])
|
||||
->whereNotNull('current_period_end')
|
||||
->orderBy('current_period_end')
|
||||
@@ -159,9 +172,9 @@ class BillingController extends Controller
|
||||
|
||||
return [
|
||||
'id' => $subscription->id,
|
||||
'plan_name' => $subscription->plan?->name ?? $subscription->type,
|
||||
'plan_price' => $subscription->plan?->price,
|
||||
'billing_cycle' => $subscription->plan?->billing_cycle,
|
||||
'plan_name' => $subscription->plan_name ?? $subscription->type,
|
||||
'plan_price' => $subscription->plan_price,
|
||||
'billing_cycle' => $subscription->plan_billing_cycle,
|
||||
'renewal_date' => $subscription->current_period_end,
|
||||
'status' => $subscription->stripe_status,
|
||||
'auto_renew' => $service?->auto_renew ?? true,
|
||||
|
||||
Reference in New Issue
Block a user