Files
2026-06-20 14:26:29 +08:00

153 lines
6.1 KiB
SQL

-- CreateEnum: AFF Log Types (if not exists)
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'AffLogType') THEN
CREATE TYPE "AffLogType" AS ENUM ('new_purchase', 'renew', 'convert');
END IF;
END $$;
-- CreateEnum: AFF Withdrawal Status (if not exists)
DO $$ BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'AffWithdrawalStatus') THEN
CREATE TYPE "AffWithdrawalStatus" AS ENUM ('pending', 'approved', 'rejected');
END IF;
END $$;
-- AlterTable: Add AFF fields to users
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "aff_balance" DECIMAL(10,2) NOT NULL DEFAULT 0;
ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "aff_activated_at" TIMESTAMP(3);
-- CreateTable: AffCode (优惠码)
CREATE TABLE IF NOT EXISTS "aff_codes" (
"id" SERIAL NOT NULL,
"code" TEXT NOT NULL,
"user_id" INTEGER NOT NULL,
"package_plan_id" INTEGER NOT NULL,
"discount_rate" DECIMAL(5,4) NOT NULL DEFAULT 0.05,
"commission_rate" DECIMAL(5,4) NOT NULL DEFAULT 0.05,
"enabled" BOOLEAN NOT NULL DEFAULT true,
"used_count" INTEGER NOT NULL DEFAULT 0,
"total_earnings" DECIMAL(10,2) NOT NULL DEFAULT 0,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "aff_codes_pkey" PRIMARY KEY ("id")
);
-- CreateTable: AffBinding (实例与优惠码绑定)
CREATE TABLE IF NOT EXISTS "aff_bindings" (
"id" SERIAL NOT NULL,
"instance_id" INTEGER NOT NULL,
"aff_code_id" INTEGER NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "aff_bindings_pkey" PRIMARY KEY ("id")
);
-- CreateTable: AffLog (AFF余额变动日志)
CREATE TABLE IF NOT EXISTS "aff_logs" (
"id" SERIAL NOT NULL,
"user_id" INTEGER NOT NULL,
"aff_code_id" INTEGER,
"instance_id" INTEGER,
"type" "AffLogType" NOT NULL,
"amount" DECIMAL(10,2) NOT NULL,
"original_amount" DECIMAL(10,2),
"balance_before" DECIMAL(10,2) NOT NULL,
"balance_after" DECIMAL(10,2) NOT NULL,
"remark" TEXT,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "aff_logs_pkey" PRIMARY KEY ("id")
);
-- CreateTable: AffWithdrawal (AFF余额转化申请)
CREATE TABLE IF NOT EXISTS "aff_withdrawals" (
"id" SERIAL NOT NULL,
"user_id" INTEGER NOT NULL,
"amount" DECIMAL(10,2) NOT NULL,
"status" "AffWithdrawalStatus" NOT NULL DEFAULT 'pending',
"reject_reason" TEXT,
"reviewed_by" INTEGER,
"reviewed_at" TIMESTAMP(3),
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "aff_withdrawals_pkey" PRIMARY KEY ("id")
);
-- CreateIndex: Unique code
CREATE UNIQUE INDEX IF NOT EXISTS "aff_codes_code_key" ON "aff_codes"("code");
-- CreateIndex: User can only have one code per plan
CREATE UNIQUE INDEX IF NOT EXISTS "aff_codes_user_id_package_plan_id_key" ON "aff_codes"("user_id", "package_plan_id");
-- CreateIndex: AffCode indexes
CREATE INDEX IF NOT EXISTS "aff_codes_user_id_idx" ON "aff_codes"("user_id");
CREATE INDEX IF NOT EXISTS "aff_codes_package_plan_id_idx" ON "aff_codes"("package_plan_id");
-- CreateIndex: AffBinding - one instance can only bind one code
CREATE UNIQUE INDEX IF NOT EXISTS "aff_bindings_instance_id_key" ON "aff_bindings"("instance_id");
CREATE INDEX IF NOT EXISTS "aff_bindings_aff_code_id_idx" ON "aff_bindings"("aff_code_id");
-- CreateIndex: AffLog indexes
CREATE INDEX IF NOT EXISTS "aff_logs_user_id_created_at_idx" ON "aff_logs"("user_id", "created_at" DESC);
CREATE INDEX IF NOT EXISTS "aff_logs_aff_code_id_idx" ON "aff_logs"("aff_code_id");
-- CreateIndex: AffWithdrawal indexes
CREATE INDEX IF NOT EXISTS "aff_withdrawals_user_id_status_idx" ON "aff_withdrawals"("user_id", "status");
CREATE INDEX IF NOT EXISTS "aff_withdrawals_status_created_at_idx" ON "aff_withdrawals"("status", "created_at");
-- AddForeignKey: AffCode -> User
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_codes_user_id_fkey') THEN
ALTER TABLE "aff_codes" ADD CONSTRAINT "aff_codes_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffCode -> PackagePlan
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_codes_package_plan_id_fkey') THEN
ALTER TABLE "aff_codes" ADD CONSTRAINT "aff_codes_package_plan_id_fkey" FOREIGN KEY ("package_plan_id") REFERENCES "package_plans"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffBinding -> Instance
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_bindings_instance_id_fkey') THEN
ALTER TABLE "aff_bindings" ADD CONSTRAINT "aff_bindings_instance_id_fkey" FOREIGN KEY ("instance_id") REFERENCES "instances"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffBinding -> AffCode
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_bindings_aff_code_id_fkey') THEN
ALTER TABLE "aff_bindings" ADD CONSTRAINT "aff_bindings_aff_code_id_fkey" FOREIGN KEY ("aff_code_id") REFERENCES "aff_codes"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffLog -> User
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_logs_user_id_fkey') THEN
ALTER TABLE "aff_logs" ADD CONSTRAINT "aff_logs_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffLog -> AffCode (SetNull on delete)
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_logs_aff_code_id_fkey') THEN
ALTER TABLE "aff_logs" ADD CONSTRAINT "aff_logs_aff_code_id_fkey" FOREIGN KEY ("aff_code_id") REFERENCES "aff_codes"("id") ON DELETE SET NULL ON UPDATE CASCADE;
END IF;
END $$;
-- AddForeignKey: AffWithdrawal -> User
DO $$
BEGIN
IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'aff_withdrawals_user_id_fkey') THEN
ALTER TABLE "aff_withdrawals" ADD CONSTRAINT "aff_withdrawals_user_id_fkey" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
END IF;
END $$;