0

0

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

花韻仙語

花韻仙語

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

|

930人浏览过

|

来源于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是合适的。

ModelGate
ModelGate

一站式AI模型管理与调用工具

下载
# ... (承接上述 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工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

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

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

166

2026.02.04

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

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

166

2026.02.04

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

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

336

2023.10.17

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

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

776

2023.10.18

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

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

97

2025.08.19

scripterror怎么解决
scripterror怎么解决

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

492

2023.10.18

500error怎么解决
500error怎么解决

500error的解决办法有检查服务器日志、检查代码、检查服务器配置、更新软件版本、重新启动服务、调试代码和寻求帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

382

2023.10.25

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

389

2023.06.29

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

26

2026.03.13

热门下载

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

精品课程

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

共101课时 | 10.2万人学习

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

共39课时 | 3.4万人学习

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

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号