let Bazaar verification find out whether a SKU is a one-time product or a subscription
Nobody has told us how the plans are defined in the Bazaar panel. The verify view always asked the in-app endpoint, so a subscription SKU would get "Product is not found" and a 503. verify_purchase now defaults to is_subscription=None: in-app first, and on that exact answer the same SKU is asked as a subscription. A wrong package name still raises at once. Seen against the live Bazaar API with a fake SKU and token only; no real purchase has gone through it yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -199,3 +199,58 @@ class BazaarValidateAgainstDocsTests(TestCase):
|
||||
)
|
||||
self._resp(mock_get, 200, {'validUntilTimestampMsec': now_ms - 1000})
|
||||
self.assertFalse(bazaar.verify_purchase(product_sku='sub', purchase_token='t', is_subscription=True).is_valid)
|
||||
|
||||
|
||||
@override_settings(
|
||||
BAZAAR_PISHKHAN_API_SECRET='pishkhan-secret', BAZAAR_REFRESH_TOKEN='',
|
||||
BAZAAR_PACKAGE_NAME='ir.example.app',
|
||||
BAZAAR_API_BASE='https://pardakht.cafebazaar.ir/devapi/v2',
|
||||
)
|
||||
class BazaarProductTypeAutoDetectTests(TestCase):
|
||||
"""نوعِ محصول (تکخرید/اشتراک) به ما گفته نشده؛ کد خودش امتحان میکند."""
|
||||
|
||||
def setUp(self):
|
||||
cache.clear()
|
||||
|
||||
def _responses(self, mock_get, *pairs):
|
||||
responses = []
|
||||
for status, body in pairs:
|
||||
r = type('R', (), {})()
|
||||
r.status_code = status
|
||||
r.json = (lambda b: (lambda: b))(body)
|
||||
responses.append(r)
|
||||
mock_get.side_effect = responses
|
||||
|
||||
@patch('payment.bazaar.requests.get')
|
||||
def test_inapp_product_is_checked_once(self, mock_get):
|
||||
self._responses(mock_get, (200, {'purchaseState': 0}))
|
||||
self.assertTrue(bazaar.verify_purchase(product_sku='monthly', purchase_token='t').is_valid)
|
||||
self.assertEqual(mock_get.call_count, 1)
|
||||
self.assertIn('/inapp/', mock_get.call_args.args[0])
|
||||
|
||||
@patch('payment.bazaar.requests.get')
|
||||
def test_unknown_inapp_product_falls_back_to_subscription(self, mock_get):
|
||||
future = timezone.now().timestamp() * 1000 + 86_400_000
|
||||
self._responses(
|
||||
mock_get,
|
||||
(404, {'error': 'invalid_value', 'error_description': 'Product is not found.'}),
|
||||
(200, {'validUntilTimestampMsec': future}),
|
||||
)
|
||||
self.assertTrue(bazaar.verify_purchase(product_sku='monthly', purchase_token='t').is_valid)
|
||||
self.assertIn('/subscriptions/monthly/purchases/t', mock_get.call_args.args[0])
|
||||
|
||||
@patch('payment.bazaar.requests.get')
|
||||
def test_forged_token_on_subscription_is_invalid(self, mock_get):
|
||||
self._responses(
|
||||
mock_get,
|
||||
(404, {'error': 'invalid_value', 'error_description': 'Product is not found.'}),
|
||||
(404, {'error': 'not_found'}),
|
||||
)
|
||||
self.assertFalse(bazaar.verify_purchase(product_sku='monthly', purchase_token='forged').is_valid)
|
||||
|
||||
@patch('payment.bazaar.requests.get')
|
||||
def test_wrong_package_does_not_fall_back(self, mock_get):
|
||||
self._responses(mock_get, (404, {'error': 'invalid_value', 'error_description': 'Package name is invalid.'}))
|
||||
with self.assertRaises(bazaar.BazaarAPIError):
|
||||
bazaar.verify_purchase(product_sku='monthly', purchase_token='t')
|
||||
self.assertEqual(mock_get.call_count, 1)
|
||||
|
||||
Reference in New Issue
Block a user