infoalloggi-monorepo/apps/infoalloggi/src/server/controllers/stripe.controller.ts
2025-08-04 17:45:44 +02:00

255 lines
7.3 KiB
TypeScript

import Stripe from "stripe";
import { env } from "~/env.mjs";
import { TRPCError } from "@trpc/server";
import PaymentStatusEnum from "~/schemas/public/PaymentStatusEnum";
import { db } from "~/server/db";
import type { Payments, PaymentsId } from "~/schemas/public/Payments";
import OrderTypeEnum from "~/schemas/public/OrderTypeEnum";
import TipologiaPosizioneEnum from "~/schemas/public/TipologiaPosizioneEnum";
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 ({
paymentId,
}: {
paymentId: PaymentsId;
}) => {
try {
const payment = await db
.selectFrom("payments")
.selectAll("payments")
.innerJoin("ordini", "ordini.ordine_id", "payments.ordine_id")
.innerJoin("prezziario", "prezziario.idprezziario", "ordini.packid")
.select(["prezziario.nome_it", "prezziario.desc_it"])
.where("id", "=", paymentId)
.executeTakeFirstOrThrow();
const paymentIntent = await stripeApi.paymentIntents.create({
amount: payment.amount_cent,
description: payment.nome_it,
currency: "eur",
//payment_method_configuration: "pmc_1P4NfjILe4KoQRqXYChFCTFj",
automatic_payment_methods: {
enabled: true,
},
metadata: {
userId: payment.userid,
servizioId: payment.servizio_id,
paymentId,
},
});
return {
clientSecret: paymentIntent.client_secret,
titolo: payment.nome_it,
prezzo: payment.amount_cent,
descrizione: payment.desc_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;
}) => {
return await db
.updateTable("payments")
.set({ intent_id: pIntentId, paymentstatus: PaymentStatusEnum.processing })
.where("id", "=", paymentId)
.returning("id")
.execute();
};
export const whIntentSucceededHandler = async ({
pIntentId,
paymentId,
pm_id,
}: {
pIntentId: Payments["intent_id"];
paymentId: PaymentsId;
pm_id: string;
}) => {
try {
const paymentMethod = await stripeApi.paymentMethods.retrieve(pm_id);
await db.transaction().execute(async (trx) => {
const payment = await trx
.updateTable("payments")
.set({
paymentstatus: PaymentStatusEnum.success,
paid_at: new Date(),
paymentmethod: paymentMethod.type,
})
.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({
userId: utente.id,
mailType: "generic",
to: utente.email,
subject: "Pagamento Confermato - Acconto Infoalloggi.it",
props: {
title: "Pagamento Confermato ",
noreply: true,
testo: `Il pagamento dell'acconto per il servizio ${ordine.packid} è stato confermato.`,
link: {
href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
},
});
break;
case OrderTypeEnum.Saldo:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
isOkSaldo: true,
isOkConsulenza:
servizio.tipologia == TipologiaPosizioneEnum.Transitorio
? true
: false,
})
.execute();
await NewMail({
userId: utente.id,
mailType: "generic",
to: utente.email,
subject: "Pagamento Confermato - Saldo Infoalloggi.it",
props: {
title: "Pagamento Confermato ",
noreply: true,
testo: `Il pagamento del saldo per il servizio ${ordine.packid} è stato confermato.`,
link: {
href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
},
});
break;
case OrderTypeEnum.Consulenza:
await trx
.updateTable("servizio")
.where("servizio_id", "=", payment.servizio_id)
.set({
isOkConsulenza: true,
})
.execute();
await NewMail({
userId: utente.id,
mailType: "generic",
to: utente.email,
subject: "Pagamento Confermato - Consulenza Infoalloggi.it",
props: {
title: "Pagamento Confermato ",
noreply: true,
testo: `Il pagamento per la consulenza è stato confermato.`,
link: {
href: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_id}`,
label: "Vai alla ricevuta",
},
},
});
break;
case OrderTypeEnum.Altro:
// TODO: Handle other types
await NewMail({
userId: utente.id,
mailType: "pagamentoConferma",
to: utente.email,
subject: "Pagamento Confermato",
props: {
receiptHref: `${env.NEXT_PUBLIC_BASE_URL}/area-riservata/payment-recap/${ordine.ordine_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({
userId: utente.id,
mailType: "pagamentoErrore",
to: utente.email,
subject: "Pagamento Fallito",
});
}
return true;
};