Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Admin paneli (admin@sase.tr) kod üretir/takip eder, ödeme sayfası kodu uygular. Kodlar Stripe Coupon + Promotion Code olarak yaşar (limit/süre/ kullanım Stripe redemption'da enforce edilir); yerel discount_codes aynası panel listeleme + checkout-anı preview içindir. - migration 0022_discount_codes + schema (discount_codes) - DiscountCodesModule: admin CRUD (@Roles admin) + /discount-codes/validate (login) - StripeService: createPromotion / deactivatePromotion / getPromotionRedemptions / previewDiscount + resolvePlanAmount; createCheckoutSession opsiyonel discountCode -> discounts[{promotion_code}] + metadata.discount_code; webhook gerçek tahsilatı (session.amount_total) yazar + ayna times_redeemed++ - web: /dashboard/admin/discount-codes paneli + ödeme adımı indirim alanı (validate preview -> indirimli özet -> kod checkout'a); tr/en çeviriler - 7 birim test (previewDiscount: % / sabit / süre / geçersiz/pasif/dolu/limit) Not: 2026-04-22 Stripe API promotionCodes.create `promotion:{type:'coupon'}` kullanıyor (üst-seviye `coupon` değil). dev'de Stripe key yok -> CREATE dev'de 503; E2E için dev'e Stripe TEST key gerekir. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
35 lines
1.5 KiB
SQL
35 lines
1.5 KiB
SQL
-- Discount codes for checkout promotions. Each row mirrors a Stripe Coupon +
|
|
-- Promotion Code; Stripe enforces the redemption cap / expiry at checkout while
|
|
-- this table powers the admin panel's listing + usage tracking and lets us
|
|
-- preview a code without a per-render Stripe call. Amounts in kuruş (TRY
|
|
-- smallest unit), matching plans.price* / payments.amount.
|
|
CREATE TABLE IF NOT EXISTS "discount_codes" (
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
"code" varchar(50) NOT NULL,
|
|
"stripe_coupon_id" text,
|
|
"stripe_promotion_code_id" text,
|
|
"discount_type" varchar(12) NOT NULL,
|
|
"percent_off" integer,
|
|
"amount_off" integer,
|
|
"duration" varchar(12) DEFAULT 'once' NOT NULL,
|
|
"duration_in_months" integer,
|
|
"max_redemptions" integer,
|
|
"times_redeemed" integer DEFAULT 0 NOT NULL,
|
|
"expires_at" timestamp with time zone,
|
|
"is_active" boolean DEFAULT true NOT NULL,
|
|
"note" text,
|
|
"created_by" uuid,
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
|
"updated_at" timestamp with time zone DEFAULT now() NOT NULL
|
|
);
|
|
--> statement-breakpoint
|
|
DO $$ BEGIN
|
|
ALTER TABLE "discount_codes" ADD CONSTRAINT "discount_codes_created_by_users_id_fk"
|
|
FOREIGN KEY ("created_by") REFERENCES "public"."users"("id") ON DELETE set null;
|
|
EXCEPTION WHEN duplicate_object THEN null;
|
|
END $$;
|
|
--> statement-breakpoint
|
|
CREATE UNIQUE INDEX IF NOT EXISTS "discount_codes_code_idx" ON "discount_codes" USING btree ("code");
|
|
--> statement-breakpoint
|
|
CREATE INDEX IF NOT EXISTS "discount_codes_active_idx" ON "discount_codes" USING btree ("is_active");
|