""" GET /api/payment/invoices — «پرداخت‌ها و فاکتورها»ی پروفایل (۲۰۲۶-۱۰-۰۱). راه‌های شکستن که این‌جا امتحان می‌شوند: دیدنِ فاکتورِ دیگری، عوض شدنِ فاکتورِ قدیمی با عوض شدنِ قیمتِ پلن، و نشان دادنِ refِ ساختگیِ کدِ ۱۰۰٪ به‌جای کدِ پیگیریِ بانکی. """ from django.core.cache import cache from django.test import TestCase from rest_framework.test import APIClient from accounts.authentication import issue_access_token from accounts.models import User from discount.models import DiscountCode from payment.models import Order from payment.services import apply_order_payment_result from subscription.models import Plan def _client(user): client = APIClient() client.credentials(HTTP_AUTHORIZATION=f'Bearer {issue_access_token(user.id)}') return client class InvoiceTests(TestCase): def setUp(self): cache.clear() self.user = User.objects.create(phone='09120007001') self.client = _client(self.user) self.plan = Plan.objects.create(title='سالانه', price=299000, duration_days=365) def tearDown(self): cache.clear() def buy(self): response = self.client.post('/api/subscription/purchase', {'planId': str(self.plan.id)}, format='json') self.assertEqual(response.status_code, 200, response.content) return Order.objects.get(pk=response.json()['orderId']) def invoices(self, client=None): response = (client or self.client).get('/api/payment/invoices') self.assertEqual(response.status_code, 200, response.content) return response.json()['invoices'] def test_paid_order_with_discount_reads_like_an_invoice(self): order = self.buy() DiscountCode.objects.create(code='MEHR20', type='percent', value=20, max_uses=5) redeem = self.client.post('/api/discount/redeem', {'code': 'MEHR20', 'orderId': str(order.id)}, format='json') self.assertEqual(redeem.status_code, 200, redeem.content) apply_order_payment_result(order=order, gateway='zarinpal', gateway_ref_id='A00000123456', new_status='paid', event='test') [invoice] = self.invoices() self.assertEqual(invoice['invoiceNumber'], f'TD-{order.id:06d}') self.assertEqual(invoice['status'], 'paid') self.assertEqual(invoice['planTitle'], 'سالانه') self.assertEqual((invoice['listPrice'], invoice['discountAmount'], invoice['amount']), (299000, 59800, 239200)) self.assertEqual(invoice['discountCode'], 'MEHR20') self.assertEqual(invoice['refId'], 'A00000123456') self.assertIsNotNone(invoice['paidAt']) def test_changing_the_plan_later_does_not_rewrite_an_old_invoice(self): self.buy() Plan.objects.filter(pk=self.plan.pk).update(title='سالانه‌ی ویژه', price=399000) [invoice] = self.invoices() self.assertEqual((invoice['planTitle'], invoice['listPrice']), ('سالانه', 299000)) def test_full_discount_shows_no_fake_bank_reference(self): order = self.buy() DiscountCode.objects.create(code='FREE100', type='percent', value=100, max_uses=5) self.client.post('/api/discount/redeem', {'code': 'FREE100', 'orderId': str(order.id)}, format='json') [invoice] = self.invoices() self.assertEqual((invoice['status'], invoice['amount'], invoice['refId']), ('paid', 0, '')) def test_unpaid_orders_are_listed_too(self): self.buy() [invoice] = self.invoices() self.assertEqual((invoice['status'], invoice['paidAt'], invoice['refId']), ('pending', None, '')) def test_someone_else_sees_nothing(self): self.buy() stranger = User.objects.create(phone='09120007002') self.assertEqual(self.invoices(_client(stranger)), []) def test_orders_from_before_the_snapshot_have_no_list_price(self): Order.objects.create(user_id=self.user.id, amount=99000, idempotency_key='old-order') [invoice] = self.invoices() self.assertEqual((invoice['listPrice'], invoice['discountAmount'], invoice['planTitle']), (None, None, '')) def test_requires_a_token(self): self.assertIn(APIClient().get('/api/payment/invoices').status_code, (401, 403))