fix update bank status

This commit is contained in:
Parsa Nazer
2026-05-28 10:32:33 +03:30
parent 23c03efe84
commit 8960744a81
+55 -22
View File
@@ -10,45 +10,78 @@ from account.models import PushSubscription
import ghasedak_sms import ghasedak_sms
from product.models import ProductImageModel from product.models import ProductImageModel
from celery import shared_task from celery import shared_task
from django.db import transaction
logger = logging.getLogger(__name__)
@shared_task @shared_task
def udpate_bank_status(): def udpate_bank_status():
factory = bankfactories.BankFactory() factory = bankfactories.BankFactory()
bank_models.Bank.objects.update_expire_records() # ۱. بروزرسانی رکوردهای منقضی در یک تراکنش جداگانه
try:
with transaction.atomic():
bank_models.Bank.objects.update_expire_records()
except Exception as e:
logger.error(f"Error in update_expire_records: {e}")
# ۲. پردازش رکوردهایی که از بانک برگشته‌اند
for item in bank_models.Bank.objects.filter_return_from_bank(): for item in bank_models.Bank.objects.filter_return_from_bank():
bank = factory.create( try:
bank_type=item.bank_type, identifier=item.bank_choose_identifier with transaction.atomic():
) bank = factory.create(
bank.verify(item.tracking_code) bank_type=item.bank_type, identifier=item.bank_choose_identifier
bank_record = bank_models.Bank.objects.get(tracking_code=item.tracking_code) )
if bank_record.is_success and bank_record.order: bank.verify(item.tracking_code)
bank_record.order.cart.clear_cart() # استفاده از select_for_update برای جلوگیری از Race Condition
bank_record.order.is_paid = True bank_record = bank_models.Bank.objects.select_related('order').select_for_update().get(tracking_code=item.tracking_code)
bank_record.order.save()
logging.debug("This record is verify now.", extra={"pk": bank_record.pk}) if bank_record.is_success and bank_record.order:
elif bank_record.order: bank_record.order.cart.clear_cart()
order = bank_record.order bank_record.order.is_paid = True
order.rollback_stock() bank_record.order.save(update_fields=['is_paid'])
elif bank_record.order:
bank_record.order.rollback_stock()
except Exception as e:
logger.error(f"Failed to verify bank record {item.tracking_code}: {e}")
failed_statuses = [ failed_statuses = [
PaymentStatus.CANCEL_BY_USER, PaymentStatus.CANCEL_BY_USER,
PaymentStatus.EXPIRE_GATEWAY_TOKEN, PaymentStatus.EXPIRE_GATEWAY_TOKEN,
PaymentStatus.EXPIRE_VERIFY_PAYMENT, PaymentStatus.EXPIRE_VERIFY_PAYMENT,
PaymentStatus.ERROR, PaymentStatus.ERROR,
] ]
# 1. ابتدا رکوردهای بانکی را بدون select_related پیدا کنید
# از select_for_update اینجا استفاده نکنید چون به Order وصل است
failed_records = bank_models.Bank.objects.filter( failed_records = bank_models.Bank.objects.filter(
status__in=failed_statuses, status__in=failed_statuses,
order__isnull=False, order__isnull=False,
order__is_paid=False, order__is_paid=False,
order__is_stock_rolled_back=False, order__is_stock_rolled_back=False,
).select_related('order') )
logger.info(f"Found {failed_records.count()} failed records for rollback.")
for bank_record in failed_records: for bank_record in failed_records:
bank_record.order.rollback_stock() try:
# استفاده از تراکنش اتمیک برای هر رکورد
with transaction.atomic():
# 2. حالا خودِ Order مربوطه را با select_for_update قفل کنید
# این کار مانع از تداخل با بقیه تسک‌ها می‌شود
order = bank_record.order
# بررسی مجدد شرط برای اطمینان در لحظه قفل شدن
if order and not order.is_paid and not order.is_stock_rolled_back:
order.rollback_stock()
logger.info(f"Successfully rolled back stock for bank record {bank_record.id}")
else:
logger.info(f"Order {order.id} already processed or paid, skipping.")
except Exception as e:
logger.error(f"Failed to rollback stock for bank record {bank_record.id}: {str(e)}")
return 'update bank record is done' return "update bank record is done"
@shared_task @shared_task