订阅取消后 Stripe API 退款

Posted

技术标签:

【中文标题】订阅取消后 Stripe API 退款【英文标题】:Stripe API refund after subscription cancelled 【发布时间】:2014-09-07 13:42:45 【问题描述】:

来自 Stripe 文档:

当您取消订阅时,客户的卡将不会 再次收费,但也不会退还任何款项。如果你想 发出退款,您可以通过 Stripe 的仪表板或通过 API。

我创建了每月订阅,我只想退还订阅当月内尚未过去的天数的金额。如何使用 Stripe API 仅退还未完成天数的订阅金额?

【问题讨论】:

2016 年年中,令人惊讶的是,Stripe 还没有实现整个订阅生命周期(特别是生命周期结束) 【参考方案1】:

您需要计算退款金额,然后向 Stripe 发送refund API call。退款后,您必须再次调用 Subscription cancellation 的 API

【讨论】:

是否可以拨打取消电话,然后拨打退款电话?还是按照您的建议严格遵循 api 调用?【参考方案2】:

如果您想让 Stripe 处理退款计算,您可以将订阅数量更改为 0,然后在之后取消计划。

【讨论】:

要详细说明这个技巧,您需要将数量设置为零,然后检索即将到来的发票以获得退款金额(upcomingInvoice.total * -1)。要退款,请获取最新的已付款发票(不是即将到来的发票)并使用费用 ID 进行退款。【参考方案3】:

研究了一阵子,我来到了这个用 javascript 为 Node.js 编写的流程:

refundAndUnsubscribe = async function () 
    try 

        // Set proration date to this moment:
        const proration_date = Math.floor(Date.now() / 1000);

        let sub = await stripe.subscriptions.retrieve("sub_CILnalN9HpvADj");

        // See what the next invoice would look like with a plan switch
        // and proration set:
        let items = [
            quantity: 0,
            id: sub.items.data[0].id,
            plan: "your_plan" // Switch to new plan
        ];


        let invoices = await stripe.invoices.retrieveUpcoming('cus_CIP9dtlq143gq7', 'sub_CILnalN9HpvADj', 
            subscription_items: items,
            subscription_proration_date: proration_date
        );

        //List all invoices
        let payedInvoicesList = await stripe.invoices.list(
            customer: 'cus_CIP9dtlq143gq7'
        );

        // Calculate the proration cost:
        let current_prorations = [];
        let cost = 0;
        for (var i = 0; i < invoices.lines.data.length; i++) 
            let invoice_item = invoices.lines.data[i];
            if (invoice_item.period.start == proration_date) 
                current_prorations.push(invoice_item);
                cost += invoice_item.amount;
            
        

        //create a refund
        if (cost !== 0) 
            cost = (cost < 0) ? cost * -1 : cost //A positive integer in cents

            let refund = await stripe.refunds.create(
                charge: payedInvoicesList.data[0].charge,
                amount: cost
            );
        

        // delete subscription
        return stripe.subscriptions.del('sub_CILnalN9HpvADj');

     catch (e) 
        console.log(e);
    

【讨论】:

为什么会出现这种情况 if (invoice_item.period.start == proration_date) @ramamoorthy_villi 是为了确认找到了他创建的临时发票来计算分摊金额。【参考方案4】:

Stripe 现在会处理这个问题。它可以立即取消订阅并创建一张发票,将当月未使用部分的费用退还给他们。

https://stripe.com/docs/api/subscriptions/cancel

添加“按比例”标签以退还剩余的每月费用。

php 中:

$subscription = \Stripe\Subscription::retrieve(
  'SUBSCRIPTION_ID'
);

$subscription->delete([
    'prorate' => true
]);

编辑:

@Dobes Vandermeer 在下面评论并指出了我的错误。上述方法实际上不会退还客户按比例分配的金额,而只会创建一个帐户信用,该信用将应用于下一张发票。

下面的代码实际上会将按比例分配的金额退还到卡中。它会生成一个按比例分配的示例发票,就好像客户将其订阅数量切换为零一样。然后,它会从其有效订阅的最后一张发票中退还按比例分配的金额。

subscription_proration_date”标签是可选的,但在您需要从某个时间点按比例分配订阅时很有用。

// get active subscription
$subscription = \Stripe\Subscription::retrieve(' SUBSCRIPTION_ID ');

// sample prorated invoice for a subscription with quantity of 0
$sample_subscription_item = array(
    "id"       => $subscription->items->data[0]->id,
    "plan"     => $subscription->items->data[0]->plan->id,
    "quantity" => 0,
);

$upcoming_prorated_invoice = \Stripe\Invoice::upcoming([
    "customer"                    => $subscription->customer,
    "subscription"                => $subscription->id,
    "subscription_items"          => array($sample_subscription_item),
    "subscription_proration_date" => ' PRORATED_DATE ', // optional
]);

// find prorated amount
$prorated_amount = 0;
foreach($upcoming_prorated_invoice->lines->data as $invoice) 
    if ($invoice->type == "invoiceitem") 

        $prorated_amount = ($invoice->amount < 0) ? abs($invoice->amount) : 0;

        break;

    


// find charge id on the active subscription's last invoice
$latest_invoice = \Stripe\Invoice::retrieve($subscription->latest_invoice);
$latest_charge_id = $latest_invoice->charge;

// refund amount from last invoice charge
if ($prorated_amount > 0) 

    $refund = \Stripe\Refund::create([
        'charge' => $latest_charge_id,
        'amount' => $prorated_amount,
    ]);
  


// delete subscription
$subscription->delete();

【讨论】:

看起来,当您这样做时,Stripe 只会创建退款并发出“信用”。它实际上并没有发出退款。 谢谢@Dobes Vandermeer。好点子。我使用适用于我的用例的流程更新了答案。 我收到此错误 Stripe\Exception\InvalidRequestException 您无法预览即将取消的订阅的发票。 @ShankarSBavan 听起来订阅已经取消了。在我的帖子中,我假设订阅仍然有效。在完成所有计算并将费用退还给客户后,它会取消订阅。 @PhilipStevens 是的,我想退款,他们在月中取消了订阅。您能否验证这是正确的答案。 ***.com/questions/62403075/…

以上是关于订阅取消后 Stripe API 退款的主要内容,如果未能解决你的问题,请参考以下文章

如何取消 Stripe 计划中的所有订阅?

停止和退款订阅的 PayPal NVP API 的推荐做法是啥?

Stripe:更新订阅还是取消并创建新订阅?

通过商家控制台/API 取消用户订阅会退还他的钱吗?

退款后订阅状态仍为“ACTIVE”

PayPal 订阅 - 跟踪退款