4 changed files with 179 additions and 1 deletions
-
103apps/account/tests/notifications/test_transaction_notifications.py
-
18apps/transaction/migrations/0003_alter_transactionparticipant_status.py
-
1apps/transaction/models.py
-
56apps/transaction/signals.py
@ -0,0 +1,103 @@ |
|||||
|
import datetime |
||||
|
from django.utils import timezone |
||||
|
from django.test import TestCase |
||||
|
from unittest.mock import patch |
||||
|
from django.core.files.uploadedfile import SimpleUploadedFile |
||||
|
|
||||
|
from dj_language.models import Language |
||||
|
from apps.account.models import StudentUser, Notification |
||||
|
from apps.course.models.course import Course, CourseCategory |
||||
|
from apps.transaction.models import TransactionParticipant |
||||
|
|
||||
|
class TransactionNotificationsFlowTests(TestCase): |
||||
|
def setUp(self): |
||||
|
# Create languages |
||||
|
self.lang_fa, _ = Language.objects.update_or_create( |
||||
|
code='fa', |
||||
|
defaults={'name': 'Persian', 'status': True, 'countries': []} |
||||
|
) |
||||
|
self.lang_en, _ = Language.objects.update_or_create( |
||||
|
code='en', |
||||
|
defaults={'name': 'English', 'status': True, 'countries': []} |
||||
|
) |
||||
|
|
||||
|
# Create category |
||||
|
self.category = CourseCategory.objects.create( |
||||
|
name=[{"title": "Category", "language_code": "en"}], |
||||
|
slug=[{"title": "category", "language_code": "en"}] |
||||
|
) |
||||
|
|
||||
|
# Create student user |
||||
|
self.student = StudentUser.objects.create( |
||||
|
email='student_tx@example.com', |
||||
|
username='student_tx', |
||||
|
fullname='Tx Student', |
||||
|
language=self.lang_fa, |
||||
|
fcm='token_tx_student' |
||||
|
) |
||||
|
|
||||
|
# Create Course |
||||
|
thumbnail = SimpleUploadedFile('thumb.jpg', b'filecontent', content_type='image/jpeg') |
||||
|
self.course = Course.objects.create( |
||||
|
title=[ |
||||
|
{"title": "Course 1", "language_code": "en"}, |
||||
|
{"title": "دوره ۱", "language_code": "fa"} |
||||
|
], |
||||
|
slug=[{"title": "course-1", "language_code": "en"}], |
||||
|
category=self.category, |
||||
|
thumbnail=thumbnail, |
||||
|
video_type=Course.VedioTypeChoices.YOUTUBE_LINK, |
||||
|
video_link='https://example.com/video', |
||||
|
is_online=False, |
||||
|
level=Course.LevelChoices.BEGINNER, |
||||
|
duration=10, |
||||
|
lessons_count=0, |
||||
|
description='Description', |
||||
|
short_description='Short description', |
||||
|
status=[{"title": "ongoing", "language_code": "en"}], |
||||
|
is_free=True, |
||||
|
) |
||||
|
|
||||
|
# Create transaction with PENDING status |
||||
|
self.tx = TransactionParticipant.objects.create( |
||||
|
user=self.student, |
||||
|
course=self.course, |
||||
|
price=150.00, |
||||
|
status=TransactionParticipant.TransactionStatus.PENDING |
||||
|
) |
||||
|
|
||||
|
@patch('apps.account.notification_service.send_notification') |
||||
|
def test_payment_successful_notification(self, mock_send): |
||||
|
# Update status to SUCCESS |
||||
|
self.tx.status = TransactionParticipant.TransactionStatus.SUCCESS |
||||
|
self.tx.save() |
||||
|
|
||||
|
# Check DB notification (in Persian) |
||||
|
notif = Notification.objects.filter(user=self.student, title="پرداخت موفقیتآمیز").first() |
||||
|
self.assertIsNotNone(notif) |
||||
|
self.assertIn("دوره ۱", notif.message) |
||||
|
self.assertTrue(mock_send.called) |
||||
|
|
||||
|
@patch('apps.account.notification_service.send_notification') |
||||
|
def test_payment_failed_notification(self, mock_send): |
||||
|
# Update status to FAILED |
||||
|
self.tx.status = TransactionParticipant.TransactionStatus.FAILED |
||||
|
self.tx.save() |
||||
|
|
||||
|
# Check DB notification (in Persian) |
||||
|
notif = Notification.objects.filter(user=self.student, title="خطا در پرداخت").first() |
||||
|
self.assertIsNotNone(notif) |
||||
|
self.assertIn("دوره ۱", notif.message) |
||||
|
self.assertTrue(mock_send.called) |
||||
|
|
||||
|
@patch('apps.account.notification_service.send_notification') |
||||
|
def test_refund_completed_notification(self, mock_send): |
||||
|
# Update status to REFUNDED |
||||
|
self.tx.status = TransactionParticipant.TransactionStatus.REFUNDED |
||||
|
self.tx.save() |
||||
|
|
||||
|
# Check DB notification (in Persian) |
||||
|
notif = Notification.objects.filter(user=self.student, title="بازگشت وجه انجام شد").first() |
||||
|
self.assertIsNotNone(notif) |
||||
|
self.assertIn("دوره ۱", notif.message) |
||||
|
self.assertTrue(mock_send.called) |
||||
@ -0,0 +1,18 @@ |
|||||
|
# Generated by Django 5.2.12 on 2026-07-08 13:01 |
||||
|
|
||||
|
from django.db import migrations, models |
||||
|
|
||||
|
|
||||
|
class Migration(migrations.Migration): |
||||
|
|
||||
|
dependencies = [ |
||||
|
('transaction', '0002_alter_participantinfo_options_and_more'), |
||||
|
] |
||||
|
|
||||
|
operations = [ |
||||
|
migrations.AlterField( |
||||
|
model_name='transactionparticipant', |
||||
|
name='status', |
||||
|
field=models.CharField(choices=[('pending', 'Pending'), ('waiting_approval', 'Waiting for Approval'), ('success', 'Success'), ('failed', 'Failed'), ('refunded', 'Refunded')], default='pending', max_length=20, verbose_name='Transaction Status'), |
||||
|
), |
||||
|
] |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue