infoalloggi-monorepo/apps/infoalloggi/src/server/controllers/stripe.controller.ts

304 lines
7.4 KiB
TypeScript

import { TRPCError } from "@trpc/server";
import { env } from "~/env";
import stripe from "~/lib/stripe";
import OrderTypeEnum from "~/schemas/public/OrderTypeEnum";
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
import type { Payments, PaymentsId } from "~/schemas/public/Payments";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
import { db } from "~/server/db";
import { NewMail } from "~/server/services/mailer";
import { getUser } from "~/server/services/user.service";
export const stripeHealthCheck = async () => {
try {
const endpoints = await stripe.webhookEndpoints.list();
return {
success: true,
endpoints,
secretKey: env.STRIPE_SECRET_KEY,
publicKey: env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY,
};
} catch (e) {
console.error("Stripe health check failed:", e);
return {
success: false,
endpoints: null,
secretKey: env.STRIPE_SECRET_KEY,
publicKey: env.NEXT_PUBLIC_STRIPE_PUBLIC_KEY,
};
}
};
export const createIntentHandler = async ({
paymentId,
}: {
paymentId: PaymentsId;
}) => {
try {
const payment = await db
.selectFrom("payments")
.selectAll("payments")
.innerJoin("users", "users.id", "payments.userid")
.select("users.email")
.innerJoin("ordini", "ordini.ordine_id", "payments.ordine_id")
.innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
.select(["prezziario.nome_it", "prezziario.desc_it"])
.where("payments.id", "=", paymentId)
.executeTakeFirstOrThrow();
const paymentIntent = await stripe.paymentIntents.create({
amount: payment.amount_cent,
//payment_method_configuration: "pmc_1P4NfjILe4KoQRqXYChFCTFj",
automatic_payment_methods: {
enabled: true,
},
currency: "eur",
description: payment.nome_it,
metadata: {
paymentId,
servizioId: payment.servizio_id,
userId: payment.userid,
},
receipt_email: payment.email,
});
return {
clientSecret: paymentIntent.client_secret,
descrizione: payment.desc_it,
prezzo: payment.amount_cent,
titolo: payment.nome_it,
};
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error creating payment intent: ${(error as Error).message}`,
});
}
};
export const whIntentCreatedHandler = async ({
pIntentId,
paymentId,
}: {
pIntentId: Payments["intent_id"];
paymentId: PaymentsId;
}) => {
try {
return await db
.updateTable("payments")
.set({
intent_id: pIntentId,
paymentstatus: PaymentStatusEnum.processing,
})
.where("id", "=", paymentId)
.returning("id")
.execute();
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error whIntentCreatedHandler: ${(error as Error).message}`,
});
}
};
export const whIntentSucceededHandler = async ({
pIntentId,
paymentId,
pm_id,
}: {
pIntentId: Payments["intent_id"];
paymentId: PaymentsId;
pm_id: string;
}) => {
try {
const paymentMethod = await stripe.paymentMethods.retrieve(pm_id);
await db.transaction().execute(async (trx) => {
const payment = await trx
.updateTable("payments")
.set({
paid_at: new Date(),
paymentmethod: paymentMethod.type,
paymentstatus: PaymentStatusEnum.success,
})
.where("intent_id", "=", pIntentId)
.where("payments.id", "=", paymentId)
.returning(["servizio_id", "ordine_id"])
.executeTakeFirstOrThrow();
const ordine = await trx
.selectFrom("ordini")
.selectAll("ordini")
.where("ordine_id", "=", payment.ordine_id)
.executeTakeFirstOrThrow();
await trx
.updateTable("ordini")
.where("ordine_id", "=", payment.ordine_id)
.set({
isActive: true,
})
.execute();
const servizio = await trx
.selectFrom("servizio")
.select("servizio.tipologia")
.where("servizio_id", "=", payment.servizio_id)
.executeTakeFirstOrThrow();
const utente = await getUser({
db: trx,
userId: ordine.userid,
});
switch (ordine.type) {
case OrderTypeEnum.Acconto:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
decorrenza: new Date(),
isOkAcconto: true,
})
.execute();
await NewMail({
template: {
mailType: "generic",
props: {
link: {
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
noreply: true,
testo: `Il pagamento dell'acconto per il servizio ${ordine.packid} è stato confermato.`,
title: "Pagamento Confermato ",
},
},
mail: {
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
to: utente.email,
},
userId: utente.id,
});
break;
case OrderTypeEnum.Saldo:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
isOkConsulenza:
servizio.tipologia === TipologiaPosizioneEnum.Transitorio,
isOkSaldo: true,
})
.execute();
await NewMail({
template: {
mailType: "generic",
props: {
link: {
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
noreply: true,
testo: `Il pagamento del saldo per il servizio ${ordine.packid} è stato confermato.`,
title: "Pagamento Confermato ",
},
},
mail: {
subject: "Pagamento Confermato - Saldo Infoalloggi.it",
to: utente.email,
},
userId: utente.id,
});
break;
case OrderTypeEnum.Consulenza:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
isOkConsulenza: true,
})
.execute();
await NewMail({
template: {
mailType: "generic",
props: {
link: {
href: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
noreply: true,
testo: `Il pagamento per la consulenza è stato confermato.`,
title: "Pagamento Confermato ",
},
},
mail: {
subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
to: utente.email,
},
userId: utente.id,
});
break;
case OrderTypeEnum.Altro:
// TODO: Handle other types
await NewMail({
template: {
mailType: "pagamentoConferma",
props: {
receiptHref: `${env.BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
},
},
mail: {
subject: "Pagamento Confermato",
to: utente.email,
},
userId: utente.id,
});
break;
}
});
return true;
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error updating payment intent: ${(error as Error).message}`,
});
}
};
export const whIntentFailedHandler = async ({
pIntentId,
}: {
pIntentId: Payments["intent_id"];
}) => {
const userId = await db
.updateTable("payments")
.set({
paymentstatus: PaymentStatusEnum.failed,
})
.returning("userid")
.where("intent_id", "=", pIntentId)
.execute();
if (userId[0]) {
const utente = await getUser({
db,
userId: userId[0].userid,
});
await NewMail({
template: {
mailType: "pagamentoErrore",
},
mail: {
subject: "Pagamento Fallito",
to: utente.email,
},
userId: utente.id,
});
}
return true;
};