from django.test import TestCase, Client from django.contrib.auth import get_user_model from django.core.management import call_command from django.urls import reverse from decimal import Decimal from django.utils import timezone from plans.models import Plan from domains.models import Domain, DomainTrafficDaily from billing.models import Invoice User = get_user_model() class BillingFlowTests(TestCase): def setUp(self): self.user = User.objects.create_user(username='u2', email='u2@example.com', password='p', is_staff=True) self.plan = Plan.objects.create(name='P', base_price_per_domain=Decimal('10.00'), included_traffic_gb_per_domain=1, overage_price_per_gb=Decimal('1.00')) today = timezone.now().date() month_start = today.replace(day=1) next_month = (month_start.replace(year=month_start.year + 1, month=1) if month_start.month == 12 else month_start.replace(month=month_start.month + 1)) cycle_end = next_month - timezone.timedelta(days=1) self.domain = Domain.objects.create(user=self.user, name='ex2.com', status=Domain.STATUS_ACTIVE, current_plan=self.plan, current_cycle_start=month_start, current_cycle_end=cycle_end) DomainTrafficDaily.objects.create(domain=self.domain, day=month_start, bytes=2 * (1024 ** 3)) def test_generate_invoice_and_apply_policy_dry(self): call_command('generate_invoices') inv = Invoice.objects.filter(user=self.user).first() self.assertIsNotNone(inv) self.assertEqual(inv.status, Invoice.STATUS_UNPAID) call_command('apply_invoice_policies', dry_run=True) inv.refresh_from_db() self.assertEqual(inv.status, Invoice.STATUS_UNPAID) def test_mark_paid_via_admin_view(self): call_command('generate_invoices') inv = Invoice.objects.filter(user=self.user).first() c = Client() c.login(username='u2', password='p') resp = c.post(reverse('admin_panel:billing_detail', kwargs={'invoice_id': inv.id}), {'action': 'mark_paid'}) self.assertEqual(resp.status_code, 302) inv.refresh_from_db() self.assertEqual(inv.status, Invoice.STATUS_PAID) def test_epay_notify_marks_paid(self): call_command('generate_invoices') inv = Invoice.objects.filter(user=self.user).first() from core.models import SystemSettings s = SystemSettings.objects.order_by('id').first() if not s: s = SystemSettings.objects.create() s.epay_api_base_url = 'https://api.example.com' s.epay_pid = 'pid1' s.epay_key = 'k123' s.save() params = { 'pid': s.epay_pid, 'out_trade_no': f'INV{inv.id}', 'money': str(inv.amount_total), 'type': 'alipay', 'trade_status': 'SUCCESS', 'sign_type': 'MD5', } import hashlib src = '&'.join(f"{k}={params[k]}" for k in sorted(params) if k not in ['sign', 'sign_type']) + '&key=' + s.epay_key params['sign'] = hashlib.md5(src.encode('utf-8')).hexdigest().upper() c = Client() resp = c.get(reverse('billing:notify'), params) self.assertEqual(resp.status_code, 200) inv.refresh_from_db() self.assertEqual(inv.status, Invoice.STATUS_PAID)