讲师中心 微信公众号

工具推荐

视频效率加速
剧云
剧云

中文短剧剧本制作平台

updream

一键生成高质量推广成片

AniShort
AniShort

AI短剧协同制作平台

Laper
Laper

剧本策划到成片协作

Stripe Checkout Session高级集成:自定义税率与优惠券应用

千宇吖_5112

千宇吖_5112

发布时间:2025-12-14 16:15:23

|

990人浏览过

|

来源于php中文网

原创

Stripe Checkout Session高级集成:自定义税率与优惠券应用

本教程详细指导如何在stripe checkout session中集成自定义税率和折扣。文章将深入解析stripe api中`taxrate`和`coupon`对象的创建与应用,纠正常见的参数配置错误,并提供包含动态税费和优惠券处理的完整代码示例。旨在帮助开发者构建功能完善、符合业务需求的stripe支付流程。

1. 理解Stripe Checkout Session与集成需求

Stripe Checkout Session是Stripe提供的一种快速、安全地收集客户支付信息的方式。在构建电子商务应用时,往往需要根据业务逻辑动态应用税费和折扣。这要求开发者能够正确地创建和管理Stripe中的TaxRate(税率)和Coupon(优惠券)对象,并将其关联到Checkout Session。

原始代码尝试集成这些功能,但在discounts参数的格式上出现了错误,导致InvalidRequestError。本教程将纠正这些错误并提供一个健壮的集成方案。

2. 集成自定义税率(Tax Rates)

Stripe允许您创建自定义税率,并将其应用于Checkout Session中的商品。这些税率可以是包含性的(价格已含税)或排他性的(税费额外计算)。

2.1 创建Stripe TaxRate对象

在将税率应用于Checkout Session之前,您需要先在Stripe中创建TaxRate对象。这些对象定义了税率的百分比、显示名称、描述和管辖区域等信息。在实际应用中,通常会持久化这些税率(例如,存储在数据库中,并仅在需要时更新Stripe),而不是每次都动态创建。

import stripe

# 假设您的Order模型关联了Tax模型,Tax模型包含name, rate等字段
# order.tax.all() 返回一个Tax对象列表

tax_rate_ids = []
for tax_obj in order.tax.all():
    # 最佳实践:检查Stripe中是否已存在同名或同配置的TaxRate,避免重复创建
    # 简单示例中,我们假设每次都创建,但生产环境应优化此逻辑
    try:
        # 尝试查找已存在的税率,如果您的Tax模型中存储了Stripe TaxRate ID
        # 例如:if tax_obj.stripe_tax_rate_id: tax_rate_ids.append(tax_obj.stripe_tax_rate_id)
        # 否则,进行创建
        tax_rate = stripe.TaxRate.create(
            display_name=tax_obj.name,
            description=f"{tax_obj.name} ({tax_obj.rate}%)",
            percentage=tax_obj.rate, # 假设tax_obj.rate是百分比数值,如5.0代表5%
            inclusive=False,         # 设置为True表示价格已含税,False表示税费额外计算
            jurisdiction="US",       # 根据实际业务设置管辖区域,例如 "US", "EU", "CA" 等
        )
        tax_rate_ids.append(tax_rate.id)
    except stripe.error.StripeError as e:
        # 处理Stripe API错误
        print(f"Error creating tax rate: {e}")
        # 根据错误类型决定是否继续或抛出异常

2.2 将TaxRate应用于Checkout Session

创建TaxRate后,您可以通过两种主要方式将其应用于Checkout Session:

  1. 应用于单个line_item(推荐): 如果您的订单包含多个商品,且每个商品可能适用不同的税率,或者您希望更精细地控制税费,这是首选方法。
  2. 应用于整个Session: 如果所有商品都适用相同的税率,或者您只有一个代表整个订单的line_item,可以在Session级别应用。

在用户提供的代码中,只有一个line_item代表整个订单,因此将其应用于line_item是合适的。

cn-json-diff
cn-json-diff

比较两个 JSON 文件并显示差异。支持嵌套结构、数组及值变更。纯 Python 标准库实现,无需 API 密钥。

下载
# ... (承接上述 tax_rate_ids 的创建) ...

