二、集成 Invoice
Stripe Billing 模块主要分成 Subscription 和 Invoice。
Subscription 即 Checkout Session Mode = Subscription,先创建 Session,再生成周期性的账单 Invoice。
Invoice 是账单本体,支持两种收款方式:自动扣款、发送账单邮件。
2.1 Lifecycle
Stripe Invoice Doc:
https://docs.stripe.com/invoicing
https://docs.stripe.com/invoicing/overview
Stripe API Doc:
https://docs.stripe.com/api/invoices
https://docs.stripe.com/api/events/types
Invoice 的生命周期:
https://docs.stripe.com/invoicing/integration/workflow-transitions
Invoice 的状态集合:
draft, deleted, open, paid, uncollectible, void
https://docs.stripe.com/api/invoices/object#invoice_object-status
Action | Invoice Status | Description |
---|---|---|
Create A Invoice | draft | 初始状态,不可支付 |
Delete A Draft Invoice | deleted | 最终状态,不可支付,彻底删除。 |
Finalize A Draft Invoice | open | 中间状态,可支付,可变更为 paid/void |
Payment Successful | paid | 最终状态,已支付 |
Void An Open/Uncollectible Invoice | void | 最终状态,不可支付,账单已关闭 |
All retries for a payment fail | uncollectible | 中间状态,可支付,可变更为 paid/void |
open vs draft
这两个状态的 Invoice 在数据上的区别:
在 finalize 之前,Invoice Object 的 number, hosted_invoice_url, invoice_pdf 均为空值。
故无法进行支付流程。
uncollectible
如何获得一个状态为 uncollectible 的 Invoice
1) 直接调用 API 指定 Invoice 状态
InvoiceMarkUncollectibleParams params = InvoiceMarkUncollectibleParams.builder().build();
Invoice invoice = resource.markUncollectible(params);
2) 在 Stripe Dashboard 可配置延期未支付账单的后续行为:
配置指路:
Billing > Manage failed payments for subscriptions > Invoice Status
https://dashboard.stripe.com/settings/billing/automatic
Leave the invoice past-due 指的是 Invoice 保持 open 状态。
此时,在 Stripe Dashboard Invoice 列表中会出现 past-due 的红色标签,但其实没有 past-due 这个状态。
如果该配置改为第二项,则账单逾期未支付会自动变更为中间状态 uncollectible。
接下来介绍常用的 API 和一些使用场景。
2.2 Create Invoice
Quickstart Guide:
https://docs.stripe.com/invoicing/quickstart-guide
Stripe API Doc:
https://docs.stripe.com/api/invoices/create
Invoice 创建以后状态为 draft,此时可任意变更 invoice 的内容,变更 products & prices 等。
API 示例:
1) Auto Charge Example
InvoiceCreateParams invoiceParams = InvoiceCreateParams.builder()
.setCustomer("cus_PxxxxxawSn")
.setCollectionMethod(InvoiceCreateParams.CollectionMethod.CHARGE_AUTOMATICALLY)
.setAutoAdvance(true).build();
Invoice invoice = Invoice.create(invoiceParams);
2) Send Email & Bank Transfer Example
InvoiceCreateParams params = InvoiceCreateParams.builder()
.setCustomer("cus_PxxxxxawSn")
.setPaymentSettings(InvoiceCreateParams.PaymentSettings.builder()
.addPaymentMethodType(
InvoiceCreateParams.PaymentSettings.PaymentMethodType.CUSTOMER_BALANCE
)
.setPaymentMethodOptions(InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.builder()
.setCustomerBalance(InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.CustomerBalance.builder()
.setFundingType("bank_transfer")
.setBankTransfer(InvoiceCreateParams.PaymentSettings.PaymentMethodOptions.CustomerBalance.BankTransfer.builder()
.setType("gb_bank_transfer").build()
).build()
).build()
).build()
)
.setCollectionMethod(InvoiceCreateParams.CollectionMethod.SEND_INVOICE)
.setDaysUntilDue(10L)
.setAutoAdvance(true)
.build()
Invoice invoice = Invoice.create(invoiceParams);
Invoice 账单详情页由 Stripe 托管,样式参考:
1) Payment Method Type - Card
2) Payment Method Type - Bank Transfer
Invoice Item
Stripe API Doc:
https://docs.stripe.com/api/invoices/line_item
与 Create Checkout 不同的是,Create Invoice 有两步:
a. 创建 Invoice Object
b. 创建 Invoice Items 即产品价格列表,并绑定到指定的 Invoice。
PriceCreateParams priceParams = PriceCreateParams.builder()
.setCurrency("usd")
.setUnitAmount(1000L)
.setProductData(PriceCreateParams.ProductData.builder()
.setName("product name").build()).build();
Price price = Price.create(priceParams);
InvoiceItemCreateParams invoiceItemParams = InvoiceItemCreateParams.builder()
.setCustomer("cus_PxxxxxawSn")
.setPrice(price.getId())
.setDescription("product description")
.setInvoice(invoice.getId()).build();
InvoiceItem invoiceItem = InvoiceItem.create(invoiceItemParams);
Auto Advance
Stripe Doc:
https://docs.stripe.com/invoicing/integration/automatic-advancement-collection
Stripe API Doc:
https://docs.stripe.com/api/invoices/create#create_invoice-auto_advance
该参数指自动推进 Invoice 的状态变更。
如果 auto_advance=false,则需要指定行为才能触发状态变更,比如 Draft Invoice 在调用 Finalize Invoice 后才会变成 Open Invoice。
如果 auto_advance=true,则 Stripe 将在 1 小时后自动将 Invoice 状态变更为 open。
Tips:
在调用 Finalize An Invoice API (小节 2.4)时,也需要设置该参数。
Collection Method
Stripe Doc:
https://docs.stripe.com/invoicing/automated-collections
Stripe API Doc:
https://docs.stripe.com/api/invoices/create#create_invoice-collection_method
该参数指收款方式,有两种收款方式可选:自动扣款、账单邮件。
1) charge_automatically
向 Customer 设置的默认支付方式扣款。
可在 Stripe Dashboard 配置重试周期、重试次数等。
2) send_invoice
向 Customer Email Address 发送账单邮件。
可设置账单逾期时间。
在 Stripe Dashboard 可配置支付提醒周期。
3) Billing Settings
配置指路:
Billing > Subscription and emails > Manage advanced invoicing features > Customer emails
https://dashboard.stripe.com/settings/billing/automatic
2.3 Delete Draft Invoice
Stripe API Doc:
https://docs.stripe.com/api/invoices/delete
仅可删除状态为 draft 的 Invoice,该删除为彻底删除,不可恢复。
删除后,在 Stripe Dashboard 无法查看该 Invoice,调用 Retrieve Invoice API 也无法查到该 Invoice。
Invoice resource = Invoice.retrieve("in_1MxxxxxxxPMv");
Invoice invoice = resource.delete();
2.4 Finalize Invoice
Stripe API Doc:
https://docs.stripe.com/api/invoices/finalize
Invoice 数据装填完成后,可调用该 API 将 Invoice 变更为 open 状态,即变为可支付状态。
Invoice resource = Invoice.retrieve("in_1MtGxxxxx6PgS6g8S");
InvoiceFinalizeInvoiceParams params = InvoiceFinalizeInvoiceParams.builder().setAutoAdvance(true).build();
Invoice invoice = resource.finalizeInvoice(params);
auto_advance=true,指 Invoice 状态由 Stripe 自动推进 ( 小节 2.2.2 Auto Advance )。
2.5 Void Invoice
Stripe API Doc:
https://docs.stripe.com/api/invoices/void
非 draft Invoice 如果需要取消,不再允许支付,可调用此接口。
Invoice resource = Invoice.retrieve("in_1MtGmxxxxxgS6g8S");
InvoiceVoidInvoiceParams params = InvoiceVoidInvoiceParams.builder().build();
Invoice invoice = resource.voidInvoice(params);
与 2.3 Delete Draft Invoice 的区别是:
Void 不可用于 Draft Invoice。
Void Invoice 在 Stripe Dashboard 可见,调用 Retrieve API 可查询,Hosted invoice page 可访问。
2.6 Retrieve A Invoice
Stripe API Doc:
https://docs.stripe.com/api/invoices/retrieve
Invoice invoice = Invoice.retrieve("in_1MtHxxxxxPMv");
Tips
Status 为 deleted 的 Invoice 已被彻底删除,不可查。
调用 Retrieve API 将抛出如下异常:
Exception in thread "main" com.stripe.exception.InvalidRequestException: No such invoice: 'in_1OoJHxxxxxx66lX'; code: resource_missing; request-id: req_EVxxxxxJ5k
at com.stripe.net.LiveStripeResponseGetter.handleApiError(LiveStripeResponseGetter.java:182)
at com.stripe.net.LiveStripeResponseGetter.handleError(LiveStripeResponseGetter.java:143)
at com.stripe.net.LiveStripeResponseGetter.request(LiveStripeResponseGetter.java:67)
at com.stripe.model.Invoice.retrieve(Invoice.java:1307)
at com.stripe.model.Invoice.retrieve(Invoice.java:1294)
at com.stripe.sample.InvoiceServer.main(InvoiceServer.java:119)
2.7 Events & Automations
Events
Invoice Events
https://docs.stripe.com/api/events/types#event_types-invoice.created
Payment Intent Events
https://docs.stripe.com/api/events/types#event_types-payment_intent.amount_capturable_updated
Price Events
https://docs.stripe.com/api/events/types#event_types-price.created
Product Events
https://docs.stripe.com/api/events/types#event_types-product.created
Automation
Overdue Invoice 不会自动触发 webhook invoice.overdue 事件。
可在 Stripe Dashboard 配置 Automation,配置指路:
Billing > Automations > Create New automation
1) Step 1
2) Step 2