/// <summary> /// Edit an existing recurring gift. This will cancel (end-date) an existing RecurringGift and then create a new one /// if the Program, Amount, Frequency, Day of Week, or Day of Month are changed. This will simply edit the existing gift /// if only the payment method (credit card, bank account) is changed. /// </summary> /// <param name="authorizedUserToken">An OAuth token for the user who is logged in to cr.net/MP</param> /// <param name="editGift">The edited values for the Recurring Gift</param> /// <param name="donor>The donor performing the edits</param> /// <returns>A RecurringGiftDto, populated with any new/updated values after any edits</returns> public RecurringGiftDto EditRecurringGift(string authorizedUserToken, RecurringGiftDto editGift, MpContactDonor donor) { var existingGift = _mpDonorService.GetRecurringGiftById(authorizedUserToken, editGift.RecurringGiftId); // Assuming payment info is changed if a token is given. var changedPayment = !string.IsNullOrWhiteSpace(editGift.StripeTokenId); var changedAmount = (int)(editGift.PlanAmount * Constants.StripeDecimalConversionValue) != existingGift.Amount; var changedProgram = !editGift.Program.Equals(existingGift.ProgramId); var changedFrequency = !editGift.PlanInterval.Equals(existingGift.Frequency == RecurringGiftFrequencyWeekly ? PlanInterval.Weekly : PlanInterval.Monthly); var changedDayOfWeek = changedFrequency || (editGift.PlanInterval == PlanInterval.Weekly && (int)editGift.StartDate.DayOfWeek != existingGift.DayOfWeek); var changedDayOfMonth = changedFrequency || (editGift.PlanInterval == PlanInterval.Monthly && editGift.StartDate.Day != existingGift.DayOfMonth); var changedStartDate = editGift.StartDate.Date != existingGift.StartDate.GetValueOrDefault().Date; var needsUpdatedStripeSubscription = changedAmount && !(changedFrequency || changedDayOfWeek || changedDayOfMonth || changedStartDate); var needsNewStripePlan = changedAmount || changedFrequency || changedDayOfWeek || changedDayOfMonth || changedStartDate; var needsNewMpRecurringGift = changedAmount || changedProgram || needsNewStripePlan; var recurringGiftId = existingGift.RecurringGiftId.GetValueOrDefault(-1); int donorAccountId; if (changedPayment) { // If the payment method changed, we need to create a new Stripe Source. var source = _paymentService.UpdateCustomerSource(existingGift.StripeCustomerId, editGift.StripeTokenId); donorAccountId = _mpDonorService.CreateDonorAccount(source.brand, DonorRoutingNumberDefault, string.IsNullOrWhiteSpace(source.bank_last4) ? source.last4 : source.bank_last4, null, //Encrypted account existingGift.DonorId, source.id, existingGift.StripeCustomerId); // If we are not going to create a new Recurring Gift, then we'll update the existing // gift with the new donor account if (!needsNewMpRecurringGift) { _mpDonorService.UpdateRecurringGiftDonorAccount(authorizedUserToken, recurringGiftId, donorAccountId); } } else { // If the payment method is not changed, set the donorAccountId with the existing ID so we can use it later donorAccountId = existingGift.DonorAccountId.GetValueOrDefault(); } // Initialize a StripeSubscription, as we need the ID later on var stripeSubscription = new StripeSubscription { Id = existingGift.SubscriptionId }; if (needsNewMpRecurringGift) { if (needsNewStripePlan) { // Create the new Stripe Plan var plan = _paymentService.CreatePlan(editGift, donor); StripeSubscription oldSubscription; if (needsUpdatedStripeSubscription) { // If we just changed the amount, we just need to update the Subscription to point to the new plan oldSubscription = _paymentService.GetSubscription(existingGift.StripeCustomerId, stripeSubscription.Id); stripeSubscription = _paymentService.UpdateSubscriptionPlan(existingGift.StripeCustomerId, stripeSubscription.Id, plan.Id, oldSubscription.TrialEnd); } else { // Otherwise, we need to cancel the old Subscription and create a new one oldSubscription = _paymentService.CancelSubscription(existingGift.StripeCustomerId, stripeSubscription.Id); stripeSubscription = _paymentService.CreateSubscription(plan.Id, existingGift.StripeCustomerId, editGift.StartDate); } // In either case, we created a new Stripe Plan above, so cancel the old one _paymentService.CancelPlan(oldSubscription.Plan.Id); } // Cancel the old recurring gift, and create a new one _mpDonorService.CancelRecurringGift(authorizedUserToken, recurringGiftId); var contact = _mpContactService.GetContactById(donor.ContactId); var congregation = contact.Congregation_ID ?? 5; recurringGiftId = _mpDonorService.CreateRecurringGiftRecord(authorizedUserToken, donor.DonorId, donorAccountId, EnumMemberSerializationUtils.ToEnumString(editGift.PlanInterval), editGift.PlanAmount, editGift.StartDate, editGift.Program, stripeSubscription.Id, congregation); } // Get the new/updated recurring gift so we can return a DTO with all the new values var newGift = _mpDonorService.GetRecurringGiftById(authorizedUserToken, recurringGiftId); var newRecurringGift = new RecurringGiftDto { RecurringGiftId = newGift.RecurringGiftId.GetValueOrDefault(), StartDate = newGift.StartDate.GetValueOrDefault(), PlanAmount = newGift.Amount, PlanInterval = newGift.Frequency == RecurringGiftFrequencyWeekly ? PlanInterval.Weekly : PlanInterval.Monthly, Program = newGift.ProgramId, DonorID = newGift.DonorId, EmailAddress = donor.Email, SubscriptionID = stripeSubscription.Id, }; SendRecurringGiftConfirmationEmail(authorizedUserToken, _recurringGiftUpdateEmailTemplateId, newGift); return(newRecurringGift); }