WIP mercado pago
This commit is contained in:
parent
f26368f405
commit
d331d8c5e4
|
@ -28,6 +28,7 @@ export const EventTypeAddonMap = {
|
|||
qr_code: dynamic(() => import("./qr_code/components/EventTypeAppCardInterface")),
|
||||
rainbow: dynamic(() => import("./rainbow/components/EventTypeAppCardInterface")),
|
||||
stripepayment: dynamic(() => import("./stripepayment/components/EventTypeAppCardInterface")),
|
||||
"mercado_pago": dynamic(() => import("./mercado_pago/components/EventTypeAppCardInterface")),
|
||||
"booking-pages-tag": dynamic(() =>
|
||||
import("./templates/booking-pages-tag/components/EventTypeAppCardInterface")
|
||||
),
|
||||
|
|
|
@ -10,6 +10,7 @@ const appStore = {
|
|||
huddle01video: import("./huddle01video"),
|
||||
jitsivideo: import("./jitsivideo"),
|
||||
larkcalendar: import("./larkcalendar"),
|
||||
mercado_pago: import("./mercado_pago"),
|
||||
office365calendar: import("./office365calendar"),
|
||||
office365video: import("./office365video"),
|
||||
plausible: import("./plausible"),
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
export { default as add } from "./add";
|
||||
export { default as webhook } from "./webhook";
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
import { BookingStatus } from "@prisma/client";
|
||||
import type { Prisma } from "@prisma/client";
|
||||
import type { NextApiRequest, NextApiResponse } from "next";
|
||||
import * as z from "zod";
|
||||
|
||||
import EventManager from "@calcom/core/EventManager";
|
||||
import { sendScheduledEmails } from "@calcom/emails";
|
||||
import { getCalEventResponses } from "@calcom/features/bookings/lib/getCalEventResponses";
|
||||
import { handleConfirmation } from "@calcom/features/bookings/lib/handleConfirmation";
|
||||
import { isPrismaObjOrUndefined, parseRecurringEvent } from "@calcom/lib";
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
import { getErrorFromUnknown } from "@calcom/lib/errors";
|
||||
import { HttpError as HttpCode } from "@calcom/lib/http-error";
|
||||
import { getTranslation } from "@calcom/lib/server/i18n";
|
||||
import prisma, { bookingMinimalSelect } from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
export const config = {
|
||||
api: {
|
||||
bodyParser: false,
|
||||
},
|
||||
};
|
||||
|
||||
async function getEventType(id: number) {
|
||||
return prisma.eventType.findUnique({
|
||||
where: {
|
||||
id,
|
||||
},
|
||||
select: {
|
||||
recurringEvent: true,
|
||||
requiresConfirmation: true,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function getBooking(bookingId: number) {
|
||||
const booking = await prisma.booking.findUnique({
|
||||
where: {
|
||||
id: bookingId,
|
||||
},
|
||||
select: {
|
||||
...bookingMinimalSelect,
|
||||
eventType: true,
|
||||
smsReminderNumber: true,
|
||||
location: true,
|
||||
eventTypeId: true,
|
||||
userId: true,
|
||||
uid: true,
|
||||
paid: true,
|
||||
destinationCalendar: true,
|
||||
status: true,
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
credentials: true,
|
||||
timeZone: true,
|
||||
email: true,
|
||||
name: true,
|
||||
locale: true,
|
||||
destinationCalendar: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!booking) throw new HttpCode({ statusCode: 204, message: "No booking found" });
|
||||
|
||||
type EventTypeRaw = Awaited<ReturnType<typeof getEventType>>;
|
||||
let eventTypeRaw: EventTypeRaw | null = null;
|
||||
if (booking.eventTypeId) {
|
||||
eventTypeRaw = await getEventType(booking.eventTypeId);
|
||||
}
|
||||
|
||||
const { user } = booking;
|
||||
|
||||
if (!user) throw new HttpCode({ statusCode: 204, message: "No user found" });
|
||||
|
||||
const t = await getTranslation(user.locale ?? "en", "common");
|
||||
const attendeesListPromises = booking.attendees.map(async (attendee) => {
|
||||
return {
|
||||
name: attendee.name,
|
||||
email: attendee.email,
|
||||
timeZone: attendee.timeZone,
|
||||
language: {
|
||||
translate: await getTranslation(attendee.locale ?? "en", "common"),
|
||||
locale: attendee.locale ?? "en",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const attendeesList = await Promise.all(attendeesListPromises);
|
||||
|
||||
const evt: CalendarEvent = {
|
||||
type: booking.title,
|
||||
title: booking.title,
|
||||
description: booking.description || undefined,
|
||||
startTime: booking.startTime.toISOString(),
|
||||
endTime: booking.endTime.toISOString(),
|
||||
customInputs: isPrismaObjOrUndefined(booking.customInputs),
|
||||
organizer: {
|
||||
email: user.email,
|
||||
name: user.name!,
|
||||
timeZone: user.timeZone,
|
||||
language: { translate: t, locale: user.locale ?? "en" },
|
||||
id: user.id,
|
||||
},
|
||||
attendees: attendeesList,
|
||||
uid: booking.uid,
|
||||
destinationCalendar: booking.destinationCalendar || user.destinationCalendar,
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw?.recurringEvent),
|
||||
};
|
||||
|
||||
return {
|
||||
booking,
|
||||
user,
|
||||
evt,
|
||||
eventTypeRaw,
|
||||
};
|
||||
}
|
||||
|
||||
async function handlePaymentSuccess(payload: z.infer<typeof MercadoPagoPayloadSchema>) {
|
||||
return true;
|
||||
const payment = await prisma.payment.findFirst({
|
||||
where: {
|
||||
externalId: paymentIntent.id,
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
bookingId: true,
|
||||
},
|
||||
});
|
||||
if (!payment?.bookingId) {
|
||||
console.log(JSON.stringify(paymentIntent), JSON.stringify(payment));
|
||||
}
|
||||
if (!payment?.bookingId) throw new HttpCode({ statusCode: 204, message: "Payment not found" });
|
||||
|
||||
const booking = await prisma.booking.findUnique({
|
||||
where: {
|
||||
id: payment.bookingId,
|
||||
},
|
||||
select: {
|
||||
...bookingMinimalSelect,
|
||||
eventType: true,
|
||||
smsReminderNumber: true,
|
||||
location: true,
|
||||
eventTypeId: true,
|
||||
userId: true,
|
||||
uid: true,
|
||||
paid: true,
|
||||
destinationCalendar: true,
|
||||
status: true,
|
||||
responses: true,
|
||||
user: {
|
||||
select: {
|
||||
id: true,
|
||||
username: true,
|
||||
credentials: true,
|
||||
timeZone: true,
|
||||
email: true,
|
||||
name: true,
|
||||
locale: true,
|
||||
destinationCalendar: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!booking) throw new HttpCode({ statusCode: 204, message: "No booking found" });
|
||||
|
||||
type EventTypeRaw = Awaited<ReturnType<typeof getEventType>>;
|
||||
let eventTypeRaw: EventTypeRaw | null = null;
|
||||
if (booking.eventTypeId) {
|
||||
eventTypeRaw = await getEventType(booking.eventTypeId);
|
||||
}
|
||||
|
||||
const { user } = booking;
|
||||
|
||||
if (!user) throw new HttpCode({ statusCode: 204, message: "No user found" });
|
||||
|
||||
const t = await getTranslation(user.locale ?? "en", "common");
|
||||
const attendeesListPromises = booking.attendees.map(async (attendee) => {
|
||||
return {
|
||||
name: attendee.name,
|
||||
email: attendee.email,
|
||||
timeZone: attendee.timeZone,
|
||||
language: {
|
||||
translate: await getTranslation(attendee.locale ?? "en", "common"),
|
||||
locale: attendee.locale ?? "en",
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const attendeesList = await Promise.all(attendeesListPromises);
|
||||
|
||||
const evt: CalendarEvent = {
|
||||
type: booking.title,
|
||||
title: booking.title,
|
||||
description: booking.description || undefined,
|
||||
startTime: booking.startTime.toISOString(),
|
||||
endTime: booking.endTime.toISOString(),
|
||||
customInputs: isPrismaObjOrUndefined(booking.customInputs),
|
||||
...getCalEventResponses({
|
||||
booking: booking,
|
||||
bookingFields: booking.eventType?.bookingFields || null,
|
||||
}),
|
||||
organizer: {
|
||||
email: user.email,
|
||||
name: user.name!,
|
||||
timeZone: user.timeZone,
|
||||
language: { translate: t, locale: user.locale ?? "en" },
|
||||
},
|
||||
attendees: attendeesList,
|
||||
uid: booking.uid,
|
||||
destinationCalendar: booking.destinationCalendar || user.destinationCalendar,
|
||||
recurringEvent: parseRecurringEvent(eventTypeRaw?.recurringEvent),
|
||||
};
|
||||
|
||||
if (booking.location) evt.location = booking.location;
|
||||
|
||||
const bookingData: Prisma.BookingUpdateInput = {
|
||||
paid: true,
|
||||
status: BookingStatus.ACCEPTED,
|
||||
};
|
||||
|
||||
const isConfirmed = booking.status === BookingStatus.ACCEPTED;
|
||||
if (isConfirmed) {
|
||||
const eventManager = new EventManager(user);
|
||||
const scheduleResult = await eventManager.create(evt);
|
||||
bookingData.references = { create: scheduleResult.referencesToCreate };
|
||||
}
|
||||
|
||||
if (eventTypeRaw?.requiresConfirmation) {
|
||||
delete bookingData.status;
|
||||
}
|
||||
|
||||
const paymentUpdate = prisma.payment.update({
|
||||
where: {
|
||||
id: payment.id,
|
||||
},
|
||||
data: {
|
||||
success: true,
|
||||
},
|
||||
});
|
||||
|
||||
const bookingUpdate = prisma.booking.update({
|
||||
where: {
|
||||
id: booking.id,
|
||||
},
|
||||
data: bookingData,
|
||||
});
|
||||
|
||||
await prisma.$transaction([paymentUpdate, bookingUpdate]);
|
||||
|
||||
if (!isConfirmed && !eventTypeRaw?.requiresConfirmation) {
|
||||
await handleConfirmation({ user, evt, prisma, bookingId: booking.id, booking, paid: true });
|
||||
} else {
|
||||
await sendScheduledEmails({ ...evt });
|
||||
}
|
||||
|
||||
throw new HttpCode({
|
||||
statusCode: 200,
|
||||
message: `Booking with id '${booking.id}' was paid and confirmed.`,
|
||||
});
|
||||
}
|
||||
|
||||
type WebhookHandler = (action: "test.created" | "created") => Promise<void>;
|
||||
|
||||
const webhookHandlers: Record<string, WebhookHandler | undefined> = {
|
||||
"test.created": handlePaymentSuccess,
|
||||
created: handlePaymentSuccess,
|
||||
};
|
||||
|
||||
const MercadoPagoPayloadSchema = z.object({
|
||||
action: z.string(),
|
||||
api_version: z.string(),
|
||||
application_id: z.string(),
|
||||
date_created: z.string(),
|
||||
id: z.string(),
|
||||
live_mode: z.enum(["false", "true"]),
|
||||
type: z.literal("test"),
|
||||
user_id: z.string(),
|
||||
data: z.object({
|
||||
id: z.string(),
|
||||
}),
|
||||
});
|
||||
|
||||
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
|
||||
try {
|
||||
if (req.method !== "POST") {
|
||||
throw new HttpCode({ statusCode: 405, message: "Method Not Allowed" });
|
||||
}
|
||||
const { body } = req;
|
||||
const parse = MercadoPagoPayloadSchema.safeParse(body);
|
||||
if (!parse.success) {
|
||||
throw new HttpCode({ statusCode: 400, message: "Bad Request" });
|
||||
}
|
||||
const { data: parsedPayload } = parse;
|
||||
const handler = webhookHandlers[parsedPayload.action];
|
||||
if (handler) {
|
||||
await handler(parsedPayload);
|
||||
} else {
|
||||
/** Not really an error, just letting Stripe know that the webhook was received but unhandled */
|
||||
throw new HttpCode({
|
||||
statusCode: 202,
|
||||
message: `Unhandled Stripe Webhook event type ${event.type}`,
|
||||
});
|
||||
}
|
||||
} catch (_err) {
|
||||
const err = getErrorFromUnknown(_err);
|
||||
console.error(`Webhook Error: ${err.message}`);
|
||||
res.status(err.statusCode ?? 500).send({
|
||||
message: err.message,
|
||||
stack: IS_PRODUCTION ? undefined : err.stack,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Return a response to acknowledge receipt of the event
|
||||
res.json({ received: true });
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import Link from "next/link";
|
||||
|
||||
import type { IMercadoPagoPaymentComponentProps } from "@calcom/app-store/mercado_pago/types";
|
||||
import { IS_PRODUCTION } from "@calcom/lib/constants";
|
||||
|
||||
export const MercadoPagoPaymentComponent = (props: IMercadoPagoPaymentComponentProps) => {
|
||||
const { payment, eventType, user, location, bookingId, bookingUid } = props;
|
||||
const paymentInitLink = IS_PRODUCTION ? payment.data.init_point : payment.data.sandbox_init_point;
|
||||
return (
|
||||
<div className="flex h-full w-full flex-col items-center justify-center">
|
||||
MercadoPago
|
||||
<Link href={paymentInitLink}>Pay</Link>
|
||||
</div>
|
||||
);
|
||||
};
|
|
@ -1,24 +1,22 @@
|
|||
import type { Booking, Payment, Prisma } from "@prisma/client";
|
||||
import { PaymentType } from "@prisma/client";
|
||||
import type { Booking, Payment, PaymentOption, Prisma } from "@prisma/client";
|
||||
import * as MercadoPago from "mercadopago";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import z from "zod";
|
||||
|
||||
import { AbstractPaymentService } from "@calcom/lib/PaymentService";
|
||||
import type { IAbstractPaymentService } from "@calcom/lib/PaymentService";
|
||||
import prisma from "@calcom/prisma";
|
||||
import type { CalendarEvent } from "@calcom/types/Calendar";
|
||||
|
||||
const mercadoPagoCredentialKeysSchema = z.object({
|
||||
access_token: z.string(),
|
||||
public_key: z.string(),
|
||||
});
|
||||
|
||||
export class PaymentService extends AbstractPaymentService {
|
||||
export class PaymentService implements IAbstractPaymentService {
|
||||
private mercadoPago: typeof MercadoPago;
|
||||
private credentials: z.infer<typeof mercadoPagoCredentialKeysSchema>;
|
||||
|
||||
constructor(credentials: { key: Prisma.JsonValue }) {
|
||||
super();
|
||||
|
||||
this.credentials = mercadoPagoCredentialKeysSchema.parse(credentials.key);
|
||||
|
||||
this.mercadoPago = MercadoPago;
|
||||
|
@ -66,7 +64,11 @@ export class PaymentService extends AbstractPaymentService {
|
|||
const paymentData = await prisma?.payment.create({
|
||||
data: {
|
||||
uid: uuidv4(),
|
||||
type: PaymentType.MERCADO_PAGO,
|
||||
app: {
|
||||
connect: {
|
||||
slug: "mercado_pago",
|
||||
},
|
||||
},
|
||||
booking: {
|
||||
connect: {
|
||||
id: bookingId,
|
||||
|
@ -99,10 +101,40 @@ export class PaymentService extends AbstractPaymentService {
|
|||
async refund(): Promise<Payment> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getPaymentPaidStatus(): string {
|
||||
|
||||
collectCard(
|
||||
payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
|
||||
bookingId: number,
|
||||
bookerEmail: string,
|
||||
paymentOption: PaymentOption
|
||||
): Promise<Payment> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getPaymentDetails(): Payment {
|
||||
chargeCard(
|
||||
payment: Pick<Prisma.PaymentUncheckedCreateInput, "amount" | "currency">,
|
||||
bookingId: number
|
||||
): Promise<Payment> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getPaymentPaidStatus(): Promise<string> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
getPaymentDetails(): Promise<Payment> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
afterPayment(
|
||||
event: CalendarEvent,
|
||||
booking: {
|
||||
user: { email: string | null; name: string | null; timeZone: string } | null;
|
||||
id: number;
|
||||
startTime: { toISOString: () => string };
|
||||
uid: string;
|
||||
},
|
||||
paymentData: Payment
|
||||
): Promise<void> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
deletePayment(paymentId: number): Promise<boolean> {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
export interface IMercadoPagoPaymentComponentProps {
|
||||
payment: {
|
||||
amount: number;
|
||||
appId: string;
|
||||
bookingId: number;
|
||||
currency: string;
|
||||
data: MercadoPagoPaymentResponse;
|
||||
paymentOption: string;
|
||||
refunded: boolean;
|
||||
success: boolean;
|
||||
uid: string;
|
||||
};
|
||||
eventType: EventType;
|
||||
user: User;
|
||||
location?: string | null;
|
||||
bookingId: number;
|
||||
bookingUid: string;
|
||||
}
|
||||
|
||||
interface MercadoPagoPaymentResponse {
|
||||
additional_info: string;
|
||||
auto_return: string;
|
||||
back_urls: {
|
||||
failure: string;
|
||||
pending: string;
|
||||
success: string;
|
||||
};
|
||||
binary_mode: boolean;
|
||||
client_id: string;
|
||||
collector_id: number;
|
||||
coupon_code: null;
|
||||
coupon_labels: null;
|
||||
date_created: string;
|
||||
date_of_expiration: null;
|
||||
expiration_date_from: null;
|
||||
expiration_date_to: null;
|
||||
expires: boolean;
|
||||
external_reference: string;
|
||||
id: string;
|
||||
init_point: string;
|
||||
internal_metadata: null;
|
||||
items: object[];
|
||||
last_updated: null;
|
||||
marketplace: string;
|
||||
marketplace_fee: number;
|
||||
metadata: object;
|
||||
notification_url: null;
|
||||
operation_type: string;
|
||||
payer: {
|
||||
name: string;
|
||||
email: string;
|
||||
phone: object;
|
||||
address: object;
|
||||
surname: string;
|
||||
};
|
||||
payment_methods: {
|
||||
installments: null;
|
||||
default_card_id: null;
|
||||
default_installments: null;
|
||||
excluded_payment_types: string[];
|
||||
excluded_payment_methods: string[];
|
||||
};
|
||||
processing_modes: null;
|
||||
product_id: null;
|
||||
redirect_urls: {
|
||||
failure: string;
|
||||
pending: string;
|
||||
success: string;
|
||||
};
|
||||
sandbox_init_point: string;
|
||||
shipments: {
|
||||
receiver_address: object;
|
||||
default_shipping_method: null;
|
||||
};
|
||||
site_id: string;
|
||||
stripeAccount: string;
|
||||
stripe_publishable_key: string;
|
||||
total_amount: null;
|
||||
}
|
|
@ -80,7 +80,7 @@ export default function MercadoPagoSetup(props: IMercadoPagoSetupProps) {
|
|||
<div className="m-auto max-w-[43em] overflow-auto rounded bg-white pb-10 md:p-10">
|
||||
<div className="md:flex md:flex-row">
|
||||
<div className="invisible md:visible">
|
||||
<img className="h-11" src="/api/app-store/mercado_pago/icon.svg" alt="Zapier Logo" />
|
||||
<img className="h-11" src="/api/app-store/mercado_pago/icon.svg" alt="Mercado Pago Logo" />
|
||||
</div>
|
||||
<div className="ml-2 ltr:mr-2 rtl:ml-2 md:ml-5">
|
||||
<p className="text-lg">Mercado Pago</p>
|
||||
|
@ -94,7 +94,7 @@ export default function MercadoPagoSetup(props: IMercadoPagoSetupProps) {
|
|||
type="text"
|
||||
name="public_key"
|
||||
id="public_key"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 text-black shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
value={newPublicKey}
|
||||
autoComplete="new-password"
|
||||
onChange={(e) => setNewPublicKey(e.target.value)}
|
||||
|
@ -110,7 +110,7 @@ export default function MercadoPagoSetup(props: IMercadoPagoSetupProps) {
|
|||
type="password"
|
||||
name="access_token"
|
||||
id="access_token"
|
||||
className="block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
className="block w-full rounded-md border-gray-300 text-black shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm"
|
||||
value={newAccessToken}
|
||||
autoComplete="new-password"
|
||||
onChange={(e) => setNewAccessToken(e.target.value)}
|
||||
|
@ -124,6 +124,7 @@ export default function MercadoPagoSetup(props: IMercadoPagoSetupProps) {
|
|||
<Select
|
||||
options={currencyOptions}
|
||||
value={selectedCurrency}
|
||||
className="text-black"
|
||||
defaultValue={selectedCurrency?.value}
|
||||
onChange={(e) => {
|
||||
if (e) {
|
||||
|
|
|
@ -6,6 +6,7 @@ import { useEffect, useState } from "react";
|
|||
import { FormattedNumber, IntlProvider } from "react-intl";
|
||||
|
||||
import { getSuccessPageLocationMessage } from "@calcom/app-store/locations";
|
||||
import { MercadoPagoPaymentComponent } from "@calcom/app-store/mercado_pago/components/MercadoPagoPaymentComponent";
|
||||
import getStripe from "@calcom/app-store/stripepayment/lib/client";
|
||||
import type { StripePaymentData } from "@calcom/app-store/stripepayment/lib/server";
|
||||
import dayjs from "@calcom/dayjs";
|
||||
|
@ -138,6 +139,16 @@ const PaymentPage: FC<PaymentPageProps> = (props) => {
|
|||
/>
|
||||
</Elements>
|
||||
)}
|
||||
{props.payment.appId === "mercado_pago" && !props.payment.success && (
|
||||
<MercadoPagoPaymentComponent
|
||||
payment={props.payment}
|
||||
eventType={props.eventType}
|
||||
user={props.user}
|
||||
location={props.booking.location}
|
||||
bookingId={props.booking.id}
|
||||
bookingUid={props.booking.uid}
|
||||
/>
|
||||
)}
|
||||
{props.payment.refunded && (
|
||||
<div className="text-default mt-4 text-center dark:text-gray-300">{t("refunded")}</div>
|
||||
)}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { AppCategories, Prisma } from "@prisma/client";
|
||||
import type { AppCategories, Prisma, PaymentOption } from "@prisma/client";
|
||||
|
||||
import appStore from "@calcom/app-store";
|
||||
import type { EventTypeAppsList } from "@calcom/app-store/utils";
|
||||
|
@ -25,6 +25,7 @@ const handlePayment = async (
|
|||
bookerEmail: string
|
||||
) => {
|
||||
const paymentApp = await appStore[paymentAppCredentials?.app?.dirName as keyof typeof appStore];
|
||||
|
||||
if (!(paymentApp && "lib" in paymentApp && "PaymentService" in paymentApp.lib)) {
|
||||
console.warn(`payment App service of type ${paymentApp} is not implemented`);
|
||||
return null;
|
||||
|
@ -32,7 +33,7 @@ const handlePayment = async (
|
|||
const PaymentService = paymentApp.lib.PaymentService;
|
||||
const paymentInstance = new PaymentService(paymentAppCredentials);
|
||||
|
||||
const paymentOption =
|
||||
const paymentOption: PaymentOption =
|
||||
selectedEventType?.metadata?.apps?.[paymentAppCredentials.appId].paymentOption || "ON_BOOKING";
|
||||
|
||||
let paymentData;
|
||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -3956,6 +3956,7 @@ __metadata:
|
|||
"@calcom/types": "*"
|
||||
"@calcom/ui": "*"
|
||||
"@calcom/zoomvideo": "*"
|
||||
"@types/mercadopago": ^1.5.8
|
||||
lodash: ^4.17.21
|
||||
qs-stringify: ^1.2.1
|
||||
languageName: unknown
|
||||
|
@ -4465,6 +4466,15 @@ __metadata:
|
|||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/mercado_pago@workspace:packages/app-store/mercado_pago":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/mercado_pago@workspace:packages/app-store/mercado_pago"
|
||||
dependencies:
|
||||
"@calcom/lib": "*"
|
||||
"@calcom/types": "*"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
||||
"@calcom/n8n@workspace:packages/app-store/n8n":
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@calcom/n8n@workspace:packages/app-store/n8n"
|
||||
|
@ -4939,6 +4949,7 @@ __metadata:
|
|||
markdown-it: ^13.0.1
|
||||
md5: ^2.3.0
|
||||
memory-cache: ^0.2.0
|
||||
mercadopago: ^1.5.14
|
||||
micro: ^10.0.1
|
||||
mime-types: ^2.1.35
|
||||
mockdate: ^3.0.5
|
||||
|
@ -12788,6 +12799,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mercadopago@npm:^1.5.8":
|
||||
version: 1.5.8
|
||||
resolution: "@types/mercadopago@npm:1.5.8"
|
||||
checksum: 0ad1e1bd98bbfe84ecf31e535aff2eb3551c7ef61d494de0b7b933182ad11d1d4300e3df12f7b179baac0c4cb0d44479f9e4467c5a168e7fd6b5f7b0575597a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/micro@npm:7.3.7":
|
||||
version: 7.3.7
|
||||
resolution: "@types/micro@npm:7.3.7"
|
||||
|
|
Loading…
Reference in New Issue
Block a user