feat: update payment preparation logic to include 'Rinnovo' type and handle errors gracefully
This commit is contained in:
parent
8716d90148
commit
73245f3564
7 changed files with 182 additions and 51 deletions
|
|
@ -1 +0,0 @@
|
|||
ALTER TABLE IF EXISTS public.ordini DROP COLUMN IF EXISTS condizioni;
|
||||
4
apps/db/migrations/35_rinnovi.up.sql
Normal file
4
apps/db/migrations/35_rinnovi.up.sql
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
ALTER TABLE IF EXISTS public.ordini DROP COLUMN IF EXISTS condizioni;
|
||||
|
||||
ALTER TYPE public."OrderTypeEnum"
|
||||
ADD VALUE IF NOT EXISTS 'Rinnovo' AFTER 'Altro';
|
||||
|
|
@ -7,7 +7,7 @@ export default function Custom500() {
|
|||
const { t } = useTranslation();
|
||||
return (
|
||||
<main>
|
||||
<div className="mx-auto flex h-screen max-w-screen-xl items-center justify-start px-4 md:px-8">
|
||||
<div className="mx-auto flex h-screen max-w-7xl items-center justify-start px-4 md:px-8">
|
||||
<div className="mx-auto max-w-lg space-y-3 text-center">
|
||||
<ShieldExclamationIcon className="mx-auto size-20 text-red-600" />
|
||||
<h3 className="font-semibold text-4xl text-accent-foreground sm:text-5xl">
|
||||
|
|
|
|||
|
|
@ -36,7 +36,10 @@ const PreviewPurchasePage: NextPageWithLayout<PreviewPurchaseProps> = ({
|
|||
<p className="text-3xl">{data.packName}</p>
|
||||
<p className="text-lg">Cod: “{data.packid}”</p>
|
||||
<p className="font-bold text-4xl">
|
||||
{formatCurrency(data.amount_cent / 100)} {data.sconto > 0 && <span className="text-green-500">(Sconto: {data.sconto}%)</span>}
|
||||
{formatCurrency(data.amount_cent / 100)}{" "}
|
||||
{data.sconto > 0 && (
|
||||
<span className="text-green-500">(Sconto: {data.sconto}%)</span>
|
||||
)}
|
||||
</p>
|
||||
<p>{data.packDesc}</p>
|
||||
</div>
|
||||
|
|
@ -130,6 +133,15 @@ export const getServerSideProps = (async (context) => {
|
|||
type: parsedType.data,
|
||||
servizioId: parsedServizioId.data,
|
||||
});
|
||||
if (!data.success) {
|
||||
console.error("Error preparing payment", data.message);
|
||||
return {
|
||||
redirect: {
|
||||
destination: `/500`,
|
||||
permanent: false,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const flag = await helper.trpc.flags.GetFlagValue.fetch({
|
||||
id: "STRIPE_DISABLED",
|
||||
|
|
@ -138,7 +150,7 @@ export const getServerSideProps = (async (context) => {
|
|||
return {
|
||||
props: {
|
||||
stripeDisabled: flag || false,
|
||||
data,
|
||||
data: data.data,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ enum OrderTypeEnum {
|
|||
Saldo = 'Saldo',
|
||||
Consulenza = 'Consulenza',
|
||||
Altro = 'Altro',
|
||||
Rinnovo = 'Rinnovo',
|
||||
};
|
||||
|
||||
export default OrderTypeEnum;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
|
|||
import {
|
||||
getPagamentoDataForCheckout,
|
||||
preparePayment,
|
||||
type PreparedPaymentData,
|
||||
} from "~/server/controllers/pagamenti.controller";
|
||||
|
||||
import { db } from "~/server/db";
|
||||
|
|
@ -44,6 +45,16 @@ export const pagamentiRouter = createTRPCRouter({
|
|||
type: z.custom<OrderTypeEnum>(),
|
||||
}),
|
||||
)
|
||||
.output(z.discriminatedUnion("", [
|
||||
z.object({
|
||||
success: z.literal(true),
|
||||
data: z.custom<PreparedPaymentData>(),
|
||||
}),
|
||||
z.object({
|
||||
success: z.literal(false),
|
||||
message: z.string(),
|
||||
}),
|
||||
]),)
|
||||
.query(async ({ input }) => {
|
||||
return await preparePayment(input.servizioId, input.type);
|
||||
}),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ export type PreparedPaymentData = {
|
|||
export const preparePayment = async (
|
||||
servizioId: ServizioServizioId,
|
||||
type: OrderTypeEnum,
|
||||
): Promise<PreparedPaymentData> => {
|
||||
): Promise<{success: true, data: PreparedPaymentData} | {success:false, message: string}> => {
|
||||
try {
|
||||
const servizio = await getServizioById(servizioId);
|
||||
const inactiveOrders = await db
|
||||
|
|
@ -43,12 +43,17 @@ export const preparePayment = async (
|
|||
if (!servizio.isOkAcconto) {
|
||||
const acconto = await AccontoSolver(servizio);
|
||||
if (!acconto.success) {
|
||||
throw new Error(
|
||||
`Acconto non trovato per il servizio: ${acconto.message}`,
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: `Acconto non trovato per il servizio: ${acconto.message}`,
|
||||
};
|
||||
|
||||
}
|
||||
if (!acconto.pack.testo_condizioni) {
|
||||
throw new Error("Condizioni non trovate per acconto");
|
||||
return {
|
||||
success: false,
|
||||
message: `Condizioni non trovate per acconto: ${acconto.pack.nome_it}`,
|
||||
};
|
||||
}
|
||||
|
||||
// servizio sta aspettando attivazione acconto
|
||||
|
|
@ -59,7 +64,7 @@ export const preparePayment = async (
|
|||
|
||||
if (preExistingAcconto) {
|
||||
// acconto già creato, procedere con questo
|
||||
return {
|
||||
return {success: true, data: {
|
||||
ordine_id: preExistingAcconto.ordine_id,
|
||||
packid: preExistingAcconto.packid,
|
||||
amount_cent: preExistingAcconto.amount_cent,
|
||||
|
|
@ -67,7 +72,7 @@ export const preparePayment = async (
|
|||
packName: acconto.pack.nome_it,
|
||||
packDesc: acconto.pack.desc_it,
|
||||
condizioni: acconto.pack.testo_condizioni,
|
||||
};
|
||||
}};
|
||||
}
|
||||
// nessun acconto preesistente, crearne uno nuovo
|
||||
|
||||
|
|
@ -78,7 +83,7 @@ export const preparePayment = async (
|
|||
type: OrderTypeEnum.Acconto,
|
||||
userid: servizio.user_id,
|
||||
});
|
||||
return {
|
||||
return {success: true, data: {
|
||||
ordine_id: ordine.ordine_id,
|
||||
packid: acconto.pack.idprezziario,
|
||||
amount_cent: acconto.pack.prezzo_cent,
|
||||
|
|
@ -86,36 +91,43 @@ export const preparePayment = async (
|
|||
packName: acconto.pack.nome_it,
|
||||
packDesc: acconto.pack.desc_it,
|
||||
condizioni: acconto.pack.testo_condizioni,
|
||||
};
|
||||
}};
|
||||
}
|
||||
return{
|
||||
success: false,
|
||||
message: "Il servizio ha già un acconto attivo, non è possibile preparare un nuovo pagamento"
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"Il servizio ha già un acconto attivo, non è possibile preparare un nuovo pagamento",
|
||||
);
|
||||
}
|
||||
case OrderTypeEnum.Saldo: {
|
||||
if (!servizio.isOkAcconto) {
|
||||
throw new Error(
|
||||
"Non è possibile procedere con il pagamento del saldo prima di aver attivato l'acconto",
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: "Non è possibile procedere con il pagamento del saldo prima di aver attivato l'acconto",
|
||||
};
|
||||
|
||||
}
|
||||
if (!servizio.isOkSaldo) {
|
||||
//find saldo pack based on servizio tipologia and permanenza/budget, if tipologia posizione
|
||||
const saldo = await SaldoSolver(servizio);
|
||||
if (!saldo.success) {
|
||||
throw new Error(
|
||||
`Saldo non trovato per il servizio: ${saldo.message}`,
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: `Saldo non trovato per il servizio: ${saldo.message}`,
|
||||
};
|
||||
}
|
||||
if (!saldo.pack.testo_condizioni) {
|
||||
throw new Error("Condizioni non trovate per saldo");
|
||||
return {
|
||||
success: false,
|
||||
message: `Condizioni non trovate per saldo: ${saldo.pack.nome_it}`,
|
||||
};
|
||||
}
|
||||
const preExistingSaldo = inactiveOrders.find(
|
||||
(ordine) => ordine.type === OrderTypeEnum.Saldo,
|
||||
);
|
||||
if (preExistingSaldo) {
|
||||
// saldo già creato, procedere con questo
|
||||
return {
|
||||
return{success: true, data: {
|
||||
ordine_id: preExistingSaldo.ordine_id,
|
||||
packid: preExistingSaldo.packid,
|
||||
amount_cent: preExistingSaldo.amount_cent,
|
||||
|
|
@ -123,7 +135,7 @@ export const preparePayment = async (
|
|||
packName: saldo.pack.nome_it,
|
||||
packDesc: saldo.pack.desc_it,
|
||||
condizioni: saldo.pack.testo_condizioni,
|
||||
};
|
||||
}};
|
||||
}
|
||||
// nessun saldo preesistente, crearne uno nuovo
|
||||
const ordine = await createOrdine({
|
||||
|
|
@ -133,7 +145,7 @@ export const preparePayment = async (
|
|||
type: OrderTypeEnum.Saldo,
|
||||
userid: servizio.user_id,
|
||||
});
|
||||
return {
|
||||
return {success: true, data: {
|
||||
ordine_id: ordine.ordine_id,
|
||||
packid: saldo.pack.idprezziario,
|
||||
amount_cent: saldo.pack.prezzo_cent,
|
||||
|
|
@ -141,18 +153,20 @@ export const preparePayment = async (
|
|||
packName: saldo.pack.nome_it,
|
||||
packDesc: saldo.pack.desc_it,
|
||||
condizioni: saldo.pack.testo_condizioni,
|
||||
};
|
||||
}};
|
||||
}
|
||||
return{
|
||||
success: false,
|
||||
message: "Il servizio ha già un saldo attivo, non è possibile preparare un nuovo pagamento"
|
||||
}
|
||||
throw new Error(
|
||||
"Il servizio ha già un saldo attivo, non è possibile preparare un nuovo pagamento",
|
||||
);
|
||||
}
|
||||
|
||||
case OrderTypeEnum.Consulenza: {
|
||||
if (!servizio.isOkAcconto || !servizio.isOkSaldo) {
|
||||
throw new Error(
|
||||
"Non è possibile procedere con il pagamento della consulenza prima di aver attivato acconto e saldo",
|
||||
);
|
||||
return {
|
||||
success: false,
|
||||
message: "Non è possibile procedere con il pagamento della consulenza prima di aver attivato acconto e saldo",
|
||||
};
|
||||
}
|
||||
if (!servizio.isOkConsulenza) {
|
||||
const existingConsulenza = inactiveOrders.find(
|
||||
|
|
@ -164,12 +178,20 @@ export const preparePayment = async (
|
|||
existingConsulenza.packid,
|
||||
);
|
||||
if (!consulenzaPack) {
|
||||
throw new Error("Pack consulenza non trovato");
|
||||
return {
|
||||
success: false,
|
||||
message: `Pack della consulenza non trovato: ${existingConsulenza.packid}`,
|
||||
}
|
||||
}
|
||||
if (!consulenzaPack.testo_condizioni) {
|
||||
throw new Error("Condizioni non trovate per consulenza");
|
||||
return {
|
||||
success: false,
|
||||
message: `Condizioni non trovate per consulenza: ${consulenzaPack.nome_it}`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
ordine_id: existingConsulenza.ordine_id,
|
||||
packid: existingConsulenza.packid,
|
||||
amount_cent: existingConsulenza.amount_cent,
|
||||
|
|
@ -177,21 +199,103 @@ export const preparePayment = async (
|
|||
packName: consulenzaPack.nome_it,
|
||||
packDesc: consulenzaPack.desc_it,
|
||||
condizioni: consulenzaPack.testo_condizioni,
|
||||
},
|
||||
};
|
||||
}
|
||||
//todo vedere se oltre a emettere un errore si vuole anche passare un messaggio alla pagina di errore
|
||||
throw new Error(
|
||||
"Il servizio non ha un pacchetto di consulenza, è necessario inserirlo prima di procedere",
|
||||
);
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: "Il servizio non ha un pacchetto di consulenza, è necessario inserirlo prima di procedere",
|
||||
};
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"Il servizio ha già una consulenza attiva, non è possibile preparare un nuovo pagamento",
|
||||
return {
|
||||
success: false,
|
||||
message: "Il servizio ha già una consulenza attiva, non è possibile preparare un nuovo pagamento",
|
||||
};
|
||||
}
|
||||
case OrderTypeEnum.Rinnovo : {
|
||||
const existingRinnovo = inactiveOrders.find(
|
||||
(ordine) => ordine.type === OrderTypeEnum.Rinnovo,
|
||||
);
|
||||
if (existingRinnovo) {
|
||||
// rinnovo già creato, procedere con questo
|
||||
const rinnovoPack = await getPrezziarioByIdHandler(
|
||||
existingRinnovo.packid,
|
||||
);
|
||||
if (!rinnovoPack) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Pack del rinnovo non trovato: ${existingRinnovo.packid}`,
|
||||
}
|
||||
}
|
||||
if (!rinnovoPack.testo_condizioni) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Condizioni non trovate per rinnovo: ${rinnovoPack.nome_it}`,
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
ordine_id: existingRinnovo.ordine_id,
|
||||
packid: existingRinnovo.packid,
|
||||
amount_cent: existingRinnovo.amount_cent,
|
||||
sconto: existingRinnovo.sconto,
|
||||
packName: rinnovoPack.nome_it,
|
||||
packDesc: rinnovoPack.desc_it,
|
||||
condizioni: rinnovoPack.testo_condizioni,
|
||||
},
|
||||
};
|
||||
}
|
||||
return {
|
||||
success: false,
|
||||
message: "Il servizio non ha un pacchetto di rinnovo, è necessario inserirlo prima di procedere",
|
||||
};
|
||||
}
|
||||
case OrderTypeEnum.Altro : {
|
||||
const existingAltro = inactiveOrders.find(
|
||||
(ordine) => ordine.type === OrderTypeEnum.Altro,
|
||||
);
|
||||
if (existingAltro) {
|
||||
// altro già creato, procedere con questo
|
||||
const altroPack = await getPrezziarioByIdHandler(
|
||||
existingAltro.packid,
|
||||
);
|
||||
if (!altroPack) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Pack dell'altro non trovato: ${existingAltro.packid}`,
|
||||
}
|
||||
}
|
||||
if (!altroPack.testo_condizioni) {
|
||||
return {
|
||||
success: false,
|
||||
message: `Condizioni non trovate per altro: ${altroPack.nome_it}`,
|
||||
};
|
||||
|
||||
}
|
||||
return {
|
||||
success: true,
|
||||
data: {
|
||||
ordine_id: existingAltro.ordine_id,
|
||||
packid: existingAltro.packid,
|
||||
amount_cent: existingAltro.amount_cent,
|
||||
sconto: existingAltro.sconto,
|
||||
packName: altroPack.nome_it,
|
||||
packDesc: altroPack.desc_it,
|
||||
condizioni: altroPack.testo_condizioni,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: false,
|
||||
message: "La preparazione del pagamento per questa tipologia non è supportata",
|
||||
};
|
||||
}
|
||||
default:
|
||||
throw new Error("Tipo di ordine non valido");
|
||||
throw new Error(`Tipo di ordine non valido: ${type satisfies never}`);
|
||||
}
|
||||
} catch (e) {
|
||||
throw new TRPCError({
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue