Django POS系统集成Stripe Terminal BBPOS WisePOS E失败:无法将付款金额推送至终端
Django POS系统集成Stripe Terminal BBPOS WisePOS E失败:无法将付款金额推送至终端
看起来你已经搞定了Stripe Terminal硬件的激活(后台能看到终端在线状态),但在把付款金额推送到终端这一步卡壳了——我帮你梳理下代码里的关键问题,以及可能遗漏的Stripe集成步骤:
一、核心问题:PaymentIntent金额单位错误
Stripe API要求金额必须传入最小货币单位(比如CAD的话是“分”,10.99加元要传1099),但你的代码里直接把payment_amount(Decimal类型的带小数金额)传给了create_payment_intent,这会导致Stripe识别的金额远小于实际应付款,终端自然不会显示正确金额。
检查你的PaymentService.create_payment_intent方法,必须加上金额转换:
def create_payment_intent(self, amount, currency, payment_method_types): # 转换为最小货币单位(例:10.99 CAD → 1099 分) stripe_amount = int(amount * 100) return stripe.PaymentIntent.create( amount=stripe_amount, currency=currency, payment_method_types=payment_method_types )
二、逻辑错位:同步等待付款完成的误区
你的代码里在后端直接调用process_payment_intent后就判断response["status"] == "succeeded",这不符合Stripe Terminal的异步流程:
- 后端调用
process_payment_intent只是把PaymentIntent推送到终端,此时终端才会显示金额并等待用户刷卡/插卡/碰卡 - 付款完成的事件是异步的,需要通过Stripe Webhook来接收通知,而不是同步等待后端响应
修复这部分逻辑:
elif payment_method in ['credit_card', 'debit_card']: payment_service = PaymentService() # 创建正确金额的PaymentIntent payment_intent = payment_service.create_payment_intent( amount=payment_amount, currency=active_currency.code, payment_method_types=["card_present"] ) order.payment_intent_id = payment_intent["id"] order.save() # 先保存PaymentIntent ID到订单 # 获取在线终端(优先用前端传的reader_id,避免多终端时出错) reader = None if reader_id: try: reader = stripe.Terminal.Reader.retrieve(reader_id) except stripe.error.InvalidRequestError: pass if not reader or reader.status != "online": readers = stripe.Terminal.Reader.list(status="online").data if not readers: raise ValueError("Aucun lecteur en ligne trouvé.") reader = readers[0] # 推送PaymentIntent到终端(这一步只是触发终端显示金额,不会立刻完成付款) stripe.Terminal.Reader.process_payment_intent( reader["id"], {"payment_intent": payment_intent["id"]} ) # 跳转到等待付款页面,提示用户操作终端 return render(request, 'pos/orders/waiting_payment.html', { 'order': order, 'payment_intent_id': payment_intent["id"], 'currency': active_currency })
三、缺失关键环节:Stripe Webhook配置
必须通过Webhook监听payment_intent.succeeded事件,才能在用户完成终端付款后更新订单状态:
- 在Stripe后台配置Webhook,添加
payment_intent.succeeded事件,指向你的Django后端接口 - 实现Webhook处理视图:
from django.views.decorators.csrf import csrf_exempt import stripe from django.conf import settings from django.http import HttpResponse from .models import Order, Bill import timezone @csrf_exempt def stripe_webhook(request): payload = request.body sig_header = request.META.get('HTTP_STRIPE_SIGNATURE') event = None try: event = stripe.Webhook.construct_event( payload, sig_header, settings.STRIPE_WEBHOOK_SECRET ) except (ValueError, stripe.error.SignatureVerificationError): return HttpResponse(status=400) # 处理付款成功事件 if event['type'] == 'payment_intent.succeeded': payment_intent = event['data']['object'] # 根据PaymentIntent ID找到对应订单 order = Order.objects.filter(payment_intent_id=payment_intent['id']).first() if order: order.status = 'completed' order.save() # 生成账单 actual_amount = Decimal(payment_intent['amount']) / 100 Bill.objects.create( order=order, bill_id=f'{order.id}-{timezone.now().strftime("%Y%m%d%H%M%S")}', payment_method=order.payment_method, payment_amount=actual_amount, received_amount=actual_amount, change_amount=Decimal('0.00') ) return HttpResponse(status=200)
四、其他检查点
- 确认终端在Stripe后台显示为在线状态,且没有被其他未完成的PaymentIntent占用
- 前端是否正确传递了
reader_id?如果有多个终端,优先用前端选择的终端ID,而不是默认取第一个 - 检查Stripe API密钥是否拥有Terminal相关的权限(确保是完整的Secret Key,不是仅用于前端的Publishable Key)
备注:内容来源于stack exchange,提问作者Mohamed Abdillah
相关产品推荐
相关产品推荐

