2025-09-05 17:49:48 +02:00
|
|
|
/**
|
|
|
|
|
* Subscription Service - Mirror backend subscription endpoints
|
|
|
|
|
*/
|
|
|
|
|
import { apiClient } from '../client';
|
2025-09-20 08:59:12 +02:00
|
|
|
import {
|
|
|
|
|
SubscriptionLimits,
|
|
|
|
|
FeatureCheckResponse,
|
|
|
|
|
UsageCheckResponse,
|
|
|
|
|
UsageSummary,
|
|
|
|
|
AvailablePlans,
|
|
|
|
|
PlanUpgradeValidation,
|
|
|
|
|
PlanUpgradeResult
|
2025-09-05 17:49:48 +02:00
|
|
|
} from '../types/subscription';
|
|
|
|
|
|
|
|
|
|
export class SubscriptionService {
|
|
|
|
|
private readonly baseUrl = '/subscriptions';
|
|
|
|
|
|
|
|
|
|
async getSubscriptionLimits(tenantId: string): Promise<SubscriptionLimits> {
|
|
|
|
|
return apiClient.get<SubscriptionLimits>(`${this.baseUrl}/${tenantId}/limits`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async checkFeatureAccess(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
featureName: string
|
|
|
|
|
): Promise<FeatureCheckResponse> {
|
|
|
|
|
return apiClient.get<FeatureCheckResponse>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/features/${featureName}/check`
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async checkUsageLimit(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
resourceType: 'users' | 'sales_records' | 'inventory_items' | 'api_requests',
|
|
|
|
|
requestedAmount?: number
|
|
|
|
|
): Promise<UsageCheckResponse> {
|
|
|
|
|
const queryParams = new URLSearchParams();
|
|
|
|
|
if (requestedAmount !== undefined) {
|
|
|
|
|
queryParams.append('requested_amount', requestedAmount.toString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const url = queryParams.toString()
|
|
|
|
|
? `${this.baseUrl}/${tenantId}/usage/${resourceType}/check?${queryParams.toString()}`
|
|
|
|
|
: `${this.baseUrl}/${tenantId}/usage/${resourceType}/check`;
|
|
|
|
|
|
|
|
|
|
return apiClient.get<UsageCheckResponse>(url);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async recordUsage(
|
|
|
|
|
tenantId: string,
|
|
|
|
|
resourceType: 'users' | 'sales_records' | 'inventory_items' | 'api_requests',
|
|
|
|
|
amount: number = 1
|
|
|
|
|
): Promise<{ success: boolean; message: string }> {
|
|
|
|
|
return apiClient.post<{ success: boolean; message: string }>(
|
|
|
|
|
`${this.baseUrl}/${tenantId}/usage/${resourceType}/record`,
|
|
|
|
|
{ amount }
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getCurrentUsage(tenantId: string): Promise<{
|
|
|
|
|
users: number;
|
|
|
|
|
sales_records: number;
|
|
|
|
|
inventory_items: number;
|
|
|
|
|
api_requests_this_hour: number;
|
|
|
|
|
}> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/${tenantId}/usage/current`);
|
|
|
|
|
}
|
2025-09-20 08:59:12 +02:00
|
|
|
|
|
|
|
|
async getUsageSummary(tenantId: string): Promise<UsageSummary> {
|
2025-09-21 13:27:50 +02:00
|
|
|
return apiClient.get<UsageSummary>(`${this.baseUrl}/${tenantId}/usage`);
|
2025-09-20 08:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getAvailablePlans(): Promise<AvailablePlans> {
|
2025-09-21 13:27:50 +02:00
|
|
|
return apiClient.get<AvailablePlans>('/subscriptions/plans');
|
2025-09-20 08:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async validatePlanUpgrade(tenantId: string, planKey: string): Promise<PlanUpgradeValidation> {
|
2025-09-21 13:27:50 +02:00
|
|
|
return apiClient.get<PlanUpgradeValidation>(`${this.baseUrl}/${tenantId}/validate-upgrade/${planKey}`);
|
2025-09-20 08:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async upgradePlan(tenantId: string, planKey: string): Promise<PlanUpgradeResult> {
|
2025-09-21 13:27:50 +02:00
|
|
|
return apiClient.post<PlanUpgradeResult>(`${this.baseUrl}/${tenantId}/upgrade?new_plan=${planKey}`, {});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async canAddLocation(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/${tenantId}/can-add-location`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async canAddProduct(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/${tenantId}/can-add-product`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async canAddUser(tenantId: string): Promise<{ can_add: boolean; reason?: string; current_count?: number; max_allowed?: number }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/${tenantId}/can-add-user`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async hasFeature(tenantId: string, featureName: string): Promise<{ has_feature: boolean; feature_value?: any; plan?: string; reason?: string }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/${tenantId}/features/${featureName}`);
|
2025-09-20 08:59:12 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
formatPrice(amount: number): string {
|
|
|
|
|
return new Intl.NumberFormat('es-ES', {
|
|
|
|
|
style: 'currency',
|
|
|
|
|
currency: 'EUR',
|
|
|
|
|
minimumFractionDigits: 0,
|
|
|
|
|
maximumFractionDigits: 2
|
|
|
|
|
}).format(amount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getPlanDisplayInfo(planKey: string): { name: string; color: string } {
|
|
|
|
|
const planInfo = {
|
|
|
|
|
starter: { name: 'Starter', color: 'blue' },
|
|
|
|
|
professional: { name: 'Professional', color: 'purple' },
|
|
|
|
|
enterprise: { name: 'Enterprise', color: 'amber' }
|
|
|
|
|
};
|
|
|
|
|
return planInfo[planKey as keyof typeof planInfo] || { name: 'Desconocido', color: 'gray' };
|
|
|
|
|
}
|
2025-09-05 17:49:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const subscriptionService = new SubscriptionService();
|