laravel-billing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLaravel Billing (Cashier)
Laravel 账单系统(Cashier)
Agent Workflow (MANDATORY)
Agent 工作流(必须遵循)
Before ANY implementation, use to spawn 3 agents:
TeamCreate- fuse-ai-pilot:explore-codebase - Check existing billing setup, User model
- fuse-ai-pilot:research-expert - Verify latest Cashier docs via Context7
- mcp__context7__query-docs - Query specific patterns (Stripe/Paddle)
After implementation, run fuse-ai-pilot:sniper for validation.
在进行任何实现之前,使用生成3个Agent:
TeamCreate- fuse-ai-pilot:explore-codebase - 检查现有账单设置、User模型
- fuse-ai-pilot:research-expert - 通过Context7验证最新的Cashier文档
- mcp__context7__query-docs - 查询特定模式(Stripe/Paddle)
实现完成后,运行fuse-ai-pilot:sniper进行验证。
Overview
概述
Laravel Cashier provides subscription billing with Stripe or Paddle. Choose based on your needs:
| Provider | Package | Best For |
|---|---|---|
| Stripe | | Full control, high volume, complex billing |
| Paddle | | Tax handling, compliance, global sales |
Laravel Cashier 提供基于Stripe或Paddle的订阅账单服务。可根据需求选择:
| 支付服务商 | 包名称 | 适用场景 |
|---|---|---|
| Stripe | | 完全控制、高交易量、复杂账单场景 |
| Paddle | | 税务处理、合规要求、全球销售场景 |
Key Difference: MoR vs Payment Processor
核心差异:支付处理器 vs 代收款商
| Aspect | Stripe | Paddle |
|---|---|---|
| Type | Payment Processor | Merchant of Record |
| Taxes | You manage (or Stripe Tax) | Paddle manages automatically |
| Invoices | Your company name | Paddle + your name |
| Compliance | Your responsibility | Paddle handles |
| Fees | ~2.9% + $0.30 | ~5% + $0.50 (all-inclusive) |
| 对比项 | Stripe | Paddle |
|---|---|---|
| 类型 | 支付处理器 | 代收款商(Merchant of Record) |
| 税务处理 | 自行管理(或使用Stripe Tax) | Paddle自动处理 |
| 发票显示 | 显示您的公司名称 | 显示Paddle + 您的名称 |
| 合规责任 | 由您负责 | Paddle负责 |
| 手续费 | ~2.9% + $0.30 | ~5% + $0.50(全包价) |
Critical Rules
重要规则
- Use webhooks - Never rely on client-side confirmations
- Handle grace periods - Allow access until subscription ends
- Never store card details - Use payment tokens/methods
- Test with test keys - Always before production
- Verify webhook signatures - Prevent spoofing attacks
- Handle incomplete payments - 3D Secure requires user action
- 使用Webhook - 绝不依赖客户端确认
- 处理宽限期 - 允许用户在订阅结束前继续访问
- 绝不存储银行卡信息 - 使用支付令牌/支付方式
- 使用测试密钥测试 - 上线前必须完成
- 验证Webhook签名 - 防止伪造攻击
- 处理未完成支付 - 3D Secure需要用户操作
Architecture
架构
app/
├── Http/
│ ├── Controllers/
│ │ └── Billing/ ← Billing controllers
│ │ ├── SubscriptionController.php
│ │ ├── CheckoutController.php
│ │ └── InvoiceController.php
│ └── Middleware/
│ └── EnsureSubscribed.php ← Subscription check
├── Models/
│ └── User.php ← Billable trait
├── Listeners/
│ └── StripeEventListener.php ← Webhook handling
└── Services/
└── BillingService.php ← Business logic
config/
├── cashier.php ← Stripe/Paddle config
└── services.php ← API keys
routes/
└── web.php ← Webhook routes (excluded from CSRF)app/
├── Http/
│ ├── Controllers/
│ │ └── Billing/ ← 账单控制器
│ │ ├── SubscriptionController.php
│ │ ├── CheckoutController.php
│ │ └── InvoiceController.php
│ └── Middleware/
│ └── EnsureSubscribed.php ← 订阅状态检查中间件
├── Models/
│ └── User.php ← 引入Billable trait
├── Listeners/
│ └── StripeEventListener.php ← Webhook事件处理
└── Services/
└── BillingService.php ← 业务逻辑层
config/
├── cashier.php ← Stripe/Paddle配置
└── services.php ← API密钥配置
routes/
└── web.php ← Webhook路由(排除CSRF验证)FuseCore Integration
FuseCore 集成
When working in a FuseCore project, billing follows the modular structure:
FuseCore/
├── Core/ # Infrastructure (priority 0)
│ └── App/Contracts/
│ └── BillingServiceInterface.php ← Billing contract
│
├── User/ # Auth module (existing)
│ └── App/Models/User.php ← Add Billable trait here
│
├── Billing/ # Billing module (new)
│ ├── App/
│ │ ├── Http/
│ │ │ ├── Controllers/
│ │ │ │ ├── SubscriptionController.php
│ │ │ │ ├── CheckoutController.php
│ │ │ │ └── WebhookController.php
│ │ │ └── Middleware/
│ │ │ └── EnsureSubscribed.php
│ │ ├── Listeners/
│ │ │ └── HandleWebhookEvents.php
│ │ └── Services/
│ │ └── BillingService.php
│ ├── Config/
│ │ └── cashier.php ← Module-level config
│ ├── Database/Migrations/
│ ├── Routes/
│ │ ├── web.php ← Webhooks (no CSRF)
│ │ └── api.php ← Subscription management
│ └── module.json # dependencies: ["User"]在FuseCore项目中,账单模块遵循以下模块化结构:
FuseCore/
├── Core/ # 基础设施层(优先级0)
│ └── App/Contracts/
│ └── BillingServiceInterface.php ← 账单服务契约
│
├── User/ # 认证模块(已存在)
│ └── App/Models/User.php ← 在此引入Billable trait
│
├── Billing/ # 账单模块(新增)
│ ├── App/
│ │ ├── Http/
│ │ │ ├── Controllers/
│ │ │ │ ├── SubscriptionController.php
│ │ │ │ ├── CheckoutController.php
│ │ │ │ └── WebhookController.php
│ │ │ └── Middleware/
│ │ │ └── EnsureSubscribed.php
│ │ ├── Listeners/
│ │ │ └── HandleWebhookEvents.php
│ │ └── Services/
│ │ └── BillingService.php
│ ├── Config/
│ │ └── cashier.php ← 模块级配置
│ ├── Database/Migrations/
│ ├── Routes/
│ │ ├── web.php ← Webhook路由(无CSRF验证)
│ │ └── api.php ← 订阅管理API
│ └── module.json # 依赖:["User"]FuseCore Billing Checklist
FuseCore 账单检查清单
- Billing code in module
/FuseCore/Billing/ - Billable trait on User model in
/FuseCore/User/ - Webhook routes in
/FuseCore/Billing/Routes/web.php - Exclude webhook from CSRF in
VerifyCsrfToken - Declare dependency in
"User"module.json
→ See fusecore skill for complete module patterns.
- 账单代码位于模块
/FuseCore/Billing/ - 在的User模型上引入Billable trait
/FuseCore/User/ - Webhook路由位于
/FuseCore/Billing/Routes/web.php - 在中排除Webhook路由
VerifyCsrfToken - 在中声明
module.json依赖"User"
→ 查看 fusecore skill 获取完整模块模式。
Decision Guide
决策指南
Stripe vs Paddle
Stripe vs Paddle
Selling to businesses (B2B)? → Stripe
├── Need OAuth for third-party apps? → Stripe Connect
└── Selling to consumers (B2C) globally?
├── Want to handle taxes yourself? → Stripe + Stripe Tax
└── Want tax compliance handled? → Paddle面向企业客户(B2B)? → Stripe
├── 需要为第三方应用提供OAuth? → Stripe Connect
└── 面向全球消费者(B2C)?
├── 希望自行处理税务? → Stripe + Stripe Tax
└── 希望由服务商处理税务合规? → PaddleSubscription vs One-Time
订阅制 vs 一次性支付
Recurring revenue? → Subscription
├── Fixed plans? → Single-price subscription
└── Usage-based? → Metered billing (Stripe) or quantity-based
Single purchase? → One-time charge
├── Digital product? → Checkout session
└── Service fee? → Direct charge recurring收入? → 订阅制
├── 固定套餐? → 单一价格订阅
└── 按使用量计费? → 计量计费(Stripe)或按数量计费
一次性购买? → 一次性收费
├── 数字产品? → 结账会话
└── 服务费? → 直接收费Key Concepts
核心概念
| Concept | Description | Reference |
|---|---|---|
| Billable | Trait that enables billing on a model | stripe.md |
| Subscription | Recurring billing cycle | subscriptions.md |
| Price ID | Stripe/Paddle price identifier | stripe.md |
| Grace Period | Time after cancellation with access | subscriptions.md |
| Webhook | Server-to-server payment notifications | webhooks.md |
| Customer Portal | Self-service billing management | checkout.md |
| 概念 | 描述 | 参考文档 |
|---|---|---|
| Billable | 为模型启用账单功能的Trait | stripe.md |
| Subscription | recurring账单周期 | subscriptions.md |
| Price ID | Stripe/Paddle的价格标识符 | stripe.md |
| Grace Period | 取消订阅后仍可访问的宽限期 | subscriptions.md |
| Webhook | 服务器到服务器的支付通知 | webhooks.md |
| Customer Portal | 自助式账单管理门户 | checkout.md |
Reference Guide
参考指南
Concepts (WHY & Architecture)
基础概念(设计思路与架构)
| Topic | Reference | When to Consult |
|---|---|---|
| Stripe Cashier | stripe.md | Stripe setup, configuration |
| Paddle Cashier | paddle.md | Paddle setup, differences |
| Subscriptions | subscriptions.md | Create, cancel, swap, pause |
| Webhooks | webhooks.md | Webhook security, handling |
| Invoices | invoices.md | PDF generation, receipts |
| Payment Methods | payment-methods.md | Cards, wallets, updates |
| Checkout | checkout.md | Hosted checkout, portal |
| Testing | testing.md | Test cards, webhook testing |
| 主题 | 参考文档 | 适用场景 |
|---|---|---|
| Stripe Cashier | stripe.md | Stripe设置、配置 |
| Paddle Cashier | paddle.md | Paddle设置、差异对比 |
| 订阅管理 | subscriptions.md | 创建、取消、切换、暂停订阅 |
| Webhook | webhooks.md | Webhook安全、事件处理 |
| 发票管理 | invoices.md | PDF生成、收据 |
| 支付方式 | payment-methods.md | 银行卡、钱包、更新支付方式 |
| 结账流程 | checkout.md | 托管结账、客户门户 |
| 测试 | testing.md | 测试银行卡、Webhook测试 |
Advanced SaaS Features
高级SaaS功能
| Topic | Reference | When to Consult |
|---|---|---|
| Metered Billing | metered-billing.md | Usage-based pricing (API, storage) |
| Team Billing | team-billing.md | Organization billing, per-seat |
| Dunning | dunning.md | Failed payment recovery |
| Feature Flags | feature-flags.md | Plan-based feature access |
| 主题 | 参考文档 | 适用场景 |
|---|---|---|
| 计量计费 | metered-billing.md | 按使用量定价(API、存储) |
| 团队账单 | team-billing.md | 组织账单、按席位计费 |
| 催缴管理 | dunning.md | 失败支付恢复 |
| 功能开关 | feature-flags.md | 基于套餐的功能访问控制 |
Templates (Complete Code)
模板(完整代码)
| Template | When to Use |
|---|---|
| UserBillable.php.md | User model with Billable trait |
| SubscriptionController.php.md | CRUD subscription operations |
| WebhookController.php.md | Custom webhook handling |
| CheckoutController.php.md | Stripe Checkout + Portal |
| InvoiceController.php.md | Invoice download |
| BillingRoutes.php.md | Complete route definitions |
| SubscriptionTest.php.md | Pest tests for billing |
| MeteredBillingController.php.md | Usage tracking and reporting |
| TeamBillable.php.md | Team model with seat management |
| DunningService.php.md | Payment recovery automation |
| FeatureFlags.php.md | Laravel Pennant per-plan features |
| 模板 | 适用场景 |
|---|---|
| UserBillable.php.md | 引入Billable trait的User模型 |
| SubscriptionController.php.md | 订阅操作的CRUD控制器 |
| WebhookController.php.md | 自定义Webhook处理 |
| CheckoutController.php.md | Stripe结账 + 客户门户 |
| InvoiceController.php.md | 发票下载 |
| BillingRoutes.php.md | 完整路由定义 |
| SubscriptionTest.php.md | 账单功能的Pest测试 |
| MeteredBillingController.php.md | 使用量跟踪与报告 |
| TeamBillable.php.md | 带席位管理的团队模型 |
| DunningService.php.md | 支付恢复自动化 |
| FeatureFlags.php.md | 基于Laravel Pennant的套餐功能控制 |
Quick Reference
快速参考
Check Subscription Status
检查订阅状态
php
// Has active subscription?
$user->subscribed('default');
// Subscribed to specific price?
$user->subscribedToPrice('price_premium', 'default');
// On trial?
$user->onTrial('default');
// Cancelled but still active?
$user->subscription('default')->onGracePeriod();php
// 是否有活跃订阅?
$user->subscribed('default');
// 是否订阅了特定价格?
$user->subscribedToPrice('price_premium', 'default');
// 是否处于试用期?
$user->onTrial('default');
// 是否已取消但仍在宽限期?
$user->subscription('default')->onGracePeriod();Create Subscription
创建订阅
php
// Simple subscription
$user->newSubscription('default', 'price_monthly')
->create($paymentMethodId);
// With trial
$user->newSubscription('default', 'price_monthly')
->trialDays(14)
->create($paymentMethodId);php
// 简单订阅
$user->newSubscription('default', 'price_monthly')
->create($paymentMethodId);
// 带试用期的订阅
$user->newSubscription('default', 'price_monthly')
->trialDays(14)
->create($paymentMethodId);Manage Subscription
管理订阅
php
$subscription = $user->subscription('default');
// Change plan
$subscription->swap('price_yearly');
// Cancel at period end
$subscription->cancel();
// Cancel immediately
$subscription->cancelNow();
// Resume cancelled subscription
$subscription->resume();php
$subscription = $user->subscription('default');
// 切换套餐
$subscription->swap('price_yearly');
// 到期时取消
$subscription->cancel();
// 立即取消
$subscription->cancelNow();
// 恢复已取消的订阅
$subscription->resume();Billing Portal
账单门户
php
// Redirect to customer portal (Stripe)
return $user->redirectToBillingPortal(route('dashboard'));
// Get portal URL
$url = $user->billingPortalUrl(route('dashboard'));php
// 重定向到客户门户(Stripe)
return $user->redirectToBillingPortal(route('dashboard'));
// 获取门户URL
$url = $user->billingPortalUrl(route('dashboard'));Best Practices
最佳实践
DO
建议
- Use webhooks for payment confirmation
- Implement grace periods for cancelled subscriptions
- Set up webhook signature verification
- Handle exceptions
IncompletePayment - Test with Stripe CLI locally
- Prune old data regularly
- 使用Webhook确认支付
- 为已取消订阅的用户提供宽限期
- 配置Webhook签名验证
- 处理异常
IncompletePayment - 本地使用Stripe CLI测试
- 定期清理旧数据
DON'T
禁忌
- Trust client-side payment confirmations
- Store card numbers (PCI compliance)
- Skip webhook verification
- Ignore failed payment webhooks
- Forget to handle 3D Secure
- Hardcode prices (use env or config)
- 信任客户端的支付确认
- 存储银行卡号(违反PCI合规)
- 跳过Webhook验证
- 忽略失败支付的Webhook
- 未处理3D Secure验证
- 硬编码价格(使用环境变量或配置文件)