line_items_data = [
    {
        'price_data': {
            'currency': 'usd',
            'unit_amount': order.get_total_cost() * 100, # Stripe金额以最小单位(美分)计
            'product_data': {
                'name': order.__str__(),
            },
        },
        'quantity': 1,
        'tax_rates': tax_rate_ids, # 将税率ID列表添加到line_item中
    },
]

# 如果选择应用于整个Session(不推荐与line_item同时使用相同的税率)
# session = stripe.checkout.Session.create(
#     # ...
#     line_items=line_items_data,
#     tax_rates=tax_rate_ids, # 在Session级别应用税率
# )

3. 集成自定义折扣(Discounts/Coupons)

Stripe通过Coupon(优惠券)对象来管理折扣。您可以创建固定金额折扣或百分比折扣的优惠券,并将其应用于Checkout Session。

3.1 创建Stripe Coupon对象

与税率类似,优惠券也应该在Stripe中创建。在生产环境中,通常会有一个管理后台来创建和管理这些优惠券,并将其Stripe ID存储在您的数据库中。

import stripe

# 假设您的Order模型关联了Discount模型,Discount模型包含amount, name等字段
# order.discount.all() 返回一个Discount对象列表

discount_items = []
for discount_obj in order.discount.all():
    # 最佳实践:检查Stripe中是否已存在同名或同配置的Coupon,避免重复创建
    # 简单示例中,我们假设每次都创建,但生产环境应优化此逻辑
    try:
        # 创建一个Stripe Coupon
        # amount_off 是固定金额折扣,以最小单位(美分)计
        # percent_off 是百分比折扣,与amount_off互斥
        coupon = stripe.Coupon.create(
            amount_off=discount_obj.amount * 100, # 假设discount_obj.amount是美元金额
            duration='once', # 'once', 'repeating', 'forever'
            currency='usd',
            name=discount_obj.name,
        )
        discount_items.append({"coupon": coupon.id}) # 正确的格式是 {"coupon": "coupon_id"}
    except stripe.error.StripeError as e:
        # 处理Stripe API错误
        print(f"Error creating coupon: {e}")
        # 根据错误类型决定是否继续或抛出异常

3.2 将Coupon应用于Checkout Session

将优惠券应用于Checkout Session需要使用discounts参数。注意:原始代码中的discounts=[{"discounts": '{{COUPON_ID}}'}]是错误的,导致了InvalidRequestError。 正确的格式是一个包含字典的列表,每个字典都应该有一个"coupon"键,其值为优惠券的ID。

# ... (承接上述 discount_items 的创建) ...

session = stripe.checkout.Session.create(
    # ... 其他参数 ...
    discounts=discount_items, # 正确的优惠券应用方式
)

4. 完整集成示例代码

以下是结合了税率和折扣的优化后的完整代码示例,基于您提供的原始结构进行改进:

import stripe
from django.views import View
from django.http import JsonResponse
from .models import Order # 假设您的Order模型在此处定义

# 请替换为您的Stripe Secret Key
stripe.api_key = 'sk_test_YOUR_STRIPE_SECRET_KEY' # 务必使用环境变量或配置文件管理密钥

