Skip to content
1 change: 1 addition & 0 deletions apps/api/v1/lib/validations/payment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { PaymentSchema } from "@calcom/prisma/zod/modelSchema/PaymentSchema";

export const schemaPaymentPublic = PaymentSchema.pick({
id: true,
uid: true,
amount: true,
success: true,
refunded: true,
Expand Down
85 changes: 68 additions & 17 deletions apps/api/v1/pages/api/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,73 @@ const swaggerHandler = withSwagger({
$ref: "#/components/schemas/Recording",
},
},
Payment: {
type: "object",
properties: {
id: {
type: "number",
example: 1,
description: "Payment ID",
},
uid: {
type: "string",
example: "payment_abc123",
description: "Payment UID used for abandoned-cart recovery",
},
amount: {
type: "number",
example: 5000,
description: "Payment amount in cents",
},
success: {
type: "boolean",
example: true,
description: "Whether the payment was successful",
},
refunded: {
type: "boolean",
example: false,
description: "Whether the payment was refunded",
},
fee: {
type: "number",
example: 150,
description: "Payment processing fee in cents",
},
paymentOption: {
type: "string",
example: "ON_BOOKING",
description: "Payment option type",
},
currency: {
type: "string",
example: "USD",
description: "Payment currency",
},
bookingId: {
type: "number",
example: 123,
description: "Associated booking ID",
},
},
required: [
"id",
"uid",
"amount",
"success",
"refunded",
"fee",
"paymentOption",
"currency",
"bookingId",
],
},
ArrayOfPayments: {
type: "array",
items: {
$ref: "#/components/schemas/Payment",
},
},
Recording: {
properties: {
id: {
Expand Down Expand Up @@ -135,23 +202,7 @@ const swaggerHandler = withSwagger({
},
},
payment: {
type: Array,
items: {
properties: {
id: {
type: "number",
example: 1,
},
success: {
type: "boolean",
example: true,
},
paymentOption: {
type: "string",
example: "ON_BOOKING",
},
},
},
$ref: "#/components/schemas/ArrayOfPayments",
},
},
},
Expand Down
43 changes: 24 additions & 19 deletions apps/api/v1/pages/api/payments/[id].ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,15 @@ import {
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* payment:
* $ref: "#/components/schemas/Payment"
* 401:
* description: Authorization information is missing or invalid.
* description: Authorization information is missing or invalid.
* 404:
* description: Payment was not found
*/
Expand All @@ -46,25 +53,23 @@ export async function paymentById(
if (safeQuery.success && method === "GET") {
const userWithBookings = await prisma.user.findUnique({
where: { id: userId },
// eslint-disable-next-line @calcom/eslint/no-prisma-include-true
include: { bookings: true },
select: { bookings: true },
});
await prisma.payment
.findUnique({ where: { id: safeQuery.data.id } })
.then((data) => schemaPaymentPublic.parse(data))
.then((payment) => {
if (!userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) {
res.status(401).json({ message: "Unauthorized" });
} else {
res.status(200).json({ payment });
}
})
.catch((error: Error) =>
res.status(404).json({
message: `Payment with id: ${safeQuery.data.id} not found`,
error,
})
);
const data = await prisma.payment.findUnique({ where: { id: safeQuery.data.id } });

if (!data) {
return res.status(404).json({
message: `Payment with id: ${safeQuery.data.id} not found`,
});
}

const payment = schemaPaymentPublic.parse(data);

if (!userWithBookings || !userWithBookings?.bookings.map((b) => b.id).includes(payment.bookingId)) {
return res.status(401).json({ message: "Unauthorized" });
}

res.status(200).json({ payment });
}
}
export default withMiddleware("HTTP_GET")(withValidQueryIdTransformParseInt(paymentById));
33 changes: 22 additions & 11 deletions apps/api/v1/pages/api/payments/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,32 +13,43 @@ import { schemaPaymentPublic } from "~/lib/validations/payment";
* summary: Find all payments
* tags:
* - payments
* parameters:
* - in: query
* name: apiKey
* required: true
* schema:
* type: string
* description: Your API key
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* type: object
* properties:
* payments:
* $ref: "#/components/schemas/ArrayOfPayments"
* 401:
* description: Authorization information is missing or invalid.
* description: Authorization information is missing or invalid.
* 404:
* description: No payments were found
* description: User not found
*
*/
async function allPayments({ userId }: NextApiRequest, res: NextApiResponse<PaymentsResponse>) {
const userWithBookings = await prisma.user.findUnique({
where: { id: userId },
include: { bookings: true },
select: { bookings: true },
});
if (!userWithBookings) throw new Error("No user found");
if (!userWithBookings) {
return res.status(404).json({ message: "User not found" });
}
const bookings = userWithBookings.bookings;
const bookingIds = bookings.map((booking) => booking.id);
const data = await prisma.payment.findMany({ where: { bookingId: { in: bookingIds } } });
const payments = data.map((payment) => schemaPaymentPublic.parse(payment));

if (payments) res.status(200).json({ payments });
else
(error: Error) =>
res.status(404).json({
message: "No Payments were found",
error,
});
res.status(200).json({ payments });
}
// NO POST FOR PAYMENTS FOR NOW
export default withMiddleware("HTTP_GET")(allPayments);
Loading
Loading