Ödənişlər Django layihəsinin real pulla qarşılaşdığı yerdir, ona görə ssenari darıxdırıcı və proqnozlaşdırıla bilən olmalıdır. Stripe Checkout ilə kart məlumatını heç vaxt görmürsünüz: view Checkout Session yaradır, müştəri Stripe səhifəsində ödəyir, nəticəni Stripe webhook ilə bildirir. Bu mövzuda Django tərəfini qururuq: Order və StripeEvent modelləri, Checkout view-su, csrf_exempt və imza yoxlaması ilə webhook view-su, idempotent emal, testlər və dj-stripe icmalı. Stripe anlayışları Stripe Checkout və Stripe webhook-ları dərslərində izah olunub. Hər yerdə test rejimi və yer tutucu açarlar işlənir.
Ssenari
- Brauzer Checkout view-nuza POST göndərir.
- View
Order(pending) və Stripe Session yaradır, sonrasession.url-ə yönləndirir. - Müştəri Stripe səhifəsində ödəyir.
- Stripe webhook-unuza
checkout.session.completedPOST edir; sifarişi yalnız bupaidedir.
| Hissə | Harada yaşayır |
|---|---|
| Qiymət və məhsul | sizin verilənlər bazası (Product), heç vaxt sorğu |
| Sifariş statusu | Order.status, yalnız webhook dəyişir |
| Gizli açar, webhook secret | mühit dəyişənləri, settings.py-da oxunur |
| Təkrardan qorunma | unique=True ilə StripeEvent.event_id |
💡 Uğur səhifəsi «təşəkkür edirik, ödənişi təsdiqləyirik» yaza və sifariş statusunu oxuya bilər. Sifarişi ödənilmiş etməməlidir.
Parametrlər və modellər
SDK pip install stripe ilə qurulur, açarlar mühitdən oxunur (parametrlər və mühitlər):
# settings.py
import os
STRIPE_SECRET_KEY = os.environ["STRIPE_SECRET_KEY"] # sk_test_...
STRIPE_WEBHOOK_SECRET = os.environ["STRIPE_WEBHOOK_SECRET"] # whsec_...Order məbləği ən kiçik vahidlərlə (sentlərlə) tam ədəd kimi saxlayır, StripeEvent isə artıq emal olunmuş hər webhook event-ini yadda saxlayır:
from django.conf import settings
from django.db import models
class Order(models.Model):
class Status(models.TextChoices):
PENDING = "pending", "Pending"
PAID = "paid", "Paid"
CANCELED = "canceled", "Canceled"
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
amount = models.PositiveIntegerField(help_text="minor units (cents)")
currency = models.CharField(max_length=3, default="usd")
status = models.CharField(
max_length=10, choices=Status.choices, default=Status.PENDING
)
stripe_session_id = models.CharField(
max_length=255, blank=True, db_index=True
)
created_at = models.DateTimeField(auto_now_add=True)
class StripeEvent(models.Model):
event_id = models.CharField(max_length=255, unique=True)
type = models.CharField(max_length=100)
received_at = models.DateTimeField(auto_now_add=True)⚠️ Pul üçün
FloatFieldişlətməyin. Tam sentlər (burada olduğu kimi) və yaDecimalFieldgötürün.