Payment providers as classes (Strategy + factory); 10342 = monthly; health logs a failed Bazaar check
- payment/providers.py: ZarinpalProvider / BazaarProvider with one interface (check_plan, sku_for, payment_url, purchase_extras, discount_blocker, reconcile_user); provider_for / provider_for_method pick one; unknown fails. create_order, purchase view, discount redeem and reconcile_user_orders use it instead of scattered ifs. - subscription.0015: Bazaar SKU 10342 on the one-month plan (owner: "probably the monthly one"). - config/health: the Bazaar check no longer swallows its exception without a log. 982 tests green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,11 +53,14 @@ class BazaarSubscriptionTests(TestCase):
|
||||
def test_migration_put_the_panel_skus_on_three_and_six_months(self):
|
||||
self.assertEqual(self.three.bazaar_sku, '10343')
|
||||
self.assertEqual(Plan.objects.get(kind='subscription', on_sale=True, duration_days=180).bazaar_sku, '10344')
|
||||
self.assertEqual(Plan.objects.get(kind='subscription', on_sale=True, duration_days=30).bazaar_sku, '')
|
||||
self.assertEqual(Plan.objects.get(kind='subscription', on_sale=True, duration_days=30).bazaar_sku, '10342')
|
||||
# بستهها هنوز در پیشخان نیستند.
|
||||
self.assertFalse(Plan.objects.filter(kind='pack').exclude(bazaar_sku='').exists())
|
||||
|
||||
def test_plan_without_sku_is_refused_for_bazaar(self):
|
||||
monthly = Plan.objects.get(kind='subscription', on_sale=True, duration_days=30)
|
||||
self.assertEqual(self.buy(monthly).status_code, 400)
|
||||
pack = Plan.objects.get(kind='pack', question_credits=20)
|
||||
self.assertEqual(self.buy(pack).status_code, 400)
|
||||
self.assertFalse(Order.objects.filter(user_id=self.user.id).exists())
|
||||
|
||||
def test_subscription_bought_in_bazaar_activates_for_the_plan(self):
|
||||
response = self.buy(self.three)
|
||||
@@ -201,3 +204,39 @@ class BazaarDynamicPriceTests(TestCase):
|
||||
self.assertEqual(other.post(f'/api/payment/bazaar/orders/{order_id}/start').status_code, 404)
|
||||
Order.objects.filter(pk=order_id).update(status='paid')
|
||||
self.assertEqual(self.start(order_id).status_code, 400)
|
||||
|
||||
|
||||
class PaymentProviderFactoryTests(TestCase):
|
||||
"""payment/providers.py: هر روش یک کلاس؛ روشِ ناشناخته خطا، نه پیشفرضِ زرینپال."""
|
||||
|
||||
def test_each_method_and_order_value_maps_to_its_class(self):
|
||||
from .providers import BazaarProvider, ZarinpalProvider, provider_for, provider_for_method
|
||||
self.assertIsInstance(provider_for_method('zarinpal'), ZarinpalProvider)
|
||||
self.assertIsInstance(provider_for_method('bazaar'), BazaarProvider)
|
||||
self.assertIsInstance(provider_for('gateway'), ZarinpalProvider)
|
||||
self.assertIsInstance(provider_for('bazaar'), BazaarProvider)
|
||||
# هر مقدارِ مدل یک کلاس دارد؛ مقدارِ تازه در مدل بیکلاس این تست را میشکند.
|
||||
self.assertEqual({k for k, _ in Order.PROVIDER_CHOICES}, {'gateway', 'bazaar'})
|
||||
for key, _ in Order.PROVIDER_CHOICES:
|
||||
provider_for(key)
|
||||
|
||||
def test_unknown_method_fails_loudly(self):
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from .providers import provider_for, provider_for_method
|
||||
with self.assertRaises(ValidationError):
|
||||
provider_for_method('paypal')
|
||||
with self.assertRaises(KeyError):
|
||||
provider_for('paypal')
|
||||
|
||||
def test_zarinpal_order_gets_a_pay_link_and_bazaar_order_none(self):
|
||||
user = User.objects.create(phone='09120007304')
|
||||
client = APIClient()
|
||||
client.credentials(HTTP_AUTHORIZATION=f'Bearer {issue_access_token(user.id)}')
|
||||
three = Plan.objects.get(kind='subscription', on_sale=True, duration_days=90)
|
||||
z = client.post('/api/subscription/purchase', {'planId': str(three.id)}, format='json').json()
|
||||
self.assertIn('/api/payment/orders/', z['paymentUrl'])
|
||||
self.assertNotIn('bazaarSku', z)
|
||||
b = client.post('/api/subscription/purchase', {'planId': str(three.id), 'paymentMethod': 'bazaar'},
|
||||
format='json', HTTP_IDEMPOTENCY_KEY='fb').json()
|
||||
self.assertIsNone(b['paymentUrl'])
|
||||
self.assertEqual(b['bazaarSku'], '10343')
|
||||
|
||||
Reference in New Issue
Block a user