fix(plans): prevent deletion of plans with active subscriptions

- Fix bulk delete and individual delete actions using before() hook with halt()
  - Add daily/weekly billing cycle options to plan resource and Polar provider
  - Enhance payment confirmation with dynamic polling and loading states
  - Add graceful handling for deleted plans in subscription display
  - Update Polar provider to support dynamic billing cycles
This commit is contained in:
idevakk
2025-12-07 02:23:14 -08:00
parent 1b438cbf89
commit 5fabec1f9d
7 changed files with 225 additions and 93 deletions

View File

@@ -1106,24 +1106,28 @@ class PolarProvider implements PaymentProviderContract
]);
}
// Convert billing cycle to Polar's format
$billingInterval = $this->convertBillingCycleToPolarInterval($plan->billing_cycle_days ?? 30);
// Create new product with correct structure
$productData = [
'name' => $plan->name,
'description' => $plan->description ?? 'Subscription plan',
'recurring_interval' => 'month',
'recurring_interval_count' => 1,
'recurring_interval' => $billingInterval['interval'],
'recurring_interval_count' => $billingInterval['interval_count'],
'prices' => [
[
'amount_type' => 'fixed',
'price_amount' => (int) ($plan->price * 100), // Convert to cents
'price_currency' => 'usd',
'recurring_interval' => 'month',
'recurring_interval_count' => 1,
'recurring_interval' => $billingInterval['interval'],
'recurring_interval_count' => $billingInterval['interval_count'],
],
],
'metadata' => [
'plan_id' => $plan->id,
'plan_name' => $plan->name,
'billing_cycle_days' => $plan->billing_cycle_days ?? 30,
],
];
@@ -2361,4 +2365,21 @@ class PolarProvider implements PaymentProviderContract
// For now, return basic stats - could be expanded with database tracking
return $stats;
}
/**
* Convert billing cycle days to Polar's recurring interval format
*/
protected function convertBillingCycleToPolarInterval(int $billingCycleDays): array
{
return match ($billingCycleDays) {
1 => ['interval' => 'day', 'interval_count' => 1], // Daily
7 => ['interval' => 'week', 'interval_count' => 1], // Weekly
30 => ['interval' => 'month', 'interval_count' => 1], // Monthly
60 => ['interval' => 'month', 'interval_count' => 2], // Bi-monthly
90 => ['interval' => 'month', 'interval_count' => 3], // Quarterly
180 => ['interval' => 'month', 'interval_count' => 6], // Semi-annual
365 => ['interval' => 'year', 'interval_count' => 1], // Yearly
default => ['interval' => 'month', 'interval_count' => 1], // Default to monthly
};
}
}