There was no way to take an order back: staff could only edit the status by hand, and turning 'paid' into 'failed' left the credits, heart days or subscription days the order had given. Two OrderAdmin actions now do it: - cancel a pending order (a payment that does arrive later still counts); - refund a paid order, after a confirmation page: takes back the pack's unspent credits (never below zero), its heart days, or the plan's subscription days, and undoes the referrer's commission. The money itself is returned in the Zarinpal / Bazaar panel; the action says so. Status is read-only in the order form. Steps in docs/operations.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
82 lines
4.3 KiB
Python
82 lines
4.3 KiB
Python
from rest_framework import serializers
|
||
|
||
|
||
class CreateOrderRequestSerializer(serializers.Serializer):
|
||
# این فراخوانی سرور-به-سرور از اپ Subscriptionه، نه از کلاینت؛ به همین
|
||
# دلیل userId اینجا مستقیماً در بدنه ارسال میشه (نه از توکن استخراج).
|
||
userId = serializers.CharField()
|
||
amount = serializers.IntegerField()
|
||
currency = serializers.CharField(required=False, default='IRT')
|
||
subscriptionId = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
||
# provider='bazaar' وقتی کاربر از همون ابتدا پرداخت درونبرنامهای بازار
|
||
# رو انتخاب کرده؛ در این حالت amount باید دقیقاً برابر قیمتِ محصولِ
|
||
# تعریفشده در پنل بازار برای همون bazaarProductSku باشه (بازار خودش
|
||
# قیمت رو کنترل میکنه، نه ما).
|
||
provider = serializers.ChoiceField(choices=['gateway', 'bazaar'], required=False, default='gateway')
|
||
bazaarProductSku = serializers.CharField(required=False, allow_blank=True)
|
||
# بستهی سوال (subscription.Plan با kind='pack'): بدونِ این، سفارشِ بسته بیplan_id ساخته میشد و
|
||
# پرداختش هیچ اعتباری نمیداد (بازبینیِ ۲۰۲۶-۱۰-۰۲).
|
||
planId = serializers.CharField(required=False, allow_null=True, allow_blank=True)
|
||
|
||
|
||
class BazaarVerifyRequestSerializer(serializers.Serializer):
|
||
orderId = serializers.CharField()
|
||
productSku = serializers.CharField(required=False, allow_blank=True)
|
||
purchaseToken = serializers.CharField()
|
||
|
||
|
||
class BazaarVerifyResponseSerializer(serializers.Serializer):
|
||
orderId = serializers.CharField()
|
||
status = serializers.CharField()
|
||
valid = serializers.BooleanField()
|
||
|
||
|
||
class CreateOrderResponseSerializer(serializers.Serializer):
|
||
orderId = serializers.CharField()
|
||
status = serializers.CharField()
|
||
# provider='bazaar' یعنی paymentUrl نداریم (کلاینت با SDK بازار خودش
|
||
# خرید میکنه، نه با ریدایرکت به یک URL).
|
||
paymentUrl = serializers.CharField(allow_null=True)
|
||
provider = serializers.CharField()
|
||
|
||
|
||
class ZarinpalCallbackResponseSerializer(serializers.Serializer):
|
||
"""فقط وقتی settings.ZARINPAL_REDIRECT_URL خالی باشه برگردونده میشه؛
|
||
وگرنه کاربر به همون URL ریدایرکت میشه، نه به این JSON."""
|
||
orderId = serializers.CharField()
|
||
status = serializers.CharField()
|
||
|
||
|
||
class TransactionSerializer(serializers.Serializer):
|
||
id = serializers.CharField()
|
||
gateway = serializers.CharField()
|
||
status = serializers.CharField()
|
||
paidAt = serializers.DateTimeField(allow_null=True)
|
||
|
||
|
||
class OrderDetailResponseSerializer(serializers.Serializer):
|
||
orderId = serializers.CharField()
|
||
status = serializers.CharField()
|
||
amount = serializers.IntegerField()
|
||
transactions = TransactionSerializer(many=True)
|
||
|
||
|
||
class InvoiceSerializer(serializers.Serializer):
|
||
orderId = serializers.CharField()
|
||
invoiceNumber = serializers.CharField(help_text='شمارهی فاکتور: «TD-» و شناسهی سفارش، شش رقمی.')
|
||
status = serializers.ChoiceField(choices=['pending', 'paid', 'failed', 'canceled', 'refunded'])
|
||
provider = serializers.CharField(help_text='gateway (زرینپال) یا bazaar')
|
||
planTitle = serializers.CharField(allow_blank=True)
|
||
listPrice = serializers.IntegerField(allow_null=True, help_text='قیمتِ پایه پیش از تخفیف؛ null برای سفارشهای پیش از ۱۴۰۵-۰۷-۰۹.')
|
||
discountAmount = serializers.IntegerField(allow_null=True)
|
||
discountCode = serializers.CharField(allow_blank=True)
|
||
amount = serializers.IntegerField(help_text='مبلغِ پرداختی (پس از تخفیف).')
|
||
currency = serializers.CharField()
|
||
createdAt = serializers.DateTimeField()
|
||
paidAt = serializers.DateTimeField(allow_null=True)
|
||
refId = serializers.CharField(allow_blank=True, help_text='کدِ پیگیریِ پرداخت (شمارهی مرجعِ زرینپال/بازار).')
|
||
|
||
|
||
class InvoiceListResponseSerializer(serializers.Serializer):
|
||
invoices = InvoiceSerializer(many=True)
|