You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在DRF后端基于Stripe实现客户间可变金额自动付款

核心方案概述

你的场景是客户间可变金额的自定义周期转账(收款方为其他客户而非平台),Stripe订阅服务不适用,需采用Stripe Connect + Setup Intents + Payment Intents + 后端定时任务的组合方案,以下是具体实现步骤和代码片段:

1. 前期准备

  • 注册Stripe Connect平台账户并启用转账功能
  • 在DRF项目中安装Stripe SDK:pip install stripe
  • 在settings.py中配置密钥:
    STRIPE_SECRET_KEY = "你的Stripe秘钥"
    STRIPE_PUBLISHABLE_KEY = "你的Stripe公钥"
    STRIPE_WEBHOOK_SECRET = "你的Webhook秘钥"
    

2. 为收款客户创建Stripe Connect账户

每个收款用户需要拥有独立的Stripe Express账户,用于接收转账:

# views.py
import stripe
from django.conf import settings
from rest_framework.response import Response
from rest_framework.views import APIView
from django.contrib.auth import get_user_model

User = get_user_model()
stripe.api_key = settings.STRIPE_SECRET_KEY

class CreateConnectAccountView(APIView):
    def post(self, request):
        user = request.user
        # 创建Express账户
        account = stripe.Account.create(
            type="express",
            country="CN", # 根据业务地区调整
            email=user.email,
            business_type="individual",
            individual={
                "first_name": user.first_name,
                "last_name": user.last_name,
            },
            capabilities={"transfers": {"requested": True}},
        )
        # 生成账户验证链接,引导用户完成身份认证
        account_link = stripe.AccountLink.create(
            account=account.id,
            refresh_url="https://你的域名/account-refresh",
            return_url="https://你的域名/account-success",
            type="account_onboarding",
        )
        # 将Stripe账户ID保存到本地用户模型
        user.stripe_connect_account_id = account.id
        user.save()
        return Response({"verify_url": account_link.url})

3. 付款客户绑定支付方式(Setup Intent)

让付款用户预先绑定银行卡,后续无需重复授权:

class SetupPaymentMethodView(APIView):
    def post(self, request):
        user = request.user
        # 若用户未创建Stripe Customer,先创建
        if not user.stripe_customer_id:
            customer = stripe.Customer.create(email=user.email)
            user.stripe_customer_id = customer.id
            user.save()
        # 创建Setup Intent
        setup_intent = stripe.SetupIntent.create(
            customer=user.stripe_customer_id,
            payment_method_types=["card"],
        )
        # 返回client_secret给前端,用于Stripe.js完成绑定
        return Response({"client_secret": setup_intent.client_secret})

前端通过Stripe.js调用stripe.confirmCardSetup完成支付方式绑定,绑定成功后将payment_method_id保存到本地数据库。

4. 定义付款计划模型

在数据库中存储用户的付款规则:

# models.py
from django.db import models
from django.contrib.auth import get_user_model

User = get_user_model()

class PaymentSchedule(models.Model):
    ACTIVE = "active"
    CANCELLED = "cancelled"
    STATUS_CHOICES = [(ACTIVE, "生效中"), (CANCELLED, "已取消")]
    
    payer = models.ForeignKey(User, related_name="initiated_plans", on_delete=models.CASCADE)
    payee = models.ForeignKey(User, related_name="received_plans", on_delete=models.CASCADE)
    amount = models.DecimalField(max_digits=10, decimal_places=2)  # 单位:元
    frequency = models.CharField(max_length=20, null=True, blank=True)  # 示例:"15_days", "monthly", "one_time"
    next_payment_date = models.DateField()
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default=ACTIVE)
    stripe_payment_method_id = models.CharField(max_length=100)  # 付款方绑定的支付方式ID

5. 定时触发付款(Celery示例)

每天扫描付款计划,发起符合条件的转账:

# tasks.py
import stripe
from django.conf import settings
from django.utils import timezone
from .models import PaymentSchedule
from dateutil.relativedelta import relativedelta

stripe.api_key = settings.STRIPE_SECRET_KEY

def process_scheduled_payments():
    today = timezone.now().date()
    # 筛选今日需执行的生效计划
    schedules = PaymentSchedule.objects.filter(
        next_payment_date__lte=today,
        status=PaymentSchedule.ACTIVE
    )
    for schedule in schedules:
        amount_cents = int(schedule.amount * 100)  # 转换为分(Stripe最小货币单位)
        try:
            # 发起转账Payment Intent
            payment_intent = stripe.PaymentIntent.create(
                amount=amount_cents,
                currency="cny",
                customer=schedule.payer.stripe_customer_id,
                payment_method=schedule.stripe_payment_method_id,
                confirm=True,
                metadata={"schedule_id": schedule.id},  # 关联本地计划ID,用于Webhook处理
                transfer_data={
                    "destination": schedule.payee.stripe_connect_account_id,
                },
                # 可选:平台收取手续费
                # application_fee_amount=int(amount_cents * 0.02)
            )
            # 更新下一次付款日期
            if schedule.frequency == "15_days":
                schedule.next_payment_date += timezone.timedelta(days=15)
            elif schedule.frequency == "monthly":
                schedule.next_payment_date += relativedelta(months=1)
            schedule.save()
        except stripe.error.StripeError as e:
            # 记录失败日志,通知用户
            print(f"计划{schedule.id}付款失败:{e.user_message}")

可通过Celery配置每日定时任务执行process_scheduled_payments,或使用Apscheduler替代。

6. Webhook处理付款状态

监听Stripe事件,同步本地记录状态:

# views.py
class StripeWebhookView(APIView):
    authentication_classes = []
    permission_classes = []

    def post(self, request):
        payload = request.body
        sig_header = request.META.get("HTTP_STRIPE_SIGNATURE")
        try:
            event = stripe.Webhook.construct_event(
                payload, sig_header, settings.STRIPE_WEBHOOK_SECRET
            )
        except (ValueError, stripe.error.SignatureVerificationError):
            return Response(status=400)
        
        # 处理付款成功事件
        if event["type"] == "payment_intent.succeeded":
            payment_intent = event["data"]["object"]
            schedule_id = payment_intent["metadata"]["schedule_id"]
            # 记录付款成功日志、通知双方用户
            pass
        # 处理付款失败事件
        elif event["type"] == "payment_intent.failed":
            payment_intent = event["data"]["object"]
            schedule_id = payment_intent["metadata"]["schedule_id"]
            # 通知付款用户失败原因、标记计划状态
            pass
        return Response(status=200)

关键注意事项

  • 所有金额需转换为对应货币的最小单位(如人民币用分)
  • 收款用户必须完成Stripe Connect账户的身份验证,否则无法接收转账
  • 需为付款失败场景添加重试机制和用户通知逻辑
  • 确保业务符合Stripe Connect的合规条款

内容的提问来源于stack exchange,提问作者stackuser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 14:22:10