[MIGRATION-V2] feat: Migrar michangarrito a estructura v2
- Prefijo v2: MCH - TRACEABILITY-MASTER.yml creado - Listo para integracion como submodulo Workspace: v2.0.0 | SIMCO: v4.0.0
This commit is contained in:
commit
97f407c661
432
.env
Normal file
432
.env
Normal file
@ -0,0 +1,432 @@
|
||||
# =============================================================================
|
||||
# MICHANGARRITO - VARIABLES DE ENTORNO
|
||||
# =============================================================================
|
||||
# Copiar este archivo a .env y configurar los valores
|
||||
# Generado: 2026-01-04
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# APLICACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
NODE_ENV=development
|
||||
APP_NAME=michangarrito
|
||||
APP_VERSION=1.0.0
|
||||
APP_DESCRIPTION="POS inteligente para micro-negocios"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PUERTOS DE SERVICIOS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
WEB_PORT=3140
|
||||
BACKEND_PORT=3141
|
||||
MCP_PORT=3142
|
||||
WHATSAPP_PORT=3143
|
||||
MOBILE_METRO_PORT=8081
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# BASE DE DATOS POSTGRESQL
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=michangarrito_dev
|
||||
DB_USER=michangarrito_dev
|
||||
# Generar con: openssl rand -base64 32
|
||||
DB_PASSWORD=MCh_dev_2025_secure
|
||||
|
||||
# URL de conexion completa (se construye automaticamente)
|
||||
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||
|
||||
# Pool de conexiones
|
||||
DB_POOL_SIZE=10
|
||||
DB_POOL_MIN=2
|
||||
|
||||
# SSL (solo produccion)
|
||||
DB_SSL=false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# REDIS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6389
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DATABASE=0
|
||||
REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}/${REDIS_DATABASE}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# JWT / AUTENTICACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Generar con: openssl rand -base64 64
|
||||
JWT_SECRET=MCh_jwt_dev_2025_AcB7x9KmPq2sWfHg4jL8nRt0vYzXw1CdEiFoGhJkLmN3pQrSuVxY5bZ6aBeC8fDg
|
||||
JWT_EXPIRES_IN=7d
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# OTP para login
|
||||
OTP_EXPIRES_MINUTES=5
|
||||
OTP_LENGTH=6
|
||||
|
||||
# PIN de acceso rapido
|
||||
PIN_LENGTH=4
|
||||
PIN_MAX_ATTEMPTS=3
|
||||
PIN_LOCKOUT_MINUTES=30
|
||||
|
||||
# Biometrico
|
||||
BIOMETRIC_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WHATSAPP BUSINESS API (Meta)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Verificacion del webhook
|
||||
WHATSAPP_VERIFY_TOKEN=MCh_wa_verify_2025_x7k9m3p5q8r2t4w6y0
|
||||
|
||||
# Token de acceso (obtener de Meta Business)
|
||||
WHATSAPP_ACCESS_TOKEN=
|
||||
|
||||
# ID del numero de telefono
|
||||
WHATSAPP_PHONE_NUMBER_ID=
|
||||
|
||||
# ID de la cuenta de negocio
|
||||
WHATSAPP_BUSINESS_ACCOUNT_ID=
|
||||
|
||||
# Webhook URL (para configurar en Meta)
|
||||
WHATSAPP_WEBHOOK_URL=https://tu-dominio.com/webhook/whatsapp
|
||||
|
||||
# Numero compartido de la plataforma (para multi-tenant)
|
||||
WHATSAPP_PLATFORM_NUMBER=+52XXXXXXXXXX
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LLM / INTELIGENCIA ARTIFICIAL
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Proveedor: openrouter, openai, anthropic, ollama
|
||||
LLM_PROVIDER=openrouter
|
||||
|
||||
# API Key del proveedor
|
||||
LLM_API_KEY=
|
||||
|
||||
# Modelo a usar
|
||||
# OpenRouter: anthropic/claude-3-haiku, openai/gpt-4o-mini, meta-llama/llama-3-8b
|
||||
# OpenAI: gpt-4o-mini, gpt-4o
|
||||
# Anthropic: claude-3-haiku-20240307, claude-3-sonnet-20240229
|
||||
# Ollama: llama3, mistral, phi3
|
||||
LLM_MODEL=anthropic/claude-3-haiku
|
||||
|
||||
# URL base del proveedor
|
||||
# OpenRouter: https://openrouter.ai/api/v1
|
||||
# OpenAI: https://api.openai.com/v1
|
||||
# Anthropic: https://api.anthropic.com/v1
|
||||
# Ollama: http://localhost:11434/api
|
||||
LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
|
||||
# Limites
|
||||
LLM_MAX_TOKENS=4096
|
||||
LLM_TEMPERATURE=0.7
|
||||
|
||||
# Tokens por defecto para nuevos usuarios
|
||||
LLM_DEFAULT_TOKENS=500
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MCP SERVER (Model Context Protocol)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
MCP_SERVER_NAME=michangarrito-mcp
|
||||
MCP_SERVER_VERSION=1.0.0
|
||||
MCP_LOG_LEVEL=info
|
||||
|
||||
# Herramientas habilitadas (separadas por coma)
|
||||
MCP_ENABLED_TOOLS=ventas,productos,inventario,clientes,fiados,pedidos,reportes,configuracion
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STRIPE (Suscripciones y Pagos)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Claves de API (modo test)
|
||||
# Obtener de: https://dashboard.stripe.com/test/apikeys
|
||||
STRIPE_SECRET_KEY=sk_test_
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_
|
||||
|
||||
# Webhook secret
|
||||
# Obtener de: https://dashboard.stripe.com/test/webhooks
|
||||
STRIPE_WEBHOOK_SECRET=whsec_
|
||||
|
||||
# IDs de productos/precios (crear en Stripe Dashboard)
|
||||
STRIPE_PRICE_CHANGARRITO=price_
|
||||
STRIPE_PRICE_TIENDITA=price_
|
||||
STRIPE_PRICE_TOKENS_1000=price_
|
||||
STRIPE_PRICE_TOKENS_3000=price_
|
||||
STRIPE_PRICE_TOKENS_8000=price_
|
||||
STRIPE_PRICE_TOKENS_20000=price_
|
||||
|
||||
# Referencia OXXO
|
||||
STRIPE_OXXO_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MERCADO PAGO (Terminal de Pago)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Access Token (obtener de Mercado Pago Developers)
|
||||
MERCADOPAGO_ACCESS_TOKEN=
|
||||
|
||||
# Public Key
|
||||
MERCADOPAGO_PUBLIC_KEY=
|
||||
|
||||
# User ID (para Point integration)
|
||||
MERCADOPAGO_USER_ID=
|
||||
|
||||
# Device ID de la terminal
|
||||
MERCADOPAGO_DEVICE_ID=
|
||||
|
||||
# Webhook URL
|
||||
MERCADOPAGO_WEBHOOK_URL=https://tu-dominio.com/webhook/mercadopago
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CLIP (Terminal de Pago)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# API Key (obtener de Clip Dashboard)
|
||||
CLIP_API_KEY=
|
||||
|
||||
# Merchant ID
|
||||
CLIP_MERCHANT_ID=
|
||||
|
||||
# Device ID de la terminal
|
||||
CLIP_DEVICE_ID=
|
||||
|
||||
# Webhook URL
|
||||
CLIP_WEBHOOK_URL=https://tu-dominio.com/webhook/clip
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CODI (Banxico QR)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Habilitado
|
||||
CODI_ENABLED=true
|
||||
|
||||
# CLABE virtual para recepcion
|
||||
CODI_CLABE=
|
||||
|
||||
# Certificado (path o base64)
|
||||
CODI_CERTIFICATE=
|
||||
|
||||
# Llave privada (path o base64)
|
||||
CODI_PRIVATE_KEY=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# FIREBASE (Push Notifications)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Project ID
|
||||
FIREBASE_PROJECT_ID=
|
||||
|
||||
# Service Account (JSON)
|
||||
# Opcion 1: Path al archivo
|
||||
FIREBASE_SERVICE_ACCOUNT_PATH=./firebase-service-account.json
|
||||
|
||||
# Opcion 2: JSON como string (para produccion)
|
||||
FIREBASE_SERVICE_ACCOUNT_JSON=
|
||||
|
||||
# Habilitado
|
||||
FIREBASE_PUSH_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# OCR / VISION (Procesamiento de Imagenes)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Google Cloud Vision
|
||||
# Obtener de: https://console.cloud.google.com/apis/credentials
|
||||
GOOGLE_VISION_API_KEY=
|
||||
|
||||
# Alternativa: Tesseract local
|
||||
OCR_PROVIDER=google
|
||||
# OCR_PROVIDER=tesseract
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TRANSCRIPCION DE AUDIO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# OpenAI Whisper API
|
||||
# Obtener de: https://platform.openai.com/api-keys
|
||||
OPENAI_API_KEY=
|
||||
|
||||
# Modelo de Whisper
|
||||
WHISPER_MODEL=whisper-1
|
||||
|
||||
# Alternativa: Whisper local
|
||||
TRANSCRIPTION_PROVIDER=openai
|
||||
# TRANSCRIPTION_PROVIDER=local
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ALMACENAMIENTO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Tipo: local, s3, cloudinary
|
||||
STORAGE_TYPE=local
|
||||
|
||||
# Local
|
||||
STORAGE_LOCAL_PATH=./uploads
|
||||
STORAGE_MAX_SIZE_MB=10
|
||||
|
||||
# AWS S3 (para produccion)
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_REGION=us-east-1
|
||||
AWS_S3_BUCKET=michangarrito-uploads
|
||||
|
||||
# Cloudinary (alternativa)
|
||||
CLOUDINARY_CLOUD_NAME=
|
||||
CLOUDINARY_API_KEY=
|
||||
CLOUDINARY_API_SECRET=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CORS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FRONTEND_URL=http://localhost:3140
|
||||
ALLOWED_ORIGINS=http://localhost:3140,http://localhost:3141,exp://localhost:8081
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LOGGING
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
LOG_LEVEL=debug
|
||||
LOG_FORMAT=pretty
|
||||
# LOG_FORMAT=json (para produccion)
|
||||
|
||||
# Sentry (error tracking - produccion)
|
||||
SENTRY_DSN=
|
||||
SENTRY_ENVIRONMENT=development
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SMTP / EMAIL (Opcional)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=1025
|
||||
SMTP_USER=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_FROM=noreply@michangarrito.com
|
||||
|
||||
# Mailhog para desarrollo
|
||||
MAILHOG_WEB_PORT=8025
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# RATE LIMITING
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
RATE_LIMIT_TTL=60
|
||||
RATE_LIMIT_LIMIT=100
|
||||
|
||||
# WhatsApp rate limits
|
||||
WHATSAPP_RATE_LIMIT_MESSAGES=1000
|
||||
WHATSAPP_RATE_LIMIT_WINDOW=86400
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CACHE
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CACHE_TTL=300
|
||||
CACHE_MAX_ITEMS=1000
|
||||
|
||||
# Cache de productos (mas largo)
|
||||
CACHE_PRODUCTS_TTL=3600
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# JOBS / QUEUES (Bull)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
BULL_REDIS_HOST=${REDIS_HOST}
|
||||
BULL_REDIS_PORT=${REDIS_PORT}
|
||||
|
||||
# Colas disponibles
|
||||
QUEUE_NOTIFICATIONS=notifications
|
||||
QUEUE_REPORTS=reports
|
||||
QUEUE_SYNC=sync
|
||||
QUEUE_WHATSAPP=whatsapp
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# EXPO / MOBILE
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
EXPO_PROJECT_ID=
|
||||
EXPO_OWNER=
|
||||
|
||||
# EAS Build
|
||||
EAS_PROJECT_ID=
|
||||
|
||||
# Updates
|
||||
EXPO_UPDATES_URL=https://u.expo.dev/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MULTI-TENANT
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Modo: single (un negocio por instancia) o multi (varios negocios)
|
||||
TENANT_MODE=multi
|
||||
|
||||
# Deteccion de tenant por:
|
||||
# - subdomain: negocio.michangarrito.com
|
||||
# - header: X-Tenant-ID
|
||||
# - whatsapp: detectar por contexto de conversacion
|
||||
TENANT_DETECTION=whatsapp
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NEGOCIO / CONFIGURACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Moneda por defecto
|
||||
DEFAULT_CURRENCY=MXN
|
||||
|
||||
# Zona horaria
|
||||
DEFAULT_TIMEZONE=America/Mexico_City
|
||||
|
||||
# Idioma
|
||||
DEFAULT_LANGUAGE=es-MX
|
||||
|
||||
# Impuestos
|
||||
DEFAULT_TAX_RATE=16
|
||||
TAX_INCLUDED=true
|
||||
|
||||
# Tickets
|
||||
TICKET_COMPANY_NAME=MiChangarrito
|
||||
TICKET_FOOTER=Gracias por su compra
|
||||
|
||||
# Horario de operacion por defecto
|
||||
DEFAULT_OPENING_HOUR=8
|
||||
DEFAULT_CLOSING_HOUR=22
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DESARROLLO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Hot reload
|
||||
HOT_RELOAD=true
|
||||
|
||||
# Debug
|
||||
DEBUG=true
|
||||
DEBUG_SQL=false
|
||||
|
||||
# Seed data
|
||||
SEED_ENABLED=true
|
||||
|
||||
# Swagger docs
|
||||
SWAGGER_ENABLED=true
|
||||
SWAGGER_PATH=/api/docs
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PRODUCCION (descomentar para produccion)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# NODE_ENV=production
|
||||
# DEBUG=false
|
||||
# LOG_FORMAT=json
|
||||
# SWAGGER_ENABLED=false
|
||||
# DB_SSL=true
|
||||
# STORAGE_TYPE=s3
|
||||
|
||||
# =============================================================================
|
||||
# FIN DE CONFIGURACION
|
||||
# =============================================================================
|
||||
62
.env.docker
Normal file
62
.env.docker
Normal file
@ -0,0 +1,62 @@
|
||||
# =============================================================================
|
||||
# MiChangarrito - Docker Environment Variables
|
||||
# =============================================================================
|
||||
# Copiar este archivo a .env y configurar los valores
|
||||
# cp .env.docker .env
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DATABASE
|
||||
# -----------------------------------------------------------------------------
|
||||
DB_USERNAME=michangarrito_dev
|
||||
DB_PASSWORD=MCh_dev_2025_secure
|
||||
DB_DATABASE=michangarrito_dev
|
||||
DB_PORT=5432
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# REDIS
|
||||
# -----------------------------------------------------------------------------
|
||||
REDIS_PORT=6379
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# BACKEND
|
||||
# -----------------------------------------------------------------------------
|
||||
BACKEND_PORT=3141
|
||||
JWT_SECRET=CHANGE_THIS_IN_PRODUCTION_MIN_64_CHARS_RANDOM_STRING_HERE_1234567890
|
||||
JWT_EXPIRES_IN=7d
|
||||
CORS_ORIGIN=http://localhost:3140
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# FRONTEND
|
||||
# -----------------------------------------------------------------------------
|
||||
FRONTEND_PORT=3140
|
||||
VITE_API_URL=http://localhost:3141/api/v1
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WHATSAPP SERVICE
|
||||
# -----------------------------------------------------------------------------
|
||||
WHATSAPP_PORT=3143
|
||||
WHATSAPP_TOKEN=
|
||||
WHATSAPP_PHONE_NUMBER_ID=
|
||||
WHATSAPP_BUSINESS_ACCOUNT_ID=
|
||||
WHATSAPP_VERIFY_TOKEN=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STRIPE
|
||||
# -----------------------------------------------------------------------------
|
||||
STRIPE_SECRET_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LLM / AI
|
||||
# -----------------------------------------------------------------------------
|
||||
OPENAI_API_KEY=
|
||||
LLM_MODEL=gpt-4o-mini
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PRODUCTION (uncomment for production)
|
||||
# -----------------------------------------------------------------------------
|
||||
# COMPOSE_PROFILES=production
|
||||
# CORS_ORIGIN=https://michangarrito.com
|
||||
# VITE_API_URL=https://api.michangarrito.com/api/v1
|
||||
433
.env.example
Normal file
433
.env.example
Normal file
@ -0,0 +1,433 @@
|
||||
# =============================================================================
|
||||
# MICHANGARRITO - VARIABLES DE ENTORNO
|
||||
# =============================================================================
|
||||
# Copiar este archivo a .env y configurar los valores
|
||||
# Generado: 2026-01-04
|
||||
# =============================================================================
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# APLICACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
NODE_ENV=development
|
||||
APP_NAME=michangarrito
|
||||
APP_VERSION=1.0.0
|
||||
APP_DESCRIPTION="POS inteligente para micro-negocios"
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PUERTOS DE SERVICIOS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
WEB_PORT=3140
|
||||
BACKEND_PORT=3141
|
||||
MCP_PORT=3142
|
||||
WHATSAPP_PORT=3143
|
||||
MOBILE_METRO_PORT=8081
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# BASE DE DATOS POSTGRESQL
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_NAME=michangarrito_dev
|
||||
DB_USER=michangarrito_dev
|
||||
# Generar con: openssl rand -base64 32
|
||||
DB_PASSWORD=
|
||||
|
||||
# URL de conexion completa (se construye automaticamente)
|
||||
DATABASE_URL=postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}
|
||||
|
||||
# Pool de conexiones
|
||||
DB_POOL_SIZE=10
|
||||
DB_POOL_MIN=2
|
||||
|
||||
# SSL (solo produccion)
|
||||
DB_SSL=false
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# REDIS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
REDIS_HOST=localhost
|
||||
REDIS_PORT=6379
|
||||
REDIS_PASSWORD=
|
||||
REDIS_DATABASE=8
|
||||
# Nota: Puerto 6379 es instancia compartida del workspace, DB 8 asignado a MiChangarrito
|
||||
REDIS_URL=redis://${REDIS_HOST}:${REDIS_PORT}/${REDIS_DATABASE}
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# JWT / AUTENTICACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Generar con: openssl rand -base64 64
|
||||
JWT_SECRET=
|
||||
JWT_EXPIRES_IN=7d
|
||||
JWT_REFRESH_EXPIRES_IN=30d
|
||||
|
||||
# OTP para login
|
||||
OTP_EXPIRES_MINUTES=5
|
||||
OTP_LENGTH=6
|
||||
|
||||
# PIN de acceso rapido
|
||||
PIN_LENGTH=4
|
||||
PIN_MAX_ATTEMPTS=3
|
||||
PIN_LOCKOUT_MINUTES=30
|
||||
|
||||
# Biometrico
|
||||
BIOMETRIC_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# WHATSAPP BUSINESS API (Meta)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Verificacion del webhook
|
||||
WHATSAPP_VERIFY_TOKEN=
|
||||
|
||||
# Token de acceso (obtener de Meta Business)
|
||||
WHATSAPP_ACCESS_TOKEN=
|
||||
|
||||
# ID del numero de telefono
|
||||
WHATSAPP_PHONE_NUMBER_ID=
|
||||
|
||||
# ID de la cuenta de negocio
|
||||
WHATSAPP_BUSINESS_ACCOUNT_ID=
|
||||
|
||||
# Webhook URL (para configurar en Meta)
|
||||
WHATSAPP_WEBHOOK_URL=https://tu-dominio.com/webhook/whatsapp
|
||||
|
||||
# Numero compartido de la plataforma (para multi-tenant)
|
||||
WHATSAPP_PLATFORM_NUMBER=+52XXXXXXXXXX
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LLM / INTELIGENCIA ARTIFICIAL
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Proveedor: openrouter, openai, anthropic, ollama
|
||||
LLM_PROVIDER=openrouter
|
||||
|
||||
# API Key del proveedor
|
||||
LLM_API_KEY=
|
||||
|
||||
# Modelo a usar
|
||||
# OpenRouter: anthropic/claude-3-haiku, openai/gpt-4o-mini, meta-llama/llama-3-8b
|
||||
# OpenAI: gpt-4o-mini, gpt-4o
|
||||
# Anthropic: claude-3-haiku-20240307, claude-3-sonnet-20240229
|
||||
# Ollama: llama3, mistral, phi3
|
||||
LLM_MODEL=anthropic/claude-3-haiku
|
||||
|
||||
# URL base del proveedor
|
||||
# OpenRouter: https://openrouter.ai/api/v1
|
||||
# OpenAI: https://api.openai.com/v1
|
||||
# Anthropic: https://api.anthropic.com/v1
|
||||
# Ollama: http://localhost:11434/api
|
||||
LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
|
||||
# Limites
|
||||
LLM_MAX_TOKENS=4096
|
||||
LLM_TEMPERATURE=0.7
|
||||
|
||||
# Tokens por defecto para nuevos usuarios
|
||||
LLM_DEFAULT_TOKENS=500
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MCP SERVER (Model Context Protocol)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
MCP_SERVER_NAME=michangarrito-mcp
|
||||
MCP_SERVER_VERSION=1.0.0
|
||||
MCP_LOG_LEVEL=info
|
||||
|
||||
# Herramientas habilitadas (separadas por coma)
|
||||
MCP_ENABLED_TOOLS=ventas,productos,inventario,clientes,fiados,pedidos,reportes,configuracion
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# STRIPE (Suscripciones y Pagos)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Claves de API (modo test)
|
||||
# Obtener de: https://dashboard.stripe.com/test/apikeys
|
||||
STRIPE_SECRET_KEY=sk_test_
|
||||
STRIPE_PUBLISHABLE_KEY=pk_test_
|
||||
|
||||
# Webhook secret
|
||||
# Obtener de: https://dashboard.stripe.com/test/webhooks
|
||||
STRIPE_WEBHOOK_SECRET=whsec_
|
||||
|
||||
# IDs de productos/precios (crear en Stripe Dashboard)
|
||||
STRIPE_PRICE_CHANGARRITO=price_
|
||||
STRIPE_PRICE_TIENDITA=price_
|
||||
STRIPE_PRICE_TOKENS_1000=price_
|
||||
STRIPE_PRICE_TOKENS_3000=price_
|
||||
STRIPE_PRICE_TOKENS_8000=price_
|
||||
STRIPE_PRICE_TOKENS_20000=price_
|
||||
|
||||
# Referencia OXXO
|
||||
STRIPE_OXXO_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MERCADO PAGO (Terminal de Pago)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Access Token (obtener de Mercado Pago Developers)
|
||||
MERCADOPAGO_ACCESS_TOKEN=
|
||||
|
||||
# Public Key
|
||||
MERCADOPAGO_PUBLIC_KEY=
|
||||
|
||||
# User ID (para Point integration)
|
||||
MERCADOPAGO_USER_ID=
|
||||
|
||||
# Device ID de la terminal
|
||||
MERCADOPAGO_DEVICE_ID=
|
||||
|
||||
# Webhook URL
|
||||
MERCADOPAGO_WEBHOOK_URL=https://tu-dominio.com/webhook/mercadopago
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CLIP (Terminal de Pago)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# API Key (obtener de Clip Dashboard)
|
||||
CLIP_API_KEY=
|
||||
|
||||
# Merchant ID
|
||||
CLIP_MERCHANT_ID=
|
||||
|
||||
# Device ID de la terminal
|
||||
CLIP_DEVICE_ID=
|
||||
|
||||
# Webhook URL
|
||||
CLIP_WEBHOOK_URL=https://tu-dominio.com/webhook/clip
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CODI (Banxico QR)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Habilitado
|
||||
CODI_ENABLED=true
|
||||
|
||||
# CLABE virtual para recepcion
|
||||
CODI_CLABE=
|
||||
|
||||
# Certificado (path o base64)
|
||||
CODI_CERTIFICATE=
|
||||
|
||||
# Llave privada (path o base64)
|
||||
CODI_PRIVATE_KEY=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# FIREBASE (Push Notifications)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Project ID
|
||||
FIREBASE_PROJECT_ID=
|
||||
|
||||
# Service Account (JSON)
|
||||
# Opcion 1: Path al archivo
|
||||
FIREBASE_SERVICE_ACCOUNT_PATH=./firebase-service-account.json
|
||||
|
||||
# Opcion 2: JSON como string (para produccion)
|
||||
FIREBASE_SERVICE_ACCOUNT_JSON=
|
||||
|
||||
# Habilitado
|
||||
FIREBASE_PUSH_ENABLED=true
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# OCR / VISION (Procesamiento de Imagenes)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Google Cloud Vision
|
||||
# Obtener de: https://console.cloud.google.com/apis/credentials
|
||||
GOOGLE_VISION_API_KEY=
|
||||
|
||||
# Alternativa: Tesseract local
|
||||
OCR_PROVIDER=google
|
||||
# OCR_PROVIDER=tesseract
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# TRANSCRIPCION DE AUDIO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# OpenAI Whisper API
|
||||
# Obtener de: https://platform.openai.com/api-keys
|
||||
OPENAI_API_KEY=
|
||||
|
||||
# Modelo de Whisper
|
||||
WHISPER_MODEL=whisper-1
|
||||
|
||||
# Alternativa: Whisper local
|
||||
TRANSCRIPTION_PROVIDER=openai
|
||||
# TRANSCRIPTION_PROVIDER=local
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# ALMACENAMIENTO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Tipo: local, s3, cloudinary
|
||||
STORAGE_TYPE=local
|
||||
|
||||
# Local
|
||||
STORAGE_LOCAL_PATH=./uploads
|
||||
STORAGE_MAX_SIZE_MB=10
|
||||
|
||||
# AWS S3 (para produccion)
|
||||
AWS_ACCESS_KEY_ID=
|
||||
AWS_SECRET_ACCESS_KEY=
|
||||
AWS_REGION=us-east-1
|
||||
AWS_S3_BUCKET=michangarrito-uploads
|
||||
|
||||
# Cloudinary (alternativa)
|
||||
CLOUDINARY_CLOUD_NAME=
|
||||
CLOUDINARY_API_KEY=
|
||||
CLOUDINARY_API_SECRET=
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CORS
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
FRONTEND_URL=http://localhost:3140
|
||||
ALLOWED_ORIGINS=http://localhost:3140,http://localhost:3141,exp://localhost:8081
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# LOGGING
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
LOG_LEVEL=debug
|
||||
LOG_FORMAT=pretty
|
||||
# LOG_FORMAT=json (para produccion)
|
||||
|
||||
# Sentry (error tracking - produccion)
|
||||
SENTRY_DSN=
|
||||
SENTRY_ENVIRONMENT=development
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SMTP / EMAIL (Opcional)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
SMTP_HOST=localhost
|
||||
SMTP_PORT=1025
|
||||
SMTP_USER=
|
||||
SMTP_PASSWORD=
|
||||
SMTP_FROM=noreply@michangarrito.com
|
||||
|
||||
# Mailhog para desarrollo
|
||||
MAILHOG_WEB_PORT=8025
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# RATE LIMITING
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
RATE_LIMIT_TTL=60
|
||||
RATE_LIMIT_LIMIT=100
|
||||
|
||||
# WhatsApp rate limits
|
||||
WHATSAPP_RATE_LIMIT_MESSAGES=1000
|
||||
WHATSAPP_RATE_LIMIT_WINDOW=86400
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CACHE
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
CACHE_TTL=300
|
||||
CACHE_MAX_ITEMS=1000
|
||||
|
||||
# Cache de productos (mas largo)
|
||||
CACHE_PRODUCTS_TTL=3600
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# JOBS / QUEUES (Bull)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
BULL_REDIS_HOST=${REDIS_HOST}
|
||||
BULL_REDIS_PORT=${REDIS_PORT}
|
||||
|
||||
# Colas disponibles
|
||||
QUEUE_NOTIFICATIONS=notifications
|
||||
QUEUE_REPORTS=reports
|
||||
QUEUE_SYNC=sync
|
||||
QUEUE_WHATSAPP=whatsapp
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# EXPO / MOBILE
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
EXPO_PROJECT_ID=
|
||||
EXPO_OWNER=
|
||||
|
||||
# EAS Build
|
||||
EAS_PROJECT_ID=
|
||||
|
||||
# Updates
|
||||
EXPO_UPDATES_URL=https://u.expo.dev/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# MULTI-TENANT
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Modo: single (un negocio por instancia) o multi (varios negocios)
|
||||
TENANT_MODE=multi
|
||||
|
||||
# Deteccion de tenant por:
|
||||
# - subdomain: negocio.michangarrito.com
|
||||
# - header: X-Tenant-ID
|
||||
# - whatsapp: detectar por contexto de conversacion
|
||||
TENANT_DETECTION=whatsapp
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# NEGOCIO / CONFIGURACION
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Moneda por defecto
|
||||
DEFAULT_CURRENCY=MXN
|
||||
|
||||
# Zona horaria
|
||||
DEFAULT_TIMEZONE=America/Mexico_City
|
||||
|
||||
# Idioma
|
||||
DEFAULT_LANGUAGE=es-MX
|
||||
|
||||
# Impuestos
|
||||
DEFAULT_TAX_RATE=16
|
||||
TAX_INCLUDED=true
|
||||
|
||||
# Tickets
|
||||
TICKET_COMPANY_NAME=MiChangarrito
|
||||
TICKET_FOOTER=Gracias por su compra
|
||||
|
||||
# Horario de operacion por defecto
|
||||
DEFAULT_OPENING_HOUR=8
|
||||
DEFAULT_CLOSING_HOUR=22
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# DESARROLLO
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# Hot reload
|
||||
HOT_RELOAD=true
|
||||
|
||||
# Debug
|
||||
DEBUG=true
|
||||
DEBUG_SQL=false
|
||||
|
||||
# Seed data
|
||||
SEED_ENABLED=true
|
||||
|
||||
# Swagger docs
|
||||
SWAGGER_ENABLED=true
|
||||
SWAGGER_PATH=/api/docs
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# PRODUCCION (descomentar para produccion)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
# NODE_ENV=production
|
||||
# DEBUG=false
|
||||
# LOG_FORMAT=json
|
||||
# SWAGGER_ENABLED=false
|
||||
# DB_SSL=true
|
||||
# STORAGE_TYPE=s3
|
||||
|
||||
# =============================================================================
|
||||
# FIN DE CONFIGURACION
|
||||
# =============================================================================
|
||||
23
.env.ports
Normal file
23
.env.ports
Normal file
@ -0,0 +1,23 @@
|
||||
# =============================================================================
|
||||
# MICHANGARRITO - ASIGNACION DE PUERTOS
|
||||
# =============================================================================
|
||||
# Referencia rapida de puertos del proyecto
|
||||
# =============================================================================
|
||||
|
||||
# Aplicaciones
|
||||
WEB_PORT=3140
|
||||
BACKEND_PORT=3141
|
||||
MCP_PORT=3142
|
||||
WHATSAPP_PORT=3143
|
||||
MOBILE_METRO_PORT=8081
|
||||
|
||||
# Infraestructura
|
||||
DB_PORT=5432
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=8 # Database number dentro de instancia compartida
|
||||
|
||||
# Desarrollo (opcionales)
|
||||
MAILHOG_SMTP_PORT=1025
|
||||
MAILHOG_WEB_PORT=8025
|
||||
|
||||
# =============================================================================
|
||||
250
.github/workflows/ci.yml
vendored
Normal file
250
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,250 @@
|
||||
# =============================================================================
|
||||
# MiChangarrito - CI/CD Pipeline
|
||||
# =============================================================================
|
||||
# Triggers: Push to main/develop, Pull Requests
|
||||
# =============================================================================
|
||||
|
||||
name: CI/CD Pipeline
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main, develop]
|
||||
pull_request:
|
||||
branches: [main, develop]
|
||||
|
||||
env:
|
||||
NODE_VERSION: '20'
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository }}
|
||||
|
||||
jobs:
|
||||
# ===========================================================================
|
||||
# BACKEND - Lint, Test, Build
|
||||
# ===========================================================================
|
||||
backend:
|
||||
name: Backend CI
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: apps/backend
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: apps/backend/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint
|
||||
|
||||
- name: Run tests
|
||||
run: npm run test -- --passWithNoTests
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: backend-dist
|
||||
path: apps/backend/dist
|
||||
retention-days: 1
|
||||
|
||||
# ===========================================================================
|
||||
# FRONTEND - Lint, Build
|
||||
# ===========================================================================
|
||||
frontend:
|
||||
name: Frontend CI
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: apps/frontend
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: apps/frontend/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint || true
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
env:
|
||||
VITE_API_URL: ${{ vars.VITE_API_URL || 'http://localhost:3141/api/v1' }}
|
||||
|
||||
- name: Upload build artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: frontend-dist
|
||||
path: apps/frontend/dist
|
||||
retention-days: 1
|
||||
|
||||
# ===========================================================================
|
||||
# WHATSAPP SERVICE - Lint, Build
|
||||
# ===========================================================================
|
||||
whatsapp-service:
|
||||
name: WhatsApp Service CI
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: apps/whatsapp-service
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: apps/whatsapp-service/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run linter
|
||||
run: npm run lint || true
|
||||
|
||||
- name: Build application
|
||||
run: npm run build
|
||||
|
||||
# ===========================================================================
|
||||
# MOBILE - Type Check
|
||||
# ===========================================================================
|
||||
mobile:
|
||||
name: Mobile CI
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: apps/mobile
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: apps/mobile/package-lock.json
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Type check
|
||||
run: npx tsc --noEmit
|
||||
|
||||
# ===========================================================================
|
||||
# DOCKER BUILD (only on main/develop push)
|
||||
# ===========================================================================
|
||||
docker-build:
|
||||
name: Docker Build
|
||||
runs-on: ubuntu-latest
|
||||
needs: [backend, frontend, whatsapp-service]
|
||||
if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/develop')
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
service: [backend, frontend, whatsapp-service]
|
||||
include:
|
||||
- service: backend
|
||||
context: ./apps/backend
|
||||
dockerfile: ./apps/backend/Dockerfile
|
||||
- service: frontend
|
||||
context: ./apps/frontend
|
||||
dockerfile: ./apps/frontend/Dockerfile
|
||||
- service: whatsapp-service
|
||||
context: ./apps/whatsapp-service
|
||||
dockerfile: ./apps/whatsapp-service/Dockerfile
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Log in to Container Registry
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}-${{ matrix.service }}
|
||||
tags: |
|
||||
type=ref,event=branch
|
||||
type=sha,prefix=
|
||||
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: ${{ matrix.context }}
|
||||
file: ${{ matrix.dockerfile }}
|
||||
push: true
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
target: production
|
||||
|
||||
# ===========================================================================
|
||||
# DEPLOY (only on main push)
|
||||
# ===========================================================================
|
||||
deploy:
|
||||
name: Deploy to Production
|
||||
runs-on: ubuntu-latest
|
||||
needs: [docker-build]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
environment: production
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Deploy to server
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
with:
|
||||
host: ${{ secrets.SERVER_HOST }}
|
||||
username: ${{ secrets.SERVER_USER }}
|
||||
key: ${{ secrets.SERVER_SSH_KEY }}
|
||||
script: |
|
||||
cd /opt/michangarrito
|
||||
docker-compose pull
|
||||
docker-compose up -d --remove-orphans
|
||||
docker system prune -f
|
||||
|
||||
- name: Notify deployment
|
||||
if: success()
|
||||
run: |
|
||||
echo "Deployment successful!"
|
||||
# Add Slack/Discord notification here if needed
|
||||
119
README.md
Normal file
119
README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# MiChangarrito - Plataforma POS Multi-tenant
|
||||
|
||||
**Version:** 0.1.0
|
||||
**Estado:** Desarrollo
|
||||
**Tipo:** STANDALONE (SaaS)
|
||||
**Sistema:** SIMCO + NEXUS v3.4
|
||||
|
||||
---
|
||||
|
||||
## Descripcion
|
||||
|
||||
Plataforma de punto de venta (POS) para tiendas pequenas y medianas en Mexico. Sistema multi-tenant con soporte para multiples canales: app movil, web, WhatsApp y asistente IA.
|
||||
|
||||
### Funcionalidades Principales
|
||||
|
||||
- Punto de venta rapido y facil
|
||||
- Gestion de productos e inventario
|
||||
- Control de clientes y fiados
|
||||
- Pedidos y ordenes
|
||||
- Integracion WhatsApp Business
|
||||
- Asistente IA para ventas
|
||||
- Reportes y analytics
|
||||
- Pagos: Stripe, MercadoPago, Clip, CoDi, SPEI
|
||||
|
||||
---
|
||||
|
||||
## Stack Tecnologico
|
||||
|
||||
| Capa | Tecnologia |
|
||||
|------|------------|
|
||||
| Backend | NestJS + TypeScript |
|
||||
| Frontend Web | React + Vite |
|
||||
| Mobile | React Native |
|
||||
| Database | PostgreSQL 16+ con RLS (Multi-tenant) |
|
||||
| Cache | Redis |
|
||||
| AI/LLM | OpenRouter, OpenAI, Claude, Ollama |
|
||||
| WhatsApp | Meta Business API |
|
||||
| Payments | Stripe, MercadoPago, Clip |
|
||||
|
||||
---
|
||||
|
||||
## Estructura del Proyecto
|
||||
|
||||
```
|
||||
michangarrito/
|
||||
├── apps/
|
||||
│ ├── backend/ # API NestJS
|
||||
│ ├── frontend/ # Web React
|
||||
│ ├── mobile/ # React Native
|
||||
│ ├── web/ # Landing page
|
||||
│ ├── mcp-server/ # Servidor MCP para LLM
|
||||
│ └── whatsapp-service/ # Integracion WhatsApp
|
||||
├── database/
|
||||
│ ├── schemas/ # DDL
|
||||
│ └── seeds/ # Datos iniciales
|
||||
├── docs/
|
||||
│ ├── 00-vision-general/
|
||||
│ ├── 01-epicas/
|
||||
│ ├── 02-especificaciones/
|
||||
│ └── 90-transversal/
|
||||
└── orchestration/
|
||||
├── 00-guidelines/
|
||||
├── inventarios/
|
||||
├── environment/
|
||||
└── trazas/
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Modulos Principales
|
||||
|
||||
1. **Auth** - Autenticacion y autorizacion
|
||||
2. **Tenants** - Multi-tenancy
|
||||
3. **Products** - Catalogo de productos
|
||||
4. **Inventory** - Control de inventario
|
||||
5. **Sales** - Punto de venta
|
||||
6. **Customers** - Clientes y fiados
|
||||
7. **Orders** - Pedidos
|
||||
8. **Reports** - Reportes y analytics
|
||||
9. **Subscriptions** - Planes y suscripciones
|
||||
10. **Payments** - Integracion de pagos
|
||||
|
||||
---
|
||||
|
||||
## Inicio Rapido
|
||||
|
||||
```bash
|
||||
# Backend
|
||||
cd apps/backend && npm install && npm run start:dev
|
||||
|
||||
# Frontend
|
||||
cd apps/frontend && npm install && npm run dev
|
||||
|
||||
# MCP Server
|
||||
cd apps/mcp-server && npm install && npm run start
|
||||
|
||||
# WhatsApp Service
|
||||
cd apps/whatsapp-service && npm install && npm run start
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Variables de Entorno
|
||||
|
||||
Ver `.env.example` para la configuracion requerida.
|
||||
|
||||
---
|
||||
|
||||
## Referencias
|
||||
|
||||
- Vision: `docs/00-vision-general/VISION-PROYECTO.md`
|
||||
- Arquitectura: `docs/00-vision-general/ARQUITECTURA-TECNICA.md`
|
||||
- Requerimientos: `docs/00-vision-general/REQUERIMIENTOS-FUNCIONALES.md`
|
||||
- Contexto: `orchestration/00-guidelines/`
|
||||
|
||||
---
|
||||
|
||||
**Creado:** 2026-01-04
|
||||
**Actualizado:** 2026-01-07
|
||||
41
apps/backend/.dockerignore
Normal file
41
apps/backend/.dockerignore
Normal file
@ -0,0 +1,41 @@
|
||||
# Dependencies
|
||||
node_modules
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Build output
|
||||
dist
|
||||
|
||||
# IDE
|
||||
.idea
|
||||
.vscode
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# Testing
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Docker
|
||||
Dockerfile
|
||||
docker-compose*.yml
|
||||
.dockerignore
|
||||
|
||||
# Documentation
|
||||
README.md
|
||||
docs
|
||||
|
||||
# Tests
|
||||
test
|
||||
*.spec.ts
|
||||
*.test.ts
|
||||
jest.config.js
|
||||
33
apps/backend/.env
Normal file
33
apps/backend/.env
Normal file
@ -0,0 +1,33 @@
|
||||
# MiChangarrito Backend - Environment Variables
|
||||
NODE_ENV=development
|
||||
|
||||
# Server
|
||||
PORT=3141
|
||||
API_PREFIX=api/v1
|
||||
|
||||
# Database
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USERNAME=michangarrito_dev
|
||||
DB_PASSWORD=MCh_dev_2025_secure
|
||||
DB_DATABASE=michangarrito_dev
|
||||
DB_SCHEMA=public
|
||||
|
||||
# JWT
|
||||
JWT_SECRET=MCh_jwt_dev_2025_AcB7x9KmPq2sWfHg4jL8nRt0vYzXw1CdEiFoGhJkLmN3pQrSuVxY5bZ6aBeC8fDg
|
||||
JWT_EXPIRES_IN=7d
|
||||
|
||||
# CORS
|
||||
CORS_ORIGIN=http://localhost:3140
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL=debug
|
||||
|
||||
# Stripe (Monetization)
|
||||
STRIPE_SECRET_KEY=
|
||||
STRIPE_WEBHOOK_SECRET=
|
||||
STRIPE_PUBLISHABLE_KEY=
|
||||
|
||||
# LLM / AI (for token consumption)
|
||||
OPENAI_API_KEY=
|
||||
LLM_MODEL=gpt-4o-mini
|
||||
89
apps/backend/Dockerfile
Normal file
89
apps/backend/Dockerfile
Normal file
@ -0,0 +1,89 @@
|
||||
# =============================================================================
|
||||
# MiChangarrito - Backend Dockerfile
|
||||
# =============================================================================
|
||||
# Multi-stage build for NestJS application
|
||||
# Puerto: 3141
|
||||
# =============================================================================
|
||||
|
||||
# Build stage
|
||||
FROM node:20-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Build application
|
||||
RUN npm run build
|
||||
|
||||
# Production stage
|
||||
FROM node:20-alpine AS production
|
||||
|
||||
# Labels
|
||||
LABEL maintainer="ISEM"
|
||||
LABEL description="MiChangarrito Backend API"
|
||||
LABEL version="1.0.0"
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install only production dependencies
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/dist ./dist
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup -g 1001 -S nodejs && \
|
||||
adduser -S nestjs -u 1001 -G nodejs
|
||||
|
||||
# Set ownership
|
||||
RUN chown -R nestjs:nodejs /app
|
||||
|
||||
USER nestjs
|
||||
|
||||
# Environment
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3141
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3141
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=40s --retries=3 \
|
||||
CMD wget --no-verbose --tries=1 --spider http://localhost:3141/api/v1/health || exit 1
|
||||
|
||||
# Start application
|
||||
CMD ["node", "dist/main"]
|
||||
|
||||
# Development stage
|
||||
FROM node:20-alpine AS development
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY package*.json ./
|
||||
|
||||
# Install all dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code
|
||||
COPY . .
|
||||
|
||||
# Environment
|
||||
ENV NODE_ENV=development
|
||||
ENV PORT=3141
|
||||
|
||||
# Expose port
|
||||
EXPOSE 3141
|
||||
|
||||
# Start in development mode
|
||||
CMD ["npm", "run", "start:dev"]
|
||||
2
apps/backend/dist/app.module.d.ts
vendored
Normal file
2
apps/backend/dist/app.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class AppModule {
|
||||
}
|
||||
77
apps/backend/dist/app.module.js
vendored
Normal file
77
apps/backend/dist/app.module.js
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AppModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const auth_module_1 = require("./modules/auth/auth.module");
|
||||
const products_module_1 = require("./modules/products/products.module");
|
||||
const categories_module_1 = require("./modules/categories/categories.module");
|
||||
const sales_module_1 = require("./modules/sales/sales.module");
|
||||
const payments_module_1 = require("./modules/payments/payments.module");
|
||||
const customers_module_1 = require("./modules/customers/customers.module");
|
||||
const inventory_module_1 = require("./modules/inventory/inventory.module");
|
||||
const orders_module_1 = require("./modules/orders/orders.module");
|
||||
const subscriptions_module_1 = require("./modules/subscriptions/subscriptions.module");
|
||||
const messaging_module_1 = require("./modules/messaging/messaging.module");
|
||||
const billing_module_1 = require("./modules/billing/billing.module");
|
||||
const integrations_module_1 = require("./modules/integrations/integrations.module");
|
||||
const referrals_module_1 = require("./modules/referrals/referrals.module");
|
||||
const codi_spei_module_1 = require("./modules/codi-spei/codi-spei.module");
|
||||
const widgets_module_1 = require("./modules/widgets/widgets.module");
|
||||
const invoices_module_1 = require("./modules/invoices/invoices.module");
|
||||
const marketplace_module_1 = require("./modules/marketplace/marketplace.module");
|
||||
let AppModule = class AppModule {
|
||||
};
|
||||
exports.AppModule = AppModule;
|
||||
exports.AppModule = AppModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
config_1.ConfigModule.forRoot({
|
||||
isGlobal: true,
|
||||
envFilePath: ['.env.local', '.env'],
|
||||
}),
|
||||
typeorm_1.TypeOrmModule.forRootAsync({
|
||||
imports: [config_1.ConfigModule],
|
||||
inject: [config_1.ConfigService],
|
||||
useFactory: (configService) => ({
|
||||
type: 'postgres',
|
||||
host: configService.get('DB_HOST', 'localhost'),
|
||||
port: configService.get('DB_PORT', 5432),
|
||||
username: configService.get('DB_USERNAME', 'michangarrito_dev'),
|
||||
password: configService.get('DB_PASSWORD', 'MCh_dev_2025_secure'),
|
||||
database: configService.get('DB_DATABASE', 'michangarrito_dev'),
|
||||
schema: configService.get('DB_SCHEMA', 'public'),
|
||||
autoLoadEntities: true,
|
||||
synchronize: false,
|
||||
logging: configService.get('NODE_ENV') === 'development',
|
||||
ssl: configService.get('DB_SSL') === 'true' ? { rejectUnauthorized: false } : false,
|
||||
}),
|
||||
}),
|
||||
auth_module_1.AuthModule,
|
||||
products_module_1.ProductsModule,
|
||||
categories_module_1.CategoriesModule,
|
||||
sales_module_1.SalesModule,
|
||||
payments_module_1.PaymentsModule,
|
||||
customers_module_1.CustomersModule,
|
||||
inventory_module_1.InventoryModule,
|
||||
orders_module_1.OrdersModule,
|
||||
subscriptions_module_1.SubscriptionsModule,
|
||||
messaging_module_1.MessagingModule,
|
||||
billing_module_1.BillingModule,
|
||||
integrations_module_1.IntegrationsModule,
|
||||
referrals_module_1.ReferralsModule,
|
||||
codi_spei_module_1.CodiSpeiModule,
|
||||
widgets_module_1.WidgetsModule,
|
||||
invoices_module_1.InvoicesModule,
|
||||
marketplace_module_1.MarketplaceModule,
|
||||
],
|
||||
})
|
||||
], AppModule);
|
||||
//# sourceMappingURL=app.module.js.map
|
||||
1
apps/backend/dist/app.module.js.map
vendored
Normal file
1
apps/backend/dist/app.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"app.module.js","sourceRoot":"","sources":["../src/app.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA6D;AAC7D,6CAAgD;AAChD,4DAAwD;AACxD,wEAAoE;AACpE,8EAA0E;AAC1E,+DAA2D;AAC3D,wEAAoE;AACpE,2EAAuE;AACvE,2EAAuE;AACvE,kEAA8D;AAC9D,uFAAmF;AACnF,2EAAuE;AACvE,qEAAiE;AACjE,oFAAgF;AAChF,2EAAuE;AACvE,2EAAsE;AACtE,qEAAiE;AACjE,wEAAoE;AACpE,iFAA6E;AAiDtE,IAAM,SAAS,GAAf,MAAM,SAAS;CAAG,CAAA;AAAZ,8BAAS;oBAAT,SAAS;IA/CrB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YAEP,qBAAY,CAAC,OAAO,CAAC;gBACnB,QAAQ,EAAE,IAAI;gBACd,WAAW,EAAE,CAAC,YAAY,EAAE,MAAM,CAAC;aACpC,CAAC;YAGF,uBAAa,CAAC,YAAY,CAAC;gBACzB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,aAA4B,EAAE,EAAE,CAAC,CAAC;oBAC7C,IAAI,EAAE,UAAU;oBAChB,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,CAAC;oBAC/C,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC;oBACxC,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,mBAAmB,CAAC;oBAC/D,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,qBAAqB,CAAC;oBACjE,QAAQ,EAAE,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,mBAAmB,CAAC;oBAC/D,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC;oBAChD,gBAAgB,EAAE,IAAI;oBACtB,WAAW,EAAE,KAAK;oBAClB,OAAO,EAAE,aAAa,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,aAAa;oBACxD,GAAG,EAAE,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK;iBACpF,CAAC;aACH,CAAC;YAGF,wBAAU;YACV,gCAAc;YACd,oCAAgB;YAChB,0BAAW;YACX,gCAAc;YACd,kCAAe;YACf,kCAAe;YACf,4BAAY;YACZ,0CAAmB;YACnB,kCAAe;YACf,8BAAa;YACb,wCAAkB;YAClB,kCAAe;YACf,iCAAc;YACd,8BAAa;YACb,gCAAc;YACd,sCAAiB;SAClB;KACF,CAAC;GACW,SAAS,CAAG"}
|
||||
1
apps/backend/dist/main.d.ts
vendored
Normal file
1
apps/backend/dist/main.d.ts
vendored
Normal file
@ -0,0 +1 @@
|
||||
export {};
|
||||
64
apps/backend/dist/main.js
vendored
Normal file
64
apps/backend/dist/main.js
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const core_1 = require("@nestjs/core");
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const helmet_1 = require("helmet");
|
||||
const app_module_1 = require("./app.module");
|
||||
async function bootstrap() {
|
||||
const app = await core_1.NestFactory.create(app_module_1.AppModule);
|
||||
const configService = app.get(config_1.ConfigService);
|
||||
app.use((0, helmet_1.default)());
|
||||
app.enableCors({
|
||||
origin: configService.get('CORS_ORIGIN', 'http://localhost:3140'),
|
||||
credentials: true,
|
||||
});
|
||||
app.setGlobalPrefix('api');
|
||||
app.useGlobalPipes(new common_1.ValidationPipe({
|
||||
whitelist: true,
|
||||
forbidNonWhitelisted: true,
|
||||
transform: true,
|
||||
transformOptions: {
|
||||
enableImplicitConversion: true,
|
||||
},
|
||||
}));
|
||||
const config = new swagger_1.DocumentBuilder()
|
||||
.setTitle('MiChangarrito API')
|
||||
.setDescription('POS inteligente para micro-negocios con integración WhatsApp y LLM. Target: Changarros, tienditas, fondas.')
|
||||
.setVersion('1.0')
|
||||
.addBearerAuth()
|
||||
.addTag('auth', 'Autenticación y registro')
|
||||
.addTag('products', 'Gestión de productos')
|
||||
.addTag('categories', 'Categorías de productos')
|
||||
.addTag('sales', 'Ventas y tickets')
|
||||
.addTag('inventory', 'Control de inventario')
|
||||
.addTag('customers', 'Clientes y fiados')
|
||||
.addTag('orders', 'Pedidos por WhatsApp')
|
||||
.addTag('payments', 'Métodos de pago')
|
||||
.addTag('subscriptions', 'Planes y tokens')
|
||||
.addTag('messaging', 'WhatsApp y notificaciones')
|
||||
.addTag('reports', 'Reportes y analytics')
|
||||
.build();
|
||||
const document = swagger_1.SwaggerModule.createDocument(app, config);
|
||||
swagger_1.SwaggerModule.setup('docs', app, document, {
|
||||
swaggerOptions: {
|
||||
persistAuthorization: true,
|
||||
},
|
||||
});
|
||||
const port = configService.get('PORT', 3000);
|
||||
await app.listen(port);
|
||||
console.log(`
|
||||
╔══════════════════════════════════════════════════════════════╗
|
||||
║ MICHANGARRITO API ║
|
||||
║ POS Inteligente para Micro-Negocios ║
|
||||
╠══════════════════════════════════════════════════════════════╣
|
||||
║ Status: Running ║
|
||||
║ Port: ${port} ║
|
||||
║ Environment: ${configService.get('NODE_ENV', 'development')} ║
|
||||
║ Docs: http://localhost:${port}/docs ║
|
||||
╚══════════════════════════════════════════════════════════════╝
|
||||
`);
|
||||
}
|
||||
bootstrap();
|
||||
//# sourceMappingURL=main.js.map
|
||||
1
apps/backend/dist/main.js.map
vendored
Normal file
1
apps/backend/dist/main.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";;AAAA,uCAA2C;AAC3C,2CAAgD;AAChD,2CAA+C;AAC/C,6CAAiE;AACjE,mCAA4B;AAC5B,6CAAyC;AAEzC,KAAK,UAAU,SAAS;IACtB,MAAM,GAAG,GAAG,MAAM,kBAAW,CAAC,MAAM,CAAC,sBAAS,CAAC,CAAC;IAChD,MAAM,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,sBAAa,CAAC,CAAC;IAG7C,GAAG,CAAC,GAAG,CAAC,IAAA,gBAAM,GAAE,CAAC,CAAC;IAGlB,GAAG,CAAC,UAAU,CAAC;QACb,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,aAAa,EAAE,uBAAuB,CAAC;QACjE,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAGH,GAAG,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAG3B,GAAG,CAAC,cAAc,CAChB,IAAI,uBAAc,CAAC;QACjB,SAAS,EAAE,IAAI;QACf,oBAAoB,EAAE,IAAI;QAC1B,SAAS,EAAE,IAAI;QACf,gBAAgB,EAAE;YAChB,wBAAwB,EAAE,IAAI;SAC/B;KACF,CAAC,CACH,CAAC;IAGF,MAAM,MAAM,GAAG,IAAI,yBAAe,EAAE;SACjC,QAAQ,CAAC,mBAAmB,CAAC;SAC7B,cAAc,CACb,4GAA4G,CAC7G;SACA,UAAU,CAAC,KAAK,CAAC;SACjB,aAAa,EAAE;SACf,MAAM,CAAC,MAAM,EAAE,0BAA0B,CAAC;SAC1C,MAAM,CAAC,UAAU,EAAE,sBAAsB,CAAC;SAC1C,MAAM,CAAC,YAAY,EAAE,yBAAyB,CAAC;SAC/C,MAAM,CAAC,OAAO,EAAE,kBAAkB,CAAC;SACnC,MAAM,CAAC,WAAW,EAAE,uBAAuB,CAAC;SAC5C,MAAM,CAAC,WAAW,EAAE,mBAAmB,CAAC;SACxC,MAAM,CAAC,QAAQ,EAAE,sBAAsB,CAAC;SACxC,MAAM,CAAC,UAAU,EAAE,iBAAiB,CAAC;SACrC,MAAM,CAAC,eAAe,EAAE,iBAAiB,CAAC;SAC1C,MAAM,CAAC,WAAW,EAAE,2BAA2B,CAAC;SAChD,MAAM,CAAC,SAAS,EAAE,sBAAsB,CAAC;SACzC,KAAK,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,uBAAa,CAAC,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC3D,uBAAa,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE;QACzC,cAAc,EAAE;YACd,oBAAoB,EAAE,IAAI;SAC3B;KACF,CAAC,CAAC;IAEH,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC7C,MAAM,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC;;;;;;kBAMI,IAAI;kBACJ,aAAa,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC;mCAC3B,IAAI;;GAEpC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,EAAE,CAAC"}
|
||||
19
apps/backend/dist/modules/auth/auth.controller.d.ts
vendored
Normal file
19
apps/backend/dist/modules/auth/auth.controller.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import { AuthService } from './auth.service';
|
||||
import { RegisterDto, LoginDto, RefreshTokenDto } from './dto/register.dto';
|
||||
export declare class AuthController {
|
||||
private readonly authService;
|
||||
constructor(authService: AuthService);
|
||||
register(dto: RegisterDto): Promise<import("./auth.service").AuthResponse>;
|
||||
login(dto: LoginDto): Promise<import("./auth.service").AuthResponse>;
|
||||
refreshToken(dto: RefreshTokenDto): Promise<import("./auth.service").AuthResponse>;
|
||||
changePin(req: {
|
||||
user: {
|
||||
sub: string;
|
||||
};
|
||||
}, body: {
|
||||
currentPin: string;
|
||||
newPin: string;
|
||||
}): Promise<{
|
||||
message: string;
|
||||
}>;
|
||||
}
|
||||
136
apps/backend/dist/modules/auth/auth.controller.js
vendored
Normal file
136
apps/backend/dist/modules/auth/auth.controller.js
vendored
Normal file
@ -0,0 +1,136 @@
|
||||
"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.AuthController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const auth_service_1 = require("./auth.service");
|
||||
const register_dto_1 = require("./dto/register.dto");
|
||||
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
|
||||
let AuthController = class AuthController {
|
||||
constructor(authService) {
|
||||
this.authService = authService;
|
||||
}
|
||||
async register(dto) {
|
||||
return this.authService.register(dto);
|
||||
}
|
||||
async login(dto) {
|
||||
return this.authService.login(dto);
|
||||
}
|
||||
async refreshToken(dto) {
|
||||
return this.authService.refreshToken(dto.refreshToken);
|
||||
}
|
||||
async changePin(req, body) {
|
||||
await this.authService.changePin(req.user.sub, body.currentPin, body.newPin);
|
||||
return { message: 'PIN cambiado exitosamente' };
|
||||
}
|
||||
};
|
||||
exports.AuthController = AuthController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('register'),
|
||||
(0, swagger_1.ApiOperation)({
|
||||
summary: 'Registrar nuevo negocio',
|
||||
description: 'Crea un nuevo tenant y usuario con periodo de prueba de 14 días',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({
|
||||
status: 201,
|
||||
description: 'Registro exitoso',
|
||||
schema: {
|
||||
properties: {
|
||||
accessToken: { type: 'string' },
|
||||
refreshToken: { type: 'string' },
|
||||
user: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
name: { type: 'string' },
|
||||
isOwner: { type: 'boolean' },
|
||||
},
|
||||
},
|
||||
tenant: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'string' },
|
||||
businessName: { type: 'string' },
|
||||
plan: { type: 'string' },
|
||||
subscriptionStatus: { type: 'string' },
|
||||
trialEndsAt: { type: 'string', format: 'date-time' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({ status: 409, description: 'Teléfono ya registrado' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [register_dto_1.RegisterDto]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], AuthController.prototype, "register", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('login'),
|
||||
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
|
||||
(0, swagger_1.ApiOperation)({
|
||||
summary: 'Iniciar sesión',
|
||||
description: 'Autenticación con teléfono y PIN',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({
|
||||
status: 200,
|
||||
description: 'Login exitoso',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({ status: 401, description: 'Credenciales inválidas' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [register_dto_1.LoginDto]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], AuthController.prototype, "login", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('refresh'),
|
||||
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
|
||||
(0, swagger_1.ApiOperation)({
|
||||
summary: 'Refrescar token',
|
||||
description: 'Obtiene un nuevo access token usando el refresh token',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({
|
||||
status: 200,
|
||||
description: 'Token refrescado exitosamente',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({ status: 401, description: 'Token inválido o expirado' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [register_dto_1.RefreshTokenDto]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], AuthController.prototype, "refreshToken", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('change-pin'),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.HttpCode)(common_1.HttpStatus.OK),
|
||||
(0, swagger_1.ApiOperation)({
|
||||
summary: 'Cambiar PIN',
|
||||
description: 'Cambiar el PIN de acceso',
|
||||
}),
|
||||
(0, swagger_1.ApiResponse)({ status: 200, description: 'PIN cambiado exitosamente' }),
|
||||
(0, swagger_1.ApiResponse)({ status: 401, description: 'PIN actual incorrecto' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], AuthController.prototype, "changePin", null);
|
||||
exports.AuthController = AuthController = __decorate([
|
||||
(0, swagger_1.ApiTags)('auth'),
|
||||
(0, common_1.Controller)('v1/auth'),
|
||||
__metadata("design:paramtypes", [auth_service_1.AuthService])
|
||||
], AuthController);
|
||||
//# sourceMappingURL=auth.controller.js.map
|
||||
1
apps/backend/dist/modules/auth/auth.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/auth.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.controller.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.controller.ts"],"names":[],"mappings":"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"}
|
||||
2
apps/backend/dist/modules/auth/auth.module.d.ts
vendored
Normal file
2
apps/backend/dist/modules/auth/auth.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class AuthModule {
|
||||
}
|
||||
45
apps/backend/dist/modules/auth/auth.module.js
vendored
Normal file
45
apps/backend/dist/modules/auth/auth.module.js
vendored
Normal file
@ -0,0 +1,45 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.AuthModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const jwt_1 = require("@nestjs/jwt");
|
||||
const passport_1 = require("@nestjs/passport");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const auth_controller_1 = require("./auth.controller");
|
||||
const auth_service_1 = require("./auth.service");
|
||||
const tenant_entity_1 = require("./entities/tenant.entity");
|
||||
const user_entity_1 = require("./entities/user.entity");
|
||||
const jwt_strategy_1 = require("./strategies/jwt.strategy");
|
||||
const jwt_auth_guard_1 = require("./guards/jwt-auth.guard");
|
||||
let AuthModule = class AuthModule {
|
||||
};
|
||||
exports.AuthModule = AuthModule;
|
||||
exports.AuthModule = AuthModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
typeorm_1.TypeOrmModule.forFeature([tenant_entity_1.Tenant, user_entity_1.User]),
|
||||
passport_1.PassportModule.register({ defaultStrategy: 'jwt' }),
|
||||
jwt_1.JwtModule.registerAsync({
|
||||
imports: [config_1.ConfigModule],
|
||||
inject: [config_1.ConfigService],
|
||||
useFactory: (configService) => ({
|
||||
secret: configService.get('JWT_SECRET'),
|
||||
signOptions: {
|
||||
expiresIn: configService.get('JWT_EXPIRES_IN', '24h'),
|
||||
},
|
||||
}),
|
||||
}),
|
||||
],
|
||||
controllers: [auth_controller_1.AuthController],
|
||||
providers: [auth_service_1.AuthService, jwt_strategy_1.JwtStrategy, jwt_auth_guard_1.JwtAuthGuard],
|
||||
exports: [auth_service_1.AuthService, jwt_auth_guard_1.JwtAuthGuard, typeorm_1.TypeOrmModule],
|
||||
})
|
||||
], AuthModule);
|
||||
//# sourceMappingURL=auth.module.js.map
|
||||
1
apps/backend/dist/modules/auth/auth.module.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/auth.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"auth.module.js","sourceRoot":"","sources":["../../../src/modules/auth/auth.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,qCAAwC;AACxC,+CAAkD;AAClD,2CAA6D;AAC7D,uDAAmD;AACnD,iDAA6C;AAC7C,4DAAkD;AAClD,wDAA8C;AAC9C,4DAAwD;AACxD,4DAAuD;AAqBhD,IAAM,UAAU,GAAhB,MAAM,UAAU;CAAG,CAAA;AAAb,gCAAU;qBAAV,UAAU;IAnBtB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,sBAAM,EAAE,kBAAI,CAAC,CAAC;YACxC,yBAAc,CAAC,QAAQ,CAAC,EAAE,eAAe,EAAE,KAAK,EAAE,CAAC;YACnD,eAAS,CAAC,aAAa,CAAC;gBACtB,OAAO,EAAE,CAAC,qBAAY,CAAC;gBACvB,MAAM,EAAE,CAAC,sBAAa,CAAC;gBACvB,UAAU,EAAE,CAAC,aAA4B,EAAE,EAAE,CAAC,CAAC;oBAC7C,MAAM,EAAE,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC;oBACvC,WAAW,EAAE;wBACX,SAAS,EAAE,aAAa,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,CAAC;qBACtD;iBACF,CAAC;aACH,CAAC;SACH;QACD,WAAW,EAAE,CAAC,gCAAc,CAAC;QAC7B,SAAS,EAAE,CAAC,0BAAW,EAAE,0BAAW,EAAE,6BAAY,CAAC;QACnD,OAAO,EAAE,CAAC,0BAAW,EAAE,6BAAY,EAAE,uBAAa,CAAC;KACpD,CAAC;GACW,UAAU,CAAG"}
|
||||
42
apps/backend/dist/modules/auth/auth.service.d.ts
vendored
Normal file
42
apps/backend/dist/modules/auth/auth.service.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Tenant } from './entities/tenant.entity';
|
||||
import { User } from './entities/user.entity';
|
||||
import { RegisterDto, LoginDto } from './dto/register.dto';
|
||||
export interface TokenPayload {
|
||||
sub: string;
|
||||
tenantId: string;
|
||||
phone: string;
|
||||
role: string;
|
||||
}
|
||||
export interface AuthResponse {
|
||||
accessToken: string;
|
||||
refreshToken: string;
|
||||
user: {
|
||||
id: string;
|
||||
name: string;
|
||||
role: string;
|
||||
phone: string;
|
||||
};
|
||||
tenant: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
businessType: string;
|
||||
subscriptionStatus: string;
|
||||
};
|
||||
}
|
||||
export declare class AuthService {
|
||||
private readonly tenantRepository;
|
||||
private readonly userRepository;
|
||||
private readonly jwtService;
|
||||
private readonly configService;
|
||||
constructor(tenantRepository: Repository<Tenant>, userRepository: Repository<User>, jwtService: JwtService, configService: ConfigService);
|
||||
private generateSlug;
|
||||
register(dto: RegisterDto): Promise<AuthResponse>;
|
||||
login(dto: LoginDto): Promise<AuthResponse>;
|
||||
refreshToken(refreshToken: string): Promise<AuthResponse>;
|
||||
changePin(userId: string, currentPin: string, newPin: string): Promise<void>;
|
||||
private generateTokens;
|
||||
}
|
||||
192
apps/backend/dist/modules/auth/auth.service.js
vendored
Normal file
192
apps/backend/dist/modules/auth/auth.service.js
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
"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.AuthService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const jwt_1 = require("@nestjs/jwt");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const bcrypt = require("bcrypt");
|
||||
const tenant_entity_1 = require("./entities/tenant.entity");
|
||||
const user_entity_1 = require("./entities/user.entity");
|
||||
let AuthService = class AuthService {
|
||||
constructor(tenantRepository, userRepository, jwtService, configService) {
|
||||
this.tenantRepository = tenantRepository;
|
||||
this.userRepository = userRepository;
|
||||
this.jwtService = jwtService;
|
||||
this.configService = configService;
|
||||
}
|
||||
generateSlug(name) {
|
||||
return name
|
||||
.toLowerCase()
|
||||
.normalize('NFD')
|
||||
.replace(/[\u0300-\u036f]/g, '')
|
||||
.replace(/[^a-z0-9]+/g, '-')
|
||||
.replace(/(^-|-$)/g, '')
|
||||
.substring(0, 45) + '-' + Date.now().toString(36).slice(-4);
|
||||
}
|
||||
async register(dto) {
|
||||
const existingTenant = await this.tenantRepository.findOne({
|
||||
where: { phone: dto.phone },
|
||||
});
|
||||
if (existingTenant) {
|
||||
throw new common_1.ConflictException('Este teléfono ya está registrado');
|
||||
}
|
||||
const pinHash = await bcrypt.hash(dto.pin, 10);
|
||||
const slug = this.generateSlug(dto.name);
|
||||
const tenant = this.tenantRepository.create({
|
||||
name: dto.name,
|
||||
slug,
|
||||
businessType: dto.businessType,
|
||||
phone: dto.phone,
|
||||
email: dto.email,
|
||||
address: dto.address,
|
||||
city: dto.city,
|
||||
whatsappNumber: dto.whatsapp || dto.phone,
|
||||
subscriptionStatus: 'trial',
|
||||
status: 'active',
|
||||
});
|
||||
const savedTenant = await this.tenantRepository.save(tenant);
|
||||
const user = this.userRepository.create({
|
||||
tenantId: savedTenant.id,
|
||||
phone: dto.phone,
|
||||
name: dto.ownerName,
|
||||
pinHash,
|
||||
role: 'owner',
|
||||
status: 'active',
|
||||
});
|
||||
const savedUser = await this.userRepository.save(user);
|
||||
return this.generateTokens(savedUser, savedTenant);
|
||||
}
|
||||
async login(dto) {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: { phone: dto.phone },
|
||||
});
|
||||
if (!user) {
|
||||
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
|
||||
}
|
||||
const tenant = await this.tenantRepository.findOne({
|
||||
where: { id: user.tenantId },
|
||||
});
|
||||
if (!tenant) {
|
||||
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
|
||||
}
|
||||
if (tenant.subscriptionStatus === 'cancelled') {
|
||||
throw new common_1.UnauthorizedException('Tu suscripción ha sido cancelada');
|
||||
}
|
||||
if (tenant.subscriptionStatus === 'suspended' || tenant.status === 'suspended') {
|
||||
throw new common_1.UnauthorizedException('Tu cuenta está suspendida. Contacta soporte.');
|
||||
}
|
||||
if (user.status !== 'active') {
|
||||
throw new common_1.UnauthorizedException('Tu cuenta está inactiva');
|
||||
}
|
||||
if (user.lockedUntil && user.lockedUntil > new Date()) {
|
||||
throw new common_1.UnauthorizedException('Cuenta bloqueada temporalmente. Intenta más tarde.');
|
||||
}
|
||||
const isValidPin = await bcrypt.compare(dto.pin, user.pinHash);
|
||||
if (!isValidPin) {
|
||||
user.failedAttempts = (user.failedAttempts || 0) + 1;
|
||||
if (user.failedAttempts >= 5) {
|
||||
user.lockedUntil = new Date(Date.now() + 15 * 60 * 1000);
|
||||
}
|
||||
await this.userRepository.save(user);
|
||||
throw new common_1.UnauthorizedException('Teléfono o PIN incorrectos');
|
||||
}
|
||||
user.failedAttempts = 0;
|
||||
user.lockedUntil = null;
|
||||
user.lastLoginAt = new Date();
|
||||
await this.userRepository.save(user);
|
||||
return this.generateTokens(user, tenant);
|
||||
}
|
||||
async refreshToken(refreshToken) {
|
||||
try {
|
||||
const payload = this.jwtService.verify(refreshToken, {
|
||||
secret: this.configService.get('JWT_SECRET'),
|
||||
});
|
||||
const user = await this.userRepository.findOne({
|
||||
where: { id: payload.sub },
|
||||
});
|
||||
if (!user) {
|
||||
throw new common_1.UnauthorizedException('Token inválido');
|
||||
}
|
||||
const tenant = await this.tenantRepository.findOne({
|
||||
where: { id: user.tenantId },
|
||||
});
|
||||
if (!tenant) {
|
||||
throw new common_1.UnauthorizedException('Token inválido');
|
||||
}
|
||||
return this.generateTokens(user, tenant);
|
||||
}
|
||||
catch {
|
||||
throw new common_1.UnauthorizedException('Token inválido o expirado');
|
||||
}
|
||||
}
|
||||
async changePin(userId, currentPin, newPin) {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: { id: userId },
|
||||
});
|
||||
if (!user) {
|
||||
throw new common_1.BadRequestException('Usuario no encontrado');
|
||||
}
|
||||
const isValidPin = await bcrypt.compare(currentPin, user.pinHash);
|
||||
if (!isValidPin) {
|
||||
throw new common_1.UnauthorizedException('PIN actual incorrecto');
|
||||
}
|
||||
user.pinHash = await bcrypt.hash(newPin, 10);
|
||||
await this.userRepository.save(user);
|
||||
}
|
||||
generateTokens(user, tenant) {
|
||||
const payload = {
|
||||
sub: user.id,
|
||||
tenantId: tenant.id,
|
||||
phone: user.phone,
|
||||
role: user.role,
|
||||
};
|
||||
const accessToken = this.jwtService.sign(payload, {
|
||||
expiresIn: this.configService.get('JWT_EXPIRES_IN', '24h'),
|
||||
});
|
||||
const refreshToken = this.jwtService.sign(payload, {
|
||||
expiresIn: this.configService.get('JWT_REFRESH_EXPIRES_IN', '7d'),
|
||||
});
|
||||
return {
|
||||
accessToken,
|
||||
refreshToken,
|
||||
user: {
|
||||
id: user.id,
|
||||
name: user.name,
|
||||
role: user.role,
|
||||
phone: user.phone,
|
||||
},
|
||||
tenant: {
|
||||
id: tenant.id,
|
||||
name: tenant.name,
|
||||
slug: tenant.slug,
|
||||
businessType: tenant.businessType,
|
||||
subscriptionStatus: tenant.subscriptionStatus,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.AuthService = AuthService;
|
||||
exports.AuthService = AuthService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(tenant_entity_1.Tenant)),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
jwt_1.JwtService,
|
||||
config_1.ConfigService])
|
||||
], AuthService);
|
||||
//# sourceMappingURL=auth.service.js.map
|
||||
1
apps/backend/dist/modules/auth/auth.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/auth.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
18
apps/backend/dist/modules/auth/dto/register.dto.d.ts
vendored
Normal file
18
apps/backend/dist/modules/auth/dto/register.dto.d.ts
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
export declare class RegisterDto {
|
||||
name: string;
|
||||
ownerName: string;
|
||||
businessType: string;
|
||||
phone: string;
|
||||
pin: string;
|
||||
whatsapp?: string;
|
||||
email?: string;
|
||||
address?: string;
|
||||
city?: string;
|
||||
}
|
||||
export declare class LoginDto {
|
||||
phone: string;
|
||||
pin: string;
|
||||
}
|
||||
export declare class RefreshTokenDto {
|
||||
refreshToken: string;
|
||||
}
|
||||
164
apps/backend/dist/modules/auth/dto/register.dto.js
vendored
Normal file
164
apps/backend/dist/modules/auth/dto/register.dto.js
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.RefreshTokenDto = exports.LoginDto = exports.RegisterDto = void 0;
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const class_validator_1 = require("class-validator");
|
||||
class RegisterDto {
|
||||
}
|
||||
exports.RegisterDto = RegisterDto;
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Nombre del negocio',
|
||||
example: 'Tacos El Güero',
|
||||
minLength: 2,
|
||||
maxLength: 100,
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.MinLength)(2),
|
||||
(0, class_validator_1.MaxLength)(100),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Nombre del propietario',
|
||||
example: 'Juan Pérez',
|
||||
minLength: 2,
|
||||
maxLength: 100,
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.MinLength)(2),
|
||||
(0, class_validator_1.MaxLength)(100),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "ownerName", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Tipo de negocio',
|
||||
example: 'tiendita',
|
||||
enum: ['tiendita', 'fonda', 'taqueria', 'abarrotes', 'tortilleria', 'otro'],
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "businessType", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Teléfono (10 dígitos)',
|
||||
example: '5512345678',
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.Matches)(/^[0-9]{10}$/, {
|
||||
message: 'El teléfono debe tener exactamente 10 dígitos',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "phone", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'PIN de acceso rápido (4-6 dígitos)',
|
||||
example: '1234',
|
||||
minLength: 4,
|
||||
maxLength: 6,
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.Matches)(/^[0-9]{4,6}$/, {
|
||||
message: 'El PIN debe tener entre 4 y 6 dígitos',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "pin", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Número de WhatsApp (opcional)',
|
||||
example: '5512345678',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.Matches)(/^[0-9]{10}$/, {
|
||||
message: 'El WhatsApp debe tener exactamente 10 dígitos',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "whatsapp", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Email (opcional)',
|
||||
example: 'juan@ejemplo.com',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsEmail)({}, { message: 'Email inválido' }),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "email", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Dirección del negocio (opcional)',
|
||||
example: 'Calle Principal #123, Colonia Centro',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(500),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "address", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Ciudad (opcional)',
|
||||
example: 'Ciudad de México',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], RegisterDto.prototype, "city", void 0);
|
||||
class LoginDto {
|
||||
}
|
||||
exports.LoginDto = LoginDto;
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Teléfono registrado',
|
||||
example: '5512345678',
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.Matches)(/^[0-9]{10}$/, {
|
||||
message: 'El teléfono debe tener exactamente 10 dígitos',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], LoginDto.prototype, "phone", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'PIN de acceso',
|
||||
example: '1234',
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
(0, class_validator_1.Matches)(/^[0-9]{4,6}$/, {
|
||||
message: 'El PIN debe tener entre 4 y 6 dígitos',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], LoginDto.prototype, "pin", void 0);
|
||||
class RefreshTokenDto {
|
||||
}
|
||||
exports.RefreshTokenDto = RefreshTokenDto;
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
description: 'Token de refresco',
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsNotEmpty)(),
|
||||
__metadata("design:type", String)
|
||||
], RefreshTokenDto.prototype, "refreshToken", void 0);
|
||||
//# sourceMappingURL=register.dto.js.map
|
||||
1
apps/backend/dist/modules/auth/dto/register.dto.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/dto/register.dto.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"register.dto.js","sourceRoot":"","sources":["../../../../src/modules/auth/dto/register.dto.ts"],"names":[],"mappings":"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"}
|
||||
40
apps/backend/dist/modules/auth/entities/tenant.entity.d.ts
vendored
Normal file
40
apps/backend/dist/modules/auth/entities/tenant.entity.d.ts
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
import { User } from './user.entity';
|
||||
export declare enum SubscriptionStatus {
|
||||
TRIAL = "trial",
|
||||
ACTIVE = "active",
|
||||
SUSPENDED = "suspended",
|
||||
CANCELLED = "cancelled"
|
||||
}
|
||||
export declare enum TenantStatus {
|
||||
ACTIVE = "active",
|
||||
INACTIVE = "inactive",
|
||||
SUSPENDED = "suspended"
|
||||
}
|
||||
export declare class Tenant {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
businessType: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
address: string;
|
||||
city: string;
|
||||
state: string;
|
||||
zipCode: string;
|
||||
timezone: string;
|
||||
currency: string;
|
||||
taxRate: number;
|
||||
taxIncluded: boolean;
|
||||
whatsappNumber: string;
|
||||
whatsappVerified: boolean;
|
||||
usesPlatformNumber: boolean;
|
||||
preferredLlmProvider: string;
|
||||
preferredPaymentProvider: string;
|
||||
currentPlanId: string;
|
||||
subscriptionStatus: string;
|
||||
status: string;
|
||||
onboardingCompleted: boolean;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
users: User[];
|
||||
}
|
||||
145
apps/backend/dist/modules/auth/entities/tenant.entity.js
vendored
Normal file
145
apps/backend/dist/modules/auth/entities/tenant.entity.js
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Tenant = exports.TenantStatus = exports.SubscriptionStatus = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
const user_entity_1 = require("./user.entity");
|
||||
var SubscriptionStatus;
|
||||
(function (SubscriptionStatus) {
|
||||
SubscriptionStatus["TRIAL"] = "trial";
|
||||
SubscriptionStatus["ACTIVE"] = "active";
|
||||
SubscriptionStatus["SUSPENDED"] = "suspended";
|
||||
SubscriptionStatus["CANCELLED"] = "cancelled";
|
||||
})(SubscriptionStatus || (exports.SubscriptionStatus = SubscriptionStatus = {}));
|
||||
var TenantStatus;
|
||||
(function (TenantStatus) {
|
||||
TenantStatus["ACTIVE"] = "active";
|
||||
TenantStatus["INACTIVE"] = "inactive";
|
||||
TenantStatus["SUSPENDED"] = "suspended";
|
||||
})(TenantStatus || (exports.TenantStatus = TenantStatus = {}));
|
||||
let Tenant = class Tenant {
|
||||
};
|
||||
exports.Tenant = Tenant;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 100 }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, unique: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "slug", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'business_type', length: 50 }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "businessType", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20 }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "phone", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 100, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "email", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "address", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "city", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "state", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'zip_code', length: 10, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "zipCode", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, default: 'America/Mexico_City' }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "timezone", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 3, default: 'MXN' }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "currency", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tax_rate', type: 'decimal', precision: 5, scale: 2, default: 16.0 }),
|
||||
__metadata("design:type", Number)
|
||||
], Tenant.prototype, "taxRate", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tax_included', default: true }),
|
||||
__metadata("design:type", Boolean)
|
||||
], Tenant.prototype, "taxIncluded", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'whatsapp_number', length: 20, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "whatsappNumber", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'whatsapp_verified', default: false }),
|
||||
__metadata("design:type", Boolean)
|
||||
], Tenant.prototype, "whatsappVerified", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'uses_platform_number', default: true }),
|
||||
__metadata("design:type", Boolean)
|
||||
], Tenant.prototype, "usesPlatformNumber", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'preferred_llm_provider', length: 20, default: 'openai' }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "preferredLlmProvider", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'preferred_payment_provider', length: 20, default: 'stripe' }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "preferredPaymentProvider", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'current_plan_id', type: 'uuid', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "currentPlanId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
name: 'subscription_status',
|
||||
length: 20,
|
||||
default: 'trial',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "subscriptionStatus", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
length: 20,
|
||||
default: 'active',
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], Tenant.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'onboarding_completed', default: false }),
|
||||
__metadata("design:type", Boolean)
|
||||
], Tenant.prototype, "onboardingCompleted", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], Tenant.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], Tenant.prototype, "updatedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.OneToMany)(() => user_entity_1.User, (user) => user.tenant),
|
||||
__metadata("design:type", Array)
|
||||
], Tenant.prototype, "users", void 0);
|
||||
exports.Tenant = Tenant = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'public', name: 'tenants' })
|
||||
], Tenant);
|
||||
//# sourceMappingURL=tenant.entity.js.map
|
||||
1
apps/backend/dist/modules/auth/entities/tenant.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/entities/tenant.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"tenant.entity.js","sourceRoot":"","sources":["../../../../src/modules/auth/entities/tenant.entity.ts"],"names":[],"mappings":"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"}
|
||||
30
apps/backend/dist/modules/auth/entities/user.entity.d.ts
vendored
Normal file
30
apps/backend/dist/modules/auth/entities/user.entity.d.ts
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import { Tenant } from './tenant.entity';
|
||||
export declare enum UserRole {
|
||||
OWNER = "owner",
|
||||
ADMIN = "admin",
|
||||
EMPLOYEE = "employee"
|
||||
}
|
||||
export declare enum UserStatus {
|
||||
ACTIVE = "active",
|
||||
INACTIVE = "inactive",
|
||||
SUSPENDED = "suspended"
|
||||
}
|
||||
export declare class User {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
phone: string;
|
||||
email: string;
|
||||
name: string;
|
||||
pinHash: string;
|
||||
biometricEnabled: boolean;
|
||||
biometricKey: string;
|
||||
role: string;
|
||||
permissions: Record<string, unknown>;
|
||||
status: string;
|
||||
lastLoginAt: Date;
|
||||
failedAttempts: number;
|
||||
lockedUntil: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
tenant: Tenant;
|
||||
}
|
||||
102
apps/backend/dist/modules/auth/entities/user.entity.js
vendored
Normal file
102
apps/backend/dist/modules/auth/entities/user.entity.js
vendored
Normal file
@ -0,0 +1,102 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.User = exports.UserStatus = exports.UserRole = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
const tenant_entity_1 = require("./tenant.entity");
|
||||
var UserRole;
|
||||
(function (UserRole) {
|
||||
UserRole["OWNER"] = "owner";
|
||||
UserRole["ADMIN"] = "admin";
|
||||
UserRole["EMPLOYEE"] = "employee";
|
||||
})(UserRole || (exports.UserRole = UserRole = {}));
|
||||
var UserStatus;
|
||||
(function (UserStatus) {
|
||||
UserStatus["ACTIVE"] = "active";
|
||||
UserStatus["INACTIVE"] = "inactive";
|
||||
UserStatus["SUSPENDED"] = "suspended";
|
||||
})(UserStatus || (exports.UserStatus = UserStatus = {}));
|
||||
let User = class User {
|
||||
};
|
||||
exports.User = User;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "tenantId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20 }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "phone", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 100, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "email", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 100 }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'pin_hash', length: 255, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "pinHash", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'biometric_enabled', default: false }),
|
||||
__metadata("design:type", Boolean)
|
||||
], User.prototype, "biometricEnabled", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'biometric_key', type: 'text', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "biometricKey", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20, default: 'owner' }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "role", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'jsonb', default: {} }),
|
||||
__metadata("design:type", Object)
|
||||
], User.prototype, "permissions", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20, default: 'active' }),
|
||||
__metadata("design:type", String)
|
||||
], User.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'last_login_at', type: 'timestamptz', nullable: true }),
|
||||
__metadata("design:type", Date)
|
||||
], User.prototype, "lastLoginAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'failed_attempts', default: 0 }),
|
||||
__metadata("design:type", Number)
|
||||
], User.prototype, "failedAttempts", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'locked_until', type: 'timestamptz', nullable: true }),
|
||||
__metadata("design:type", Date)
|
||||
], User.prototype, "lockedUntil", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], User.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], User.prototype, "updatedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.ManyToOne)(() => tenant_entity_1.Tenant, (tenant) => tenant.users),
|
||||
(0, typeorm_1.JoinColumn)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", tenant_entity_1.Tenant)
|
||||
], User.prototype, "tenant", void 0);
|
||||
exports.User = User = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'auth', name: 'users' })
|
||||
], User);
|
||||
//# sourceMappingURL=user.entity.js.map
|
||||
1
apps/backend/dist/modules/auth/entities/user.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/entities/user.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"user.entity.js","sourceRoot":"","sources":["../../../../src/modules/auth/entities/user.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAQiB;AACjB,mDAAyC;AAEzC,IAAY,QAIX;AAJD,WAAY,QAAQ;IAClB,2BAAe,CAAA;IACf,2BAAe,CAAA;IACf,iCAAqB,CAAA;AACvB,CAAC,EAJW,QAAQ,wBAAR,QAAQ,QAInB;AAED,IAAY,UAIX;AAJD,WAAY,UAAU;IACpB,+BAAiB,CAAA;IACjB,mCAAqB,CAAA;IACrB,qCAAuB,CAAA;AACzB,CAAC,EAJW,UAAU,0BAAV,UAAU,QAIrB;AAGM,IAAM,IAAI,GAAV,MAAM,IAAI;CAqDhB,CAAA;AArDY,oBAAI;AAEf;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;gCACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;sCACb;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;mCACT;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mCAC1B;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;;kCACX;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qCAC1C;AAGhB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;;8CAC5B;AAG1B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;0CAC3C;AAGrB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;;kCAC5B;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;;yCACF;AAGrC;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;;oCAC3B;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BAC1D,IAAI;yCAAC;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;4CACzB;AAGvB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BACzD,IAAI;yCAAC;AAGlB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;uCAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;uCAAC;AAKhB;IAFC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,sBAAM,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC;IACjD,IAAA,oBAAU,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;8BAC1B,sBAAM;oCAAC;eApDJ,IAAI;IADhB,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;GAC7B,IAAI,CAqDhB"}
|
||||
7
apps/backend/dist/modules/auth/guards/jwt-auth.guard.d.ts
vendored
Normal file
7
apps/backend/dist/modules/auth/guards/jwt-auth.guard.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
import { ExecutionContext } from '@nestjs/common';
|
||||
declare const JwtAuthGuard_base: import("@nestjs/passport").Type<import("@nestjs/passport").IAuthGuard>;
|
||||
export declare class JwtAuthGuard extends JwtAuthGuard_base {
|
||||
canActivate(context: ExecutionContext): boolean | Promise<boolean> | import("rxjs").Observable<boolean>;
|
||||
handleRequest<TUser>(err: Error | null, user: TUser): TUser;
|
||||
}
|
||||
export {};
|
||||
27
apps/backend/dist/modules/auth/guards/jwt-auth.guard.js
vendored
Normal file
27
apps/backend/dist/modules/auth/guards/jwt-auth.guard.js
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.JwtAuthGuard = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const passport_1 = require("@nestjs/passport");
|
||||
let JwtAuthGuard = class JwtAuthGuard extends (0, passport_1.AuthGuard)('jwt') {
|
||||
canActivate(context) {
|
||||
return super.canActivate(context);
|
||||
}
|
||||
handleRequest(err, user) {
|
||||
if (err || !user) {
|
||||
throw err || new common_1.UnauthorizedException('Token inválido o expirado');
|
||||
}
|
||||
return user;
|
||||
}
|
||||
};
|
||||
exports.JwtAuthGuard = JwtAuthGuard;
|
||||
exports.JwtAuthGuard = JwtAuthGuard = __decorate([
|
||||
(0, common_1.Injectable)()
|
||||
], JwtAuthGuard);
|
||||
//# sourceMappingURL=jwt-auth.guard.js.map
|
||||
1
apps/backend/dist/modules/auth/guards/jwt-auth.guard.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/guards/jwt-auth.guard.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../../src/modules/auth/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAqF;AACrF,+CAA6C;AAGtC,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,IAAA,oBAAS,EAAC,KAAK,CAAC;IAChD,WAAW,CAAC,OAAyB;QACnC,OAAO,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,aAAa,CAAQ,GAAiB,EAAE,IAAW;QACjD,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YACjB,MAAM,GAAG,IAAI,IAAI,8BAAqB,CAAC,2BAA2B,CAAC,CAAC;QACtE,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAA;AAXY,oCAAY;uBAAZ,YAAY;IADxB,IAAA,mBAAU,GAAE;GACA,YAAY,CAWxB"}
|
||||
17
apps/backend/dist/modules/auth/strategies/jwt.strategy.d.ts
vendored
Normal file
17
apps/backend/dist/modules/auth/strategies/jwt.strategy.d.ts
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
import { Strategy } from 'passport-jwt';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Repository } from 'typeorm';
|
||||
import { User } from '../entities/user.entity';
|
||||
import { TokenPayload } from '../auth.service';
|
||||
declare const JwtStrategy_base: new (...args: any[]) => Strategy;
|
||||
export declare class JwtStrategy extends JwtStrategy_base {
|
||||
private readonly configService;
|
||||
private readonly userRepository;
|
||||
constructor(configService: ConfigService, userRepository: Repository<User>);
|
||||
validate(payload: TokenPayload): Promise<{
|
||||
sub: string;
|
||||
tenantId: string;
|
||||
phone: string;
|
||||
}>;
|
||||
}
|
||||
export {};
|
||||
54
apps/backend/dist/modules/auth/strategies/jwt.strategy.js
vendored
Normal file
54
apps/backend/dist/modules/auth/strategies/jwt.strategy.js
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
"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.JwtStrategy = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const passport_1 = require("@nestjs/passport");
|
||||
const passport_jwt_1 = require("passport-jwt");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const user_entity_1 = require("../entities/user.entity");
|
||||
let JwtStrategy = class JwtStrategy extends (0, passport_1.PassportStrategy)(passport_jwt_1.Strategy) {
|
||||
constructor(configService, userRepository) {
|
||||
super({
|
||||
jwtFromRequest: passport_jwt_1.ExtractJwt.fromAuthHeaderAsBearerToken(),
|
||||
ignoreExpiration: false,
|
||||
secretOrKey: configService.get('JWT_SECRET'),
|
||||
});
|
||||
this.configService = configService;
|
||||
this.userRepository = userRepository;
|
||||
}
|
||||
async validate(payload) {
|
||||
const user = await this.userRepository.findOne({
|
||||
where: { id: payload.sub },
|
||||
});
|
||||
if (!user) {
|
||||
throw new common_1.UnauthorizedException('Usuario no encontrado');
|
||||
}
|
||||
return {
|
||||
sub: payload.sub,
|
||||
tenantId: payload.tenantId,
|
||||
phone: payload.phone,
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.JwtStrategy = JwtStrategy;
|
||||
exports.JwtStrategy = JwtStrategy = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(user_entity_1.User)),
|
||||
__metadata("design:paramtypes", [config_1.ConfigService,
|
||||
typeorm_2.Repository])
|
||||
], JwtStrategy);
|
||||
//# sourceMappingURL=jwt.strategy.js.map
|
||||
1
apps/backend/dist/modules/auth/strategies/jwt.strategy.js.map
vendored
Normal file
1
apps/backend/dist/modules/auth/strategies/jwt.strategy.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"jwt.strategy.js","sourceRoot":"","sources":["../../../../src/modules/auth/strategies/jwt.strategy.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAAmE;AACnE,+CAAoD;AACpD,+CAAoD;AACpD,2CAA+C;AAC/C,6CAAmD;AACnD,qCAAqC;AACrC,yDAA+C;AAIxC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,IAAA,2BAAgB,EAAC,uBAAQ,CAAC;IACzD,YACmB,aAA4B,EAE5B,cAAgC;QAEjD,KAAK,CAAC;YACJ,cAAc,EAAE,yBAAU,CAAC,2BAA2B,EAAE;YACxD,gBAAgB,EAAE,KAAK;YACvB,WAAW,EAAE,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC;SAC7C,CAAC,CAAC;QARc,kBAAa,GAAb,aAAa,CAAe;QAE5B,mBAAc,GAAd,cAAc,CAAkB;IAOnD,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,OAAqB;QAClC,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC;YAC7C,KAAK,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,GAAG,EAAE;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,8BAAqB,CAAC,uBAAuB,CAAC,CAAC;QAC3D,CAAC;QAED,OAAO;YACL,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC;IACJ,CAAC;CACF,CAAA;AA5BY,kCAAW;sBAAX,WAAW;IADvB,IAAA,mBAAU,GAAE;IAIR,WAAA,IAAA,0BAAgB,EAAC,kBAAI,CAAC,CAAA;qCADS,sBAAa;QAEZ,oBAAU;GAJlC,WAAW,CA4BvB"}
|
||||
38
apps/backend/dist/modules/billing/billing.controller.d.ts
vendored
Normal file
38
apps/backend/dist/modules/billing/billing.controller.d.ts
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
import { BillingService } from './billing.service';
|
||||
export declare class BillingController {
|
||||
private readonly billingService;
|
||||
constructor(billingService: BillingService);
|
||||
getPlans(): Promise<import("../subscriptions/entities/plan.entity").Plan[]>;
|
||||
getTokenPackages(): Promise<import("./billing.service").TokenPackage[]>;
|
||||
getBillingSummary(req: any): Promise<{
|
||||
subscription: import("../subscriptions/entities/subscription.entity").Subscription | null;
|
||||
plan: import("../subscriptions/entities/plan.entity").Plan | null;
|
||||
tokenBalance: import("../subscriptions/entities/token-balance.entity").TokenBalance | null;
|
||||
invoices: any[];
|
||||
}>;
|
||||
getTokenBalance(req: any): Promise<import("../subscriptions/entities/token-balance.entity").TokenBalance | {
|
||||
availableTokens: number;
|
||||
usedTokens: number;
|
||||
totalTokens: number;
|
||||
}>;
|
||||
getTokenUsage(req: any, limit?: string): Promise<import("../subscriptions/entities/token-usage.entity").TokenUsage[]>;
|
||||
createSubscriptionCheckout(req: any, body: {
|
||||
planCode: string;
|
||||
successUrl: string;
|
||||
cancelUrl: string;
|
||||
}): Promise<{
|
||||
checkoutUrl: string;
|
||||
}>;
|
||||
createTokenCheckout(req: any, body: {
|
||||
packageCode: string;
|
||||
successUrl: string;
|
||||
cancelUrl: string;
|
||||
}): Promise<{
|
||||
checkoutUrl: string;
|
||||
}>;
|
||||
createPortalSession(req: any, body: {
|
||||
returnUrl: string;
|
||||
}): Promise<{
|
||||
portalUrl: string;
|
||||
}>;
|
||||
}
|
||||
113
apps/backend/dist/modules/billing/billing.controller.js
vendored
Normal file
113
apps/backend/dist/modules/billing/billing.controller.js
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
"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.BillingController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const jwt_auth_guard_1 = require("../auth/guards/jwt-auth.guard");
|
||||
const billing_service_1 = require("./billing.service");
|
||||
let BillingController = class BillingController {
|
||||
constructor(billingService) {
|
||||
this.billingService = billingService;
|
||||
}
|
||||
async getPlans() {
|
||||
return this.billingService.getPlans();
|
||||
}
|
||||
async getTokenPackages() {
|
||||
return this.billingService.getTokenPackages();
|
||||
}
|
||||
async getBillingSummary(req) {
|
||||
return this.billingService.getBillingSummary(req.user.tenantId);
|
||||
}
|
||||
async getTokenBalance(req) {
|
||||
const balance = await this.billingService.getTokenBalance(req.user.tenantId);
|
||||
return balance || { availableTokens: 0, usedTokens: 0, totalTokens: 0 };
|
||||
}
|
||||
async getTokenUsage(req, limit) {
|
||||
return this.billingService.getTokenUsageHistory(req.user.tenantId, limit ? parseInt(limit, 10) : 50);
|
||||
}
|
||||
async createSubscriptionCheckout(req, body) {
|
||||
return this.billingService.createSubscriptionCheckout(req.user.tenantId, body.planCode, body.successUrl, body.cancelUrl);
|
||||
}
|
||||
async createTokenCheckout(req, body) {
|
||||
return this.billingService.createTokenPurchaseCheckout(req.user.tenantId, body.packageCode, body.successUrl, body.cancelUrl);
|
||||
}
|
||||
async createPortalSession(req, body) {
|
||||
return this.billingService.createPortalSession(req.user.tenantId, body.returnUrl);
|
||||
}
|
||||
};
|
||||
exports.BillingController = BillingController;
|
||||
__decorate([
|
||||
(0, common_1.Get)('plans'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "getPlans", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('token-packages'),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "getTokenPackages", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('summary'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "getBillingSummary", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('token-balance'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "getTokenBalance", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('token-usage'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('limit')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "getTokenUsage", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('checkout/subscription'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "createSubscriptionCheckout", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('checkout/tokens'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "createTokenCheckout", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('portal'),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], BillingController.prototype, "createPortalSession", null);
|
||||
exports.BillingController = BillingController = __decorate([
|
||||
(0, common_1.Controller)('billing'),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
__metadata("design:paramtypes", [billing_service_1.BillingService])
|
||||
], BillingController);
|
||||
//# sourceMappingURL=billing.controller.js.map
|
||||
1
apps/backend/dist/modules/billing/billing.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/billing/billing.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"billing.controller.js","sourceRoot":"","sources":["../../../src/modules/billing/billing.controller.ts"],"names":[],"mappings":"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"}
|
||||
2
apps/backend/dist/modules/billing/billing.module.d.ts
vendored
Normal file
2
apps/backend/dist/modules/billing/billing.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class BillingModule {
|
||||
}
|
||||
40
apps/backend/dist/modules/billing/billing.module.js
vendored
Normal file
40
apps/backend/dist/modules/billing/billing.module.js
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BillingModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const billing_service_1 = require("./billing.service");
|
||||
const billing_controller_1 = require("./billing.controller");
|
||||
const stripe_service_1 = require("./stripe.service");
|
||||
const webhooks_controller_1 = require("./webhooks.controller");
|
||||
const subscription_entity_1 = require("../subscriptions/entities/subscription.entity");
|
||||
const plan_entity_1 = require("../subscriptions/entities/plan.entity");
|
||||
const token_balance_entity_1 = require("../subscriptions/entities/token-balance.entity");
|
||||
const token_usage_entity_1 = require("../subscriptions/entities/token-usage.entity");
|
||||
let BillingModule = class BillingModule {
|
||||
};
|
||||
exports.BillingModule = BillingModule;
|
||||
exports.BillingModule = BillingModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
config_1.ConfigModule,
|
||||
typeorm_1.TypeOrmModule.forFeature([
|
||||
subscription_entity_1.Subscription,
|
||||
plan_entity_1.Plan,
|
||||
token_balance_entity_1.TokenBalance,
|
||||
token_usage_entity_1.TokenUsage,
|
||||
]),
|
||||
],
|
||||
controllers: [billing_controller_1.BillingController, webhooks_controller_1.WebhooksController],
|
||||
providers: [billing_service_1.BillingService, stripe_service_1.StripeService],
|
||||
exports: [billing_service_1.BillingService, stripe_service_1.StripeService],
|
||||
})
|
||||
], BillingModule);
|
||||
//# sourceMappingURL=billing.module.js.map
|
||||
1
apps/backend/dist/modules/billing/billing.module.js.map
vendored
Normal file
1
apps/backend/dist/modules/billing/billing.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"billing.module.js","sourceRoot":"","sources":["../../../src/modules/billing/billing.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,2CAA8C;AAC9C,6CAAgD;AAChD,uDAAmD;AACnD,6DAAyD;AACzD,qDAAiD;AACjD,+DAA2D;AAC3D,uFAA6E;AAC7E,uEAA6D;AAC7D,yFAA8E;AAC9E,qFAA0E;AAgBnE,IAAM,aAAa,GAAnB,MAAM,aAAa;CAAG,CAAA;AAAhB,sCAAa;wBAAb,aAAa;IAdzB,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,qBAAY;YACZ,uBAAa,CAAC,UAAU,CAAC;gBACvB,kCAAY;gBACZ,kBAAI;gBACJ,mCAAY;gBACZ,+BAAU;aACX,CAAC;SACH;QACD,WAAW,EAAE,CAAC,sCAAiB,EAAE,wCAAkB,CAAC;QACpD,SAAS,EAAE,CAAC,gCAAc,EAAE,8BAAa,CAAC;QAC1C,OAAO,EAAE,CAAC,gCAAc,EAAE,8BAAa,CAAC;KACzC,CAAC;GACW,aAAa,CAAG"}
|
||||
47
apps/backend/dist/modules/billing/billing.service.d.ts
vendored
Normal file
47
apps/backend/dist/modules/billing/billing.service.d.ts
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { StripeService } from './stripe.service';
|
||||
import { Subscription } from '../subscriptions/entities/subscription.entity';
|
||||
import { Plan } from '../subscriptions/entities/plan.entity';
|
||||
import { TokenBalance } from '../subscriptions/entities/token-balance.entity';
|
||||
import { TokenUsage } from '../subscriptions/entities/token-usage.entity';
|
||||
export interface TokenPackage {
|
||||
code: string;
|
||||
name: string;
|
||||
tokens: number;
|
||||
priceMxn: number;
|
||||
stripePriceId?: string;
|
||||
}
|
||||
export declare class BillingService {
|
||||
private stripeService;
|
||||
private subscriptionRepo;
|
||||
private planRepo;
|
||||
private tokenBalanceRepo;
|
||||
private tokenUsageRepo;
|
||||
private readonly logger;
|
||||
private readonly tokenPackages;
|
||||
constructor(stripeService: StripeService, subscriptionRepo: Repository<Subscription>, planRepo: Repository<Plan>, tokenBalanceRepo: Repository<TokenBalance>, tokenUsageRepo: Repository<TokenUsage>);
|
||||
getPlans(): Promise<Plan[]>;
|
||||
getTokenPackages(): TokenPackage[];
|
||||
createSubscriptionCheckout(tenantId: string, planCode: string, successUrl: string, cancelUrl: string): Promise<{
|
||||
checkoutUrl: string;
|
||||
}>;
|
||||
createTokenPurchaseCheckout(tenantId: string, packageCode: string, successUrl: string, cancelUrl: string): Promise<{
|
||||
checkoutUrl: string;
|
||||
}>;
|
||||
createPortalSession(tenantId: string, returnUrl: string): Promise<{
|
||||
portalUrl: string;
|
||||
}>;
|
||||
handleSubscriptionCreated(stripeSubscriptionId: string, stripeCustomerId: string, stripePriceId: string): Promise<void>;
|
||||
handleSubscriptionCancelled(stripeSubscriptionId: string): Promise<void>;
|
||||
handleTokenPurchase(tenantId: string, packageCode: string, tokens: number): Promise<void>;
|
||||
getTokenBalance(tenantId: string): Promise<TokenBalance | null>;
|
||||
addTokensToBalance(tenantId: string, tokens: number, source: 'subscription' | 'purchase' | 'bonus'): Promise<TokenBalance>;
|
||||
consumeTokens(tenantId: string, tokens: number, action: string, description?: string): Promise<boolean>;
|
||||
getTokenUsageHistory(tenantId: string, limit?: number): Promise<TokenUsage[]>;
|
||||
getBillingSummary(tenantId: string): Promise<{
|
||||
subscription: Subscription | null;
|
||||
plan: Plan | null;
|
||||
tokenBalance: TokenBalance | null;
|
||||
invoices: any[];
|
||||
}>;
|
||||
}
|
||||
220
apps/backend/dist/modules/billing/billing.service.js
vendored
Normal file
220
apps/backend/dist/modules/billing/billing.service.js
vendored
Normal file
@ -0,0 +1,220 @@
|
||||
"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); }
|
||||
};
|
||||
var BillingService_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.BillingService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const stripe_service_1 = require("./stripe.service");
|
||||
const subscription_entity_1 = require("../subscriptions/entities/subscription.entity");
|
||||
const plan_entity_1 = require("../subscriptions/entities/plan.entity");
|
||||
const token_balance_entity_1 = require("../subscriptions/entities/token-balance.entity");
|
||||
const token_usage_entity_1 = require("../subscriptions/entities/token-usage.entity");
|
||||
let BillingService = BillingService_1 = class BillingService {
|
||||
constructor(stripeService, subscriptionRepo, planRepo, tokenBalanceRepo, tokenUsageRepo) {
|
||||
this.stripeService = stripeService;
|
||||
this.subscriptionRepo = subscriptionRepo;
|
||||
this.planRepo = planRepo;
|
||||
this.tokenBalanceRepo = tokenBalanceRepo;
|
||||
this.tokenUsageRepo = tokenUsageRepo;
|
||||
this.logger = new common_1.Logger(BillingService_1.name);
|
||||
this.tokenPackages = [
|
||||
{ code: 'tokens_1000', name: '1,000 Tokens', tokens: 1000, priceMxn: 29 },
|
||||
{ code: 'tokens_3000', name: '3,000 Tokens', tokens: 3000, priceMxn: 69 },
|
||||
{ code: 'tokens_8000', name: '8,000 Tokens', tokens: 8000, priceMxn: 149 },
|
||||
{ code: 'tokens_20000', name: '20,000 Tokens', tokens: 20000, priceMxn: 299 },
|
||||
];
|
||||
}
|
||||
async getPlans() {
|
||||
return this.planRepo.find({
|
||||
where: { status: 'active' },
|
||||
order: { priceMonthly: 'ASC' },
|
||||
});
|
||||
}
|
||||
getTokenPackages() {
|
||||
return this.tokenPackages;
|
||||
}
|
||||
async createSubscriptionCheckout(tenantId, planCode, successUrl, cancelUrl) {
|
||||
const plan = await this.planRepo.findOne({ where: { code: planCode, status: 'active' } });
|
||||
if (!plan || !plan.stripePriceIdMonthly) {
|
||||
throw new common_1.NotFoundException('Plan no encontrado');
|
||||
}
|
||||
const subscription = await this.subscriptionRepo.findOne({ where: { tenantId } });
|
||||
if (!subscription?.stripeCustomerId) {
|
||||
throw new common_1.BadRequestException('Cliente de Stripe no configurado');
|
||||
}
|
||||
const session = await this.stripeService.createCheckoutSession({
|
||||
customerId: subscription.stripeCustomerId,
|
||||
priceId: plan.stripePriceIdMonthly,
|
||||
mode: 'subscription',
|
||||
successUrl,
|
||||
cancelUrl,
|
||||
metadata: { tenantId, planCode },
|
||||
});
|
||||
return { checkoutUrl: session.url };
|
||||
}
|
||||
async createTokenPurchaseCheckout(tenantId, packageCode, successUrl, cancelUrl) {
|
||||
const tokenPackage = this.tokenPackages.find((p) => p.code === packageCode);
|
||||
if (!tokenPackage) {
|
||||
throw new common_1.NotFoundException('Paquete de tokens no encontrado');
|
||||
}
|
||||
const subscription = await this.subscriptionRepo.findOne({ where: { tenantId } });
|
||||
if (!subscription?.stripeCustomerId) {
|
||||
throw new common_1.BadRequestException('Cliente de Stripe no configurado');
|
||||
}
|
||||
const paymentIntent = await this.stripeService.createPaymentIntent({
|
||||
amount: tokenPackage.priceMxn * 100,
|
||||
customerId: subscription.stripeCustomerId,
|
||||
metadata: {
|
||||
tenantId,
|
||||
packageCode,
|
||||
tokens: tokenPackage.tokens.toString(),
|
||||
},
|
||||
});
|
||||
return { checkoutUrl: paymentIntent.client_secret };
|
||||
}
|
||||
async createPortalSession(tenantId, returnUrl) {
|
||||
const subscription = await this.subscriptionRepo.findOne({ where: { tenantId } });
|
||||
if (!subscription?.stripeCustomerId) {
|
||||
throw new common_1.BadRequestException('Cliente de Stripe no configurado');
|
||||
}
|
||||
const session = await this.stripeService.createPortalSession({
|
||||
customerId: subscription.stripeCustomerId,
|
||||
returnUrl,
|
||||
});
|
||||
return { portalUrl: session.url };
|
||||
}
|
||||
async handleSubscriptionCreated(stripeSubscriptionId, stripeCustomerId, stripePriceId) {
|
||||
let plan = await this.planRepo.findOne({ where: { stripePriceIdMonthly: stripePriceId } });
|
||||
if (!plan) {
|
||||
plan = await this.planRepo.findOne({ where: { stripePriceIdYearly: stripePriceId } });
|
||||
}
|
||||
if (!plan) {
|
||||
this.logger.warn(`Plan not found for price: ${stripePriceId}`);
|
||||
return;
|
||||
}
|
||||
const subscription = await this.subscriptionRepo.findOne({
|
||||
where: { stripeCustomerId },
|
||||
});
|
||||
if (subscription) {
|
||||
subscription.planId = plan.id;
|
||||
subscription.stripeSubscriptionId = stripeSubscriptionId;
|
||||
subscription.status = subscription_entity_1.SubscriptionStatus.ACTIVE;
|
||||
subscription.currentPeriodStart = new Date();
|
||||
subscription.currentPeriodEnd = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000);
|
||||
await this.subscriptionRepo.save(subscription);
|
||||
if (plan.includedTokens > 0) {
|
||||
await this.addTokensToBalance(subscription.tenantId, plan.includedTokens, 'subscription');
|
||||
}
|
||||
this.logger.log(`Subscription activated for tenant: ${subscription.tenantId}`);
|
||||
}
|
||||
}
|
||||
async handleSubscriptionCancelled(stripeSubscriptionId) {
|
||||
const subscription = await this.subscriptionRepo.findOne({
|
||||
where: { stripeSubscriptionId },
|
||||
});
|
||||
if (subscription) {
|
||||
subscription.status = subscription_entity_1.SubscriptionStatus.CANCELLED;
|
||||
subscription.cancelledAt = new Date();
|
||||
await this.subscriptionRepo.save(subscription);
|
||||
this.logger.log(`Subscription cancelled for tenant: ${subscription.tenantId}`);
|
||||
}
|
||||
}
|
||||
async handleTokenPurchase(tenantId, packageCode, tokens) {
|
||||
await this.addTokensToBalance(tenantId, tokens, 'purchase');
|
||||
this.logger.log(`Added ${tokens} tokens to tenant: ${tenantId}`);
|
||||
}
|
||||
async getTokenBalance(tenantId) {
|
||||
return this.tokenBalanceRepo.findOne({ where: { tenantId } });
|
||||
}
|
||||
async addTokensToBalance(tenantId, tokens, source) {
|
||||
let balance = await this.tokenBalanceRepo.findOne({ where: { tenantId } });
|
||||
if (!balance) {
|
||||
balance = this.tokenBalanceRepo.create({
|
||||
tenantId,
|
||||
usedTokens: 0,
|
||||
availableTokens: 0,
|
||||
});
|
||||
}
|
||||
balance.availableTokens += tokens;
|
||||
return this.tokenBalanceRepo.save(balance);
|
||||
}
|
||||
async consumeTokens(tenantId, tokens, action, description) {
|
||||
const balance = await this.tokenBalanceRepo.findOne({ where: { tenantId } });
|
||||
if (!balance || balance.availableTokens < tokens) {
|
||||
return false;
|
||||
}
|
||||
balance.usedTokens += tokens;
|
||||
balance.availableTokens -= tokens;
|
||||
await this.tokenBalanceRepo.save(balance);
|
||||
const usage = this.tokenUsageRepo.create({
|
||||
tenantId,
|
||||
tokensUsed: tokens,
|
||||
action,
|
||||
description,
|
||||
});
|
||||
await this.tokenUsageRepo.save(usage);
|
||||
return true;
|
||||
}
|
||||
async getTokenUsageHistory(tenantId, limit = 50) {
|
||||
return this.tokenUsageRepo.find({
|
||||
where: { tenantId },
|
||||
order: { createdAt: 'DESC' },
|
||||
take: limit,
|
||||
});
|
||||
}
|
||||
async getBillingSummary(tenantId) {
|
||||
const subscription = await this.subscriptionRepo.findOne({
|
||||
where: { tenantId },
|
||||
relations: ['plan'],
|
||||
});
|
||||
const tokenBalance = await this.getTokenBalance(tenantId);
|
||||
let invoices = [];
|
||||
if (subscription?.stripeCustomerId) {
|
||||
try {
|
||||
invoices = await this.stripeService.listInvoices(subscription.stripeCustomerId, 5);
|
||||
}
|
||||
catch (error) {
|
||||
this.logger.warn('Could not fetch invoices from Stripe');
|
||||
}
|
||||
}
|
||||
return {
|
||||
subscription,
|
||||
plan: subscription?.plan || null,
|
||||
tokenBalance,
|
||||
invoices: invoices.map((inv) => ({
|
||||
id: inv.id,
|
||||
amount: inv.amount_paid / 100,
|
||||
status: inv.status,
|
||||
date: new Date(inv.created * 1000),
|
||||
pdfUrl: inv.invoice_pdf,
|
||||
})),
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.BillingService = BillingService;
|
||||
exports.BillingService = BillingService = BillingService_1 = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(subscription_entity_1.Subscription)),
|
||||
__param(2, (0, typeorm_1.InjectRepository)(plan_entity_1.Plan)),
|
||||
__param(3, (0, typeorm_1.InjectRepository)(token_balance_entity_1.TokenBalance)),
|
||||
__param(4, (0, typeorm_1.InjectRepository)(token_usage_entity_1.TokenUsage)),
|
||||
__metadata("design:paramtypes", [stripe_service_1.StripeService,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository])
|
||||
], BillingService);
|
||||
//# sourceMappingURL=billing.service.js.map
|
||||
1
apps/backend/dist/modules/billing/billing.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/billing/billing.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
56
apps/backend/dist/modules/billing/stripe.service.d.ts
vendored
Normal file
56
apps/backend/dist/modules/billing/stripe.service.d.ts
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import Stripe from 'stripe';
|
||||
export declare class StripeService {
|
||||
private configService;
|
||||
private readonly logger;
|
||||
private stripe;
|
||||
constructor(configService: ConfigService);
|
||||
private ensureStripe;
|
||||
createCustomer(params: {
|
||||
email?: string;
|
||||
phone: string;
|
||||
name: string;
|
||||
tenantId: string;
|
||||
}): Promise<Stripe.Customer>;
|
||||
getCustomer(customerId: string): Promise<Stripe.Customer | null>;
|
||||
createSubscription(params: {
|
||||
customerId: string;
|
||||
priceId: string;
|
||||
trialDays?: number;
|
||||
}): Promise<Stripe.Subscription>;
|
||||
cancelSubscription(subscriptionId: string): Promise<Stripe.Subscription>;
|
||||
getSubscription(subscriptionId: string): Promise<Stripe.Subscription | null>;
|
||||
updateSubscription(subscriptionId: string, params: Stripe.SubscriptionUpdateParams): Promise<Stripe.Subscription>;
|
||||
createPaymentIntent(params: {
|
||||
amount: number;
|
||||
customerId: string;
|
||||
metadata?: Record<string, string>;
|
||||
}): Promise<Stripe.PaymentIntent>;
|
||||
createCheckoutSession(params: {
|
||||
customerId: string;
|
||||
priceId: string;
|
||||
mode: 'subscription' | 'payment';
|
||||
successUrl: string;
|
||||
cancelUrl: string;
|
||||
metadata?: Record<string, string>;
|
||||
}): Promise<Stripe.Checkout.Session>;
|
||||
createPortalSession(params: {
|
||||
customerId: string;
|
||||
returnUrl: string;
|
||||
}): Promise<Stripe.BillingPortal.Session>;
|
||||
constructWebhookEvent(payload: string | Buffer, signature: string, webhookSecret: string): Stripe.Event;
|
||||
createProduct(params: {
|
||||
name: string;
|
||||
description?: string;
|
||||
metadata?: Record<string, string>;
|
||||
}): Promise<Stripe.Product>;
|
||||
createPrice(params: {
|
||||
productId: string;
|
||||
unitAmount: number;
|
||||
recurring?: {
|
||||
interval: 'month' | 'year';
|
||||
};
|
||||
metadata?: Record<string, string>;
|
||||
}): Promise<Stripe.Price>;
|
||||
listInvoices(customerId: string, limit?: number): Promise<Stripe.Invoice[]>;
|
||||
}
|
||||
160
apps/backend/dist/modules/billing/stripe.service.js
vendored
Normal file
160
apps/backend/dist/modules/billing/stripe.service.js
vendored
Normal file
@ -0,0 +1,160 @@
|
||||
"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 StripeService_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.StripeService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const stripe_1 = require("stripe");
|
||||
let StripeService = StripeService_1 = class StripeService {
|
||||
constructor(configService) {
|
||||
this.configService = configService;
|
||||
this.logger = new common_1.Logger(StripeService_1.name);
|
||||
const secretKey = this.configService.get('STRIPE_SECRET_KEY');
|
||||
if (!secretKey) {
|
||||
this.logger.warn('STRIPE_SECRET_KEY not configured - billing features disabled');
|
||||
return;
|
||||
}
|
||||
this.stripe = new stripe_1.default(secretKey);
|
||||
}
|
||||
ensureStripe() {
|
||||
if (!this.stripe) {
|
||||
throw new Error('Stripe not configured');
|
||||
}
|
||||
}
|
||||
async createCustomer(params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.customers.create({
|
||||
email: params.email,
|
||||
phone: params.phone,
|
||||
name: params.name,
|
||||
metadata: {
|
||||
tenantId: params.tenantId,
|
||||
},
|
||||
});
|
||||
}
|
||||
async getCustomer(customerId) {
|
||||
this.ensureStripe();
|
||||
try {
|
||||
const customer = await this.stripe.customers.retrieve(customerId);
|
||||
return customer.deleted ? null : customer;
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async createSubscription(params) {
|
||||
this.ensureStripe();
|
||||
const subscriptionParams = {
|
||||
customer: params.customerId,
|
||||
items: [{ price: params.priceId }],
|
||||
payment_behavior: 'default_incomplete',
|
||||
payment_settings: {
|
||||
save_default_payment_method: 'on_subscription',
|
||||
},
|
||||
expand: ['latest_invoice.payment_intent'],
|
||||
};
|
||||
if (params.trialDays) {
|
||||
subscriptionParams.trial_period_days = params.trialDays;
|
||||
}
|
||||
return this.stripe.subscriptions.create(subscriptionParams);
|
||||
}
|
||||
async cancelSubscription(subscriptionId) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.subscriptions.cancel(subscriptionId);
|
||||
}
|
||||
async getSubscription(subscriptionId) {
|
||||
this.ensureStripe();
|
||||
try {
|
||||
return await this.stripe.subscriptions.retrieve(subscriptionId);
|
||||
}
|
||||
catch (error) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
async updateSubscription(subscriptionId, params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.subscriptions.update(subscriptionId, params);
|
||||
}
|
||||
async createPaymentIntent(params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.paymentIntents.create({
|
||||
amount: params.amount,
|
||||
currency: 'mxn',
|
||||
customer: params.customerId,
|
||||
metadata: params.metadata || {},
|
||||
automatic_payment_methods: {
|
||||
enabled: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
async createCheckoutSession(params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.checkout.sessions.create({
|
||||
customer: params.customerId,
|
||||
mode: params.mode,
|
||||
line_items: [{ price: params.priceId, quantity: 1 }],
|
||||
success_url: params.successUrl,
|
||||
cancel_url: params.cancelUrl,
|
||||
metadata: params.metadata || {},
|
||||
locale: 'es',
|
||||
payment_method_types: params.mode === 'subscription'
|
||||
? ['card']
|
||||
: ['card', 'oxxo'],
|
||||
});
|
||||
}
|
||||
async createPortalSession(params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.billingPortal.sessions.create({
|
||||
customer: params.customerId,
|
||||
return_url: params.returnUrl,
|
||||
});
|
||||
}
|
||||
constructWebhookEvent(payload, signature, webhookSecret) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.webhooks.constructEvent(payload, signature, webhookSecret);
|
||||
}
|
||||
async createProduct(params) {
|
||||
this.ensureStripe();
|
||||
return this.stripe.products.create({
|
||||
name: params.name,
|
||||
description: params.description,
|
||||
metadata: params.metadata || {},
|
||||
});
|
||||
}
|
||||
async createPrice(params) {
|
||||
this.ensureStripe();
|
||||
const priceParams = {
|
||||
product: params.productId,
|
||||
unit_amount: params.unitAmount,
|
||||
currency: 'mxn',
|
||||
metadata: params.metadata || {},
|
||||
};
|
||||
if (params.recurring) {
|
||||
priceParams.recurring = params.recurring;
|
||||
}
|
||||
return this.stripe.prices.create(priceParams);
|
||||
}
|
||||
async listInvoices(customerId, limit = 10) {
|
||||
this.ensureStripe();
|
||||
const invoices = await this.stripe.invoices.list({
|
||||
customer: customerId,
|
||||
limit,
|
||||
});
|
||||
return invoices.data;
|
||||
}
|
||||
};
|
||||
exports.StripeService = StripeService;
|
||||
exports.StripeService = StripeService = StripeService_1 = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__metadata("design:paramtypes", [config_1.ConfigService])
|
||||
], StripeService);
|
||||
//# sourceMappingURL=stripe.service.js.map
|
||||
1
apps/backend/dist/modules/billing/stripe.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/billing/stripe.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"stripe.service.js","sourceRoot":"","sources":["../../../src/modules/billing/stripe.service.ts"],"names":[],"mappings":"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"}
|
||||
19
apps/backend/dist/modules/billing/webhooks.controller.d.ts
vendored
Normal file
19
apps/backend/dist/modules/billing/webhooks.controller.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
import { RawBodyRequest } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { Request } from 'express';
|
||||
import { StripeService } from './stripe.service';
|
||||
import { BillingService } from './billing.service';
|
||||
export declare class WebhooksController {
|
||||
private stripeService;
|
||||
private billingService;
|
||||
private configService;
|
||||
private readonly logger;
|
||||
constructor(stripeService: StripeService, billingService: BillingService, configService: ConfigService);
|
||||
handleStripeWebhook(req: RawBodyRequest<Request>, signature: string): Promise<{
|
||||
received: boolean;
|
||||
error?: undefined;
|
||||
} | {
|
||||
error: string;
|
||||
received?: undefined;
|
||||
}>;
|
||||
}
|
||||
105
apps/backend/dist/modules/billing/webhooks.controller.js
vendored
Normal file
105
apps/backend/dist/modules/billing/webhooks.controller.js
vendored
Normal file
@ -0,0 +1,105 @@
|
||||
"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); }
|
||||
};
|
||||
var WebhooksController_1;
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WebhooksController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const config_1 = require("@nestjs/config");
|
||||
const stripe_service_1 = require("./stripe.service");
|
||||
const billing_service_1 = require("./billing.service");
|
||||
let WebhooksController = WebhooksController_1 = class WebhooksController {
|
||||
constructor(stripeService, billingService, configService) {
|
||||
this.stripeService = stripeService;
|
||||
this.billingService = billingService;
|
||||
this.configService = configService;
|
||||
this.logger = new common_1.Logger(WebhooksController_1.name);
|
||||
}
|
||||
async handleStripeWebhook(req, signature) {
|
||||
const webhookSecret = this.configService.get('STRIPE_WEBHOOK_SECRET');
|
||||
if (!webhookSecret) {
|
||||
this.logger.warn('STRIPE_WEBHOOK_SECRET not configured');
|
||||
return { received: true };
|
||||
}
|
||||
let event;
|
||||
try {
|
||||
event = this.stripeService.constructWebhookEvent(req.rawBody, signature, webhookSecret);
|
||||
}
|
||||
catch (err) {
|
||||
this.logger.error(`Webhook signature verification failed: ${err.message}`);
|
||||
return { error: 'Invalid signature' };
|
||||
}
|
||||
this.logger.log(`Received Stripe event: ${event.type}`);
|
||||
try {
|
||||
switch (event.type) {
|
||||
case 'customer.subscription.created':
|
||||
case 'customer.subscription.updated': {
|
||||
const subscription = event.data.object;
|
||||
await this.billingService.handleSubscriptionCreated(subscription.id, subscription.customer, subscription.items.data[0].price.id);
|
||||
break;
|
||||
}
|
||||
case 'customer.subscription.deleted': {
|
||||
const subscription = event.data.object;
|
||||
await this.billingService.handleSubscriptionCancelled(subscription.id);
|
||||
break;
|
||||
}
|
||||
case 'payment_intent.succeeded': {
|
||||
const paymentIntent = event.data.object;
|
||||
const metadata = paymentIntent.metadata;
|
||||
if (metadata.packageCode && metadata.tenantId && metadata.tokens) {
|
||||
await this.billingService.handleTokenPurchase(metadata.tenantId, metadata.packageCode, parseInt(metadata.tokens, 10));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 'invoice.payment_succeeded': {
|
||||
const invoice = event.data.object;
|
||||
this.logger.log(`Invoice paid: ${invoice.id}`);
|
||||
break;
|
||||
}
|
||||
case 'invoice.payment_failed': {
|
||||
const invoice = event.data.object;
|
||||
this.logger.warn(`Invoice payment failed: ${invoice.id}`);
|
||||
break;
|
||||
}
|
||||
case 'checkout.session.completed': {
|
||||
const session = event.data.object;
|
||||
this.logger.log(`Checkout completed: ${session.id}`);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
this.logger.debug(`Unhandled event type: ${event.type}`);
|
||||
}
|
||||
}
|
||||
catch (error) {
|
||||
this.logger.error(`Error processing webhook: ${error.message}`);
|
||||
}
|
||||
return { received: true };
|
||||
}
|
||||
};
|
||||
exports.WebhooksController = WebhooksController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('stripe'),
|
||||
(0, common_1.HttpCode)(200),
|
||||
__param(0, (0, common_1.Req)()),
|
||||
__param(1, (0, common_1.Headers)('stripe-signature')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], WebhooksController.prototype, "handleStripeWebhook", null);
|
||||
exports.WebhooksController = WebhooksController = WebhooksController_1 = __decorate([
|
||||
(0, common_1.Controller)('webhooks'),
|
||||
__metadata("design:paramtypes", [stripe_service_1.StripeService,
|
||||
billing_service_1.BillingService,
|
||||
config_1.ConfigService])
|
||||
], WebhooksController);
|
||||
//# sourceMappingURL=webhooks.controller.js.map
|
||||
1
apps/backend/dist/modules/billing/webhooks.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/billing/webhooks.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"webhooks.controller.js","sourceRoot":"","sources":["../../../src/modules/billing/webhooks.controller.ts"],"names":[],"mappings":"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"}
|
||||
36
apps/backend/dist/modules/categories/categories.controller.d.ts
vendored
Normal file
36
apps/backend/dist/modules/categories/categories.controller.d.ts
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
import { CategoriesService } from './categories.service';
|
||||
import { CreateCategoryDto, UpdateCategoryDto } from './dto/category.dto';
|
||||
export declare class CategoriesController {
|
||||
private readonly categoriesService;
|
||||
constructor(categoriesService: CategoriesService);
|
||||
findAll(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, includeInactive?: boolean): Promise<import("./entities/category.entity").Category[]>;
|
||||
findOne(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, id: string): Promise<import("./entities/category.entity").Category>;
|
||||
create(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, dto: CreateCategoryDto): Promise<import("./entities/category.entity").Category>;
|
||||
update(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, id: string, dto: UpdateCategoryDto): Promise<import("./entities/category.entity").Category>;
|
||||
toggleActive(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, id: string): Promise<import("./entities/category.entity").Category>;
|
||||
delete(req: {
|
||||
user: {
|
||||
tenantId: string;
|
||||
};
|
||||
}, id: string): Promise<void>;
|
||||
}
|
||||
113
apps/backend/dist/modules/categories/categories.controller.js
vendored
Normal file
113
apps/backend/dist/modules/categories/categories.controller.js
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
"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.CategoriesController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const categories_service_1 = require("./categories.service");
|
||||
const category_dto_1 = require("./dto/category.dto");
|
||||
const jwt_auth_guard_1 = require("../auth/guards/jwt-auth.guard");
|
||||
let CategoriesController = class CategoriesController {
|
||||
constructor(categoriesService) {
|
||||
this.categoriesService = categoriesService;
|
||||
}
|
||||
async findAll(req, includeInactive) {
|
||||
return this.categoriesService.findAll(req.user.tenantId, includeInactive);
|
||||
}
|
||||
async findOne(req, id) {
|
||||
return this.categoriesService.findOne(req.user.tenantId, id);
|
||||
}
|
||||
async create(req, dto) {
|
||||
return this.categoriesService.create(req.user.tenantId, dto);
|
||||
}
|
||||
async update(req, id, dto) {
|
||||
return this.categoriesService.update(req.user.tenantId, id, dto);
|
||||
}
|
||||
async toggleActive(req, id) {
|
||||
return this.categoriesService.toggleActive(req.user.tenantId, id);
|
||||
}
|
||||
async delete(req, id) {
|
||||
await this.categoriesService.delete(req.user.tenantId, id);
|
||||
}
|
||||
};
|
||||
exports.CategoriesController = CategoriesController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar categorías' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('includeInactive')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Boolean]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "findAll", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)(':id'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Obtener categoría por ID' }),
|
||||
(0, swagger_1.ApiParam)({ name: 'id', description: 'ID de la categoría' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "findOne", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Crear categoría' }),
|
||||
(0, swagger_1.ApiResponse)({ status: 201, description: 'Categoría creada' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, category_dto_1.CreateCategoryDto]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "create", null);
|
||||
__decorate([
|
||||
(0, common_1.Put)(':id'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Actualizar categoría' }),
|
||||
(0, swagger_1.ApiParam)({ name: 'id', description: 'ID de la categoría' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String, category_dto_1.UpdateCategoryDto]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "update", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)(':id/toggle-active'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Activar/desactivar categoría' }),
|
||||
(0, swagger_1.ApiParam)({ name: 'id', description: 'ID de la categoría' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "toggleActive", null);
|
||||
__decorate([
|
||||
(0, common_1.Delete)(':id'),
|
||||
(0, common_1.HttpCode)(common_1.HttpStatus.NO_CONTENT),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Eliminar categoría' }),
|
||||
(0, swagger_1.ApiParam)({ name: 'id', description: 'ID de la categoría' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id', common_1.ParseUUIDPipe)),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CategoriesController.prototype, "delete", null);
|
||||
exports.CategoriesController = CategoriesController = __decorate([
|
||||
(0, swagger_1.ApiTags)('categories'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('v1/categories'),
|
||||
__metadata("design:paramtypes", [categories_service_1.CategoriesService])
|
||||
], CategoriesController);
|
||||
//# sourceMappingURL=categories.controller.js.map
|
||||
1
apps/backend/dist/modules/categories/categories.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/categories/categories.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.controller.js","sourceRoot":"","sources":["../../../src/modules/categories/categories.controller.ts"],"names":[],"mappings":"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"}
|
||||
2
apps/backend/dist/modules/categories/categories.module.d.ts
vendored
Normal file
2
apps/backend/dist/modules/categories/categories.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class CategoriesModule {
|
||||
}
|
||||
30
apps/backend/dist/modules/categories/categories.module.js
vendored
Normal file
30
apps/backend/dist/modules/categories/categories.module.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CategoriesModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const categories_controller_1 = require("./categories.controller");
|
||||
const categories_service_1 = require("./categories.service");
|
||||
const category_entity_1 = require("./entities/category.entity");
|
||||
const auth_module_1 = require("../auth/auth.module");
|
||||
let CategoriesModule = class CategoriesModule {
|
||||
};
|
||||
exports.CategoriesModule = CategoriesModule;
|
||||
exports.CategoriesModule = CategoriesModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
typeorm_1.TypeOrmModule.forFeature([category_entity_1.Category]),
|
||||
auth_module_1.AuthModule,
|
||||
],
|
||||
controllers: [categories_controller_1.CategoriesController],
|
||||
providers: [categories_service_1.CategoriesService],
|
||||
exports: [categories_service_1.CategoriesService, typeorm_1.TypeOrmModule],
|
||||
})
|
||||
], CategoriesModule);
|
||||
//# sourceMappingURL=categories.module.js.map
|
||||
1
apps/backend/dist/modules/categories/categories.module.js.map
vendored
Normal file
1
apps/backend/dist/modules/categories/categories.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.module.js","sourceRoot":"","sources":["../../../src/modules/categories/categories.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,mEAA+D;AAC/D,6DAAyD;AACzD,gEAAsD;AACtD,qDAAiD;AAW1C,IAAM,gBAAgB,GAAtB,MAAM,gBAAgB;CAAG,CAAA;AAAnB,4CAAgB;2BAAhB,gBAAgB;IAT5B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,0BAAQ,CAAC,CAAC;YACpC,wBAAU;SACX;QACD,WAAW,EAAE,CAAC,4CAAoB,CAAC;QACnC,SAAS,EAAE,CAAC,sCAAiB,CAAC;QAC9B,OAAO,EAAE,CAAC,sCAAiB,EAAE,uBAAa,CAAC;KAC5C,CAAC;GACW,gBAAgB,CAAG"}
|
||||
13
apps/backend/dist/modules/categories/categories.service.d.ts
vendored
Normal file
13
apps/backend/dist/modules/categories/categories.service.d.ts
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { Category } from './entities/category.entity';
|
||||
import { CreateCategoryDto, UpdateCategoryDto } from './dto/category.dto';
|
||||
export declare class CategoriesService {
|
||||
private readonly categoryRepository;
|
||||
constructor(categoryRepository: Repository<Category>);
|
||||
findAll(tenantId: string, includeInactive?: boolean): Promise<Category[]>;
|
||||
findOne(tenantId: string, id: string): Promise<Category>;
|
||||
create(tenantId: string, dto: CreateCategoryDto): Promise<Category>;
|
||||
update(tenantId: string, id: string, dto: UpdateCategoryDto): Promise<Category>;
|
||||
delete(tenantId: string, id: string): Promise<void>;
|
||||
toggleActive(tenantId: string, id: string): Promise<Category>;
|
||||
}
|
||||
90
apps/backend/dist/modules/categories/categories.service.js
vendored
Normal file
90
apps/backend/dist/modules/categories/categories.service.js
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
"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.CategoriesService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const category_entity_1 = require("./entities/category.entity");
|
||||
const MAX_CATEGORIES = 20;
|
||||
let CategoriesService = class CategoriesService {
|
||||
constructor(categoryRepository) {
|
||||
this.categoryRepository = categoryRepository;
|
||||
}
|
||||
async findAll(tenantId, includeInactive = false) {
|
||||
const where = { tenantId };
|
||||
if (!includeInactive) {
|
||||
where.status = 'active';
|
||||
}
|
||||
return this.categoryRepository.find({
|
||||
where,
|
||||
order: { sortOrder: 'ASC', name: 'ASC' },
|
||||
});
|
||||
}
|
||||
async findOne(tenantId, id) {
|
||||
const category = await this.categoryRepository.findOne({
|
||||
where: { id, tenantId },
|
||||
});
|
||||
if (!category) {
|
||||
throw new common_1.NotFoundException('Categoría no encontrada');
|
||||
}
|
||||
return category;
|
||||
}
|
||||
async create(tenantId, dto) {
|
||||
const count = await this.categoryRepository.count({ where: { tenantId } });
|
||||
if (count >= MAX_CATEGORIES) {
|
||||
throw new common_1.BadRequestException(`Has alcanzado el límite de ${MAX_CATEGORIES} categorías`);
|
||||
}
|
||||
const existing = await this.categoryRepository.findOne({
|
||||
where: { tenantId, name: dto.name },
|
||||
});
|
||||
if (existing) {
|
||||
throw new common_1.ConflictException('Ya existe una categoría con ese nombre');
|
||||
}
|
||||
const category = this.categoryRepository.create({
|
||||
...dto,
|
||||
tenantId,
|
||||
});
|
||||
return this.categoryRepository.save(category);
|
||||
}
|
||||
async update(tenantId, id, dto) {
|
||||
const category = await this.findOne(tenantId, id);
|
||||
if (dto.name && dto.name !== category.name) {
|
||||
const existing = await this.categoryRepository.findOne({
|
||||
where: { tenantId, name: dto.name },
|
||||
});
|
||||
if (existing) {
|
||||
throw new common_1.ConflictException('Ya existe una categoría con ese nombre');
|
||||
}
|
||||
}
|
||||
Object.assign(category, dto);
|
||||
return this.categoryRepository.save(category);
|
||||
}
|
||||
async delete(tenantId, id) {
|
||||
const category = await this.findOne(tenantId, id);
|
||||
await this.categoryRepository.remove(category);
|
||||
}
|
||||
async toggleActive(tenantId, id) {
|
||||
const category = await this.findOne(tenantId, id);
|
||||
category.status = category.status === 'active' ? 'inactive' : 'active';
|
||||
return this.categoryRepository.save(category);
|
||||
}
|
||||
};
|
||||
exports.CategoriesService = CategoriesService;
|
||||
exports.CategoriesService = CategoriesService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(category_entity_1.Category)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository])
|
||||
], CategoriesService);
|
||||
//# sourceMappingURL=categories.service.js.map
|
||||
1
apps/backend/dist/modules/categories/categories.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/categories/categories.service.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"categories.service.js","sourceRoot":"","sources":["../../../src/modules/categories/categories.service.ts"],"names":[],"mappings":"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"}
|
||||
15
apps/backend/dist/modules/categories/dto/category.dto.d.ts
vendored
Normal file
15
apps/backend/dist/modules/categories/dto/category.dto.d.ts
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
export declare class CreateCategoryDto {
|
||||
name: string;
|
||||
description?: string;
|
||||
color?: string;
|
||||
icon?: string;
|
||||
sortOrder?: number;
|
||||
}
|
||||
export declare class UpdateCategoryDto {
|
||||
name?: string;
|
||||
description?: string;
|
||||
color?: string;
|
||||
icon?: string;
|
||||
sortOrder?: number;
|
||||
status?: string;
|
||||
}
|
||||
80
apps/backend/dist/modules/categories/dto/category.dto.js
vendored
Normal file
80
apps/backend/dist/modules/categories/dto/category.dto.js
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UpdateCategoryDto = exports.CreateCategoryDto = void 0;
|
||||
const class_validator_1 = require("class-validator");
|
||||
class CreateCategoryDto {
|
||||
}
|
||||
exports.CreateCategoryDto = CreateCategoryDto;
|
||||
__decorate([
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], CreateCategoryDto.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
__metadata("design:type", String)
|
||||
], CreateCategoryDto.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(7),
|
||||
__metadata("design:type", String)
|
||||
], CreateCategoryDto.prototype, "color", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], CreateCategoryDto.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsNumber)(),
|
||||
__metadata("design:type", Number)
|
||||
], CreateCategoryDto.prototype, "sortOrder", void 0);
|
||||
class UpdateCategoryDto {
|
||||
}
|
||||
exports.UpdateCategoryDto = UpdateCategoryDto;
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], UpdateCategoryDto.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
__metadata("design:type", String)
|
||||
], UpdateCategoryDto.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(7),
|
||||
__metadata("design:type", String)
|
||||
], UpdateCategoryDto.prototype, "color", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.MaxLength)(50),
|
||||
__metadata("design:type", String)
|
||||
], UpdateCategoryDto.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsNumber)(),
|
||||
__metadata("design:type", Number)
|
||||
], UpdateCategoryDto.prototype, "sortOrder", void 0);
|
||||
__decorate([
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
(0, class_validator_1.IsString)(),
|
||||
__metadata("design:type", String)
|
||||
], UpdateCategoryDto.prototype, "status", void 0);
|
||||
//# sourceMappingURL=category.dto.js.map
|
||||
1
apps/backend/dist/modules/categories/dto/category.dto.js.map
vendored
Normal file
1
apps/backend/dist/modules/categories/dto/category.dto.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"category.dto.js","sourceRoot":"","sources":["../../../../src/modules/categories/dto/category.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qDAA4E;AAE5E,MAAa,iBAAiB;CAsB7B;AAtBD,8CAsBC;AAnBC;IAFC,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,EAAE,CAAC;;+CACD;AAIb;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;sDACU;AAKrB;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,CAAC,CAAC;;gDACE;AAKf;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,EAAE,CAAC;;+CACA;AAId;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACQ;AAGrB,MAAa,iBAAiB;CA2B7B;AA3BD,8CA2BC;AAvBC;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,EAAE,CAAC;;+CACA;AAId;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;sDACU;AAKrB;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,CAAC,CAAC;;gDACE;AAKf;IAHC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;IACV,IAAA,2BAAS,EAAC,EAAE,CAAC;;+CACA;AAId;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;oDACQ;AAInB;IAFC,IAAA,4BAAU,GAAE;IACZ,IAAA,0BAAQ,GAAE;;iDACK"}
|
||||
14
apps/backend/dist/modules/categories/entities/category.entity.d.ts
vendored
Normal file
14
apps/backend/dist/modules/categories/entities/category.entity.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
import { Product } from '../../products/entities/product.entity';
|
||||
export declare class Category {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
name: string;
|
||||
description: string;
|
||||
icon: string;
|
||||
color: string;
|
||||
sortOrder: number;
|
||||
status: string;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
products: Product[];
|
||||
}
|
||||
65
apps/backend/dist/modules/categories/entities/category.entity.js
vendored
Normal file
65
apps/backend/dist/modules/categories/entities/category.entity.js
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Category = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
const product_entity_1 = require("../../products/entities/product.entity");
|
||||
let Category = class Category {
|
||||
};
|
||||
exports.Category = Category;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "tenantId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50 }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "name", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'text', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "icon", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 7, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "color", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sort_order', default: 0 }),
|
||||
__metadata("design:type", Number)
|
||||
], Category.prototype, "sortOrder", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20, default: 'active' }),
|
||||
__metadata("design:type", String)
|
||||
], Category.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], Category.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], Category.prototype, "updatedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.OneToMany)(() => product_entity_1.Product, (product) => product.category),
|
||||
__metadata("design:type", Array)
|
||||
], Category.prototype, "products", void 0);
|
||||
exports.Category = Category = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'catalog', name: 'categories' })
|
||||
], Category);
|
||||
//# sourceMappingURL=category.entity.js.map
|
||||
1
apps/backend/dist/modules/categories/entities/category.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/categories/entities/category.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"category.entity.js","sourceRoot":"","sources":["../../../../src/modules/categories/entities/category.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAOiB;AACjB,2EAAiE;AAG1D,IAAM,QAAQ,GAAd,MAAM,QAAQ;CAkCpB,CAAA;AAlCY,4BAAQ;AAEnB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;oCACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;0CACb;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;;sCACV;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;6CACrB;AAGpB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;sCAC1B;AAGb;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;uCACxB;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;;2CACzB;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC;;wCAC3B;AAGf;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;2CAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;2CAAC;AAIhB;IADC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,wBAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,CAAC;;0CACpC;mBAjCT,QAAQ;IADpB,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;GACrC,QAAQ,CAkCpB"}
|
||||
31
apps/backend/dist/modules/codi-spei/codi-spei.controller.d.ts
vendored
Normal file
31
apps/backend/dist/modules/codi-spei/codi-spei.controller.d.ts
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
import { CodiSpeiService } from './codi-spei.service';
|
||||
import { GenerateQrDto } from './dto/generate-qr.dto';
|
||||
export declare class CodiSpeiController {
|
||||
private readonly codiSpeiService;
|
||||
constructor(codiSpeiService: CodiSpeiService);
|
||||
generateQr(req: any, dto: GenerateQrDto): Promise<import("./entities/codi-transaction.entity").CodiTransaction>;
|
||||
getCodiStatus(id: string): Promise<import("./entities/codi-transaction.entity").CodiTransaction>;
|
||||
getCodiTransactions(req: any, limit?: number): Promise<import("./entities/codi-transaction.entity").CodiTransaction[]>;
|
||||
codiWebhook(payload: any): Promise<{
|
||||
success: boolean;
|
||||
}>;
|
||||
getClabe(req: any): Promise<{
|
||||
clabe: any;
|
||||
message: string;
|
||||
beneficiaryName?: undefined;
|
||||
status?: undefined;
|
||||
} | {
|
||||
clabe: string;
|
||||
beneficiaryName: string;
|
||||
status: import("./entities/virtual-account.entity").VirtualAccountStatus;
|
||||
message?: undefined;
|
||||
}>;
|
||||
createClabe(req: any, body: {
|
||||
beneficiaryName: string;
|
||||
}): Promise<import("./entities/virtual-account.entity").VirtualAccount>;
|
||||
getSpeiTransactions(req: any, limit?: number): Promise<import("./entities/spei-transaction.entity").SpeiTransaction[]>;
|
||||
speiWebhook(payload: any): Promise<{
|
||||
success: boolean;
|
||||
}>;
|
||||
getSummary(req: any, date?: string): Promise<any>;
|
||||
}
|
||||
164
apps/backend/dist/modules/codi-spei/codi-spei.controller.js
vendored
Normal file
164
apps/backend/dist/modules/codi-spei/codi-spei.controller.js
vendored
Normal file
@ -0,0 +1,164 @@
|
||||
"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.CodiSpeiController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const jwt_auth_guard_1 = require("../auth/guards/jwt-auth.guard");
|
||||
const codi_spei_service_1 = require("./codi-spei.service");
|
||||
const generate_qr_dto_1 = require("./dto/generate-qr.dto");
|
||||
let CodiSpeiController = class CodiSpeiController {
|
||||
constructor(codiSpeiService) {
|
||||
this.codiSpeiService = codiSpeiService;
|
||||
}
|
||||
generateQr(req, dto) {
|
||||
return this.codiSpeiService.generateQr(req.user.tenantId, dto);
|
||||
}
|
||||
getCodiStatus(id) {
|
||||
return this.codiSpeiService.getCodiStatus(id);
|
||||
}
|
||||
getCodiTransactions(req, limit) {
|
||||
return this.codiSpeiService.getCodiTransactions(req.user.tenantId, limit);
|
||||
}
|
||||
async codiWebhook(payload) {
|
||||
await this.codiSpeiService.handleCodiWebhook(payload);
|
||||
return { success: true };
|
||||
}
|
||||
async getClabe(req) {
|
||||
const account = await this.codiSpeiService.getVirtualAccount(req.user.tenantId);
|
||||
if (!account) {
|
||||
return { clabe: null, message: 'No tiene CLABE virtual configurada' };
|
||||
}
|
||||
return {
|
||||
clabe: account.clabe,
|
||||
beneficiaryName: account.beneficiaryName,
|
||||
status: account.status,
|
||||
};
|
||||
}
|
||||
createClabe(req, body) {
|
||||
return this.codiSpeiService.createVirtualAccount(req.user.tenantId, body.beneficiaryName);
|
||||
}
|
||||
getSpeiTransactions(req, limit) {
|
||||
return this.codiSpeiService.getSpeiTransactions(req.user.tenantId, limit);
|
||||
}
|
||||
async speiWebhook(payload) {
|
||||
await this.codiSpeiService.handleSpeiWebhook(payload.clabe, payload);
|
||||
return { success: true };
|
||||
}
|
||||
async getSummary(req, date) {
|
||||
const targetDate = date ? new Date(date) : undefined;
|
||||
return this.codiSpeiService.getSummary(req.user.tenantId, targetDate);
|
||||
}
|
||||
};
|
||||
exports.CodiSpeiController = CodiSpeiController;
|
||||
__decorate([
|
||||
(0, common_1.Post)('codi/generate-qr'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Generar QR CoDi para cobro' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, generate_qr_dto_1.GenerateQrDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CodiSpeiController.prototype, "generateQr", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('codi/status/:id'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Obtener estado de transaccion CoDi' }),
|
||||
__param(0, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CodiSpeiController.prototype, "getCodiStatus", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('codi/transactions'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar transacciones CoDi' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'limit', required: false }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('limit')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Number]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CodiSpeiController.prototype, "getCodiTransactions", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('codi/webhook'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Webhook para confirmacion CoDi' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CodiSpeiController.prototype, "codiWebhook", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('spei/clabe'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Obtener CLABE virtual del tenant' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CodiSpeiController.prototype, "getClabe", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('spei/create-clabe'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Crear CLABE virtual para el tenant' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CodiSpeiController.prototype, "createClabe", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('spei/transactions'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar transacciones SPEI recibidas' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'limit', required: false }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('limit')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, Number]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CodiSpeiController.prototype, "getSpeiTransactions", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('spei/webhook'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Webhook para notificacion SPEI' }),
|
||||
__param(0, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CodiSpeiController.prototype, "speiWebhook", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('payments/summary'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Resumen de pagos CoDi/SPEI del dia' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'date', required: false }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('date')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], CodiSpeiController.prototype, "getSummary", null);
|
||||
exports.CodiSpeiController = CodiSpeiController = __decorate([
|
||||
(0, swagger_1.ApiTags)('codi-spei'),
|
||||
(0, common_1.Controller)('v1'),
|
||||
__metadata("design:paramtypes", [codi_spei_service_1.CodiSpeiService])
|
||||
], CodiSpeiController);
|
||||
//# sourceMappingURL=codi-spei.controller.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/codi-spei.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/codi-spei.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"codi-spei.controller.js","sourceRoot":"","sources":["../../../src/modules/codi-spei/codi-spei.controller.ts"],"names":[],"mappings":"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"}
|
||||
2
apps/backend/dist/modules/codi-spei/codi-spei.module.d.ts
vendored
Normal file
2
apps/backend/dist/modules/codi-spei/codi-spei.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class CodiSpeiModule {
|
||||
}
|
||||
30
apps/backend/dist/modules/codi-spei/codi-spei.module.js
vendored
Normal file
30
apps/backend/dist/modules/codi-spei/codi-spei.module.js
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CodiSpeiModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const codi_spei_controller_1 = require("./codi-spei.controller");
|
||||
const codi_spei_service_1 = require("./codi-spei.service");
|
||||
const virtual_account_entity_1 = require("./entities/virtual-account.entity");
|
||||
const codi_transaction_entity_1 = require("./entities/codi-transaction.entity");
|
||||
const spei_transaction_entity_1 = require("./entities/spei-transaction.entity");
|
||||
let CodiSpeiModule = class CodiSpeiModule {
|
||||
};
|
||||
exports.CodiSpeiModule = CodiSpeiModule;
|
||||
exports.CodiSpeiModule = CodiSpeiModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [
|
||||
typeorm_1.TypeOrmModule.forFeature([virtual_account_entity_1.VirtualAccount, codi_transaction_entity_1.CodiTransaction, spei_transaction_entity_1.SpeiTransaction]),
|
||||
],
|
||||
controllers: [codi_spei_controller_1.CodiSpeiController],
|
||||
providers: [codi_spei_service_1.CodiSpeiService],
|
||||
exports: [codi_spei_service_1.CodiSpeiService],
|
||||
})
|
||||
], CodiSpeiModule);
|
||||
//# sourceMappingURL=codi-spei.module.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/codi-spei.module.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/codi-spei.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"codi-spei.module.js","sourceRoot":"","sources":["../../../src/modules/codi-spei/codi-spei.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,iEAA4D;AAC5D,2DAAsD;AACtD,8EAAmE;AACnE,gFAAqE;AACrE,gFAAqE;AAU9D,IAAM,cAAc,GAApB,MAAM,cAAc;CAAG,CAAA;AAAjB,wCAAc;yBAAd,cAAc;IAR1B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE;YACP,uBAAa,CAAC,UAAU,CAAC,CAAC,uCAAc,EAAE,yCAAe,EAAE,yCAAe,CAAC,CAAC;SAC7E;QACD,WAAW,EAAE,CAAC,yCAAkB,CAAC;QACjC,SAAS,EAAE,CAAC,mCAAe,CAAC;QAC5B,OAAO,EAAE,CAAC,mCAAe,CAAC;KAC3B,CAAC;GACW,cAAc,CAAG"}
|
||||
33
apps/backend/dist/modules/codi-spei/codi-spei.service.d.ts
vendored
Normal file
33
apps/backend/dist/modules/codi-spei/codi-spei.service.d.ts
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
import { Repository, DataSource } from 'typeorm';
|
||||
import { VirtualAccount } from './entities/virtual-account.entity';
|
||||
import { CodiTransaction } from './entities/codi-transaction.entity';
|
||||
import { SpeiTransaction } from './entities/spei-transaction.entity';
|
||||
import { GenerateQrDto } from './dto/generate-qr.dto';
|
||||
export declare class CodiSpeiService {
|
||||
private readonly virtualAccountRepo;
|
||||
private readonly codiRepo;
|
||||
private readonly speiRepo;
|
||||
private readonly dataSource;
|
||||
constructor(virtualAccountRepo: Repository<VirtualAccount>, codiRepo: Repository<CodiTransaction>, speiRepo: Repository<SpeiTransaction>, dataSource: DataSource);
|
||||
getVirtualAccount(tenantId: string): Promise<VirtualAccount | null>;
|
||||
createVirtualAccount(tenantId: string, beneficiaryName: string, provider?: string): Promise<VirtualAccount>;
|
||||
generateQr(tenantId: string, dto: GenerateQrDto): Promise<CodiTransaction>;
|
||||
getCodiStatus(id: string): Promise<CodiTransaction>;
|
||||
confirmCodi(id: string, providerData: any): Promise<CodiTransaction>;
|
||||
getCodiTransactions(tenantId: string, limit?: number): Promise<CodiTransaction[]>;
|
||||
getSpeiTransactions(tenantId: string, limit?: number): Promise<SpeiTransaction[]>;
|
||||
receiveSpei(tenantId: string, data: {
|
||||
amount: number;
|
||||
senderClabe?: string;
|
||||
senderName?: string;
|
||||
senderRfc?: string;
|
||||
senderBank?: string;
|
||||
reference?: string;
|
||||
trackingKey?: string;
|
||||
providerData?: any;
|
||||
}): Promise<SpeiTransaction>;
|
||||
reconcileSpei(id: string, saleId: string): Promise<SpeiTransaction>;
|
||||
getSummary(tenantId: string, date?: Date): Promise<any>;
|
||||
handleCodiWebhook(payload: any): Promise<void>;
|
||||
handleSpeiWebhook(clabe: string, payload: any): Promise<void>;
|
||||
}
|
||||
193
apps/backend/dist/modules/codi-spei/codi-spei.service.js
vendored
Normal file
193
apps/backend/dist/modules/codi-spei/codi-spei.service.js
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
"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.CodiSpeiService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const virtual_account_entity_1 = require("./entities/virtual-account.entity");
|
||||
const codi_transaction_entity_1 = require("./entities/codi-transaction.entity");
|
||||
const spei_transaction_entity_1 = require("./entities/spei-transaction.entity");
|
||||
let CodiSpeiService = class CodiSpeiService {
|
||||
constructor(virtualAccountRepo, codiRepo, speiRepo, dataSource) {
|
||||
this.virtualAccountRepo = virtualAccountRepo;
|
||||
this.codiRepo = codiRepo;
|
||||
this.speiRepo = speiRepo;
|
||||
this.dataSource = dataSource;
|
||||
}
|
||||
async getVirtualAccount(tenantId) {
|
||||
return this.virtualAccountRepo.findOne({
|
||||
where: { tenantId, status: virtual_account_entity_1.VirtualAccountStatus.ACTIVE },
|
||||
});
|
||||
}
|
||||
async createVirtualAccount(tenantId, beneficiaryName, provider = 'stp') {
|
||||
const existing = await this.getVirtualAccount(tenantId);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
const mockClabe = `646180${Math.floor(Math.random() * 1000000000000).toString().padStart(12, '0')}`;
|
||||
const account = this.virtualAccountRepo.create({
|
||||
tenantId,
|
||||
provider,
|
||||
clabe: mockClabe,
|
||||
beneficiaryName,
|
||||
status: virtual_account_entity_1.VirtualAccountStatus.ACTIVE,
|
||||
});
|
||||
return this.virtualAccountRepo.save(account);
|
||||
}
|
||||
async generateQr(tenantId, dto) {
|
||||
const result = await this.dataSource.query(`SELECT generate_codi_reference($1) as reference`, [tenantId]);
|
||||
const reference = result[0].reference;
|
||||
const expiresAt = new Date();
|
||||
expiresAt.setMinutes(expiresAt.getMinutes() + 5);
|
||||
const qrData = JSON.stringify({
|
||||
type: 'codi',
|
||||
amount: dto.amount,
|
||||
reference,
|
||||
merchant: tenantId,
|
||||
expires: expiresAt.toISOString(),
|
||||
});
|
||||
const transaction = this.codiRepo.create({
|
||||
tenantId,
|
||||
saleId: dto.saleId,
|
||||
qrData,
|
||||
amount: dto.amount,
|
||||
reference,
|
||||
description: dto.description || `Cobro ${reference}`,
|
||||
status: codi_transaction_entity_1.CodiTransactionStatus.PENDING,
|
||||
expiresAt,
|
||||
});
|
||||
return this.codiRepo.save(transaction);
|
||||
}
|
||||
async getCodiStatus(id) {
|
||||
const transaction = await this.codiRepo.findOne({ where: { id } });
|
||||
if (!transaction) {
|
||||
throw new common_1.NotFoundException('Transaccion CoDi no encontrada');
|
||||
}
|
||||
if (transaction.status === codi_transaction_entity_1.CodiTransactionStatus.PENDING &&
|
||||
new Date() > transaction.expiresAt) {
|
||||
transaction.status = codi_transaction_entity_1.CodiTransactionStatus.EXPIRED;
|
||||
await this.codiRepo.save(transaction);
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
async confirmCodi(id, providerData) {
|
||||
const transaction = await this.getCodiStatus(id);
|
||||
if (transaction.status !== codi_transaction_entity_1.CodiTransactionStatus.PENDING) {
|
||||
throw new common_1.BadRequestException(`Transaccion no esta pendiente: ${transaction.status}`);
|
||||
}
|
||||
transaction.status = codi_transaction_entity_1.CodiTransactionStatus.CONFIRMED;
|
||||
transaction.confirmedAt = new Date();
|
||||
transaction.providerResponse = providerData;
|
||||
return this.codiRepo.save(transaction);
|
||||
}
|
||||
async getCodiTransactions(tenantId, limit = 50) {
|
||||
return this.codiRepo.find({
|
||||
where: { tenantId },
|
||||
order: { createdAt: 'DESC' },
|
||||
take: limit,
|
||||
});
|
||||
}
|
||||
async getSpeiTransactions(tenantId, limit = 50) {
|
||||
return this.speiRepo.find({
|
||||
where: { tenantId },
|
||||
order: { receivedAt: 'DESC' },
|
||||
take: limit,
|
||||
});
|
||||
}
|
||||
async receiveSpei(tenantId, data) {
|
||||
const account = await this.getVirtualAccount(tenantId);
|
||||
const transaction = this.speiRepo.create({
|
||||
tenantId,
|
||||
virtualAccountId: account?.id,
|
||||
amount: data.amount,
|
||||
senderClabe: data.senderClabe,
|
||||
senderName: data.senderName,
|
||||
senderRfc: data.senderRfc,
|
||||
senderBank: data.senderBank,
|
||||
reference: data.reference,
|
||||
trackingKey: data.trackingKey,
|
||||
status: spei_transaction_entity_1.SpeiTransactionStatus.RECEIVED,
|
||||
receivedAt: new Date(),
|
||||
providerData: data.providerData,
|
||||
});
|
||||
return this.speiRepo.save(transaction);
|
||||
}
|
||||
async reconcileSpei(id, saleId) {
|
||||
const transaction = await this.speiRepo.findOne({ where: { id } });
|
||||
if (!transaction) {
|
||||
throw new common_1.NotFoundException('Transaccion SPEI no encontrada');
|
||||
}
|
||||
transaction.saleId = saleId;
|
||||
transaction.status = spei_transaction_entity_1.SpeiTransactionStatus.RECONCILED;
|
||||
transaction.reconciledAt = new Date();
|
||||
return this.speiRepo.save(transaction);
|
||||
}
|
||||
async getSummary(tenantId, date) {
|
||||
const targetDate = date || new Date();
|
||||
const dateStr = targetDate.toISOString().split('T')[0];
|
||||
const result = await this.dataSource.query(`SELECT * FROM get_codi_spei_summary($1, $2::date)`, [tenantId, dateStr]);
|
||||
return result[0] || {
|
||||
codi_count: 0,
|
||||
codi_total: 0,
|
||||
spei_count: 0,
|
||||
spei_total: 0,
|
||||
};
|
||||
}
|
||||
async handleCodiWebhook(payload) {
|
||||
const { reference, status, transactionId } = payload;
|
||||
const transaction = await this.codiRepo.findOne({
|
||||
where: { reference },
|
||||
});
|
||||
if (!transaction) {
|
||||
throw new common_1.NotFoundException('Transaccion no encontrada');
|
||||
}
|
||||
if (status === 'confirmed') {
|
||||
await this.confirmCodi(transaction.id, {
|
||||
providerTransactionId: transactionId,
|
||||
...payload,
|
||||
});
|
||||
}
|
||||
}
|
||||
async handleSpeiWebhook(clabe, payload) {
|
||||
const account = await this.virtualAccountRepo.findOne({
|
||||
where: { clabe },
|
||||
});
|
||||
if (!account) {
|
||||
throw new common_1.NotFoundException('Cuenta virtual no encontrada');
|
||||
}
|
||||
await this.receiveSpei(account.tenantId, {
|
||||
amount: payload.amount,
|
||||
senderClabe: payload.senderClabe,
|
||||
senderName: payload.senderName,
|
||||
senderRfc: payload.senderRfc,
|
||||
senderBank: payload.senderBank,
|
||||
reference: payload.reference,
|
||||
trackingKey: payload.trackingKey,
|
||||
providerData: payload,
|
||||
});
|
||||
}
|
||||
};
|
||||
exports.CodiSpeiService = CodiSpeiService;
|
||||
exports.CodiSpeiService = CodiSpeiService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(virtual_account_entity_1.VirtualAccount)),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(codi_transaction_entity_1.CodiTransaction)),
|
||||
__param(2, (0, typeorm_1.InjectRepository)(spei_transaction_entity_1.SpeiTransaction)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.DataSource])
|
||||
], CodiSpeiService);
|
||||
//# sourceMappingURL=codi-spei.service.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/codi-spei.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/codi-spei.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
5
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.d.ts
vendored
Normal file
5
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export declare class GenerateQrDto {
|
||||
amount: number;
|
||||
description?: string;
|
||||
saleId?: string;
|
||||
}
|
||||
48
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.js
vendored
Normal file
48
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.js
vendored
Normal file
@ -0,0 +1,48 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GenerateQrDto = void 0;
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const class_validator_1 = require("class-validator");
|
||||
class GenerateQrDto {
|
||||
}
|
||||
exports.GenerateQrDto = GenerateQrDto;
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
example: 150.5,
|
||||
description: 'Monto a cobrar',
|
||||
}),
|
||||
(0, class_validator_1.IsNumber)(),
|
||||
(0, class_validator_1.Min)(1),
|
||||
(0, class_validator_1.Max)(8000),
|
||||
__metadata("design:type", Number)
|
||||
], GenerateQrDto.prototype, "amount", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
example: 'Venta #123',
|
||||
description: 'Descripcion del cobro',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
__metadata("design:type", String)
|
||||
], GenerateQrDto.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, swagger_1.ApiProperty)({
|
||||
example: 'sale-uuid',
|
||||
description: 'ID de la venta asociada',
|
||||
required: false,
|
||||
}),
|
||||
(0, class_validator_1.IsString)(),
|
||||
(0, class_validator_1.IsOptional)(),
|
||||
__metadata("design:type", String)
|
||||
], GenerateQrDto.prototype, "saleId", void 0);
|
||||
//# sourceMappingURL=generate-qr.dto.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/dto/generate-qr.dto.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"generate-qr.dto.js","sourceRoot":"","sources":["../../../../src/modules/codi-spei/dto/generate-qr.dto.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,6CAA8C;AAC9C,qDAA2E;AAE3E,MAAa,aAAa;CA2BzB;AA3BD,sCA2BC;AAnBC;IAPC,IAAA,qBAAW,EAAC;QACX,OAAO,EAAE,KAAK;QACd,WAAW,EAAE,gBAAgB;KAC9B,CAAC;IACD,IAAA,0BAAQ,GAAE;IACV,IAAA,qBAAG,EAAC,CAAC,CAAC;IACN,IAAA,qBAAG,EAAC,IAAI,CAAC;;6CACK;AASf;IAPC,IAAA,qBAAW,EAAC;QACX,OAAO,EAAE,YAAY;QACrB,WAAW,EAAE,uBAAuB;QACpC,QAAQ,EAAE,KAAK;KAChB,CAAC;IACD,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;kDACQ;AASrB;IAPC,IAAA,qBAAW,EAAC;QACX,OAAO,EAAE,WAAW;QACpB,WAAW,EAAE,yBAAyB;QACtC,QAAQ,EAAE,KAAK;KAChB,CAAC;IACD,IAAA,0BAAQ,GAAE;IACV,IAAA,4BAAU,GAAE;;6CACG"}
|
||||
23
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.d.ts
vendored
Normal file
23
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
export declare enum CodiTransactionStatus {
|
||||
PENDING = "pending",
|
||||
CONFIRMED = "confirmed",
|
||||
EXPIRED = "expired",
|
||||
CANCELLED = "cancelled"
|
||||
}
|
||||
export declare class CodiTransaction {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
saleId: string;
|
||||
qrData: string;
|
||||
qrImageUrl: string;
|
||||
amount: number;
|
||||
reference: string;
|
||||
description: string;
|
||||
status: CodiTransactionStatus;
|
||||
expiresAt: Date;
|
||||
confirmedAt: Date;
|
||||
providerTransactionId: string;
|
||||
providerResponse: Record<string, any>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
91
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.js
vendored
Normal file
91
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.js
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CodiTransaction = exports.CodiTransactionStatus = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
var CodiTransactionStatus;
|
||||
(function (CodiTransactionStatus) {
|
||||
CodiTransactionStatus["PENDING"] = "pending";
|
||||
CodiTransactionStatus["CONFIRMED"] = "confirmed";
|
||||
CodiTransactionStatus["EXPIRED"] = "expired";
|
||||
CodiTransactionStatus["CANCELLED"] = "cancelled";
|
||||
})(CodiTransactionStatus || (exports.CodiTransactionStatus = CodiTransactionStatus = {}));
|
||||
let CodiTransaction = class CodiTransaction {
|
||||
};
|
||||
exports.CodiTransaction = CodiTransaction;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "tenantId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sale_id', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "saleId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'qr_data', type: 'text' }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "qrData", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'qr_image_url', type: 'text', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "qrImageUrl", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'decimal', precision: 10, scale: 2 }),
|
||||
__metadata("design:type", Number)
|
||||
], CodiTransaction.prototype, "amount", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "reference", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 200, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
type: 'varchar',
|
||||
length: 20,
|
||||
default: CodiTransactionStatus.PENDING,
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'expires_at', type: 'timestamptz' }),
|
||||
__metadata("design:type", Date)
|
||||
], CodiTransaction.prototype, "expiresAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'confirmed_at', type: 'timestamptz', nullable: true }),
|
||||
__metadata("design:type", Date)
|
||||
], CodiTransaction.prototype, "confirmedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'provider_transaction_id', length: 100, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], CodiTransaction.prototype, "providerTransactionId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'provider_response', type: 'jsonb', nullable: true }),
|
||||
__metadata("design:type", Object)
|
||||
], CodiTransaction.prototype, "providerResponse", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], CodiTransaction.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], CodiTransaction.prototype, "updatedAt", void 0);
|
||||
exports.CodiTransaction = CodiTransaction = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'sales', name: 'codi_transactions' })
|
||||
], CodiTransaction);
|
||||
//# sourceMappingURL=codi-transaction.entity.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/entities/codi-transaction.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"codi-transaction.entity.js","sourceRoot":"","sources":["../../../../src/modules/codi-spei/entities/codi-transaction.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAMiB;AAEjB,IAAY,qBAKX;AALD,WAAY,qBAAqB;IAC/B,4CAAmB,CAAA;IACnB,gDAAuB,CAAA;IACvB,4CAAmB,CAAA;IACnB,gDAAuB,CAAA;AACzB,CAAC,EALW,qBAAqB,qCAArB,qBAAqB,QAKhC;AAGM,IAAM,eAAe,GAArB,MAAM,eAAe;CAiD3B,CAAA;AAjDY,0CAAe;AAE1B;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;2CACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;iDACb;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CAC7B;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;;+CAC3B;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDAC5C;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;+CACtC;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDACrB;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACpB;AAOpB;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,qBAAqB,CAAC,OAAO;KACvC,CAAC;;+CAC4B;AAG9B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;8BACzC,IAAI;kDAAC;AAGhB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BACzD,IAAI;oDAAC;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,yBAAyB,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;8DAC3C;AAG9B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;yDAC/B;AAGtC;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;0BAhDL,eAAe;IAD3B,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;GAC1C,eAAe,CAiD3B"}
|
||||
27
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.d.ts
vendored
Normal file
27
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
import { VirtualAccount } from './virtual-account.entity';
|
||||
export declare enum SpeiTransactionStatus {
|
||||
RECEIVED = "received",
|
||||
RECONCILED = "reconciled",
|
||||
DISPUTED = "disputed"
|
||||
}
|
||||
export declare class SpeiTransaction {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
virtualAccountId: string;
|
||||
saleId: string;
|
||||
amount: number;
|
||||
senderClabe: string;
|
||||
senderName: string;
|
||||
senderRfc: string;
|
||||
senderBank: string;
|
||||
reference: string;
|
||||
description: string;
|
||||
trackingKey: string;
|
||||
status: SpeiTransactionStatus;
|
||||
receivedAt: Date;
|
||||
reconciledAt: Date;
|
||||
providerData: Record<string, any>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
virtualAccount: VirtualAccount;
|
||||
}
|
||||
108
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.js
vendored
Normal file
108
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.js
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SpeiTransaction = exports.SpeiTransactionStatus = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
const virtual_account_entity_1 = require("./virtual-account.entity");
|
||||
var SpeiTransactionStatus;
|
||||
(function (SpeiTransactionStatus) {
|
||||
SpeiTransactionStatus["RECEIVED"] = "received";
|
||||
SpeiTransactionStatus["RECONCILED"] = "reconciled";
|
||||
SpeiTransactionStatus["DISPUTED"] = "disputed";
|
||||
})(SpeiTransactionStatus || (exports.SpeiTransactionStatus = SpeiTransactionStatus = {}));
|
||||
let SpeiTransaction = class SpeiTransaction {
|
||||
};
|
||||
exports.SpeiTransaction = SpeiTransaction;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "tenantId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'virtual_account_id', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "virtualAccountId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sale_id', nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "saleId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'decimal', precision: 10, scale: 2 }),
|
||||
__metadata("design:type", Number)
|
||||
], SpeiTransaction.prototype, "amount", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sender_clabe', length: 18, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "senderClabe", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sender_name', length: 100, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "senderName", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sender_rfc', length: 13, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "senderRfc", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'sender_bank', length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "senderBank", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "reference", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 200, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "description", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tracking_key', length: 50, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "trackingKey", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
type: 'varchar',
|
||||
length: 20,
|
||||
default: SpeiTransactionStatus.RECEIVED,
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], SpeiTransaction.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'received_at', type: 'timestamptz' }),
|
||||
__metadata("design:type", Date)
|
||||
], SpeiTransaction.prototype, "receivedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'reconciled_at', type: 'timestamptz', nullable: true }),
|
||||
__metadata("design:type", Date)
|
||||
], SpeiTransaction.prototype, "reconciledAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'provider_data', type: 'jsonb', nullable: true }),
|
||||
__metadata("design:type", Object)
|
||||
], SpeiTransaction.prototype, "providerData", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], SpeiTransaction.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], SpeiTransaction.prototype, "updatedAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.ManyToOne)(() => virtual_account_entity_1.VirtualAccount),
|
||||
(0, typeorm_1.JoinColumn)({ name: 'virtual_account_id' }),
|
||||
__metadata("design:type", virtual_account_entity_1.VirtualAccount)
|
||||
], SpeiTransaction.prototype, "virtualAccount", void 0);
|
||||
exports.SpeiTransaction = SpeiTransaction = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'sales', name: 'spei_transactions' })
|
||||
], SpeiTransaction);
|
||||
//# sourceMappingURL=spei-transaction.entity.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/entities/spei-transaction.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"spei-transaction.entity.js","sourceRoot":"","sources":["../../../../src/modules/codi-spei/entities/spei-transaction.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAQiB;AACjB,qEAA0D;AAE1D,IAAY,qBAIX;AAJD,WAAY,qBAAqB;IAC/B,8CAAqB,CAAA;IACrB,kDAAyB,CAAA;IACzB,8CAAqB,CAAA;AACvB,CAAC,EAJW,qBAAqB,qCAArB,qBAAqB,QAIhC;AAGM,IAAM,eAAe,GAArB,MAAM,eAAe;CA+D3B,CAAA;AA/DY,0CAAe;AAE1B;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;2CACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;iDACb;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;yDAC9B;AAGzB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;+CAC7B;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;;+CACtC;AAGf;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACzC;AAGpB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDAC1C;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDACzC;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;mDACzC;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;kDACrB;AAGlB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACpB;AAGpB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;oDACzC;AAOpB;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,qBAAqB,CAAC,QAAQ;KACxC,CAAC;;+CAC4B;AAG9B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC;8BACzC,IAAI;mDAAC;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;8BACzD,IAAI;qDAAC;AAGnB;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;qDAC/B;AAGlC;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;kDAAC;AAKhB;IAFC,IAAA,mBAAS,EAAC,GAAG,EAAE,CAAC,uCAAc,CAAC;IAC/B,IAAA,oBAAU,EAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,CAAC;8BAC3B,uCAAc;uDAAC;0BA9DpB,eAAe;IAD3B,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,CAAC;GAC1C,eAAe,CA+D3B"}
|
||||
16
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.d.ts
vendored
Normal file
16
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.d.ts
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
export declare enum VirtualAccountStatus {
|
||||
ACTIVE = "active",
|
||||
SUSPENDED = "suspended",
|
||||
CLOSED = "closed"
|
||||
}
|
||||
export declare class VirtualAccount {
|
||||
id: string;
|
||||
tenantId: string;
|
||||
provider: string;
|
||||
clabe: string;
|
||||
beneficiaryName: string;
|
||||
status: VirtualAccountStatus;
|
||||
metadata: Record<string, any>;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
66
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.js
vendored
Normal file
66
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.js
vendored
Normal file
@ -0,0 +1,66 @@
|
||||
"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);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.VirtualAccount = exports.VirtualAccountStatus = void 0;
|
||||
const typeorm_1 = require("typeorm");
|
||||
var VirtualAccountStatus;
|
||||
(function (VirtualAccountStatus) {
|
||||
VirtualAccountStatus["ACTIVE"] = "active";
|
||||
VirtualAccountStatus["SUSPENDED"] = "suspended";
|
||||
VirtualAccountStatus["CLOSED"] = "closed";
|
||||
})(VirtualAccountStatus || (exports.VirtualAccountStatus = VirtualAccountStatus = {}));
|
||||
let VirtualAccount = class VirtualAccount {
|
||||
};
|
||||
exports.VirtualAccount = VirtualAccount;
|
||||
__decorate([
|
||||
(0, typeorm_1.PrimaryGeneratedColumn)('uuid'),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "id", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'tenant_id' }),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "tenantId", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 20, default: 'stp' }),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "provider", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ length: 18, unique: true }),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "clabe", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ name: 'beneficiary_name', length: 100, nullable: true }),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "beneficiaryName", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({
|
||||
type: 'varchar',
|
||||
length: 20,
|
||||
default: VirtualAccountStatus.ACTIVE,
|
||||
}),
|
||||
__metadata("design:type", String)
|
||||
], VirtualAccount.prototype, "status", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.Column)({ type: 'jsonb', nullable: true }),
|
||||
__metadata("design:type", Object)
|
||||
], VirtualAccount.prototype, "metadata", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.CreateDateColumn)({ name: 'created_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], VirtualAccount.prototype, "createdAt", void 0);
|
||||
__decorate([
|
||||
(0, typeorm_1.UpdateDateColumn)({ name: 'updated_at' }),
|
||||
__metadata("design:type", Date)
|
||||
], VirtualAccount.prototype, "updatedAt", void 0);
|
||||
exports.VirtualAccount = VirtualAccount = __decorate([
|
||||
(0, typeorm_1.Entity)({ schema: 'sales', name: 'virtual_accounts' })
|
||||
], VirtualAccount);
|
||||
//# sourceMappingURL=virtual-account.entity.js.map
|
||||
1
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.js.map
vendored
Normal file
1
apps/backend/dist/modules/codi-spei/entities/virtual-account.entity.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"virtual-account.entity.js","sourceRoot":"","sources":["../../../../src/modules/codi-spei/entities/virtual-account.entity.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAMiB;AAEjB,IAAY,oBAIX;AAJD,WAAY,oBAAoB;IAC9B,yCAAiB,CAAA;IACjB,+CAAuB,CAAA;IACvB,yCAAiB,CAAA;AACnB,CAAC,EAJW,oBAAoB,oCAApB,oBAAoB,QAI/B;AAGM,IAAM,cAAc,GAApB,MAAM,cAAc;CA+B1B,CAAA;AA/BY,wCAAc;AAEzB;IADC,IAAA,gCAAsB,EAAC,MAAM,CAAC;;0CACpB;AAGX;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC;;gDACb;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;;gDACtB;AAGjB;IADC,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;;6CACvB;AAGd;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;uDAC1C;AAOxB;IALC,IAAA,gBAAM,EAAC;QACN,IAAI,EAAE,SAAS;QACf,MAAM,EAAE,EAAE;QACV,OAAO,EAAE,oBAAoB,CAAC,MAAM;KACrC,CAAC;;8CAC2B;AAG7B;IADC,IAAA,gBAAM,EAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;;gDACZ;AAG9B;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;iDAAC;AAGhB;IADC,IAAA,0BAAgB,EAAC,EAAE,IAAI,EAAE,YAAY,EAAE,CAAC;8BAC9B,IAAI;iDAAC;yBA9BL,cAAc;IAD1B,IAAA,gBAAM,EAAC,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;GACzC,cAAc,CA+B1B"}
|
||||
29
apps/backend/dist/modules/customers/customers.controller.d.ts
vendored
Normal file
29
apps/backend/dist/modules/customers/customers.controller.d.ts
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
import { CustomersService } from './customers.service';
|
||||
import { CreateCustomerDto, UpdateCustomerDto, CreateFiadoDto, PayFiadoDto } from './dto/customer.dto';
|
||||
export declare class CustomersController {
|
||||
private readonly customersService;
|
||||
constructor(customersService: CustomersService);
|
||||
findAll(req: any): Promise<import("./entities/customer.entity").Customer[]>;
|
||||
getWithFiados(req: any): Promise<import("./entities/customer.entity").Customer[]>;
|
||||
findByPhone(req: any, phone: string): Promise<import("./entities/customer.entity").Customer>;
|
||||
findOne(req: any, id: string): Promise<import("./entities/customer.entity").Customer>;
|
||||
getStats(req: any, id: string): Promise<{
|
||||
customer: import("./entities/customer.entity").Customer;
|
||||
stats: {
|
||||
totalPurchases: number;
|
||||
purchaseCount: number;
|
||||
fiadoBalance: number;
|
||||
fiadoLimit: number;
|
||||
fiadoAvailable: number;
|
||||
pendingFiados: number;
|
||||
};
|
||||
}>;
|
||||
create(req: any, dto: CreateCustomerDto): Promise<import("./entities/customer.entity").Customer>;
|
||||
update(req: any, id: string, dto: UpdateCustomerDto): Promise<import("./entities/customer.entity").Customer>;
|
||||
toggleActive(req: any, id: string): Promise<import("./entities/customer.entity").Customer>;
|
||||
getFiados(req: any, customerId?: string): Promise<import("./entities/fiado.entity").Fiado[]>;
|
||||
getPendingFiados(req: any): Promise<import("./entities/fiado.entity").Fiado[]>;
|
||||
createFiado(req: any, dto: CreateFiadoDto): Promise<import("./entities/fiado.entity").Fiado>;
|
||||
payFiado(req: any, id: string, dto: PayFiadoDto): Promise<import("./entities/fiado.entity").Fiado>;
|
||||
cancelFiado(req: any, id: string): Promise<import("./entities/fiado.entity").Fiado>;
|
||||
}
|
||||
190
apps/backend/dist/modules/customers/customers.controller.js
vendored
Normal file
190
apps/backend/dist/modules/customers/customers.controller.js
vendored
Normal file
@ -0,0 +1,190 @@
|
||||
"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.CustomersController = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const swagger_1 = require("@nestjs/swagger");
|
||||
const jwt_auth_guard_1 = require("../auth/guards/jwt-auth.guard");
|
||||
const customers_service_1 = require("./customers.service");
|
||||
const customer_dto_1 = require("./dto/customer.dto");
|
||||
let CustomersController = class CustomersController {
|
||||
constructor(customersService) {
|
||||
this.customersService = customersService;
|
||||
}
|
||||
findAll(req) {
|
||||
return this.customersService.findAll(req.user.tenantId);
|
||||
}
|
||||
getWithFiados(req) {
|
||||
return this.customersService.getWithFiados(req.user.tenantId);
|
||||
}
|
||||
findByPhone(req, phone) {
|
||||
return this.customersService.findByPhone(req.user.tenantId, phone);
|
||||
}
|
||||
findOne(req, id) {
|
||||
return this.customersService.findOne(req.user.tenantId, id);
|
||||
}
|
||||
getStats(req, id) {
|
||||
return this.customersService.getCustomerStats(req.user.tenantId, id);
|
||||
}
|
||||
create(req, dto) {
|
||||
return this.customersService.create(req.user.tenantId, dto);
|
||||
}
|
||||
update(req, id, dto) {
|
||||
return this.customersService.update(req.user.tenantId, id, dto);
|
||||
}
|
||||
toggleActive(req, id) {
|
||||
return this.customersService.toggleActive(req.user.tenantId, id);
|
||||
}
|
||||
getFiados(req, customerId) {
|
||||
return this.customersService.getFiados(req.user.tenantId, customerId);
|
||||
}
|
||||
getPendingFiados(req) {
|
||||
return this.customersService.getPendingFiados(req.user.tenantId);
|
||||
}
|
||||
createFiado(req, dto) {
|
||||
return this.customersService.createFiado(req.user.tenantId, dto);
|
||||
}
|
||||
payFiado(req, id, dto) {
|
||||
return this.customersService.payFiado(req.user.tenantId, id, dto, req.user.id);
|
||||
}
|
||||
cancelFiado(req, id) {
|
||||
return this.customersService.cancelFiado(req.user.tenantId, id);
|
||||
}
|
||||
};
|
||||
exports.CustomersController = CustomersController;
|
||||
__decorate([
|
||||
(0, common_1.Get)(),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar todos los clientes' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "findAll", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('with-fiados'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar clientes con fiado habilitado' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "getWithFiados", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('phone/:phone'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Buscar cliente por teléfono' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('phone')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "findByPhone", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)(':id'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Obtener cliente por ID' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "findOne", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)(':id/stats'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Obtener estadísticas del cliente' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "getStats", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)(),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Crear nuevo cliente' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, customer_dto_1.CreateCustomerDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "create", null);
|
||||
__decorate([
|
||||
(0, common_1.Put)(':id'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Actualizar cliente' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String, customer_dto_1.UpdateCustomerDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "update", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)(':id/toggle-active'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Activar/desactivar cliente' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "toggleActive", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('fiados/all'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar todos los fiados' }),
|
||||
(0, swagger_1.ApiQuery)({ name: 'customerId', required: false }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Query)('customerId')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "getFiados", null);
|
||||
__decorate([
|
||||
(0, common_1.Get)('fiados/pending'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Listar fiados pendientes' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "getPendingFiados", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('fiados'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Crear nuevo fiado' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, customer_dto_1.CreateFiadoDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "createFiado", null);
|
||||
__decorate([
|
||||
(0, common_1.Post)('fiados/:id/pay'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Registrar pago de fiado' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__param(2, (0, common_1.Body)()),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String, customer_dto_1.PayFiadoDto]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "payFiado", null);
|
||||
__decorate([
|
||||
(0, common_1.Patch)('fiados/:id/cancel'),
|
||||
(0, swagger_1.ApiOperation)({ summary: 'Cancelar fiado' }),
|
||||
__param(0, (0, common_1.Request)()),
|
||||
__param(1, (0, common_1.Param)('id')),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [Object, String]),
|
||||
__metadata("design:returntype", void 0)
|
||||
], CustomersController.prototype, "cancelFiado", null);
|
||||
exports.CustomersController = CustomersController = __decorate([
|
||||
(0, swagger_1.ApiTags)('customers'),
|
||||
(0, swagger_1.ApiBearerAuth)(),
|
||||
(0, common_1.UseGuards)(jwt_auth_guard_1.JwtAuthGuard),
|
||||
(0, common_1.Controller)('v1/customers'),
|
||||
__metadata("design:paramtypes", [customers_service_1.CustomersService])
|
||||
], CustomersController);
|
||||
//# sourceMappingURL=customers.controller.js.map
|
||||
1
apps/backend/dist/modules/customers/customers.controller.js.map
vendored
Normal file
1
apps/backend/dist/modules/customers/customers.controller.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"customers.controller.js","sourceRoot":"","sources":["../../../src/modules/customers/customers.controller.ts"],"names":[],"mappings":"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"}
|
||||
2
apps/backend/dist/modules/customers/customers.module.d.ts
vendored
Normal file
2
apps/backend/dist/modules/customers/customers.module.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
export declare class CustomersModule {
|
||||
}
|
||||
28
apps/backend/dist/modules/customers/customers.module.js
vendored
Normal file
28
apps/backend/dist/modules/customers/customers.module.js
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
"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;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.CustomersModule = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const customers_controller_1 = require("./customers.controller");
|
||||
const customers_service_1 = require("./customers.service");
|
||||
const customer_entity_1 = require("./entities/customer.entity");
|
||||
const fiado_entity_1 = require("./entities/fiado.entity");
|
||||
const fiado_payment_entity_1 = require("./entities/fiado-payment.entity");
|
||||
let CustomersModule = class CustomersModule {
|
||||
};
|
||||
exports.CustomersModule = CustomersModule;
|
||||
exports.CustomersModule = CustomersModule = __decorate([
|
||||
(0, common_1.Module)({
|
||||
imports: [typeorm_1.TypeOrmModule.forFeature([customer_entity_1.Customer, fiado_entity_1.Fiado, fiado_payment_entity_1.FiadoPayment])],
|
||||
controllers: [customers_controller_1.CustomersController],
|
||||
providers: [customers_service_1.CustomersService],
|
||||
exports: [customers_service_1.CustomersService],
|
||||
})
|
||||
], CustomersModule);
|
||||
//# sourceMappingURL=customers.module.js.map
|
||||
1
apps/backend/dist/modules/customers/customers.module.js.map
vendored
Normal file
1
apps/backend/dist/modules/customers/customers.module.js.map
vendored
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"file":"customers.module.js","sourceRoot":"","sources":["../../../src/modules/customers/customers.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AACxC,6CAAgD;AAChD,iEAA6D;AAC7D,2DAAuD;AACvD,gEAAsD;AACtD,0DAAgD;AAChD,0EAA+D;AAQxD,IAAM,eAAe,GAArB,MAAM,eAAe;CAAG,CAAA;AAAlB,0CAAe;0BAAf,eAAe;IAN3B,IAAA,eAAM,EAAC;QACN,OAAO,EAAE,CAAC,uBAAa,CAAC,UAAU,CAAC,CAAC,0BAAQ,EAAE,oBAAK,EAAE,mCAAY,CAAC,CAAC,CAAC;QACpE,WAAW,EAAE,CAAC,0CAAmB,CAAC;QAClC,SAAS,EAAE,CAAC,oCAAgB,CAAC;QAC7B,OAAO,EAAE,CAAC,oCAAgB,CAAC;KAC5B,CAAC;GACW,eAAe,CAAG"}
|
||||
34
apps/backend/dist/modules/customers/customers.service.d.ts
vendored
Normal file
34
apps/backend/dist/modules/customers/customers.service.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
import { Repository } from 'typeorm';
|
||||
import { Customer } from './entities/customer.entity';
|
||||
import { Fiado } from './entities/fiado.entity';
|
||||
import { FiadoPayment } from './entities/fiado-payment.entity';
|
||||
import { CreateCustomerDto, UpdateCustomerDto, CreateFiadoDto, PayFiadoDto } from './dto/customer.dto';
|
||||
export declare class CustomersService {
|
||||
private readonly customerRepo;
|
||||
private readonly fiadoRepo;
|
||||
private readonly fiadoPaymentRepo;
|
||||
constructor(customerRepo: Repository<Customer>, fiadoRepo: Repository<Fiado>, fiadoPaymentRepo: Repository<FiadoPayment>);
|
||||
findAll(tenantId: string): Promise<Customer[]>;
|
||||
findOne(tenantId: string, id: string): Promise<Customer>;
|
||||
findByPhone(tenantId: string, phone: string): Promise<Customer | null>;
|
||||
create(tenantId: string, dto: CreateCustomerDto): Promise<Customer>;
|
||||
update(tenantId: string, id: string, dto: UpdateCustomerDto): Promise<Customer>;
|
||||
toggleActive(tenantId: string, id: string): Promise<Customer>;
|
||||
getWithFiados(tenantId: string): Promise<Customer[]>;
|
||||
createFiado(tenantId: string, dto: CreateFiadoDto): Promise<Fiado>;
|
||||
getFiados(tenantId: string, customerId?: string): Promise<Fiado[]>;
|
||||
getPendingFiados(tenantId: string): Promise<Fiado[]>;
|
||||
payFiado(tenantId: string, fiadoId: string, dto: PayFiadoDto, userId?: string): Promise<Fiado>;
|
||||
cancelFiado(tenantId: string, fiadoId: string): Promise<Fiado>;
|
||||
getCustomerStats(tenantId: string, customerId: string): Promise<{
|
||||
customer: Customer;
|
||||
stats: {
|
||||
totalPurchases: number;
|
||||
purchaseCount: number;
|
||||
fiadoBalance: number;
|
||||
fiadoLimit: number;
|
||||
fiadoAvailable: number;
|
||||
pendingFiados: number;
|
||||
};
|
||||
}>;
|
||||
}
|
||||
202
apps/backend/dist/modules/customers/customers.service.js
vendored
Normal file
202
apps/backend/dist/modules/customers/customers.service.js
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
"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.CustomersService = void 0;
|
||||
const common_1 = require("@nestjs/common");
|
||||
const typeorm_1 = require("@nestjs/typeorm");
|
||||
const typeorm_2 = require("typeorm");
|
||||
const customer_entity_1 = require("./entities/customer.entity");
|
||||
const fiado_entity_1 = require("./entities/fiado.entity");
|
||||
const fiado_payment_entity_1 = require("./entities/fiado-payment.entity");
|
||||
let CustomersService = class CustomersService {
|
||||
constructor(customerRepo, fiadoRepo, fiadoPaymentRepo) {
|
||||
this.customerRepo = customerRepo;
|
||||
this.fiadoRepo = fiadoRepo;
|
||||
this.fiadoPaymentRepo = fiadoPaymentRepo;
|
||||
}
|
||||
async findAll(tenantId) {
|
||||
return this.customerRepo.find({
|
||||
where: { tenantId, status: 'active' },
|
||||
order: { name: 'ASC' },
|
||||
});
|
||||
}
|
||||
async findOne(tenantId, id) {
|
||||
const customer = await this.customerRepo.findOne({
|
||||
where: { id, tenantId },
|
||||
relations: ['fiados'],
|
||||
});
|
||||
if (!customer) {
|
||||
throw new common_1.NotFoundException('Cliente no encontrado');
|
||||
}
|
||||
return customer;
|
||||
}
|
||||
async findByPhone(tenantId, phone) {
|
||||
return this.customerRepo.findOne({
|
||||
where: { tenantId, phone },
|
||||
});
|
||||
}
|
||||
async create(tenantId, dto) {
|
||||
const customer = this.customerRepo.create({
|
||||
...dto,
|
||||
tenantId,
|
||||
});
|
||||
return this.customerRepo.save(customer);
|
||||
}
|
||||
async update(tenantId, id, dto) {
|
||||
const customer = await this.findOne(tenantId, id);
|
||||
Object.assign(customer, dto);
|
||||
return this.customerRepo.save(customer);
|
||||
}
|
||||
async toggleActive(tenantId, id) {
|
||||
const customer = await this.findOne(tenantId, id);
|
||||
customer.status = customer.status === 'active' ? 'inactive' : 'active';
|
||||
return this.customerRepo.save(customer);
|
||||
}
|
||||
async getWithFiados(tenantId) {
|
||||
return this.customerRepo.find({
|
||||
where: { tenantId, fiadoEnabled: true },
|
||||
order: { currentFiadoBalance: 'DESC' },
|
||||
});
|
||||
}
|
||||
async createFiado(tenantId, dto) {
|
||||
const customer = await this.findOne(tenantId, dto.customerId);
|
||||
if (!customer.fiadoEnabled) {
|
||||
throw new common_1.BadRequestException('El cliente no tiene habilitado el fiado');
|
||||
}
|
||||
const newBalance = Number(customer.currentFiadoBalance) + dto.amount;
|
||||
if (customer.fiadoLimit > 0 && newBalance > customer.fiadoLimit) {
|
||||
throw new common_1.BadRequestException(`El fiado excede el límite. Límite: $${customer.fiadoLimit}, Balance actual: $${customer.currentFiadoBalance}`);
|
||||
}
|
||||
const fiado = this.fiadoRepo.create({
|
||||
tenantId,
|
||||
customerId: dto.customerId,
|
||||
saleId: dto.saleId,
|
||||
amount: dto.amount,
|
||||
remainingAmount: dto.amount,
|
||||
description: dto.description,
|
||||
dueDate: dto.dueDate ? new Date(dto.dueDate) : null,
|
||||
status: fiado_entity_1.FiadoStatus.PENDING,
|
||||
});
|
||||
await this.fiadoRepo.save(fiado);
|
||||
customer.currentFiadoBalance = newBalance;
|
||||
await this.customerRepo.save(customer);
|
||||
return fiado;
|
||||
}
|
||||
async getFiados(tenantId, customerId) {
|
||||
const where = { tenantId };
|
||||
if (customerId) {
|
||||
where.customerId = customerId;
|
||||
}
|
||||
return this.fiadoRepo.find({
|
||||
where,
|
||||
relations: ['customer', 'payments'],
|
||||
order: { createdAt: 'DESC' },
|
||||
});
|
||||
}
|
||||
async getPendingFiados(tenantId) {
|
||||
return this.fiadoRepo.find({
|
||||
where: [
|
||||
{ tenantId, status: fiado_entity_1.FiadoStatus.PENDING },
|
||||
{ tenantId, status: fiado_entity_1.FiadoStatus.PARTIAL },
|
||||
],
|
||||
relations: ['customer'],
|
||||
order: { createdAt: 'ASC' },
|
||||
});
|
||||
}
|
||||
async payFiado(tenantId, fiadoId, dto, userId) {
|
||||
const fiado = await this.fiadoRepo.findOne({
|
||||
where: { id: fiadoId, tenantId },
|
||||
relations: ['customer'],
|
||||
});
|
||||
if (!fiado) {
|
||||
throw new common_1.NotFoundException('Fiado no encontrado');
|
||||
}
|
||||
if (fiado.status === fiado_entity_1.FiadoStatus.PAID) {
|
||||
throw new common_1.BadRequestException('Este fiado ya está pagado');
|
||||
}
|
||||
if (dto.amount > Number(fiado.remainingAmount)) {
|
||||
throw new common_1.BadRequestException(`El monto excede el saldo pendiente: $${fiado.remainingAmount}`);
|
||||
}
|
||||
const payment = this.fiadoPaymentRepo.create({
|
||||
fiadoId,
|
||||
amount: dto.amount,
|
||||
paymentMethod: dto.paymentMethod || 'cash',
|
||||
notes: dto.notes,
|
||||
receivedBy: userId,
|
||||
});
|
||||
await this.fiadoPaymentRepo.save(payment);
|
||||
fiado.paidAmount = Number(fiado.paidAmount) + dto.amount;
|
||||
fiado.remainingAmount = Number(fiado.remainingAmount) - dto.amount;
|
||||
if (fiado.remainingAmount <= 0) {
|
||||
fiado.status = fiado_entity_1.FiadoStatus.PAID;
|
||||
fiado.paidAt = new Date();
|
||||
}
|
||||
else {
|
||||
fiado.status = fiado_entity_1.FiadoStatus.PARTIAL;
|
||||
}
|
||||
await this.fiadoRepo.save(fiado);
|
||||
const customer = fiado.customer;
|
||||
customer.currentFiadoBalance = Number(customer.currentFiadoBalance) - dto.amount;
|
||||
await this.customerRepo.save(customer);
|
||||
return fiado;
|
||||
}
|
||||
async cancelFiado(tenantId, fiadoId) {
|
||||
const fiado = await this.fiadoRepo.findOne({
|
||||
where: { id: fiadoId, tenantId },
|
||||
relations: ['customer'],
|
||||
});
|
||||
if (!fiado) {
|
||||
throw new common_1.NotFoundException('Fiado no encontrado');
|
||||
}
|
||||
if (fiado.status === fiado_entity_1.FiadoStatus.PAID) {
|
||||
throw new common_1.BadRequestException('No se puede cancelar un fiado pagado');
|
||||
}
|
||||
const customer = fiado.customer;
|
||||
customer.currentFiadoBalance = Number(customer.currentFiadoBalance) - Number(fiado.remainingAmount);
|
||||
await this.customerRepo.save(customer);
|
||||
fiado.status = fiado_entity_1.FiadoStatus.CANCELLED;
|
||||
return this.fiadoRepo.save(fiado);
|
||||
}
|
||||
async getCustomerStats(tenantId, customerId) {
|
||||
const customer = await this.findOne(tenantId, customerId);
|
||||
const pendingFiados = await this.fiadoRepo.count({
|
||||
where: [
|
||||
{ customerId, status: fiado_entity_1.FiadoStatus.PENDING },
|
||||
{ customerId, status: fiado_entity_1.FiadoStatus.PARTIAL },
|
||||
],
|
||||
});
|
||||
return {
|
||||
customer,
|
||||
stats: {
|
||||
totalPurchases: customer.totalPurchases,
|
||||
purchaseCount: customer.purchaseCount,
|
||||
fiadoBalance: customer.currentFiadoBalance,
|
||||
fiadoLimit: customer.fiadoLimit,
|
||||
fiadoAvailable: Math.max(0, Number(customer.fiadoLimit) - Number(customer.currentFiadoBalance)),
|
||||
pendingFiados,
|
||||
},
|
||||
};
|
||||
}
|
||||
};
|
||||
exports.CustomersService = CustomersService;
|
||||
exports.CustomersService = CustomersService = __decorate([
|
||||
(0, common_1.Injectable)(),
|
||||
__param(0, (0, typeorm_1.InjectRepository)(customer_entity_1.Customer)),
|
||||
__param(1, (0, typeorm_1.InjectRepository)(fiado_entity_1.Fiado)),
|
||||
__param(2, (0, typeorm_1.InjectRepository)(fiado_payment_entity_1.FiadoPayment)),
|
||||
__metadata("design:paramtypes", [typeorm_2.Repository,
|
||||
typeorm_2.Repository,
|
||||
typeorm_2.Repository])
|
||||
], CustomersService);
|
||||
//# sourceMappingURL=customers.service.js.map
|
||||
1
apps/backend/dist/modules/customers/customers.service.js.map
vendored
Normal file
1
apps/backend/dist/modules/customers/customers.service.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
26
apps/backend/dist/modules/customers/dto/customer.dto.d.ts
vendored
Normal file
26
apps/backend/dist/modules/customers/dto/customer.dto.d.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
export declare class CreateCustomerDto {
|
||||
name: string;
|
||||
phone?: string;
|
||||
whatsapp?: string;
|
||||
email?: string;
|
||||
address?: string;
|
||||
notes?: string;
|
||||
fiadoEnabled?: boolean;
|
||||
fiadoLimit?: number;
|
||||
}
|
||||
declare const UpdateCustomerDto_base: import("@nestjs/common").Type<Partial<CreateCustomerDto>>;
|
||||
export declare class UpdateCustomerDto extends UpdateCustomerDto_base {
|
||||
}
|
||||
export declare class CreateFiadoDto {
|
||||
customerId: string;
|
||||
saleId?: string;
|
||||
amount: number;
|
||||
description?: string;
|
||||
dueDate?: string;
|
||||
}
|
||||
export declare class PayFiadoDto {
|
||||
amount: number;
|
||||
paymentMethod?: string;
|
||||
notes?: string;
|
||||
}
|
||||
export {};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user