Not every payment goes through: the card has no money left, it is blocked, or the bank says no. Then the payment provider answers 402 Payment Required with an error instead of a payment. Our provider declines every amount over 1000 and answers {"error": "card_declined"}. There is no "id" in it, so payment["id"] crashes and the customer gets an error page.
Check the status code first. Before you use another service's answer, look at response.status_code. The same idea with the supplier and a product it doesn't sell:
response = requests.get(SUPPLIER + "/stock/99")
if response.status_code == 404:
return jsonify({"error": "Unknown product"}), 404
data = response.json()
A declined card is not a bug in your shop, so the answer is not 500. It is not 502 either: the provider worked and gave a clear answer. Answer 402 yourself, pass the provider's reason on, and return before the UPDATE, so the order stays pending and the customer can try another card.
POST /orders/9/pay → 402 {"error": "Payment declined", "reason": "card_declined"}
GET /orders/9 → 200 {…, "payment_id": null, "status": "pending", "total": 1250}
POST /orders/8/pay → 201 {"amount": 80, "order_id": 8, "payment_id": "pay_1"}
Your task: in pay_order, right after payment = response.json(), check whether the provider answered 402. If it did, answer "Payment declined" with 402, and pass the provider's "error" on under "reason".
Assignment
Follow the Coding Tutorial to handle a declined card in POST /orders/<id>/pay.
Hint
The provider's reason is payment["error"]. A return ends the function, so with the if above the UPDATE, a declined order is never marked paid.
Free plan: 30 tutor messages. PRO is unlimited.
