Only handle refunds when there are payments, otherwise skip (#6974)

This commit is contained in:
Alex van Andel
2023-02-09 15:43:28 +00:00
committed by GitHub
parent 156f3e5de2
commit 5353610d9a
2 changed files with 75 additions and 71 deletions
+15 -17
View File
@@ -17,13 +17,12 @@ import {
DialogClose,
DialogContent,
DialogFooter,
DialogHeader,
MeetingTimeInTimezones,
showToast,
TextArea,
Tooltip,
ActionType,
TableActions,
TextAreaField,
} from "@calcom/ui";
import { FiCheck, FiClock, FiMapPin, FiRefreshCcw, FiSend, FiSlash, FiX } from "@calcom/ui/components/icon";
@@ -245,24 +244,23 @@ function BookingListItem(booking: BookingItemProps) {
)}
{/* NOTE: Should refactor this dialog component as is being rendered multiple times */}
<Dialog open={rejectionDialogIsOpen} onOpenChange={setRejectionDialogIsOpen}>
<DialogContent>
<DialogHeader title={t("rejection_reason_title")} />
<p className="-mt-4 text-sm text-gray-500">{t("rejection_reason_description")}</p>
<p className="mt-6 mb-2 text-sm font-bold text-black">
{t("rejection_reason")}
<span className="font-normal text-gray-500"> (Optional)</span>
</p>
<TextArea
name={t("rejection_reason")}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
className="mb-5 sm:mb-6"
/>
<DialogContent title={t("rejection_reason_title")} description={t("rejection_reason_description")}>
<div>
<TextAreaField
name="rejectionReason"
label={
<>
{t("rejection_reason")}
<span className="font-normal text-gray-500"> (Optional)</span>
</>
}
value={rejectionReason}
onChange={(e) => setRejectionReason(e.target.value)}
/>
</div>
<DialogFooter>
<DialogClose />
<Button
disabled={mutation.isLoading}
onClick={() => {
@@ -774,6 +774,8 @@ export const bookingsRouter = router({
/** When a booking that requires payment its being confirmed but doesn't have any payment,
* we shouldn’t save it on DestinationCalendars
*
* FIXME: This can cause unintended confirmations on rejection.
*/
if (booking.payment.length > 0 && !booking.paid) {
await prisma.booking.update({
@@ -1077,69 +1079,73 @@ export const bookingsRouter = router({
},
});
} else {
const successPayment = booking.payment.find((payment) => payment.success);
if (!successPayment) {
throw new Error("Cannot reject a booking without a successful payment");
}
// handle refunds
if (!!booking.payment.length) {
const successPayment = booking.payment.find((payment) => payment.success);
if (!successPayment) {
throw new Error("Cannot reject a booking without a successful payment");
}
let eventTypeOwnerId;
if (booking.eventType?.owner) {
eventTypeOwnerId = booking.eventType.owner.id;
} else if (booking.eventType?.teamId) {
const teamOwner = await prisma.membership.findFirst({
let eventTypeOwnerId;
if (booking.eventType?.owner) {
eventTypeOwnerId = booking.eventType.owner.id;
} else if (booking.eventType?.teamId) {
const teamOwner = await prisma.membership.findFirst({
where: {
teamId: booking.eventType.teamId,
role: MembershipRole.OWNER,
},
select: {
userId: true,
},
});
eventTypeOwnerId = teamOwner?.userId;
}
if (!eventTypeOwnerId) {
throw new Error("Event Type owner not found for obtaining payment app credentials");
}
const paymentAppCredentials = await prisma.credential.findMany({
where: {
teamId: booking.eventType.teamId,
role: MembershipRole.OWNER,
userId: eventTypeOwnerId,
appId: successPayment.appId,
},
select: {
userId: true,
},
});
eventTypeOwnerId = teamOwner?.userId;
}
if (!eventTypeOwnerId) {
throw new Error("Event Type owner not found for obtaining payment app credentials");
}
const paymentAppCredentials = await prisma.credential.findMany({
where: {
userId: eventTypeOwnerId,
appId: successPayment.appId,
},
select: {
key: true,
appId: true,
app: {
select: {
categories: true,
dirName: true,
key: true,
appId: true,
app: {
select: {
categories: true,
dirName: true,
},
},
},
},
});
});
const paymentAppCredential = paymentAppCredentials.find((credential) => {
return credential.appId === successPayment.appId;
});
const paymentAppCredential = paymentAppCredentials.find((credential) => {
return credential.appId === successPayment.appId;
});
if (!paymentAppCredential) {
throw new Error("Payment app credentials not found");
}
// Posible to refactor TODO:
const paymentApp = appStore[paymentAppCredential?.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;
}
const PaymentService = paymentApp.lib.PaymentService;
const paymentInstance = new PaymentService(paymentAppCredential);
const paymentData = await paymentInstance.refund(successPayment.id);
if (!paymentData.refunded) {
throw new Error("Payment could not be refunded");
if (!paymentAppCredential) {
throw new Error("Payment app credentials not found");
}
// Posible to refactor TODO:
const paymentApp = appStore[paymentAppCredential?.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;
}
const PaymentService = paymentApp.lib.PaymentService;
const paymentInstance = new PaymentService(paymentAppCredential);
const paymentData = await paymentInstance.refund(successPayment.id);
if (!paymentData.refunded) {
throw new Error("Payment could not be refunded");
}
}
// end handle refunds.
await prisma.booking.update({
where: {