feat(contracts): Add contracts permission to subscription tiers

- Add contracts_enabled field to SubscriptionPlan model
- Add contracts toggle to plan create/edit modal in platform settings
- Hide contracts menu item for tenants without contracts permission
- Protect /contracts routes with canUse('contracts') check
- Add HasContractsPermission to contracts API ViewSets
- Add contracts to PlanPermissions interface and feature definitions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
poduck
2025-12-05 23:28:51 -05:00
parent 35f4301fe1
commit 023ea7f020
12 changed files with 105 additions and 13 deletions

View File

@@ -523,6 +523,7 @@ const StripeSettingsTab: React.FC = () => {
};
const TiersSettingsTab: React.FC = () => {
const { t } = useTranslation();
const { data: plans, isLoading, error } = useSubscriptionPlans();
const createPlanMutation = useCreateSubscriptionPlan();
const updatePlanMutation = useUpdateSubscriptionPlan();
@@ -864,6 +865,8 @@ const PlanModal: React.FC<PlanModalProps> = ({ plan, onSave, onClose, isLoading
masked_calling_price_per_minute_cents: plan?.masked_calling_price_per_minute_cents ?? 5,
proxy_number_enabled: plan?.proxy_number_enabled ?? false,
proxy_number_monthly_fee_cents: plan?.proxy_number_monthly_fee_cents ?? 200,
// Contracts feature
contracts_enabled: plan?.contracts_enabled ?? false,
// Default credit settings
default_auto_reload_enabled: plan?.default_auto_reload_enabled ?? false,
default_auto_reload_threshold_cents: plan?.default_auto_reload_threshold_cents ?? 1000,
@@ -1251,6 +1254,25 @@ const PlanModal: React.FC<PlanModalProps> = ({ plan, onSave, onClose, isLoading
)}
</div>
{/* Contracts Feature */}
<div className="p-4 border border-gray-200 dark:border-gray-700 rounded-lg">
<div className="flex items-center justify-between">
<div>
<h4 className="text-sm font-medium text-gray-900 dark:text-white">Contracts</h4>
<p className="text-xs text-gray-500 dark:text-gray-400">Allow tenants to create and manage contracts with customers</p>
</div>
<label className="flex items-center gap-2">
<input
type="checkbox"
checked={formData.contracts_enabled || false}
onChange={(e) => setFormData((prev) => ({ ...prev, contracts_enabled: e.target.checked }))}
className="rounded border-gray-300 text-blue-600 focus:ring-blue-500"
/>
<span className="text-sm text-gray-700 dark:text-gray-300">Enabled</span>
</label>
</div>
</div>
{/* Default Credit Settings */}
<div className="p-4 border border-gray-200 dark:border-gray-700 rounded-lg">
<h4 className="text-sm font-medium text-gray-900 dark:text-white mb-3">Default Credit Settings</h4>