Only handle refunds when there are payments, otherwise skip (#6974)
This commit is contained in:
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user