cal.pub0.org/packages/trpc/server/routers/viewer/payments.tsx

127 lines
3.7 KiB
TypeScript
Raw Normal View History

Stripe add the ability to place hold on cards (#8022) * Add payment option to schema * Add payment option to Stripe zod * Set payment option on event type * Create manual payment intent in Stripe * Set payment option from Stripe app * Add payment option to DB * Pass React.ReactNode to checkbox * Create uncaptured payment intent * WIP * Capture card in setup intent * Show charge card option * Charge card from booking page * Bug fixes * Clean up * Clean up app card * Add no-show fee messaging on booking page * Send payment email on payment & add price * Fix messaging * Create no show fee charged email * Send charge fee collected email * Disable submit on card failure * Clean up * Serverside prevent charging card again if already charged * Only confirm booking if paid for * Type fixes * More type fixes * More type fixes * Type fix * Type fixes * UI changes * Payment component rework * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/components/dialog/ChargeCardDialog.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update packages/trpc/server/routers/viewer/payments.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Revert GTM config * Adjust payment option dropdown * Show alert when seats are set * Small bug fixes * Create collect card method * clean up * Prevent seats & charge no-show fee to be enabled together * Do not charge no-show fee on unconfirmed bookings * Add check to collect card method * Webhook send request emails * Fix some dark mode colours * Change awaiting payment language * Type fixes * Set height of Select and TextField both to 38px to fix alignment * Fix message seats & payment error message * Type fix --------- Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-04-11 21:44:14 +00:00
import { z } from "zod";
import appStore from "@calcom/app-store";
import dayjs from "@calcom/dayjs";
import { sendNoShowFeeChargedEmail } from "@calcom/emails";
import { getTranslation } from "@calcom/lib/server/i18n";
import type { CalendarEvent } from "@calcom/types/Calendar";
import { TRPCError } from "@trpc/server";
import authedProcedure from "../../procedures/authedProcedure";
import { router } from "../../trpc";
Stripe add the ability to place hold on cards (#8022) * Add payment option to schema * Add payment option to Stripe zod * Set payment option on event type * Create manual payment intent in Stripe * Set payment option from Stripe app * Add payment option to DB * Pass React.ReactNode to checkbox * Create uncaptured payment intent * WIP * Capture card in setup intent * Show charge card option * Charge card from booking page * Bug fixes * Clean up * Clean up app card * Add no-show fee messaging on booking page * Send payment email on payment & add price * Fix messaging * Create no show fee charged email * Send charge fee collected email * Disable submit on card failure * Clean up * Serverside prevent charging card again if already charged * Only confirm booking if paid for * Type fixes * More type fixes * More type fixes * Type fix * Type fixes * UI changes * Payment component rework * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/components/dialog/ChargeCardDialog.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update packages/trpc/server/routers/viewer/payments.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Revert GTM config * Adjust payment option dropdown * Show alert when seats are set * Small bug fixes * Create collect card method * clean up * Prevent seats & charge no-show fee to be enabled together * Do not charge no-show fee on unconfirmed bookings * Add check to collect card method * Webhook send request emails * Fix some dark mode colours * Change awaiting payment language * Type fixes * Set height of Select and TextField both to 38px to fix alignment * Fix message seats & payment error message * Type fix --------- Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-04-11 21:44:14 +00:00
export const paymentsRouter = router({
chargeCard: authedProcedure
.input(
z.object({
bookingId: z.number(),
})
)
.mutation(async ({ ctx, input }) => {
const { prisma } = ctx;
const booking = await prisma.booking.findFirst({
where: {
id: input.bookingId,
},
include: {
payment: true,
user: true,
attendees: true,
eventType: true,
},
});
if (!booking) {
throw new Error("Booking not found");
}
if (booking.payment[0].success) {
throw new TRPCError({
code: "BAD_REQUEST",
message: `The no show fee for ${booking.id} has already been charged.`,
});
}
const tOrganizer = await getTranslation(booking.user?.locale ?? "en", "common");
const attendeesListPromises = [];
for (const attendee of booking.attendees) {
const attendeeObject = {
name: attendee.name,
email: attendee.email,
timeZone: attendee.timeZone,
language: {
translate: await getTranslation(attendee.locale ?? "en", "common"),
locale: attendee.locale ?? "en",
},
};
attendeesListPromises.push(attendeeObject);
}
const attendeesList = await Promise.all(attendeesListPromises);
const evt: CalendarEvent = {
type: (booking?.eventType?.title as string) || booking?.title,
title: booking.title,
startTime: dayjs(booking.startTime).format(),
endTime: dayjs(booking.endTime).format(),
organizer: {
email: booking.user?.email || "",
name: booking.user?.name || "Nameless",
timeZone: booking.user?.timeZone || "",
language: { translate: tOrganizer, locale: booking.user?.locale ?? "en" },
},
attendees: attendeesList,
paymentInfo: {
amount: booking.payment[0].amount,
currency: booking.payment[0].currency,
paymentOption: booking.payment[0].paymentOption,
},
};
const paymentCredential = await prisma.credential.findFirst({
where: {
userId: ctx.user.id,
appId: booking.payment[0].appId,
},
include: {
app: true,
},
});
if (!paymentCredential?.app) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Invalid payment credential" });
}
const paymentApp = await appStore[paymentCredential?.app?.dirName as keyof typeof appStore];
if (!("lib" in paymentApp && "PaymentService" in paymentApp.lib)) {
throw new TRPCError({ code: "BAD_REQUEST", message: "Payment service not found" });
}
const PaymentService = paymentApp.lib.PaymentService;
const paymentInstance = new PaymentService(paymentCredential);
try {
const paymentData = await paymentInstance.chargeCard(booking.payment[0]);
Stripe add the ability to place hold on cards (#8022) * Add payment option to schema * Add payment option to Stripe zod * Set payment option on event type * Create manual payment intent in Stripe * Set payment option from Stripe app * Add payment option to DB * Pass React.ReactNode to checkbox * Create uncaptured payment intent * WIP * Capture card in setup intent * Show charge card option * Charge card from booking page * Bug fixes * Clean up * Clean up app card * Add no-show fee messaging on booking page * Send payment email on payment & add price * Fix messaging * Create no show fee charged email * Send charge fee collected email * Disable submit on card failure * Clean up * Serverside prevent charging card again if already charged * Only confirm booking if paid for * Type fixes * More type fixes * More type fixes * Type fix * Type fixes * UI changes * Payment component rework * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/public/static/locales/en/common.json Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update apps/web/components/dialog/ChargeCardDialog.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Update packages/trpc/server/routers/viewer/payments.tsx Co-authored-by: Alex van Andel <me@alexvanandel.com> * Revert GTM config * Adjust payment option dropdown * Show alert when seats are set * Small bug fixes * Create collect card method * clean up * Prevent seats & charge no-show fee to be enabled together * Do not charge no-show fee on unconfirmed bookings * Add check to collect card method * Webhook send request emails * Fix some dark mode colours * Change awaiting payment language * Type fixes * Set height of Select and TextField both to 38px to fix alignment * Fix message seats & payment error message * Type fix --------- Co-authored-by: Alex van Andel <me@alexvanandel.com>
2023-04-11 21:44:14 +00:00
if (!paymentData) {
throw new TRPCError({ code: "NOT_FOUND", message: `Could not generate payment data` });
}
await sendNoShowFeeChargedEmail(attendeesListPromises[0], evt);
return paymentData;
} catch (err) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: `Error processing payment with error ${err}`,
});
}
}),
});