class CreateCheckoutSessionOrderView(View):
    def get(self, request, *args, **kwargs):
        order_id = self.kwargs["order_id"]
        DOMAIN: str = 'http://127.0.0.1:8000' # 生产环境请使用您的实际域名

        try:
            order = Order.objects.get(id=order_id)
        except Order.DoesNotExist:
            return JsonResponse({'error': 'Order not found'}, status=404)

        # --- 1. 处理自定义税率 ---
        tax_rate_ids = []
        for tax in order.tax.all(): # 假设order关联了多个Tax对象
            try:
                # 在生产环境中,您应该查询数据库或Stripe来获取已存在的TaxRate ID
                # 避免每次都创建新的TaxRate
                tax_rate = stripe.TaxRate.create(
                    display_name=tax.name,
                    description=f"{tax.name} ({tax.rate}%)",
                    percentage=tax.rate, # 假设tax.rate是百分比,如5.0代表5%
                    jurisdiction="US",   # 根据实际业务设置
                    inclusive=False,     # 设为True则价格含税,False则税费额外计算
                    active=True,         # 确保税率是激活状态
                )
                tax_rate_ids.append(tax_rate.id)
            except stripe.error.StripeError as e:
                print(f"Error creating Stripe TaxRate for {tax.name}: {e}")
                # 根据业务需求处理错误,例如跳过此税率或返回错误

        # --- 2. 处理自定义折扣 ---
        discounts_list = []
        for discount in order.discount.all(): # 假设order关联了多个Discount对象
            try:
                # 在生产环境中,您应该查询数据库或Stripe来获取已存在的Coupon ID
                # 避免每次都创建新的Coupon
                coupon = stripe.Coupon.create(
                    amount_off=discount.amount * 100, # amount_off以最小货币单位(美分)计
                    duration='once', # 'once', 'repeating', 'forever'
                    currency='usd',
                    name=discount.name,
                )
                discounts_list.append({"coupon": coupon.id}) # 正确的折扣参数格式
            except stripe.error.StripeError as e:
                print(f"Error creating Stripe Coupon for {discount.name}: {e}")
                # 根据业务需求处理错误

        # --- 3. 创建Stripe Checkout Session ---
        try:
            session = stripe.checkout.Session.create(
                payment_method_types=['card'],
                line_items=[
                    {
                        'price_data': {
                            'currency': 'usd',
                            'unit_amount': order.get_total_cost() * 100, # 总金额以最小货币单位计
                            'product_data': {
                                'name': order.__str__(),
                                'images': [order.get_thumbnail_url()] if hasattr(order, 'get_thumbnail_url') else [], # 可选:添加商品图片
                            },
                        },
                        'quantity': 1,
                        'tax_rates': tax_rate_ids, # 将收集到的税率ID应用于line_item
                    },
                ],
                payment_intent_data={
                    'metadata': {
                        'order_id': order.id,
                    },
                },
                mode='payment',
                success_url=DOMAIN + '/success/?session_id={CHECKOUT_SESSION_ID}', # 推荐添加session_id参数
                cancel_url=DOMAIN + '/cancel/',
                discounts=discounts_list, # 将收集到的折扣应用于Session
            )
            return JsonResponse({'id': session.id})

        except stripe.error.StripeError as e:
            # 捕获Stripe API可能抛出的所有错误
            print(f"Error creating Stripe Checkout Session: {e}")
            return JsonResponse({'error': str(e)}, status=500)
        except Exception as e:
            # 捕获其他未知错误
            print(f"An unexpected error occurred: {e}")
            return JsonResponse({'error': 'An unexpected error occurred'}, status=500)

5. 注意事项与最佳实践

  1. Stripe API Key管理: 永远不要将您的Stripe Secret Key硬编码到代码中。使用环境变量、Django设置文件或专门的密钥管理服务来安全地存储和访问它。
  2. Stripe对象持久化: 在生产环境中,频繁地创建TaxRate和Coupon对象是不高效且不必要的。
    • 税率: 通常税率是相对稳定的。您可以在Stripe仪表板中创建它们一次,然后将它们的Stripe ID存储在您的数据库中(例如,在您的Tax模型中添加stripe_tax_rate_id字段)。在创建Checkout Session时,直接从数据库中检索这些ID。
    • 优惠券: 优惠券可能更具动态性。对于预设的优惠券,同样可以存储其Stripe ID。对于用户输入的促销码,您需要使用PromotionCode对象,它链接到Coupon。
  3. 错误处理: 务必捕获stripe.error.StripeError及其子类,以便优雅地处理Stripe API调用失败的情况,并向用户提供有意义的反馈。
  4. 金额单位: Stripe API要求所有金额都以最小货币单位(例如,美元为美分,欧元为欧分)表示。请确保在传递unit_amount和amount_off时进行正确的转换(例如,乘以100)。
  5. success_url中的session_id: 在success_url中添加?session_id={CHECKOUT_SESSION_ID}是一个很好的实践。当客户成功完成支付后,Stripe会将实际的Session ID填充到此URL中,您的成功页面可以使用此ID来检索Session详情并验证支付状态。
  6. 测试: 在将代码部署到生产环境之前,务必在Stripe的测试模式下进行彻底测试,以确保税费和折扣的计算和应用符合预期。
  7. Webhook: 对于更复杂的订单流程(例如,需要更新订单状态、发送确认邮件等),强烈建议设置Stripe Webhook来监听支付事件(如checkout.session.completed)。

总结

