feat: add portal recharge page

This commit is contained in:
QiuSW
2026-07-03 14:49:45 +08:00
parent 4a10c2bb92
commit c2e411fe45
18 changed files with 518 additions and 31 deletions
+113 -1
View File
@@ -9,7 +9,7 @@ from django.test import Client, TestCase, override_settings
from django.utils import timezone
from rest_framework.test import APIClient
from apps.billing.models import CallRecord, PointsLedger, RechargeOrder
from apps.billing.models import CallRecord, ExchangeRate, PointsLedger, RechargeOrder
from apps.users.models import ApiKey, UserWallet
@@ -434,3 +434,115 @@ class PortalAccountFlowTests(TestCase):
self.assertContains(response, "15")
self.assertNotContains(response, "other-alias")
self.assertNotContains(response, other_key.key_prefix)
def test_recharge_page_requires_login_and_shows_form(self):
user = self.create_verified_user()
UserWallet.objects.create(user=user, points_balance=25)
anonymous_response = self.client.get("/recharge")
self.assertEqual(anonymous_response.status_code, 302)
self.assertTrue(anonymous_response["Location"].startswith("/login?next="))
self.client.force_login(user)
response = self.client.get("/recharge")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["balance"].points_balance, 25)
self.assertContains(response, "充值金额")
self.assertContains(response, "创建订单")
self.assertContains(response, "qrcode@1.5.4")
self.assertContains(response, "QRCode.toCanvas")
def test_recharge_page_post_creates_pending_order_without_crediting_wallet_or_ledger(self):
user = self.create_verified_user()
UserWallet.objects.create(user=user, points_balance=5)
ExchangeRate.objects.create(
currency="CNY",
points_per_unit=Decimal("10.0000"),
effective_from=timezone.now(),
)
self.client.force_login(user)
response = self.client.post(
"/recharge",
{"amount": "20.00", "pay_method": RechargeOrder.PayMethod.WEIXIN},
)
self.assertEqual(response.status_code, 302)
self.assertTrue(response["Location"].startswith("/recharge?order_no="))
order = RechargeOrder.objects.get(user=user)
self.assertEqual(order.amount_money, Decimal("20.00"))
self.assertEqual(order.exchange_rate, Decimal("10.0000"))
self.assertEqual(order.points_granted, 200)
self.assertEqual(order.status, RechargeOrder.Status.PENDING)
self.assertTrue(order.code_url.startswith("weixin://wxpay/cmhub-mock"))
self.assertIsNotNone(order.expires_at)
wallet = UserWallet.objects.get(user=user)
self.assertEqual(wallet.points_balance, 5)
self.assertFalse(
PointsLedger.objects.filter(
user=user,
ref_order_id=order.id,
).exists()
)
follow_response = self.client.get(response["Location"])
self.assertEqual(follow_response.status_code, 200)
self.assertEqual(follow_response.context["current_order"], order)
self.assertContains(follow_response, order.order_no)
self.assertContains(follow_response, "weixin://wxpay/cmhub-mock")
self.assertContains(follow_response, 'data-status-url="/api/v1/recharge/status"')
self.assertContains(follow_response, "data-recharge-order")
def test_recharge_page_current_order_only_shows_current_user_order(self):
user = self.create_verified_user()
other_user = self.create_verified_user()
UserWallet.objects.create(user=user, points_balance=0)
other_order = self.create_recharge_order(
other_user,
order_no="R-OTHER-RECHARGE-PAGE-504",
amount="50.00",
points=500,
status=RechargeOrder.Status.PENDING,
)
self.client.force_login(user)
response = self.client.get(f"/recharge?order_no={other_order.order_no}")
self.assertEqual(response.status_code, 200)
self.assertIsNone(response.context["current_order"])
self.assertNotContains(response, other_order.order_no)
@override_settings(RECHARGE_MAX_AMOUNT_CNY="100.00")
def test_recharge_page_rejects_amount_above_configured_maximum(self):
user = self.create_verified_user()
UserWallet.objects.create(user=user, points_balance=0)
ExchangeRate.objects.create(
currency="CNY",
points_per_unit=Decimal("10.0000"),
effective_from=timezone.now(),
)
self.client.force_login(user)
response = self.client.post(
"/recharge",
{"amount": "100.01", "pay_method": RechargeOrder.PayMethod.ALIPAY},
)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "单笔充值金额不能超过 100.00 CNY")
self.assertFalse(RechargeOrder.objects.filter(user=user).exists())
def test_recharge_page_post_is_csrf_protected(self):
user = self.create_verified_user()
csrf_client = Client(enforce_csrf_checks=True)
csrf_client.force_login(user)
response = csrf_client.post(
"/recharge",
{"amount": "20.00", "pay_method": RechargeOrder.PayMethod.WEIXIN},
)
self.assertEqual(response.status_code, 403)
self.assertFalse(RechargeOrder.objects.filter(user=user).exists())