michangarrito/apps/backend/dist/modules/subscriptions/subscriptions.service.js
rckrdmrd 48dea7a5d0 feat: Initial commit - michangarrito
Marketplace móvil para negocios locales mexicanos.

Estructura inicial:
- apps/backend (NestJS API)
- apps/frontend (React Web)
- apps/mobile (Expo/React Native)
- apps/mcp-server (Claude MCP Server)
- apps/whatsapp-service (WhatsApp Business API)
- database/ (PostgreSQL DDL)
- docs/ (Documentación)

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-07 04:41:02 -06:00

163 lines
6.9 KiB
JavaScript

"use strict";
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SubscriptionsService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("@nestjs/typeorm");
const typeorm_2 = require("typeorm");
const plan_entity_1 = require("./entities/plan.entity");
const subscription_entity_1 = require("./entities/subscription.entity");
const token_balance_entity_1 = require("./entities/token-balance.entity");
const token_usage_entity_1 = require("./entities/token-usage.entity");
let SubscriptionsService = class SubscriptionsService {
constructor(planRepo, subscriptionRepo, tokenBalanceRepo, tokenUsageRepo) {
this.planRepo = planRepo;
this.subscriptionRepo = subscriptionRepo;
this.tokenBalanceRepo = tokenBalanceRepo;
this.tokenUsageRepo = tokenUsageRepo;
}
async getPlans() {
return this.planRepo.find({
where: { status: 'active' },
order: { priceMonthly: 'ASC' },
});
}
async getPlanByCode(code) {
const plan = await this.planRepo.findOne({ where: { code } });
if (!plan) {
throw new common_1.NotFoundException('Plan no encontrado');
}
return plan;
}
async getSubscription(tenantId) {
return this.subscriptionRepo.findOne({
where: { tenantId },
relations: ['plan'],
});
}
async createSubscription(tenantId, planCode) {
const plan = await this.getPlanByCode(planCode);
const now = new Date();
const periodEnd = new Date(now);
periodEnd.setMonth(periodEnd.getMonth() + 1);
const trialEnds = new Date(now);
trialEnds.setDate(trialEnds.getDate() + 14);
const subscription = this.subscriptionRepo.create({
tenantId,
planId: plan.id,
currentPeriodStart: now,
currentPeriodEnd: periodEnd,
status: subscription_entity_1.SubscriptionStatus.TRIAL,
trialEndsAt: trialEnds,
});
await this.subscriptionRepo.save(subscription);
await this.initializeTokenBalance(tenantId, plan.includedTokens);
return subscription;
}
async cancelSubscription(tenantId) {
const subscription = await this.getSubscription(tenantId);
if (!subscription) {
throw new common_1.NotFoundException('Suscripción no encontrada');
}
subscription.cancelAtPeriodEnd = true;
subscription.cancelledAt = new Date();
return this.subscriptionRepo.save(subscription);
}
async getTokenBalance(tenantId) {
let balance = await this.tokenBalanceRepo.findOne({ where: { tenantId } });
if (!balance) {
balance = await this.initializeTokenBalance(tenantId, 0);
}
return balance;
}
async initializeTokenBalance(tenantId, tokens) {
const existing = await this.tokenBalanceRepo.findOne({ where: { tenantId } });
if (existing) {
existing.availableTokens = tokens;
existing.lastResetAt = new Date();
return this.tokenBalanceRepo.save(existing);
}
const balance = this.tokenBalanceRepo.create({
tenantId,
availableTokens: tokens,
usedTokens: 0,
lastResetAt: new Date(),
});
return this.tokenBalanceRepo.save(balance);
}
async consumeTokens(tenantId, tokensToUse, action, metadata) {
const balance = await this.getTokenBalance(tenantId);
if (balance.availableTokens < tokensToUse) {
throw new common_1.BadRequestException(`Tokens insuficientes. Disponibles: ${balance.availableTokens}, Requeridos: ${tokensToUse}`);
}
const usage = this.tokenUsageRepo.create({
tenantId,
tokensUsed: tokensToUse,
action,
...metadata,
});
await this.tokenUsageRepo.save(usage);
balance.availableTokens -= tokensToUse;
balance.usedTokens += tokensToUse;
return this.tokenBalanceRepo.save(balance);
}
async addTokens(tenantId, tokens) {
const balance = await this.getTokenBalance(tenantId);
balance.availableTokens += tokens;
return this.tokenBalanceRepo.save(balance);
}
async getTokenUsage(tenantId, limit = 50) {
return this.tokenUsageRepo.find({
where: { tenantId },
order: { createdAt: 'DESC' },
take: limit,
});
}
async getSubscriptionStats(tenantId) {
const subscription = await this.getSubscription(tenantId);
const balance = await this.getTokenBalance(tenantId);
const daysRemaining = subscription
? Math.max(0, Math.ceil((subscription.currentPeriodEnd.getTime() - Date.now()) / (1000 * 60 * 60 * 24)))
: 0;
return {
subscription: subscription
? {
plan: subscription.plan?.name,
status: subscription.status,
currentPeriodEnd: subscription.currentPeriodEnd,
daysRemaining,
cancelAtPeriodEnd: subscription.cancelAtPeriodEnd,
}
: null,
tokens: {
available: balance.availableTokens,
used: balance.usedTokens,
total: balance.availableTokens + balance.usedTokens,
},
};
}
};
exports.SubscriptionsService = SubscriptionsService;
exports.SubscriptionsService = SubscriptionsService = __decorate([
(0, common_1.Injectable)(),
__param(0, (0, typeorm_1.InjectRepository)(plan_entity_1.Plan)),
__param(1, (0, typeorm_1.InjectRepository)(subscription_entity_1.Subscription)),
__param(2, (0, typeorm_1.InjectRepository)(token_balance_entity_1.TokenBalance)),
__param(3, (0, typeorm_1.InjectRepository)(token_usage_entity_1.TokenUsage)),
__metadata("design:paramtypes", [typeorm_2.Repository,
typeorm_2.Repository,
typeorm_2.Repository,
typeorm_2.Repository])
], SubscriptionsService);
//# sourceMappingURL=subscriptions.service.js.map