feat: add paid webhook (#8721)
* feat: add BOOKING_PAID on enums * feat: trigger the BOOKING_PAID webhook * refactor: create payment variable * feat: add REJECTED and REQUESTED on enums * feat: create migration to booking werbhooks * Update packages/features/webhooks/lib/constants.ts Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> * Update packages/prisma/schema.prisma Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> * Update packages/prisma/migrations/20230513235419_add_booking_webhooks/migration.sql Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> --------- Co-authored-by: Syed Ali Shahbaz <52925846+alishaz-polymath@users.noreply.github.com> Co-authored-by: alannnc <alannnc@gmail.com> Co-authored-by: Omar López <zomars@me.com>pull/9618/head
parent
4d30264950
commit
895b3ca7c9
|
@ -7,6 +7,7 @@ export const WEBHOOK_TRIGGER_EVENTS_GROUPED_BY_APP = {
|
|||
WebhookTriggerEvents.BOOKING_CANCELLED,
|
||||
WebhookTriggerEvents.BOOKING_CREATED,
|
||||
WebhookTriggerEvents.BOOKING_RESCHEDULED,
|
||||
WebhookTriggerEvents.BOOKING_PAID,
|
||||
WebhookTriggerEvents.MEETING_ENDED,
|
||||
WebhookTriggerEvents.BOOKING_REQUESTED,
|
||||
WebhookTriggerEvents.BOOKING_REJECTED,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
-- AlterEnum
|
||||
-- This migration adds more than one value to an enum.
|
||||
-- With PostgreSQL versions 11 and earlier, this is not possible
|
||||
-- in a single migration. This can be worked around by creating
|
||||
-- multiple migrations, each migration adding only one value to
|
||||
-- the enum.
|
||||
|
||||
|
||||
ALTER TYPE "WebhookTriggerEvents" ADD VALUE 'BOOKING_PAID';
|
|
@ -498,6 +498,7 @@ enum PaymentOption {
|
|||
|
||||
enum WebhookTriggerEvents {
|
||||
BOOKING_CREATED
|
||||
BOOKING_PAID
|
||||
BOOKING_RESCHEDULED
|
||||
BOOKING_REQUESTED
|
||||
BOOKING_CANCELLED
|
||||
|
|
|
@ -3,7 +3,9 @@ import { z } from "zod";
|
|||
import appStore from "@calcom/app-store";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
import { sendNoShowFeeChargedEmail } from "@calcom/emails";
|
||||
import getWebhooks from "@calcom/features/webhooks/lib/getWebhooks";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import sendPayload from "@calcom/lib/server/webhooks/sendPayload";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
@ -33,11 +35,13 @@ export const paymentsRouter = router({
|
|||
},
|
||||
});
|
||||
|
||||
const payment = booking.payment[0];
|
||||
|
||||
if (!booking) {
|
||||
throw new Error("Booking not found");
|
||||
}
|
||||
|
||||
if (booking.payment[0].success) {
|
||||
if (payment.success) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: `The no show fee for ${booking.id} has already been charged.`,
|
||||
|
@ -77,16 +81,16 @@ export const paymentsRouter = router({
|
|||
},
|
||||
attendees: attendeesList,
|
||||
paymentInfo: {
|
||||
amount: booking.payment[0].amount,
|
||||
currency: booking.payment[0].currency,
|
||||
paymentOption: booking.payment[0].paymentOption,
|
||||
amount: payment.amount,
|
||||
currency: payment.currency,
|
||||
paymentOption: payment.paymentOption,
|
||||
},
|
||||
};
|
||||
|
||||
const paymentCredential = await prisma.credential.findFirst({
|
||||
where: {
|
||||
userId: ctx.user.id,
|
||||
appId: booking.payment[0].appId,
|
||||
appId: payment.appId,
|
||||
},
|
||||
include: {
|
||||
app: true,
|
||||
|
@ -107,12 +111,32 @@ export const paymentsRouter = router({
|
|||
const paymentInstance = new PaymentService(paymentCredential);
|
||||
|
||||
try {
|
||||
const paymentData = await paymentInstance.chargeCard(booking.payment[0]);
|
||||
const paymentData = await paymentInstance.chargeCard(payment);
|
||||
|
||||
if (!paymentData) {
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: `Could not generate payment data` });
|
||||
}
|
||||
|
||||
const subscriberOptions = {
|
||||
userId: ctx.user.id || 0,
|
||||
eventTypeId: booking.eventTypeId || 0,
|
||||
triggerEvent: WebhookTriggerEvents.BOOKING_PAID,
|
||||
};
|
||||
|
||||
const subscribers = await getWebhooks(subscriberOptions);
|
||||
|
||||
await Promise.all(
|
||||
subscribers.map(async (subscriber) => {
|
||||
sendPayload(subscriber.secret, WebhookTriggerEvents.BOOKING_PAID, {
|
||||
...evt,
|
||||
bookingId: booking.id,
|
||||
paymentId: payment.id,
|
||||
paymentData,
|
||||
eventTypeId: subscriberOptions.eventTypeId,
|
||||
});
|
||||
})
|
||||
);
|
||||
|
||||
await sendNoShowFeeChargedEmail(attendeesListPromises[0], evt);
|
||||
|
||||
return paymentData;
|
||||
|
|
Loading…
Reference in New Issue