/// <summary> /// Request an immediate transaction for the booking cancellation fee, if any /// (cancellation must be previously calculated on the booking, with amounts at pricing totalPrice and serviceFeeAmount, as usual). /// It manages when there is no price to charge, and just skip the step without error. /// The removal of a temporary card is performed after all (doesn't matter if a transaction was needed or not). /// The transaction is "immediate" because is asked to be submitted and released now (the flow /// for a normal booking payment is to authorize, later settle, later release, but on this case /// we require to Braintree to do all that steps at the moment). /// /// REVIEWED #771 /// </summary> /// <param name="booking"></param> /// <returns>It returns the transactionID generated, original booking object is not updated. /// Errors in the process are throwed.</returns> public static string BookingCancellationPaymentFromCard(LcRest.Booking booking) { string cancellationTransactionID = null; var gateway = NewBraintreeGateway(); if (booking.pricingSummary.totalPrice.HasValue && booking.pricingSummary.totalPrice > 0) { if (String.IsNullOrEmpty(booking.paymentMethodID)) { throw new ConstraintException("Cannot charge booking cancellation fee because there is no payment method."); } TransactionRequest request = new TransactionRequest { Amount = booking.pricingSummary.totalPrice.Value, // Marketplace #408: since provider receive the money directly, Braintree must discount // the next amount in concept of fees and pay that to the Marketplace Owner (us, Loconomics) ServiceFeeAmount = booking.pricingSummary.serviceFeeAmount, CustomerId = GetCustomerId(booking.clientUserID), PaymentMethodToken = booking.paymentMethodID, // Now, with Marketplace #408, the receiver of the money for each transaction is // the provider through account at Braintree, and not the Loconomics account: //MerchantAccountId = LcPayment.BraintreeMerchantAccountId, MerchantAccountId = GetProviderPaymentAccountId(booking.serviceProfessionalUserID), // We explicitely ask for an immediate transaction (it's the default, but let's being explicit): Options = new TransactionOptionsRequest { // Marketplace #408: we normally hold it, but this is a cancellation so don't hold, pay at the moment HoldInEscrow = false, // Submit now for charge SubmitForSettlement = true } }; var r = gateway.Transaction.Sale(request); if (!r.IsSuccess()) { throw new Exception(r.Message); } // Get the transactionID else if (r.Target != null && !String.IsNullOrEmpty(r.Target.Id)) { cancellationTransactionID = r.Target.Id; } } // Remove temporary card: It's a complementary task, so we avoid exceptions (if possible) to interrupt the process try { // If the card is a TEMPorarly card (just to perform this transaction) // it must be removed now since was successful used if (booking.paymentMethodID.StartsWith(TempSavedCardPrefix)) { gateway.CreditCard.Delete(booking.paymentMethodID); } } catch { } return(cancellationTransactionID); }
/// <summary> /// Performs a transaction to authorize the payment on the client payment method, but /// not charging still, using the data from the given booking and the saved paymentMethodID. /// Booking is NOT checked before perform the task, use the LcRest.Booking API to securely run pre-condition /// checks before authorize transaction. The booking must have the data loaded for the pricingSummary. /// /// REVIEWED #771 /// </summary> /// <param name="booking"></param> /// <param name="paymentMethodID">AKA creditCardToken</param> /// <returns>It returns the transactionID generated, original booking object is not updated. /// Errors in the process are throwed.</returns> public static string AuthorizeBookingTransaction(LcRest.Booking booking) { if (booking.pricingSummary == null || !booking.pricingSummary.totalPrice.HasValue || booking.pricingSummary.totalPrice.Value <= 0) { throw new ConstraintException("To authorize a booking payment is required a price to charge."); } var gateway = NewBraintreeGateway(); TransactionRequest request = new TransactionRequest { Amount = booking.pricingSummary.totalPrice.Value, // Marketplace #408: since provider receive the money directly, Braintree must discount // the next amount in concept of fees and pay that to the Marketplace Owner (us, Loconomics ;-) ServiceFeeAmount = booking.pricingSummary.serviceFeeAmount, CustomerId = GetCustomerId(booking.clientUserID), PaymentMethodToken = booking.paymentMethodID, // Now, with Marketplace #408, the receiver of the money for each transaction is // the provider through account at Braintree, and not the Loconomics account: //MerchantAccountId = LcPayment.BraintreeMerchantAccountId, MerchantAccountId = GetProviderPaymentAccountId(booking.serviceProfessionalUserID), Options = new TransactionOptionsRequest { // Marketplace #408: don't pay provider still, wait for the final confirmation 'release scrow' HoldInEscrow = true, // Do not submit, just authorize: SubmitForSettlement = false } }; var r = gateway.Transaction.Sale(request); // Everything goes fine if (r.IsSuccess()) { // Get the transactionID if (r.Target != null && !String.IsNullOrEmpty(r.Target.Id)) { // If the card is a TEMPorarly card (just to perform this transaction) // it must be removed now since was successful used // IMPORTANT: Since an error on this subtask is not important to the // user and will break a success process creating a new problem if throwed (because transactionID // gets lost), // is catched and managed internally by Loconomics stuff that can check and fix transparentely // this minor error. try { if (booking.paymentMethodID.StartsWith(TempSavedCardPrefix)) { gateway.CreditCard.Delete(booking.paymentMethodID); } } catch (Exception ex) { try { LcMessaging.NotifyError(String.Format("LcPayment.AuthorizeBookingTransaction..DeleteBraintreeTempCard({0});bookingID={1}", booking.paymentMethodID, booking.bookingID), "", ex.Message); LcLogger.LogAspnetError(ex); } catch { } } // r.Target.Id => transactionID return(r.Target.Id); } else { // Transaction worked but impossible to know the transactionID (weird, is even possible?), // notify error throw new Exception("Impossible to know transaction details, please contact support. BookingID #" + booking.bookingID.ToString()); } } else { throw new Exception(r.Message); } }