Tenant-Based Billing: Fixing Cashier Customer Model
Introduction
After consolidating billing to a tenant-based system (Phase 3), we encountered an issue with the Cashier package. The default customer model was still set to User, causing errors when Stripe webhook events triggered.
The Problem
The stripe_id column, expected by Cashier, was not found because it was looking in the User model instead of the Tenant model. This mismatch occurred because we had recently shifted our billing logic to operate at the tenant level.
The Solution
We updated the AppServiceProvider to instruct Cashier to use the Tenant model as the customer model. This ensures that Cashier correctly interacts with our tenant-specific billing data.
use App\Models\Tenant;
use Laravel\Cashier\Cashier;
public function boot(): void
{
Cashier::useCustomerModel(Tenant::class);
Model::preventLazyLoading(! $this->app->isProduction());
}
Explanation
The Cashier::useCustomerModel(Tenant::class) line tells Cashier to use the Tenant model when performing customer-related operations, such as creating subscriptions or handling webhooks. This resolves the stripe_id column not found error and aligns Cashier with our tenant-based billing architecture.
Lessons Learned
When refactoring or making significant changes to your application's architecture, especially concerning core components like billing, it's crucial to ensure that all dependencies and related packages are updated to reflect the new structure. Overlooking seemingly minor configurations can lead to unexpected errors and integration issues. Always double-check package configurations after major architectural changes.