chore: update iyzico integration and enhance payment processing logic
All checks were successful
Deploy / deploy (push) Successful in 7m0s

Refactored the iyzico payment integration to improve the handling of payment callbacks and order status updates. Added signature validation for responses to ensure data integrity. Enhanced the `initializeCheckoutForm` function to include buyer's name and surname, and updated the order schema to enforce unique constraints on iyzico tokens. Improved error handling and logging for payment processing, ensuring better tracking of payment states and issues. Updated the app database to reflect these changes.
This commit is contained in:
bilalgursen
2026-08-11 00:30:53 +03:00
parent 70b254c3b2
commit 08419e6d1c
12 changed files with 1417 additions and 44 deletions

View File

@@ -6,10 +6,21 @@ import { redirect } from "next/navigation";
import { verifySession } from "@/lib/session";
import { appDb, schema } from "@/lib/appdb";
import { URUNLER } from "@/lib/credits";
import { initializeCheckoutForm } from "@/lib/iyzico";
import { initializeCheckoutForm, initImzaDurumu } from "@/lib/iyzico";
export type OdemeBaslatDurum = { error?: string } | undefined;
const GENEL_HATA =
"Ödeme şu anda başlatılamıyor; kartından çekim yapılmadı. Birazdan tekrar dener misin?";
/** "Bilal Gürsen" → ["Bilal", "Gürsen"]; iyzico ad ve soyadı ayrı ve dolu ister. */
function adSoyadAyir(tamAd: string): [string, string] {
const parcalar = tamAd.trim().split(/\s+/).filter(Boolean);
if (parcalar.length === 0) return ["KolayTercih", "Kullanıcısı"];
if (parcalar.length === 1) return [parcalar[0], parcalar[0]];
return [parcalar.slice(0, -1).join(" "), parcalar[parcalar.length - 1]];
}
export async function baslatOdeme(
_prev: OdemeBaslatDurum,
formData: FormData,
@@ -37,6 +48,7 @@ export async function baslatOdeme(
const buyerIp =
h.get("x-forwarded-for")?.split(",")[0]?.trim() ?? "85.34.78.112";
const appUrl = process.env.NEXT_PUBLIC_APP_URL ?? "http://localhost:3000";
const [ad, soyad] = adSoyadAyir(session.user.name ?? "");
let init;
try {
@@ -46,6 +58,9 @@ export async function baslatOdeme(
urunAdi: `KolayTercih — ${urun.label}`,
email: session.user.email,
userId: session.user.id,
ad,
soyad,
// iyzico bu adrese hem başarıyı hem başarısızlığı POST'lar; geçerli SSL şart
callbackUrl: `${appUrl}/api/odeme/callback`,
buyerIp,
});
@@ -53,18 +68,28 @@ export async function baslatOdeme(
if (err instanceof Error && err.message === "IYZICO_KEYS_MISSING") {
// Yapılandırma detayı log'a; kullanıcıya altyapı sızdırmayan mesaj
console.error("[odeme] iyzico anahtarları eksik — ödeme başlatılamadı");
return {
error:
"Ödeme şu anda başlatılamıyor; kartından çekim yapılmadı. Birazdan tekrar dener misin?",
};
return { error: GENEL_HATA };
}
throw err;
console.error("[odeme] iyzico initialize hatası", err);
return { error: GENEL_HATA };
}
if (init.status !== "success" || !init.paymentPageUrl || !init.token) {
return {
error: init.errorMessage ?? "Ödeme başlatılamadı. Tekrar dener misin?",
};
// initialize aşamasında karta hiç dokunulmaz: buradaki hatalar kart/kullanıcı
// kaynaklı değil, bizim yapılandırmamızdandır (anahtar, üye işyeri ayarı,
// sepet kuralı). iyzico'nun mesajı log'a gider, kullanıcıya genel mesaj.
console.error("[odeme] initialize başarısız", {
orderId,
errorCode: init.errorCode,
errorMessage: init.errorMessage,
});
return { error: GENEL_HATA };
}
// Yanıtın bütünlüğü: imza tutmuyorsa kullanıcıyı o ödeme sayfasına yollama.
if (initImzaDurumu(init) === "gecersiz") {
console.error("[odeme] initialize imzası geçersiz", { orderId });
return { error: GENEL_HATA };
}
await appDb