2021-12-09 15:51:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  PaymentType ,  Prisma  }  from  "@prisma/client" ;  
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								import  Stripe  from  "stripe" ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  {  v4  as  uuidv4  }  from  "uuid" ;  
						 
					
						
							
								
									
										
										
										
											2021-09-22 19:52:38 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2022-03-16 23:36:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  getErrorFromUnknown  }  from  "@calcom/lib/errors" ;  
						 
					
						
							
								
									
										
										
										
											2022-03-03 19:29:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  prisma  from  "@calcom/prisma" ;  
						 
					
						
							
								
									
										
										
										
											2022-03-09 22:56:05 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  createPaymentLink  }  from  "@calcom/stripe/client" ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								import  stripe ,  {  PaymentData  }  from  "@calcom/stripe/server" ;  
						 
					
						
							
								
									
										
										
										
											2022-03-23 22:00:30 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  CalendarEvent  }  from  "@calcom/types/Calendar" ;  
						 
					
						
							
								
									
										
										
										
											2022-03-03 19:29:19 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-26 11:03:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								import  {  sendAwaitingPaymentEmail ,  sendOrganizerPaymentRefundFailedEmail  }  from  "@lib/emails/email-manager" ;  
						 
					
						
							
								
									
										
										
										
											2021-09-22 19:52:38 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-26 11:03:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								export  type  PaymentInfo  =  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  link? : string  |  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  reason? : string  |  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  id? : string  |  null ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								const  paymentFeePercentage  =  process . env . PAYMENT_FEE_PERCENTAGE ! ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								const  paymentFeeFixed  =  process . env . PAYMENT_FEE_FIXED ! ;  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								export  async  function  handlePayment (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  evt : CalendarEvent , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  selectedEventType :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    price : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    currency : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } , 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-09 15:51:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  stripeCredential :  {  key : Prisma.JsonValue  } , 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  booking :  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-05 22:46:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    user :  {  email : string  |  null ;  name : string  |  null ;  timeZone : string  }  |  null ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    id : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    startTime :  {  toISOString :  ( )  = >  string  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    uid : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  paymentFee  =  Math . round ( 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-05 22:46:48 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    selectedEventType . price  *  parseFloat ( ` ${ paymentFeePercentage } ` )  +  parseInt ( ` ${ paymentFeeFixed } ` ) 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								  ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  {  stripe_user_id ,  stripe_publishable_key  }  =  stripeCredential . key  as  Stripe . OAuthToken ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  params : Stripe.PaymentIntentCreateParams  =  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    amount : selectedEventType.price , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    currency : selectedEventType.currency , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    payment_method_types :  [ "card" ] , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    application_fee_amount : paymentFee , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  paymentIntent  =  await  stripe . paymentIntents . create ( params ,  {  stripeAccount : stripe_user_id  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  payment  =  await  prisma . payment . create ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    data :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      type :  PaymentType . STRIPE , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      uid : uuidv4 ( ) , 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-17 16:58:23 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      booking :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        connect :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								          id : booking.id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } , 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      amount : selectedEventType.price , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      fee : paymentFee , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      currency : selectedEventType.currency , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      success : false , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      refunded : false , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      data : Object.assign ( { } ,  paymentIntent ,  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        stripe_publishable_key , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        stripeAccount : stripe_user_id , 
							 
						 
					
						
							
								
									
										
										
										
											2022-01-06 17:28:31 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      } )  /* We should treat this */  as  PaymentData  /* but Prisma doesn't know how to handle it, so it we treat it */  as  unknown  /* and then */  as  Prisma . InputJsonValue , 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      externalId : paymentIntent.id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-11-26 11:03:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  await  sendAwaitingPaymentEmail ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    . . . evt , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    paymentInfo :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      link : createPaymentLink ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        paymentUid : payment.uid , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        name : booking.user?.name , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        date : booking.startTime.toISOString ( ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } ) , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  return  payment ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								export  async  function  refund (  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  booking :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    id : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    uid : string ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    startTime : Date ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    payment :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      id : number ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      success : boolean ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      refunded : boolean ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      externalId : string ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-12-09 15:51:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      data : Prisma.JsonValue ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      type :  PaymentType ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } [ ] ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  calEvent : CalendarEvent 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								)  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  try  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  payment  =  booking . payment . find ( ( e )  = >  e . success  &&  ! e . refunded ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! payment )  return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-12-09 15:51:37 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    if  ( payment . type  !==  PaymentType . STRIPE )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      await  handleRefundError ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        event : calEvent , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        reason :  "cannot refund non Stripe payment" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        paymentId :  "unknown" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    const  refund  =  await  stripe . refunds . create ( 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        payment_intent : payment.externalId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      {  stripeAccount :  ( payment . data  as  unknown  as  PaymentData ) [ "stripeAccount" ]  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( ! refund  ||  refund . status  ===  "failed" )  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      await  handleRefundError ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        event : calEvent , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        reason : refund?.failure_reason  ||  "unknown" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        paymentId : payment.externalId , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      return ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    await  prisma . payment . update ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      where :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        id : payment.id , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      data :  { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        refunded : true , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  catch  ( e )  { 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-28 22:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								    const  err  =  getErrorFromUnknown ( e ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    console . error ( err ,  "Refund failed" ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								    await  handleRefundError ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      event : calEvent , 
							 
						 
					
						
							
								
									
										
										
										
											2021-10-28 22:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								      reason : err.message  ||  "unknown" , 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								      paymentId :  "unknown" , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } ) ; 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
									
										
										
										
											2021-10-28 22:58:26 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								async  function  handleRefundError ( opts :  {  event : CalendarEvent ;  reason : string ;  paymentId : string  } )  {  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  console . error ( ` refund failed:  ${ opts . reason }  for booking ' ${ opts . event . uid } ' ` ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-11-26 11:03:43 +00:00 
										
									 
								 
							 
							
								
									
										 
								
							 
							
								 
							
							
								  await  sendOrganizerPaymentRefundFailedEmail ( { 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    . . . opts . event , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    paymentInfo :  {  reason : opts.reason ,  id : opts.paymentId  } , 
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } ) ; 
							 
						 
					
						
							
								
									
										
										
										
											2021-09-22 18:36:13 +00:00 
										
									 
								 
							 
							
								
							 
							
								 
							
							
								}