Initial commit - Horux Despachos NL

This commit is contained in:
2026-05-03 16:47:53 -06:00
commit b00b677c54
647 changed files with 133843 additions and 0 deletions

View File

@@ -0,0 +1,634 @@
-- CreateEnum
CREATE TYPE "Plan" AS ENUM ('starter', 'business', 'business_ia', 'custom', 'enterprise');
-- CreateEnum
CREATE TYPE "PlatformRole" AS ENUM ('platform_admin', 'platform_ti', 'platform_support', 'platform_sales', 'platform_finance');
-- CreateEnum
CREATE TYPE "SatSyncType" AS ENUM ('initial', 'daily', 'incremental');
-- CreateEnum
CREATE TYPE "SatSyncStatus" AS ENUM ('pending', 'running', 'completed', 'failed');
-- CreateEnum
CREATE TYPE "CfdiSyncType" AS ENUM ('emitidos', 'recibidos');
-- CreateTable
CREATE TABLE "tenants" (
"id" TEXT NOT NULL,
"nombre" TEXT NOT NULL,
"rfc" TEXT NOT NULL,
"plan" "Plan" NOT NULL DEFAULT 'starter',
"database_name" TEXT NOT NULL,
"cfdi_limit" INTEGER NOT NULL DEFAULT 100,
"users_limit" INTEGER NOT NULL DEFAULT 1,
"active" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expires_at" TIMESTAMP(3),
"trial_ends_at" TIMESTAMP(3),
"facturapi_org_id" TEXT,
"codigo_postal" VARCHAR(5),
"calle" VARCHAR(255),
"num_exterior" VARCHAR(20),
"num_interior" VARCHAR(20),
"colonia" VARCHAR(255),
"ciudad" VARCHAR(100),
"municipio" VARCHAR(100),
"estado" VARCHAR(100),
"telefono" VARCHAR(20),
CONSTRAINT "tenants_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "users" (
"id" TEXT NOT NULL,
"email" TEXT NOT NULL,
"password_hash" TEXT NOT NULL,
"nombre" TEXT NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT true,
"last_login" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"token_version" INTEGER NOT NULL DEFAULT 0,
"last_tenant_id" TEXT,
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "tenant_memberships" (
"id" SERIAL NOT NULL,
"user_id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"rol_id" INTEGER NOT NULL,
"is_owner" BOOLEAN NOT NULL DEFAULT false,
"active" BOOLEAN NOT NULL DEFAULT true,
"joined_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "tenant_memberships_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "roles" (
"id" SERIAL NOT NULL,
"nombre" VARCHAR(20) NOT NULL,
"descripcion" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "roles_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "refresh_tokens" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires_at" TIMESTAMP(3) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "refresh_tokens_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "password_reset_tokens" (
"id" TEXT NOT NULL,
"user_id" TEXT NOT NULL,
"token" TEXT NOT NULL,
"expires_at" TIMESTAMP(3) NOT NULL,
"used_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "password_reset_tokens_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "regimenes" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(3) NOT NULL,
"descripcion" TEXT NOT NULL,
"tipo_persona" VARCHAR(20) NOT NULL,
"activo" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "regimenes_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "tenant_regimenes_ignorados" (
"id" SERIAL NOT NULL,
"tenant_id" TEXT NOT NULL,
"regimen_id" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "tenant_regimenes_ignorados_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "tenant_regimenes_activos" (
"id" SERIAL NOT NULL,
"tenant_id" TEXT NOT NULL,
"regimen_id" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "tenant_regimenes_activos_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "eventos_fiscales_catalogo" (
"id" SERIAL NOT NULL,
"titulo" TEXT NOT NULL,
"descripcion" TEXT,
"tipo" VARCHAR(20) NOT NULL,
"dia_base" INTEGER NOT NULL,
"mes_relativo" INTEGER NOT NULL DEFAULT 1,
"mes_fijo" INTEGER,
"recurrencia" VARCHAR(20) NOT NULL DEFAULT 'mensual',
"usa_extension_rfc" BOOLEAN NOT NULL DEFAULT false,
"regimenes" TEXT NOT NULL DEFAULT 'todos',
"condicion" VARCHAR(50),
"activo" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "eventos_fiscales_catalogo_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "lista_negra" (
"id" SERIAL NOT NULL,
"rfc" VARCHAR(13) NOT NULL,
"nombre" TEXT NOT NULL,
"situacion" VARCHAR(30) NOT NULL,
"updated_at" TIMESTAMP(3) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "lista_negra_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "dias_inhabiles" (
"id" SERIAL NOT NULL,
"fecha" DATE NOT NULL,
"nombre" TEXT NOT NULL,
CONSTRAINT "dias_inhabiles_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "isr_resico_tasas" (
"id" SERIAL NOT NULL,
"anio" INTEGER NOT NULL,
"monto_maximo" DECIMAL(18,2) NOT NULL,
"porcentaje" DECIMAL(5,2) NOT NULL,
CONSTRAINT "isr_resico_tasas_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "isr_tarifas" (
"id" SERIAL NOT NULL,
"anio" INTEGER NOT NULL,
"limite_inferior" DECIMAL(18,2) NOT NULL,
"limite_superior" DECIMAL(18,2),
"cuota_fija" DECIMAL(18,2) NOT NULL,
"porcentaje_excedente" DECIMAL(5,2) NOT NULL,
CONSTRAINT "isr_tarifas_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "coeficiente_utilidad" (
"id" SERIAL NOT NULL,
"tenant_id" TEXT NOT NULL,
"anio" INTEGER NOT NULL,
"coeficiente" DECIMAL(10,4) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "coeficiente_utilidad_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "fiel_credentials" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"rfc" VARCHAR(13) NOT NULL,
"cer_data" BYTEA NOT NULL,
"key_data" BYTEA NOT NULL,
"key_password_encrypted" BYTEA NOT NULL,
"cer_iv" BYTEA NOT NULL,
"cer_tag" BYTEA NOT NULL,
"key_iv" BYTEA NOT NULL,
"key_tag" BYTEA NOT NULL,
"password_iv" BYTEA NOT NULL,
"password_tag" BYTEA NOT NULL,
"serial_number" VARCHAR(50),
"valid_from" TIMESTAMP(3) NOT NULL,
"valid_until" TIMESTAMP(3) NOT NULL,
"is_active" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "fiel_credentials_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "subscriptions" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"plan" "Plan" NOT NULL,
"mp_preapproval_id" TEXT,
"status" TEXT NOT NULL DEFAULT 'pending',
"amount" DECIMAL(10,2) NOT NULL,
"frequency" TEXT NOT NULL DEFAULT 'monthly',
"current_period_start" TIMESTAMP(3),
"current_period_end" TIMESTAMP(3),
"pending_plan" "Plan",
"pending_frequency" TEXT,
"pending_effective_at" TIMESTAMP(3),
"upgrade_preference_id" TEXT,
"upgrade_target_plan" "Plan",
"upgrade_target_amount" DECIMAL(10,2),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "subscriptions_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "user_platform_roles" (
"id" SERIAL NOT NULL,
"user_id" TEXT NOT NULL,
"role" "PlatformRole" NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"created_by" TEXT,
CONSTRAINT "user_platform_roles_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "audit_log" (
"id" TEXT NOT NULL,
"user_id" TEXT,
"tenant_id" TEXT,
"action" VARCHAR(64) NOT NULL,
"entity_type" VARCHAR(32),
"entity_id" TEXT,
"metadata" JSONB,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "audit_log_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "trial_usages" (
"id" SERIAL NOT NULL,
"rfc" VARCHAR(13) NOT NULL,
"tenant_id" TEXT,
"started_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "trial_usages_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "plan_prices" (
"id" SERIAL NOT NULL,
"plan" "Plan" NOT NULL,
"frequency" TEXT NOT NULL,
"amount" DECIMAL(10,2) NOT NULL,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "plan_prices_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "payments" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"subscription_id" TEXT,
"mp_payment_id" TEXT,
"amount" DECIMAL(10,2) NOT NULL,
"status" TEXT NOT NULL DEFAULT 'pending',
"payment_method" TEXT,
"paid_at" TIMESTAMP(3),
"facturapi_invoice_id" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "payments_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "sat_sync_jobs" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"type" "SatSyncType" NOT NULL,
"status" "SatSyncStatus" NOT NULL DEFAULT 'pending',
"date_from" DATE NOT NULL,
"date_to" DATE NOT NULL,
"cfdi_type" "CfdiSyncType",
"sat_request_id" VARCHAR(50),
"sat_package_ids" TEXT[],
"cfdis_found" INTEGER NOT NULL DEFAULT 0,
"cfdis_downloaded" INTEGER NOT NULL DEFAULT 0,
"cfdis_inserted" INTEGER NOT NULL DEFAULT 0,
"cfdis_updated" INTEGER NOT NULL DEFAULT 0,
"progress_percent" INTEGER NOT NULL DEFAULT 0,
"error_message" TEXT,
"started_at" TIMESTAMP(3),
"completed_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"retry_count" INTEGER NOT NULL DEFAULT 0,
"next_retry_at" TIMESTAMP(3),
CONSTRAINT "sat_sync_jobs_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_forma_pago" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(2) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_forma_pago_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_metodo_pago" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(3) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_metodo_pago_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_uso_cfdi" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(4) NOT NULL,
"descripcion" TEXT NOT NULL,
"persona_fisica" BOOLEAN NOT NULL DEFAULT true,
"persona_moral" BOOLEAN NOT NULL DEFAULT true,
CONSTRAINT "cat_uso_cfdi_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_moneda" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(3) NOT NULL,
"descripcion" TEXT NOT NULL,
"decimales" INTEGER NOT NULL DEFAULT 2,
CONSTRAINT "cat_moneda_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_clave_unidad" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(10) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_clave_unidad_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_clave_prod_serv" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(8) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_clave_prod_serv_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_objeto_imp" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(2) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_objeto_imp_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_tipo_relacion" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(2) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_tipo_relacion_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "cat_exportacion" (
"id" SERIAL NOT NULL,
"clave" VARCHAR(2) NOT NULL,
"descripcion" TEXT NOT NULL,
CONSTRAINT "cat_exportacion_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "timbre_suscripciones" (
"id" SERIAL NOT NULL,
"tenant_id" TEXT NOT NULL,
"tipo" VARCHAR(10) NOT NULL,
"timbres_limite" INTEGER NOT NULL,
"timbres_usados" INTEGER NOT NULL DEFAULT 0,
"periodo_inicio" DATE NOT NULL,
"periodo_fin" DATE NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "timbre_suscripciones_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "tenants_rfc_key" ON "tenants"("rfc");
-- CreateIndex
CREATE UNIQUE INDEX "tenants_database_name_key" ON "tenants"("database_name");
-- CreateIndex
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
-- CreateIndex
CREATE INDEX "tenant_memberships_user_id_active_idx" ON "tenant_memberships"("user_id", "active");
-- CreateIndex
CREATE INDEX "tenant_memberships_tenant_id_active_idx" ON "tenant_memberships"("tenant_id", "active");
-- CreateIndex
CREATE UNIQUE INDEX "tenant_memberships_user_id_tenant_id_key" ON "tenant_memberships"("user_id", "tenant_id");
-- CreateIndex
CREATE UNIQUE INDEX "roles_nombre_key" ON "roles"("nombre");
-- CreateIndex
CREATE UNIQUE INDEX "refresh_tokens_token_key" ON "refresh_tokens"("token");
-- CreateIndex
CREATE UNIQUE INDEX "password_reset_tokens_token_key" ON "password_reset_tokens"("token");
-- CreateIndex
CREATE INDEX "password_reset_tokens_user_id_idx" ON "password_reset_tokens"("user_id");
-- CreateIndex
CREATE INDEX "password_reset_tokens_expires_at_idx" ON "password_reset_tokens"("expires_at");
-- CreateIndex
CREATE UNIQUE INDEX "regimenes_clave_key" ON "regimenes"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "tenant_regimenes_ignorados_tenant_id_regimen_id_key" ON "tenant_regimenes_ignorados"("tenant_id", "regimen_id");
-- CreateIndex
CREATE UNIQUE INDEX "tenant_regimenes_activos_tenant_id_regimen_id_key" ON "tenant_regimenes_activos"("tenant_id", "regimen_id");
-- CreateIndex
CREATE UNIQUE INDEX "lista_negra_rfc_key" ON "lista_negra"("rfc");
-- CreateIndex
CREATE INDEX "lista_negra_rfc_idx" ON "lista_negra"("rfc");
-- CreateIndex
CREATE UNIQUE INDEX "dias_inhabiles_fecha_key" ON "dias_inhabiles"("fecha");
-- CreateIndex
CREATE UNIQUE INDEX "isr_resico_tasas_anio_monto_maximo_key" ON "isr_resico_tasas"("anio", "monto_maximo");
-- CreateIndex
CREATE UNIQUE INDEX "isr_tarifas_anio_limite_inferior_key" ON "isr_tarifas"("anio", "limite_inferior");
-- CreateIndex
CREATE UNIQUE INDEX "coeficiente_utilidad_tenant_id_anio_key" ON "coeficiente_utilidad"("tenant_id", "anio");
-- CreateIndex
CREATE UNIQUE INDEX "fiel_credentials_tenant_id_key" ON "fiel_credentials"("tenant_id");
-- CreateIndex
CREATE INDEX "subscriptions_tenant_id_idx" ON "subscriptions"("tenant_id");
-- CreateIndex
CREATE INDEX "subscriptions_status_idx" ON "subscriptions"("status");
-- CreateIndex
CREATE INDEX "subscriptions_pending_effective_at_idx" ON "subscriptions"("pending_effective_at");
-- CreateIndex
CREATE INDEX "user_platform_roles_role_idx" ON "user_platform_roles"("role");
-- CreateIndex
CREATE UNIQUE INDEX "user_platform_roles_user_id_role_key" ON "user_platform_roles"("user_id", "role");
-- CreateIndex
CREATE INDEX "audit_log_user_id_created_at_idx" ON "audit_log"("user_id", "created_at");
-- CreateIndex
CREATE INDEX "audit_log_tenant_id_created_at_idx" ON "audit_log"("tenant_id", "created_at");
-- CreateIndex
CREATE INDEX "audit_log_action_created_at_idx" ON "audit_log"("action", "created_at");
-- CreateIndex
CREATE INDEX "audit_log_entity_type_entity_id_idx" ON "audit_log"("entity_type", "entity_id");
-- CreateIndex
CREATE UNIQUE INDEX "trial_usages_rfc_key" ON "trial_usages"("rfc");
-- CreateIndex
CREATE UNIQUE INDEX "plan_prices_plan_frequency_key" ON "plan_prices"("plan", "frequency");
-- CreateIndex
CREATE INDEX "payments_tenant_id_idx" ON "payments"("tenant_id");
-- CreateIndex
CREATE INDEX "payments_subscription_id_idx" ON "payments"("subscription_id");
-- CreateIndex
CREATE INDEX "sat_sync_jobs_tenant_id_idx" ON "sat_sync_jobs"("tenant_id");
-- CreateIndex
CREATE INDEX "sat_sync_jobs_status_idx" ON "sat_sync_jobs"("status");
-- CreateIndex
CREATE INDEX "sat_sync_jobs_status_next_retry_at_idx" ON "sat_sync_jobs"("status", "next_retry_at");
-- CreateIndex
CREATE UNIQUE INDEX "cat_forma_pago_clave_key" ON "cat_forma_pago"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_metodo_pago_clave_key" ON "cat_metodo_pago"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_uso_cfdi_clave_key" ON "cat_uso_cfdi"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_moneda_clave_key" ON "cat_moneda"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_clave_unidad_clave_key" ON "cat_clave_unidad"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_clave_prod_serv_clave_key" ON "cat_clave_prod_serv"("clave");
-- CreateIndex
CREATE INDEX "cat_clave_prod_serv_descripcion_idx" ON "cat_clave_prod_serv"("descripcion");
-- CreateIndex
CREATE UNIQUE INDEX "cat_objeto_imp_clave_key" ON "cat_objeto_imp"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_tipo_relacion_clave_key" ON "cat_tipo_relacion"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "cat_exportacion_clave_key" ON "cat_exportacion"("clave");
-- CreateIndex
CREATE UNIQUE INDEX "timbre_suscripciones_tenant_id_key" ON "timbre_suscripciones"("tenant_id");
-- AddForeignKey
ALTER TABLE "tenant_memberships" ADD CONSTRAINT "tenant_memberships_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_memberships" ADD CONSTRAINT "tenant_memberships_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_memberships" ADD CONSTRAINT "tenant_memberships_rol_id_fkey" FOREIGN KEY ("rol_id") REFERENCES "roles"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_regimenes_ignorados" ADD CONSTRAINT "tenant_regimenes_ignorados_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_regimenes_ignorados" ADD CONSTRAINT "tenant_regimenes_ignorados_regimen_id_fkey" FOREIGN KEY ("regimen_id") REFERENCES "regimenes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_regimenes_activos" ADD CONSTRAINT "tenant_regimenes_activos_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "tenant_regimenes_activos" ADD CONSTRAINT "tenant_regimenes_activos_regimen_id_fkey" FOREIGN KEY ("regimen_id") REFERENCES "regimenes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "coeficiente_utilidad" ADD CONSTRAINT "coeficiente_utilidad_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "fiel_credentials" ADD CONSTRAINT "fiel_credentials_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "subscriptions" ADD CONSTRAINT "subscriptions_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "user_platform_roles" ADD CONSTRAINT "user_platform_roles_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "payments" ADD CONSTRAINT "payments_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "payments" ADD CONSTRAINT "payments_subscription_id_fkey" FOREIGN KEY ("subscription_id") REFERENCES "subscriptions"("id") ON DELETE SET NULL ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "sat_sync_jobs" ADD CONSTRAINT "sat_sync_jobs_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "timbre_suscripciones" ADD CONSTRAINT "timbre_suscripciones_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,47 @@
-- CreateEnum
CREATE TYPE "PaymentKind" AS ENUM ('subscription', 'timbres_pack');
-- AlterTable
ALTER TABLE "payments" ADD COLUMN "kind" "PaymentKind" NOT NULL DEFAULT 'subscription';
-- CreateTable
CREATE TABLE "timbre_paquetes_catalogo" (
"id" SERIAL NOT NULL,
"cantidad" INTEGER NOT NULL,
"precio" DECIMAL(10,2) NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "timbre_paquetes_catalogo_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "timbre_paquetes" (
"id" SERIAL NOT NULL,
"tenant_id" TEXT NOT NULL,
"payment_id" TEXT,
"cantidad" INTEGER NOT NULL,
"usados" INTEGER NOT NULL DEFAULT 0,
"precio" DECIMAL(10,2) NOT NULL,
"adquirido_en" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"expira_en" TIMESTAMP(3) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "timbre_paquetes_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "timbre_paquetes_catalogo_cantidad_key" ON "timbre_paquetes_catalogo"("cantidad");
-- CreateIndex
CREATE UNIQUE INDEX "timbre_paquetes_payment_id_key" ON "timbre_paquetes"("payment_id");
-- CreateIndex
CREATE INDEX "timbre_paquetes_tenant_id_expira_en_idx" ON "timbre_paquetes"("tenant_id", "expira_en");
-- AddForeignKey
ALTER TABLE "timbre_paquetes" ADD CONSTRAINT "timbre_paquetes_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "timbre_paquetes" ADD CONSTRAINT "timbre_paquetes_payment_id_fkey" FOREIGN KEY ("payment_id") REFERENCES "payments"("id") ON DELETE SET NULL ON UPDATE CASCADE;

View File

@@ -0,0 +1,16 @@
-- CreateEnum
CREATE TYPE "VerticalProfile" AS ENUM ('CONTABLE', 'JURIDICO', 'ARQUITECTURA');
-- CreateEnum
CREATE TYPE "DbMode" AS ENUM ('BYO', 'MANAGED');
-- AlterTable
ALTER TABLE "tenants" ADD COLUMN "connector_last_seen" TIMESTAMP(3),
ADD COLUMN "connector_token_enc" TEXT,
ADD COLUMN "connector_tunnel_hostname" TEXT,
ADD COLUMN "connector_version" VARCHAR(20),
ADD COLUMN "db_connection_enc" TEXT,
ADD COLUMN "db_connection_iv" TEXT,
ADD COLUMN "db_mode" "DbMode",
ADD COLUMN "db_schema_version" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "vertical_profile" "VerticalProfile";

View File

@@ -0,0 +1,35 @@
-- CreateTable
CREATE TABLE "plan_catalogo" (
"id" TEXT NOT NULL,
"codename" VARCHAR(50) NOT NULL,
"nombre" TEXT NOT NULL,
"verticalProfile" "VerticalProfile" NOT NULL,
"precio_base" DECIMAL(10,2) NOT NULL,
"frecuencia" VARCHAR(10) NOT NULL,
"limits" JSONB NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "plan_catalogo_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "plan_addon_catalogo" (
"id" TEXT NOT NULL,
"codename" VARCHAR(50) NOT NULL,
"nombre" TEXT NOT NULL,
"verticalProfile" "VerticalProfile",
"precio" DECIMAL(10,2) NOT NULL,
"frecuencia" VARCHAR(10) NOT NULL,
"delta" JSONB NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT true,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "plan_addon_catalogo_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "plan_catalogo_codename_key" ON "plan_catalogo"("codename");
-- CreateIndex
CREATE UNIQUE INDEX "plan_addon_catalogo_codename_key" ON "plan_addon_catalogo"("codename");

View File

@@ -0,0 +1,28 @@
-- CreateTable
CREATE TABLE "subscription_addons" (
"id" TEXT NOT NULL,
"subscription_id" TEXT NOT NULL,
"plan_addon_catalogo_id" TEXT NOT NULL,
"mp_preapproval_id" TEXT,
"status" TEXT NOT NULL DEFAULT 'pending',
"quantity" INTEGER NOT NULL DEFAULT 1,
"amount" DECIMAL(10,2) NOT NULL,
"current_period_start" TIMESTAMP(3),
"current_period_end" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "subscription_addons_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "subscription_addons_subscription_id_idx" ON "subscription_addons"("subscription_id");
-- CreateIndex
CREATE UNIQUE INDEX "subscription_addons_subscription_id_plan_addon_catalogo_id_key" ON "subscription_addons"("subscription_id", "plan_addon_catalogo_id");
-- AddForeignKey
ALTER TABLE "subscription_addons" ADD CONSTRAINT "subscription_addons_subscription_id_fkey" FOREIGN KEY ("subscription_id") REFERENCES "subscriptions"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "subscription_addons" ADD CONSTRAINT "subscription_addons_plan_addon_catalogo_id_fkey" FOREIGN KEY ("plan_addon_catalogo_id") REFERENCES "plan_addon_catalogo"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

View File

@@ -0,0 +1,19 @@
-- CreateTable
CREATE TABLE "connector_heartbeats" (
"id" TEXT NOT NULL,
"tenant_id" TEXT NOT NULL,
"timestamp" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"latency_ms" INTEGER NOT NULL,
"version" VARCHAR(20) NOT NULL,
"pg_version" VARCHAR(50),
"status" VARCHAR(20) NOT NULL,
"error_msg" TEXT,
CONSTRAINT "connector_heartbeats_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE INDEX "connector_heartbeats_tenant_id_timestamp_idx" ON "connector_heartbeats"("tenant_id", "timestamp");
-- AddForeignKey
ALTER TABLE "connector_heartbeats" ADD CONSTRAINT "connector_heartbeats_tenant_id_fkey" FOREIGN KEY ("tenant_id") REFERENCES "tenants"("id") ON DELETE CASCADE ON UPDATE CASCADE;

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "sat_sync_jobs" ADD COLUMN "contribuyente_id" TEXT;

View File

@@ -0,0 +1,10 @@
-- AlterEnum
-- This migration adds more than one value to an enum.
-- With PostgreSQL versions 11 and earlier, this is not possible
-- in a single migration. This can be worked around by creating
-- multiple migrations, each migration adding only one value to
-- the enum.
ALTER TYPE "Plan" ADD VALUE 'business_control';
ALTER TYPE "Plan" ADD VALUE 'business_cloud';

View File

@@ -0,0 +1,18 @@
-- Add-ons por contribuyente: permite que SubscriptionAddon se asocie a un
-- contribuyente específico (ej. Lolita IA $250/mes activable por RFC) además
-- de los add-ons a nivel tenant (modulos, +RFCs, +timbres) que tienen
-- contribuyente_id = NULL.
ALTER TABLE "subscription_addons"
ADD COLUMN "contribuyente_id" TEXT;
-- Eliminar el UNIQUE (subscription_id, plan_addon_catalogo_id). Ahora el
-- mismo add-on (p. ej. lolita_ia_contribuyente) puede tener N filas por
-- subscription, una por cada contribuyente que lo contrate.
ALTER TABLE "subscription_addons"
DROP CONSTRAINT IF EXISTS "subscription_addons_subscription_id_plan_addon_catalogo_id_key";
-- Índice por (subscription_id, contribuyente_id) para lookups rápidos
-- "qué add-ons tiene este contribuyente"
CREATE INDEX IF NOT EXISTS "subscription_addons_subscription_id_contribuyente_id_idx"
ON "subscription_addons"("subscription_id", "contribuyente_id");

View File

@@ -0,0 +1,2 @@
-- AlterEnum
ALTER TYPE "Plan" ADD VALUE 'mi_empresa';

View File

@@ -0,0 +1,18 @@
-- CreateTable
CREATE TABLE "despacho_plan_prices" (
"plan" TEXT NOT NULL,
"monthly" DECIMAL(10,2),
"first_year" DECIMAL(10,2) NOT NULL,
"renewal" DECIMAL(10,2) NOT NULL,
"permite_monthly" BOOLEAN NOT NULL DEFAULT false,
"updated_at" TIMESTAMP(3) NOT NULL,
CONSTRAINT "despacho_plan_prices_pkey" PRIMARY KEY ("plan")
);
-- Seed inicial con valores actuales del catálogo `DESPACHO_PLAN_PRICES`.
INSERT INTO "despacho_plan_prices" ("plan", "monthly", "first_year", "renewal", "permite_monthly", "updated_at") VALUES
('mi_empresa', 580, 5800, 5800, true, NOW()),
('mi_empresa_plus', 900, 9000, 9000, true, NOW()),
('business_control', NULL, 25850, 25850, false, NOW()),
('business_cloud', NULL, 43000, 43000, false, NOW());

View File

@@ -0,0 +1,19 @@
-- AlterEnum
BEGIN;
CREATE TYPE "Plan_new" AS ENUM ('trial', 'custom', 'business_control', 'business_cloud', 'mi_empresa', 'mi_empresa_plus');
ALTER TABLE "tenants" ALTER COLUMN "plan" DROP DEFAULT;
ALTER TABLE "tenants" ALTER COLUMN "plan" TYPE "Plan_new" USING ("plan"::text::"Plan_new");
ALTER TABLE "subscriptions" ALTER COLUMN "plan" TYPE "Plan_new" USING ("plan"::text::"Plan_new");
ALTER TABLE "subscriptions" ALTER COLUMN "pending_plan" TYPE "Plan_new" USING ("pending_plan"::text::"Plan_new");
ALTER TABLE "subscriptions" ALTER COLUMN "upgrade_target_plan" TYPE "Plan_new" USING ("upgrade_target_plan"::text::"Plan_new");
ALTER TABLE "plan_prices" ALTER COLUMN "plan" TYPE "Plan_new" USING ("plan"::text::"Plan_new");
ALTER TYPE "Plan" RENAME TO "Plan_old";
ALTER TYPE "Plan_new" RENAME TO "Plan";
DROP TYPE "Plan_old";
ALTER TABLE "tenants" ALTER COLUMN "plan" SET DEFAULT 'trial';
COMMIT;
-- AlterTable
ALTER TABLE "tenants" DROP COLUMN "cfdi_limit",
DROP COLUMN "users_limit",
ALTER COLUMN "plan" SET DEFAULT 'trial';

View File

@@ -0,0 +1,55 @@
-- Step 1: Add new columns as nullable (preserva las 4 filas existentes con sus precios)
ALTER TABLE "despacho_plan_prices"
ADD COLUMN "nombre" VARCHAR(50),
ADD COLUMN "max_rfcs" INTEGER,
ADD COLUMN "max_users" INTEGER,
ADD COLUMN "db_mode" "DbMode",
ADD COLUMN "timbres_incluidos_mes" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "permite_servidor_backup" BOOLEAN NOT NULL DEFAULT false;
-- Step 2: Backfill limits para las 4 filas existentes desde el catálogo TS
UPDATE "despacho_plan_prices" SET
"nombre" = 'Mi Empresa',
"max_rfcs" = 1,
"max_users" = 3,
"timbres_incluidos_mes" = 50,
"db_mode" = 'MANAGED'
WHERE "plan" = 'mi_empresa';
UPDATE "despacho_plan_prices" SET
"nombre" = 'Mi Empresa +',
"max_rfcs" = 1,
"max_users" = 3,
"timbres_incluidos_mes" = 50,
"db_mode" = 'MANAGED'
WHERE "plan" = 'mi_empresa_plus';
UPDATE "despacho_plan_prices" SET
"nombre" = 'Business Control',
"max_rfcs" = 100,
"max_users" = -1,
"timbres_incluidos_mes" = 0,
"db_mode" = 'BYO',
"permite_servidor_backup" = true
WHERE "plan" = 'business_control';
UPDATE "despacho_plan_prices" SET
"nombre" = 'Enterprise',
"max_rfcs" = 100,
"max_users" = -1,
"timbres_incluidos_mes" = 0,
"db_mode" = 'BYO',
"permite_servidor_backup" = true
WHERE "plan" = 'business_cloud';
-- Step 3: Set NOT NULL después del backfill (las 4 filas ya están completas)
ALTER TABLE "despacho_plan_prices"
ALTER COLUMN "nombre" SET NOT NULL,
ALTER COLUMN "max_rfcs" SET NOT NULL,
ALTER COLUMN "max_users" SET NOT NULL,
ALTER COLUMN "db_mode" SET NOT NULL;
-- Step 4: Hacer firstYear y renewal nullable para soportar trial y custom (sin precio fijo)
ALTER TABLE "despacho_plan_prices"
ALTER COLUMN "first_year" DROP NOT NULL,
ALTER COLUMN "renewal" DROP NOT NULL;

View File

@@ -0,0 +1,5 @@
-- Drop tabla plan_catalogo (modelo huérfano nunca usado por código activo).
-- Las 2 filas que tenía estaban desincronizadas con el catálogo TS y nunca
-- se referenciaron desde código real. El catálogo despacho vive ahora en
-- `despacho_plan_prices` (extendida con limits en migración 20260430195000).
DROP TABLE "plan_catalogo";

View File

@@ -0,0 +1,10 @@
-- Add column with default false (no-op para filas existentes)
ALTER TABLE "despacho_plan_prices"
ADD COLUMN "permite_sat_incremental" BOOLEAN NOT NULL DEFAULT false;
-- Backfill: planes que SÍ deben tener incremental (3 syncs/día adicionales).
-- Mi Empresa + tiene API + Lolita IA y precio premium ($9k anual);
-- Business Control y Enterprise son los planes despacho con escala alta.
UPDATE "despacho_plan_prices"
SET "permite_sat_incremental" = true
WHERE "plan" IN ('mi_empresa_plus', 'business_control', 'business_cloud');

View File

@@ -0,0 +1,7 @@
-- Cache cifrada de la Live Secret Key de la organización Facturapi del tenant
-- central (Horux 360 admin que emite facturas de subscripción a clientes).
-- AES-256-GCM con derivación FIEL_ENCRYPTION_KEY — mismo patrón que FIEL.
ALTER TABLE "tenants"
ADD COLUMN "facturapi_org_key_enc" BYTEA,
ADD COLUMN "facturapi_org_key_iv" BYTEA,
ADD COLUMN "facturapi_org_key_tag" BYTEA;

View File

@@ -0,0 +1,5 @@
-- Drop tabla plan_prices (modelo legacy Horux 360 sin filas activas).
-- Catálogo se reemplazó por DespachoPlanPrice (despacho_plan_prices) en
-- migración 20260430195000_extend_despacho_plan_prices_with_limits.
-- Sin callers activos en código (verificado vía typecheck post-cleanup).
DROP TABLE "plan_prices";

View File

@@ -0,0 +1,5 @@
-- Tracking de aviso pre-vencimiento por suscripción. Permite que el cron diario
-- evite enviar dos emails del mismo bucket de días al mismo owner.
ALTER TABLE "subscriptions"
ADD COLUMN "last_reminder_day" INTEGER,
ADD COLUMN "last_reminder_sent_at" TIMESTAMP(3);

View File

@@ -0,0 +1,8 @@
-- Preferencias de auto-facturación de pagos de suscripción.
-- factPreferencia: 'publico_general' o 'mis_datos' (default: mis_datos)
-- factUsoCfdi: clave SAT del uso CFDI default (G03 = Gastos en general)
-- factRegimenPreferido: clave del régimen fiscal a usar cuando hay multi-régimen
ALTER TABLE "tenants"
ADD COLUMN "fact_preferencia" VARCHAR(20) DEFAULT 'mis_datos' NOT NULL,
ADD COLUMN "fact_uso_cfdi" VARCHAR(5) DEFAULT 'G03' NOT NULL,
ADD COLUMN "fact_regimen_preferido" VARCHAR(3);

View File

@@ -0,0 +1,4 @@
-- Onboarding auto-dismiss: 4 logins ó pasos completados, lo que pase primero.
ALTER TABLE "users"
ADD COLUMN "login_count" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "onboarding_dismissed_at" TIMESTAMP(3);

View File

@@ -0,0 +1,6 @@
-- Mapa { kindKey: requestId } para reusar requests del SAT en reintentos.
-- Hasta antes de este cambio, cada retry creaba nuevas solicitudes — agotaba
-- la cuota del SAT y abandonaba requests anteriores. Ahora el retry consulta
-- los requestIds previos antes de crear nuevos.
ALTER TABLE "sat_sync_jobs"
ADD COLUMN "sat_request_ids" JSONB NOT NULL DEFAULT '{}'::jsonb;

View File

@@ -0,0 +1,6 @@
-- Distingue extracciones tipo `initial` con rango personalizado (UI custom)
-- de bootstrap inicial puro. Política de retry distinta:
-- initial bootstrap → 3 retries a 6h, 12h, 24h
-- initial custom → 2 retries a 6h, 12h
ALTER TABLE "sat_sync_jobs"
ADD COLUMN "is_custom_range" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (i.e. Git)
provider = "postgresql"