通过本教程,您应该已经掌握了在Stripe Checkout Session中正确集成自定义税率和折扣的方法。关键在于理解Stripe TaxRate和Coupon对象的创建,以及在stripe.checkout.Session.create方法中line_items的tax_rates参数和discounts参数的正确格式。遵循最佳实践,特别是关于Stripe对象持久化和错误处理,将有助于构建一个稳定、高效的支付系统。

热门AI工具

更多
Laper
Laper Hot

Laper是专为编剧、导演和制片人推出的 AI 原生剧本创作工具。

二狗PPT
二狗PPT Hot

一款AI演示文稿工具,主要用于专为中式职场打造的AI PPT生成工具,适合需要提升相关任务效率的用户。

SkildArt
SkildArt Hot

SkildArt是一款AI文本写作工具,一站式 AI 视觉创作平台。

立刻MV
立刻MV Hot

立刻MV是一款AI文本写作工具,AI 音乐视频(MV)创作工具。

DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

超级简历WonderCV

一款AI办公效率工具,主要用于免费求职简历模版下载制作,应届生职场人必备简历制作神器,适合需要提升相关任务效率的用户。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

讯飞智文

一款面向学习和办公场景的AI文档创作工具,可辅助生成PPT与Word文档,提高资料整理和内容制作效率。

相关专题

更多
Python Web 框架 Django 深度开发
Python Web 框架 Django 深度开发

本专题系统讲解 Python Django 框架的核心功能与进阶开发技巧,包括 Django 项目结构、数据库模型与迁移、视图与模板渲染、表单与认证管理、RESTful API 开发、Django 中间件与缓存优化、部署与性能调优。通过实战案例,帮助学习者掌握 使用 Django 快速构建功能全面的 Web 应用与全栈开发能力。

593

2026.02.04

Python Django REST Framework接口安全与认证体系实践
Python Django REST Framework接口安全与认证体系实践

本专题围绕 Django REST Framework 展开,深入讲解 API 认证、JWT 鉴权、权限控制、接口安全防护以及防攻击策略设计。通过完整后端案例,帮助开发者构建安全可靠的 Web API 服务体系。

260

2026.06.29

Python Web 框架 Django 深度开发
Python Web 框架 Django 深度开发

本专题系统讲解 Python Django 框架的核心功能与进阶开发技巧,包括 Django 项目结构、数据库模型与迁移、视图与模板渲染、表单与认证管理、RESTful API 开发、Django 中间件与缓存优化、部署与性能调优。通过实战案例,帮助学习者掌握 使用 Django 快速构建功能全面的 Web 应用与全栈开发能力。

593

2026.02.04

Python Django REST Framework接口安全与认证体系实践
Python Django REST Framework接口安全与认证体系实践

本专题围绕 Django REST Framework 展开,深入讲解 API 认证、JWT 鉴权、权限控制、接口安全防护以及防攻击策略设计。通过完整后端案例,帮助开发者构建安全可靠的 Web API 服务体系。

260

2026.06.29

session失效的原因
session失效的原因

session失效的原因有会话超时、会话数量限制、会话完整性检查、服务器重启、浏览器或设备问题等等。详细介绍:1、会话超时:服务器为Session设置了一个默认的超时时间,当用户在一段时间内没有与服务器交互时,Session将自动失效;2、会话数量限制:服务器为每个用户的Session数量设置了一个限制,当用户创建的Session数量超过这个限制时,最新的会覆盖最早的等等。

580

2023.10.17

session失效解决方法
session失效解决方法

session失效通常是由于 session 的生存时间过期或者服务器关闭导致的。其解决办法:1、延长session的生存时间;2、使用持久化存储;3、使用cookie;4、异步更新session;5、使用会话管理中间件。

876

2023.10.18

cookie与session的区别
cookie与session的区别

本专题整合了cookie与session的区别和使用方法等相关内容,阅读专题下面的文章了解更详细的内容。

1966

2025.08.19

scripterror怎么解决
scripterror怎么解决

scripterror的解决办法有检查语法、文件路径、检查网络连接、浏览器兼容性、使用try-catch语句、使用开发者工具进行调试、更新浏览器和JavaScript库或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1069

2023.10.18

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

60

2026.11.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 21.3万人学习

JS进阶与BootStrap学习
JS进阶与BootStrap学习

共39课时 | 4.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn