我正在开发 POS 系统,我想连接 Stripe 物理读卡器,而不是模拟读卡器。 这是我的 JavaScript 代码,用于初始化、Redears 发现和连接阅读器。
// Initialize Stripe Terminal
const terminal = StripeTerminal.create({
onFetchConnectionToken: async () => {
try {
const response = await fetch("http://127.0.0.1:8000/create_connection_token/", { method: 'POST' });
if (!response.ok) {
throw new Error("Failed to fetch connection token");
}
const { secret } = await response.json();
return secret;
} catch (error) {
console.error("Error fetching connection token:", error);
throw error;
}
},
onUnexpectedReaderDisconnect: () => {
console.error("Reader unexpectedly disconnected.");
alert("Le terminal s'est déconnecté de manière inattendue. Veuillez vérifier la connexion et réessayer.");
},
});
console.log("Stripe Terminal initialized.");
// Discover readers
async function discoverReaders() {
try {
console.log("Discovering readers...");
const config = {
simulated: false,
location: "LOCATION_ID"
};
const discoverResult = await terminal.discoverReaders(config);
console.log("Discover Result:", discoverResult);
if (discoverResult.error) {
console.error('Error discovering readers:', discoverResult.error.message);
alert('Erreur lors de la découverte des lecteurs. Vérifiez votre configuration réseau.');
return null;
}
if (discoverResult.discoveredReaders.length === 0) {
console.warn("No available readers. Ensure the terminal is powered on and connected.");
alert("Aucun terminal trouvé. Vérifiez la connectivité et la configuration réseau.");
return null;
}
console.log("Discovered readers:", discoverResult.discoveredReaders);
alert("Lecteurs découverts avec succès.");
return discoverResult.discoveredReaders[0];
} catch (error) {
console.error("Error during reader discovery:", error);
alert("Une erreur inattendue s'est produite lors de la découverte des lecteurs.");
return null;
}
}
// Connect to a reader
async function connectReader(reader) {
try {
console.log("Attempting to connect to reader:", reader.label);
// Connect to the selected reader
const connectResult = await terminal.connectReader(reader);
// Handle connection errors
if (connectResult.error) {
console.error("Failed to connect:", connectResult.error.message);
alert(`Connexion échouée : ${connectResult.error.message}`);
return false;
}
console.log("Connected to reader:", connectResult.reader.label);
alert(`Connecté au lecteur : ${connectResult.reader.label}`);
return true;
} catch (error) {
console.error("Error during reader connection:", error);
alert("Une erreur inattendue s'est produite lors de la connexion au terminal. Consultez la console pour plus de détails.");
return false;
}
}
// Example usage: Discover and connect to a reader
async function handleReaderSetup() {
const reader = await discoverReaders();
if (reader) {
await connectReader(reader);
}
}
我能够使用 Stripe API 连接阅读器,并且从我的 stripe 中我可以看到阅读器是否在线。 然而,当我运行应用程序并尝试将钱发送给读者进行付款时,它显示Aucun 终端问题。 Vérifiez la connectivité et la configuration réseau。这意味着英文未找到终端。检查连接和网络配置。 令人困惑的是,当我运行此命令时:
import stripe
stripe.api_key = "sk_live_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
try:
# List all readers
readers = stripe.terminal.Reader.list()
print("Readers:", readers)
except stripe.error.StripeError as e:
print("Stripe error:", e)
except Exception as e:
print("An unexpected error occurred:", e)
我得到这个输出:
Readers: {
"data": [ { "action": null, "device_sw_version": "2.27.7.0", "device_type": "bbpos_wisepos_e",
"id": "tmr_XXXXXXXXXXXXXX",
"ip_address": "x.0.0.xxx",
"label": "Testing_Reader",
"last_seen_at": 1735518518163,
"livemode": true,
"location": "tml_ZZZZZZZZZZZZ",
"metadata": {},
"object": "terminal.reader",
"serial_number": "YYYYYYYYYYYYY",
"status": "online"
}
],
"has_more": false,
"object": "list",
"url": "/v1/terminal/readers"
}
另外,这个命令:
stripe terminal readers list
显示此结果:
{
"object": "list",
"data": [
{
"id": "tmr_XXXXXXXXXXXXXX",
"object": "terminal.reader",
"action": null,
"device_sw_version": "2.27.7.0",
"device_type": "bbpos_wisepos_e",
"ip_address": "x.0.0.xxx",
"label": "Testing_Reader",
"last_seen_at": 1735517252951,
"livemode": true,
"location": "tml_ZZZZZZZZZZZZ",
"metadata": {},
"serial_number": "YYYYYYYYYYYYY",
"status": "online"
}
],
"has_more": false,
"url": "/v1/terminal/readers"
我真的不明白,为什么要点击这个按钮
<button type="button" id="send-to-terminal" class="btn btn-primary" data-order-id="{{ order.id }}"> Envoyer au terminal</button> gives me the error I mentioned above.
欲了解更多详情,我也有这项服务:
import stripe
import logging
from decimal import Decimal
from django.conf import settings
class PaymentService:
def __init__(self):
"""Initialize the PaymentService with the Stripe API key."""
stripe.api_key = settings.STRIPE_SECRET_KEY
self.logger = logging.getLogger(__name__)
def get_online_reader(self):
"""
Fetch the first online terminal reader from Stripe.
:return: Stripe Terminal Reader object.
:raises: ValueError if no online reader is found.
"""
try:
readers = stripe.terminal.Reader.list(status="online").data
if not readers:
self.logger.error("Aucun lecteur de terminal en ligne trouvé.")
raise ValueError("Aucun lecteur de terminal en ligne trouvé.")
return readers[0] # Return the first online reader
except stripe.error.StripeError as e:
self.logger.error(f"Erreur Stripe lors de la récupération des lecteurs: {str(e)}")
raise Exception(f"Erreur Stripe: {str(e)}")
def create_payment_intent(self, amount, currency="CAD", payment_method_types=None, capture_method="automatic"):
"""
Create a payment intent for a terminal transaction.
:param amount: Decimal, total amount to charge.
:param currency: str, currency code (default: "CAD").
:param payment_method_types: list, payment methods (default: ["card_present"]).
:param capture_method: str, capture method for the payment intent.
:return: Stripe PaymentIntent object.
"""
try:
if payment_method_types is None:
payment_method_types = ["card_present"]
payment_intent = stripe.PaymentIntent.create(
amount=int(round(amount, 2) * 100), # Convert to cents
currency=currency.lower(),
payment_method_types=payment_method_types,
capture_method=capture_method # Explicitly include this argument
)
self.logger.info(f"PaymentIntent created: {payment_intent['id']}")
return payment_intent
except stripe.error.StripeError as e:
self.logger.error(f"Stripe error while creating PaymentIntent: {str(e)}")
raise Exception(f"Stripe error: {str(e)}")
except Exception as e:
self.logger.error(f"Unexpected error while creating PaymentIntent: {str(e)}")
raise Exception(f"Unexpected error: {str(e)}")
def send_to_terminal(self, payment_intent_id):
"""
Send a payment intent to the online terminal reader for processing.
:param payment_intent_id: str, ID of the PaymentIntent.
:return: Stripe response from the terminal reader.
"""
try:
# Retrieve the Reader ID from settings
reader_id = settings.STRIPE_READER_ID # Ensure this is correctly set in your configuration
# Send the payment intent to the terminal
response = stripe.terminal.Reader.process_payment_intent(
reader_id, {"payment_intent": payment_intent_id}
)
self.logger.info(f"PaymentIntent {payment_intent_id} sent to reader {reader_id}.")
return response
except stripe.error.StripeError as e:
self.logger.error(f"Erreur Stripe lors de l'envoi au terminal: {str(e)}")
raise Exception(f"Erreur Stripe: {str(e)}")
except Exception as e:
self.logger.error(f"Unexpected error while sending to terminal: {str(e)}")
raise Exception(f"Unexpected error: {str(e)}")
以及这些观点:
@login_required
def send_to_terminal(request, order_id):
"""
Send the payment amount to the terminal.
"""
if request.method == "POST":
try:
# Validate amount
amount = Decimal(request.POST.get('amount', 0))
if amount <= 0:
return JsonResponse({'success': False, 'error': 'Montant non valide.'}, status=400)
# Create PaymentIntent
payment_intent = stripe.PaymentIntent.create(
amount=int(amount * 100),
currency="CAD",
payment_method_types=["card_present"]
)
# List online readers dynamically
readers = stripe.terminal.Reader.list(status="online").data
if not readers:
return JsonResponse({'success': False, 'error': 'Aucun lecteur en ligne trouvé.'}, status=404)
# Use the first available reader
reader = readers[0]
# Send PaymentIntent to the terminal
response = stripe.terminal.Reader.process_payment_intent(
reader["id"], {"payment_intent": payment_intent["id"]}
)
# Handle the response
if response.get("status") == "succeeded":
return JsonResponse({
'success': True,
'payment_intent_id': payment_intent["id"],
'message': 'Paiement envoyé avec succès au terminal.'
})
else:
return JsonResponse({
'success': False,
'error': response.get("error", "Erreur inconnue du terminal.")
}, status=400)
except stripe.error.StripeError as e:
return JsonResponse({'success': False, 'error': f"Erreur Stripe : {str(e)}"}, status=500)
except Exception as e:
return JsonResponse({'success': False, 'error': f"Une erreur inattendue s'est produite: {str(e)}"}, status=500)
return JsonResponse({'success': False, 'error': 'Méthode non autorisée.'}, status=405)
@csrf_exempt # Allow requests from the frontend if CSRF tokens are not included
def create_connection_token(request):
try:
# Create a connection token
connection_token = stripe.terminal.ConnectionToken.create()
return JsonResponse({"secret": connection_token.secret})
except stripe.error.StripeError as e:
# Handle Stripe API errors
return JsonResponse({"error": str(e)}, status=500)
except Exception as e:
# Handle other unexpected errors
return JsonResponse({"error": f"Unexpected error: {str(e)}"}, status=500)
只是想让您知道我已经解决了该问题。这不是与 Stripe 相关的问题,而是与 Reader 本身相关的问题。阅读器在实时模式下运行,但使用的默认 API 密钥是测试 API 密钥。
从这个角度来看,我要检测问题所在并解决它。
[![@csrf_exempt
def create_connection_token(request):
try:
print(f"Stripe API Key: {stripe.api_key}")
connection_token = stripe.terminal.ConnectionToken.create()
print(f"Generated Connection Token: {connection_token.secret}")
return JsonResponse({"secret": connection_token.secret})
except stripe.error.StripeError as e:
print(f"Stripe error: {e}")
return JsonResponse({"error": str(e)}, status=500)
except Exception as e:
print(f"Unexpected error: {e}")
return JsonResponse({"error": f"Unexpected error: {str(e)}"}, status=500)][1]][1]
现在我可以将我的 POS 连接到读卡器并将支付金额发送给它。