feat: kimlik doğrulama, ödeme, kredi ve AI rapor sihirbazı ekle
- better-auth ile giriş/oturum yönetimi (src/lib/auth, giris sayfası) - iyzico ödeme entegrasyonu ve paket satın alma akışı - kredi sistemi ve uygulama veritabanı şeması (drizzle) - AI destekli rapor üretimi ve tercih sihirbazı - rapor yazdırma sayfası ve site header/kullanıcı menüsü Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
112
src/lib/iyzico.ts
Normal file
112
src/lib/iyzico.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import Iyzipay from "iyzipay";
|
||||
|
||||
// iyzipay CJS + callback tabanlı; burada promisify'lı ince bir katman var.
|
||||
// Anahtarlar boşsa (henüz sandbox hesabı yoksa) çağrı anlaşılır bir hatayla düşer.
|
||||
|
||||
const globalForIyzi = globalThis as unknown as { __iyzipay?: Iyzipay };
|
||||
|
||||
function getClient(): Iyzipay {
|
||||
if (!process.env.IYZICO_API_KEY || !process.env.IYZICO_SECRET_KEY) {
|
||||
throw new Error("IYZICO_KEYS_MISSING");
|
||||
}
|
||||
if (!globalForIyzi.__iyzipay) {
|
||||
globalForIyzi.__iyzipay = new Iyzipay({
|
||||
apiKey: process.env.IYZICO_API_KEY,
|
||||
secretKey: process.env.IYZICO_SECRET_KEY,
|
||||
uri: process.env.IYZICO_BASE_URL ?? "https://sandbox-api.iyzipay.com",
|
||||
});
|
||||
}
|
||||
return globalForIyzi.__iyzipay;
|
||||
}
|
||||
|
||||
export interface CheckoutFormInitSonuc {
|
||||
status: string;
|
||||
token?: string;
|
||||
paymentPageUrl?: string;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
export interface CheckoutFormSonuc {
|
||||
status: string;
|
||||
paymentStatus?: string; // "SUCCESS" beklenir
|
||||
conversationId?: string;
|
||||
paymentId?: string;
|
||||
paidPrice?: string | number;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
export function initializeCheckoutForm(opts: {
|
||||
orderId: string;
|
||||
fiyatKurus: number;
|
||||
urunAdi: string;
|
||||
email: string;
|
||||
userId: string;
|
||||
callbackUrl: string;
|
||||
buyerIp: string;
|
||||
}): Promise<CheckoutFormInitSonuc> {
|
||||
const price = (opts.fiyatKurus / 100).toFixed(2);
|
||||
// iyzico buyer bloğu zorunlu alanlar ister; dijital üründe adres sembolik
|
||||
const adres = {
|
||||
contactName: "KolayTercih Kullanıcısı",
|
||||
city: "Istanbul",
|
||||
country: "Turkey",
|
||||
address: "Dijital teslimat",
|
||||
};
|
||||
const request = {
|
||||
locale: Iyzipay.LOCALE.TR,
|
||||
conversationId: opts.orderId,
|
||||
price,
|
||||
paidPrice: price,
|
||||
currency: Iyzipay.CURRENCY.TRY,
|
||||
basketId: opts.orderId,
|
||||
paymentGroup: Iyzipay.PAYMENT_GROUP.PRODUCT,
|
||||
callbackUrl: opts.callbackUrl,
|
||||
enabledInstallments: [1],
|
||||
buyer: {
|
||||
id: opts.userId,
|
||||
name: "KolayTercih",
|
||||
surname: "Kullanıcısı",
|
||||
gsmNumber: "+905000000000",
|
||||
email: opts.email,
|
||||
identityNumber: "11111111111",
|
||||
registrationAddress: adres.address,
|
||||
ip: opts.buyerIp,
|
||||
city: adres.city,
|
||||
country: adres.country,
|
||||
},
|
||||
shippingAddress: adres,
|
||||
billingAddress: adres,
|
||||
basketItems: [
|
||||
{
|
||||
id: opts.orderId,
|
||||
name: opts.urunAdi,
|
||||
category1: "Dijital Hizmet",
|
||||
itemType: Iyzipay.BASKET_ITEM_TYPE.VIRTUAL,
|
||||
price,
|
||||
},
|
||||
],
|
||||
};
|
||||
return new Promise((resolve, reject) => {
|
||||
getClient().checkoutFormInitialize.create(
|
||||
request as never,
|
||||
(err: unknown, result: CheckoutFormInitSonuc) => {
|
||||
if (err) reject(err);
|
||||
else resolve(result);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function retrieveCheckoutForm(
|
||||
token: string,
|
||||
): Promise<CheckoutFormSonuc> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getClient().checkoutForm.retrieve(
|
||||
{ locale: Iyzipay.LOCALE.TR, token } as never,
|
||||
(err: unknown, result: CheckoutFormSonuc) => {
|
||||
if (err) reject(err);
|
||||
else resolve(result);
|
||||
},
|
||||
);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user