Fix plan permissions using correct billing feature codes
The /api/business/current/ endpoint was using legacy permission key names instead of the actual feature codes from the billing catalog. This caused tenants on paid plans to be incorrectly locked out of features. - Updated current_business_view to use correct feature codes (e.g., 'can_use_plugins' instead of 'plugins', 'sms_enabled' instead of 'sms_reminders') - Updated test to mock billing subscription and has_feature correctly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -163,23 +163,24 @@ def current_business_view(request):
|
||||
subdomain = domain_parts[0]
|
||||
|
||||
# Get plan permissions from billing system entitlements
|
||||
# Use the actual feature codes from the billing catalog
|
||||
permissions = {
|
||||
'sms_reminders': tenant.has_feature('sms_reminders'),
|
||||
'webhooks': tenant.has_feature('webhooks'),
|
||||
'sms_reminders': tenant.has_feature('sms_enabled'),
|
||||
'webhooks': tenant.has_feature('integrations_enabled'),
|
||||
'api_access': tenant.has_feature('api_access'),
|
||||
'custom_domain': tenant.has_feature('custom_domain'),
|
||||
'white_label': tenant.has_feature('white_label'),
|
||||
'custom_oauth': tenant.has_feature('custom_oauth'),
|
||||
'plugins': tenant.has_feature('plugins'),
|
||||
'custom_oauth': tenant.has_feature('can_manage_oauth'),
|
||||
'plugins': tenant.has_feature('can_use_plugins'),
|
||||
'can_create_plugins': tenant.has_feature('can_create_plugins'),
|
||||
'tasks': tenant.has_feature('tasks'),
|
||||
'export_data': tenant.has_feature('export_data'),
|
||||
'video_conferencing': tenant.has_feature('video_conferencing'),
|
||||
'two_factor_auth': tenant.has_feature('two_factor_auth'),
|
||||
'masked_calling': tenant.has_feature('masked_calling'),
|
||||
'pos_system': tenant.has_feature('pos_system'),
|
||||
'mobile_app': tenant.has_feature('mobile_app'),
|
||||
'contracts': tenant.has_feature('contracts'),
|
||||
'tasks': tenant.has_feature('can_use_tasks'),
|
||||
'export_data': tenant.has_feature('can_export_data'),
|
||||
'video_conferencing': tenant.has_feature('can_add_video_conferencing'),
|
||||
'two_factor_auth': tenant.has_feature('team_permissions'),
|
||||
'masked_calling': tenant.has_feature('masked_calling_enabled'),
|
||||
'pos_system': tenant.has_feature('can_use_pos'),
|
||||
'mobile_app': tenant.has_feature('mobile_app_access'),
|
||||
'contracts': tenant.has_feature('can_use_contracts'),
|
||||
'multi_location': tenant.has_feature('multi_location'),
|
||||
}
|
||||
|
||||
@@ -219,7 +220,7 @@ def current_business_view(request):
|
||||
'website_pages': {},
|
||||
'customer_dashboard_content': [],
|
||||
# Platform permissions
|
||||
'can_manage_oauth_credentials': tenant.has_feature('custom_oauth'),
|
||||
'can_manage_oauth_credentials': tenant.has_feature('can_manage_oauth'),
|
||||
'payments_enabled': tenant.payment_mode != 'none',
|
||||
# Plan permissions (what features are available based on subscription)
|
||||
'plan_permissions': permissions,
|
||||
|
||||
@@ -263,7 +263,6 @@ class TestCurrentBusinessView:
|
||||
mock_tenant.id = 1
|
||||
mock_tenant.name = 'Demo Business'
|
||||
mock_tenant.schema_name = 'demo'
|
||||
mock_tenant.subscription_tier = 'PROFESSIONAL'
|
||||
mock_tenant.is_active = True
|
||||
mock_tenant.created_on = Mock()
|
||||
mock_tenant.created_on.isoformat.return_value = '2024-01-01T00:00:00'
|
||||
@@ -277,26 +276,43 @@ class TestCurrentBusinessView:
|
||||
mock_tenant.booking_return_url = ''
|
||||
mock_tenant.service_selection_heading = 'Choose'
|
||||
mock_tenant.service_selection_subheading = 'Select'
|
||||
mock_tenant.can_use_sms_reminders = True
|
||||
mock_tenant.can_use_webhooks = False
|
||||
mock_tenant.can_api_access = False
|
||||
mock_tenant.can_use_custom_domain = False
|
||||
mock_tenant.can_white_label = False
|
||||
mock_tenant.can_manage_oauth_credentials = False
|
||||
mock_tenant.can_use_plugins = True
|
||||
mock_tenant.can_create_plugins = False
|
||||
mock_tenant.can_use_tasks = True
|
||||
mock_tenant.can_export_data = False
|
||||
mock_tenant.can_add_video_conferencing = False
|
||||
mock_tenant.can_require_2fa = False
|
||||
mock_tenant.can_use_masked_phone_numbers = False
|
||||
mock_tenant.can_use_pos = False
|
||||
mock_tenant.can_use_mobile_app = True
|
||||
mock_tenant.can_use_contracts = False
|
||||
mock_tenant.subscription_plan = None
|
||||
mock_tenant.payment_mode = 'stripe'
|
||||
mock_tenant.domains.filter.return_value.first.return_value = mock_domain
|
||||
|
||||
# Mock billing subscription (plan is "pro")
|
||||
mock_plan = Mock()
|
||||
mock_plan.code = 'pro'
|
||||
mock_plan_version = Mock()
|
||||
mock_plan_version.plan = mock_plan
|
||||
mock_subscription = Mock()
|
||||
mock_subscription.plan_version = mock_plan_version
|
||||
mock_tenant.billing_subscription = mock_subscription
|
||||
|
||||
# Mock has_feature to return correct values for billing feature codes
|
||||
def has_feature_impl(feature_code):
|
||||
feature_map = {
|
||||
'sms_enabled': True,
|
||||
'integrations_enabled': False,
|
||||
'api_access': False,
|
||||
'custom_domain': False,
|
||||
'white_label': False,
|
||||
'can_manage_oauth': False,
|
||||
'can_use_plugins': True,
|
||||
'can_create_plugins': False,
|
||||
'can_use_tasks': True,
|
||||
'can_export_data': False,
|
||||
'can_add_video_conferencing': False,
|
||||
'team_permissions': False,
|
||||
'masked_calling_enabled': False,
|
||||
'can_use_pos': False,
|
||||
'mobile_app_access': True,
|
||||
'can_use_contracts': False,
|
||||
'multi_location': False,
|
||||
}
|
||||
return feature_map.get(feature_code, False)
|
||||
|
||||
mock_tenant.has_feature = Mock(side_effect=has_feature_impl)
|
||||
|
||||
request.user = Mock()
|
||||
request.user.tenant = mock_tenant
|
||||
|
||||
@@ -306,7 +322,7 @@ class TestCurrentBusinessView:
|
||||
assert response.data['id'] == 1
|
||||
assert response.data['name'] == 'Demo Business'
|
||||
assert response.data['subdomain'] == 'demo'
|
||||
assert response.data['tier'] == 'PROFESSIONAL'
|
||||
assert response.data['plan'] == 'pro'
|
||||
assert response.data['plan_permissions']['sms_reminders'] is True
|
||||
assert response.data['plan_permissions']['plugins'] is True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user