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

277 lines
6.8 KiB
TypeScript
Raw Normal View History

2025-08-28 18:27:07 +02:00
import { TRPCError } from "@trpc/server";
2025-08-04 17:45:44 +02:00
import Stripe from "stripe";
import { env } from "~/env";
2025-08-28 18:27:07 +02:00
import OrderTypeEnum from "~/schemas/public/OrderTypeEnum";
2025-08-04 17:45:44 +02:00
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
import type { Payments, PaymentsId } from "~/schemas/public/Payments";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
2025-08-28 18:27:07 +02:00
import { db } from "~/server/db";
2025-08-04 17:45:44 +02:00
import { NewMail } from "~/server/services/mailer";
import { getUser } from "~/server/services/user.service";
const stripeApi = new Stripe(env.STRIPE_SECRET_KEY);
export const createIntentHandler = async ({
2025-08-28 18:27:07 +02:00
paymentId,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
paymentId: PaymentsId;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
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)
2025-08-28 18:27:07 +02:00
.executeTakeFirstOrThrow();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const paymentIntent = await stripeApi.paymentIntents.create({
amount: payment.amount_cent,
//payment_method_configuration: "pmc_1P4NfjILe4KoQRqXYChFCTFj",
automatic_payment_methods: {
enabled: true,
},
2025-08-29 16:18:32 +02:00
currency: "eur",
description: payment.nome_it,
2025-08-28 18:27:07 +02:00
metadata: {
paymentId,
2025-08-29 16:18:32 +02:00
servizioId: payment.servizio_id,
userId: payment.userid,
2025-08-28 18:27:07 +02:00
},
receipt_email: payment.email,
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
return {
clientSecret: paymentIntent.client_secret,
descrizione: payment.desc_it,
2025-08-29 16:18:32 +02:00
prezzo: payment.amount_cent,
titolo: payment.nome_it,
2025-08-28 18:27:07 +02:00
};
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error creating payment intent: ${(error as Error).message}`,
});
}
2025-08-04 17:45:44 +02:00
};
export const whIntentCreatedHandler = async ({
2025-08-28 18:27:07 +02:00
pIntentId,
paymentId,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
pIntentId: Payments["intent_id"];
paymentId: PaymentsId;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
return await db
.updateTable("payments")
.set({ intent_id: pIntentId, paymentstatus: PaymentStatusEnum.processing })
.where("id", "=", paymentId)
.returning("id")
.execute();
2025-08-04 17:45:44 +02:00
};
export const whIntentSucceededHandler = async ({
2025-08-28 18:27:07 +02:00
pIntentId,
paymentId,
pm_id,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
pIntentId: Payments["intent_id"];
paymentId: PaymentsId;
pm_id: string;
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
try {
const paymentMethod = await stripeApi.paymentMethods.retrieve(pm_id);
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await db.transaction().execute(async (trx) => {
const payment = await trx
.updateTable("payments")
.set({
paid_at: new Date(),
paymentmethod: paymentMethod.type,
2025-08-29 16:18:32 +02:00
paymentstatus: PaymentStatusEnum.success,
2025-08-28 18:27:07 +02:00
})
.where("intent_id", "=", pIntentId)
.where("payments.id", "=", paymentId)
.returning(["servizio_id", "ordine_id"])
.executeTakeFirstOrThrow();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const ordine = await trx
.selectFrom("ordini")
.selectAll("ordini")
.where("ordine_id", "=", payment.ordine_id)
.executeTakeFirstOrThrow();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await trx
.updateTable("ordini")
.where("ordine_id", "=", payment.ordine_id)
.set({
isActive: true,
})
.execute();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const servizio = await trx
.selectFrom("servizio")
.select("servizio.tipologia")
.where("servizio_id", "=", payment.servizio_id)
.executeTakeFirstOrThrow();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
const utente = await getUser({
db: trx,
userId: ordine.userid,
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
switch (ordine.type) {
case OrderTypeEnum.Acconto:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
decorrenza: new Date(),
isOkAcconto: true,
})
.execute();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await NewMail({
template: {
mailType: "generic",
2025-08-04 17:45:44 +02:00
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 ",
2025-08-28 18:27:07 +02:00
},
},
mail: {
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
to: utente.email,
},
2025-08-29 16:18:32 +02:00
userId: utente.id,
2025-08-28 18:27:07 +02:00
});
break;
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
case OrderTypeEnum.Saldo:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
isOkConsulenza:
servizio.tipologia === TipologiaPosizioneEnum.Transitorio,
2025-08-29 16:18:32 +02:00
isOkSaldo: true,
2025-08-28 18:27:07 +02:00
})
.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 ",
2025-08-28 18:27:07 +02:00
},
},
mail: {
subject: "Pagamento Confermato - Saldo Infoalloggi.it",
to: utente.email,
},
2025-08-29 16:18:32 +02:00
userId: utente.id,
2025-08-28 18:27:07 +02:00
});
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 ",
2025-08-28 18:27:07 +02:00
},
},
mail: {
subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
to: utente.email,
},
2025-08-29 16:18:32 +02:00
userId: utente.id,
2025-08-28 18:27:07 +02:00
});
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,
2025-08-28 18:27:07 +02:00
},
2025-08-29 16:18:32 +02:00
userId: utente.id,
2025-08-28 18:27:07 +02:00
});
break;
}
});
return true;
} catch (error) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error updating payment intent: ${(error as Error).message}`,
});
}
2025-08-04 17:45:44 +02:00
};
export const whIntentFailedHandler = async ({
2025-08-28 18:27:07 +02:00
pIntentId,
2025-08-04 17:45:44 +02:00
}: {
2025-08-28 18:27:07 +02:00
pIntentId: Payments["intent_id"];
2025-08-04 17:45:44 +02:00
}) => {
2025-08-28 18:27:07 +02:00
const userId = await db
.updateTable("payments")
.set({
paymentstatus: PaymentStatusEnum.failed,
})
.returning("userid")
.where("intent_id", "=", pIntentId)
.execute();
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
if (userId[0]) {
const utente = await getUser({
db,
userId: userId[0].userid,
});
2025-08-04 17:45:44 +02:00
2025-08-28 18:27:07 +02:00
await NewMail({
template: {
mailType: "pagamentoErrore",
},
mail: {
subject: "Pagamento Fallito",
to: utente.email,
},
2025-08-29 16:18:32 +02:00
userId: utente.id,
2025-08-28 18:27:07 +02:00
});
}
return true;
2025-08-04 17:45:44 +02:00
};