public int?CreateDonationForInvoice(StripeInvoice invoice) { if (string.IsNullOrWhiteSpace(invoice.Charge) || invoice.Amount <= 0) { _logger.Info(string.Format("No charge or amount on invoice {0} for subscription {1} - this is likely a trial-period donation, skipping", invoice.Id, invoice.Subscription)); if (_logger.IsDebugEnabled) { _logger.Debug(string.Format("Invoice: {0}", JsonConvert.SerializeObject(invoice))); } return(null); } // Make sure we don't create duplicate donations for the same charge (could happen if we get a transfer and a invoice.payment_succeeded events near each other try { var donation = _mpDonationRepository.GetDonationByProcessorPaymentId(invoice.Charge); if (donation != null) { _logger.Info(string.Format("Donation already located for charge id {0}, not creating duplicate (existing donation {1})", invoice.Charge, donation.donationId)); return(donation.donationId); } } catch (DonationNotFoundException) { _logger.Info(string.Format("Donation not located for charge id {0}, this is expected", invoice.Charge)); } var charge = _paymentService.GetCharge(invoice.Charge); var createDonation = _mpDonorRepository.GetRecurringGiftForSubscription(invoice.Subscription, charge.ProcessorId); _mpDonorRepository.UpdateRecurringGiftFailureCount(createDonation.RecurringGiftId.Value, Constants.ResetFailCount); var donationStatus = charge.Status == "succeeded" ? DonationStatus.Succeeded : DonationStatus.Pending; var fee = charge.BalanceTransaction != null ? charge.BalanceTransaction.Fee : null; var amount = charge.Amount / Constants.StripeDecimalConversionValue; var donationAndDistribution = new MpDonationAndDistributionRecord { DonationAmt = amount, FeeAmt = fee, DonorId = createDonation.DonorId, ProgramId = createDonation.ProgramId, ChargeId = invoice.Charge, PymtType = createDonation.PaymentType, ProcessorId = invoice.Customer, SetupDate = invoice.Date, RegisteredDonor = true, RecurringGift = true, RecurringGiftId = createDonation.RecurringGiftId, DonorAcctId = createDonation.DonorAccountId.HasValue ? createDonation.DonorAccountId.ToString() : null, DonationStatus = (int)donationStatus }; return(_mpDonorRepository.CreateDonationAndDistributionRecord(donationAndDistribution, false)); }
public MpPaymentDetailReturn PostPayment(MpDonationAndDistributionRecord paymentRecord) { //check if invoice exists if (!_invoiceRepository.InvoiceExists(paymentRecord.InvoiceId)) { throw new InvoiceNotFoundException(paymentRecord.InvoiceId); } //check if contact exists if (_contactRepository.GetContactById(paymentRecord.ContactId) == null) { throw new ContactNotFoundException(paymentRecord.ContactId); } if (paymentRecord.ProcessorId.Length > 50) { throw new Exception("Max length of 50 exceeded for transaction code"); } var pymtId = PaymentType.GetPaymentType(paymentRecord.PymtType).id; var fee = paymentRecord.FeeAmt.HasValue ? paymentRecord.FeeAmt / Constants.StripeDecimalConversionValue : null; //check if payment type exists if (!_paymentTypeRepository.PaymentTypeExists(pymtId)) { throw new PaymentTypeNotFoundException(pymtId); } //create payment -- send model var payment = new MpPayment { InvoiceNumber = paymentRecord.InvoiceId.ToString(), ContactId = paymentRecord.ContactId, TransactionCode = paymentRecord.ProcessorId, PaymentDate = DateTime.Now, PaymentTotal = paymentRecord.DonationAmt, PaymentTypeId = pymtId, PaymentStatus = _defaultPaymentStatus, ProcessorFeeAmount = fee }; var paymentDetail = new MpPaymentDetail { Payment = payment, PaymentAmount = paymentRecord.DonationAmt, InvoiceDetailId = _invoiceRepository.GetInvoiceDetailForInvoice(paymentRecord.InvoiceId).InvoiceDetailId }; var result = _paymentRepository.CreatePaymentAndDetail(paymentDetail); if (result.Status) { //update invoice payment status var invoice = _invoiceRepository.GetInvoice(paymentRecord.InvoiceId); var payments = _paymentRepository.GetPaymentsForInvoice(paymentRecord.InvoiceId); payments = payments.Where(p => p.PaymentStatus != _declinedPaymentStatus).ToList(); var paymentTotal = payments.Sum(p => p.PaymentTotal); _invoiceRepository.SetInvoiceStatus(paymentRecord.InvoiceId, paymentTotal >= invoice.InvoiceTotal ? _paidinfullStatus : _somepaidStatus); return(result.Value); } else { throw new Exception("Unable to save payment data"); } }
public int CreateDonationAndDistributionRecord(MpDonationAndDistributionRecord donationAndDistribution, bool sendConfirmationEmail = true) { var pymtId = PaymentType.GetPaymentType(donationAndDistribution.PymtType).id; var fee = donationAndDistribution.FeeAmt.HasValue ? donationAndDistribution.FeeAmt / Constants.StripeDecimalConversionValue : null; var apiToken = ApiLogin(); var donationValues = new Dictionary <string, object> { { "Donor_ID", donationAndDistribution.DonorId }, { "Donation_Amount", donationAndDistribution.DonationAmt }, { "Processor_Fee_Amount", fee }, { "Payment_Type_ID", pymtId }, { "Donation_Date", donationAndDistribution.SetupDate }, { "Transaction_code", donationAndDistribution.ChargeId }, { "Registered_Donor", donationAndDistribution.RegisteredDonor }, { "Anonymous", donationAndDistribution.Anonymous }, { "Processor_ID", donationAndDistribution.ProcessorId }, { "Donation_Status_Date", donationAndDistribution.SetupDate }, { "Donation_Status_ID", donationAndDistribution.DonationStatus ?? 1 }, //hardcoded to pending if no status specified { "Recurring_Gift_ID", donationAndDistribution.RecurringGiftId }, { "Is_Recurring_Gift", donationAndDistribution.RecurringGift }, { "Donor_Account_ID", donationAndDistribution.DonorAcctId }, { "Source_Url", donationAndDistribution.SourceUrl }, { "Predefined_Amount", donationAndDistribution.PredefinedAmount }, }; if (!string.IsNullOrWhiteSpace(donationAndDistribution.CheckScannerBatchName)) { donationValues["Check_Scanner_Batch"] = donationAndDistribution.CheckScannerBatchName; } if (!string.IsNullOrWhiteSpace(donationAndDistribution.CheckNumber)) { donationValues["Item_Number"] = donationAndDistribution.CheckNumber; } if (!string.IsNullOrWhiteSpace(donationAndDistribution.Notes)) { donationValues["Notes"] = donationAndDistribution.Notes; } int donationId; try { donationId = _ministryPlatformService.CreateRecord(_donationPageId, donationValues, apiToken, true); } catch (Exception e) { throw new ApplicationException(string.Format("CreateDonationRecord failed. Donor Id: {0}", donationAndDistribution.DonorId), e); } if (donationAndDistribution.HasDistributions) { foreach (var distribution in donationAndDistribution.Distributions) { CreateDistributionRecord(donationId, distribution.donationDistributionAmt / Constants.StripeDecimalConversionValue, distribution.donationDistributionProgram, distribution.PledgeId, apiToken); } } else if (string.IsNullOrWhiteSpace(donationAndDistribution.ProgramId)) { return(donationId); } else { CreateDistributionRecord(donationId, donationAndDistribution.DonationAmt, donationAndDistribution.ProgramId, donationAndDistribution.PledgeId, apiToken); } if (!sendConfirmationEmail) { return(donationId); } if (sendConfirmationEmail) { try { SetupConfirmationEmail(Convert.ToInt32(donationAndDistribution.ProgramId), donationAndDistribution.DonorId, donationAndDistribution.DonationAmt, donationAndDistribution.SetupDate, donationAndDistribution.PymtType, donationAndDistribution.PledgeId ?? 0); } catch (Exception e) { _logger.Error(string.Format("Failed when processing the template for Donation Id: {0}", donationId), e); } } return(donationId); }
private IHttpActionResult CreateDonationAndDistributionUnauthenticated(CreateDonationDTO dto) { bool isPayment = false; try { var donor = _gatewayDonorService.GetContactDonorForEmail(dto.EmailAddress); var charge = _stripeService.ChargeCustomer(donor.ProcessorId, dto.Amount, donor.DonorId, isPayment); var fee = charge.BalanceTransaction != null ? charge.BalanceTransaction.Fee : null; int?pledgeId = null; if (dto.PledgeCampaignId != null && dto.PledgeDonorId != null) { var pledge = _mpPledgeService.GetPledgeByCampaignAndDonor(dto.PledgeCampaignId.Value, dto.PledgeDonorId.Value); if (pledge != null) { pledgeId = pledge.PledgeId; } } var donationAndDistribution = new MpDonationAndDistributionRecord { DonationAmt = dto.Amount, FeeAmt = fee, DonorId = donor.DonorId, ProgramId = dto.ProgramId, PledgeId = pledgeId, ChargeId = charge.Id, PymtType = dto.PaymentType, ProcessorId = donor.ProcessorId, SetupDate = DateTime.Now, RegisteredDonor = false, Anonymous = dto.Anonymous, PredefinedAmount = dto.PredefinedAmount, SourceUrl = dto.SourceUrl }; var donationId = _mpDonorService.CreateDonationAndDistributionRecord(donationAndDistribution); if (!dto.GiftMessage.IsNullOrWhiteSpace() && pledgeId != null) { SendMessageFromDonor(pledgeId.Value, donationId, dto.GiftMessage); } var response = new DonationDTO() { ProgramId = dto.ProgramId, Amount = (int)dto.Amount, Id = donationId.ToString(), Email = donor.Email }; return(Ok(response)); } catch (PaymentProcessorException stripeException) { return(stripeException.GetStripeResult()); } catch (Exception exception) { var apiError = new ApiErrorDto("Donation Post Failed", exception); throw new HttpResponseException(apiError.HttpResponseMessage); } }
private IHttpActionResult CreateDonationAndDistributionAuthenticated(String token, CreateDonationDTO dto) { var isPayment = (dto.TransactionType != null && dto.TransactionType.Equals("PAYMENT")); try { if (isPayment) { //check if invoice exists before create Stripe Charge if (dto.InvoiceId != null && !_invoiceRepository.InvoiceExists(dto.InvoiceId.Value)) { var apiError = new ApiErrorDto("Invoice Not Found", new InvoiceNotFoundException(dto.InvoiceId.Value)); throw new HttpResponseException(apiError.HttpResponseMessage); } } var contactId = _authenticationService.GetContactId(token); var donor = _mpDonorService.GetContactDonor(contactId); var charge = _stripeService.ChargeCustomer(donor.ProcessorId, dto.Amount, donor.DonorId, isPayment); var fee = charge.BalanceTransaction != null ? charge.BalanceTransaction.Fee : null; int?pledgeId = null; if (dto.PledgeCampaignId != null && dto.PledgeDonorId != null) { var pledge = _mpPledgeService.GetPledgeByCampaignAndDonor(dto.PledgeCampaignId.Value, dto.PledgeDonorId.Value); if (pledge != null) { pledgeId = pledge.PledgeId; } } if (!isPayment) { var donationAndDistribution = new MpDonationAndDistributionRecord { DonationAmt = dto.Amount, FeeAmt = fee, DonorId = donor.DonorId, ProgramId = dto.ProgramId, PledgeId = pledgeId, ChargeId = charge.Id, PymtType = dto.PaymentType, ProcessorId = donor.ProcessorId, SetupDate = DateTime.Now, RegisteredDonor = true, Anonymous = dto.Anonymous, SourceUrl = dto.SourceUrl, PredefinedAmount = dto.PredefinedAmount }; var donationId = _mpDonorService.CreateDonationAndDistributionRecord(donationAndDistribution, !dto.TripDeposit); if (!dto.GiftMessage.IsNullOrWhiteSpace() && pledgeId != null) { SendMessageFromDonor(pledgeId.Value, donationId, dto.GiftMessage); } var response = new DonationDTO { ProgramId = dto.ProgramId, Amount = (int)dto.Amount, Id = donationId.ToString(), Email = donor.Email }; return(Ok(response)); } else //Payment flow (non-contribution transaction) { if (!ModelState.IsValid) { var errors = ModelState.Values.SelectMany(val => val.Errors).Aggregate("", (current, err) => current + err.Exception.Message); var dataError = new ApiErrorDto("Payment data Invalid", new InvalidOperationException("Invalid Payment Data" + errors)); throw new HttpResponseException(dataError.HttpResponseMessage); } try { var invoiceId = dto.InvoiceId != null ? dto.InvoiceId.Value : 0; var payment = new MpDonationAndDistributionRecord { DonationAmt = dto.Amount, PymtType = dto.PaymentType, ProcessorId = charge.Id, ContactId = contactId, InvoiceId = invoiceId, FeeAmt = fee }; var paymentReturn = _paymentService.PostPayment(payment); var response = new DonationDTO { Amount = (int)dto.Amount, Email = donor.Email, PaymentId = paymentReturn.PaymentId }; return(Ok(response)); } catch (InvoiceNotFoundException e) { var apiError = new ApiErrorDto("Invoice Not Found", e); throw new HttpResponseException(apiError.HttpResponseMessage); } catch (ContactNotFoundException e) { var apiError = new ApiErrorDto("Contact Not Found", e); throw new HttpResponseException(apiError.HttpResponseMessage); } catch (PaymentTypeNotFoundException e) { var apiError = new ApiErrorDto("PaymentType Not Found", e); throw new HttpResponseException(apiError.HttpResponseMessage); } catch (Exception e) { var apiError = new ApiErrorDto("SavePayment Failed", e); throw new HttpResponseException(apiError.HttpResponseMessage); } } } catch (PaymentProcessorException stripeException) { return(stripeException.GetStripeResult()); } catch (Exception exception) { var apiError = new ApiErrorDto("Donation/Payment Post Failed", exception); throw new HttpResponseException(apiError.HttpResponseMessage); } }
private IHttpActionResult CreateDonationAndDistributionUnauthenticated(CreateDonationDTO dto) { bool isPayment = false; MpContactDonor donor = null; try { donor = _gatewayDonorService.GetContactDonorForEmail(dto.EmailAddress); var charge = _stripeService.ChargeCustomer(donor.ProcessorId, dto.Amount, donor.DonorId, isPayment); var fee = charge.BalanceTransaction != null ? charge.BalanceTransaction.Fee : null; int?pledgeId = null; if (dto.PledgeCampaignId != null && dto.PledgeDonorId != null) { var pledge = _mpPledgeService.GetPledgeByCampaignAndDonor(dto.PledgeCampaignId.Value, dto.PledgeDonorId.Value); if (pledge != null) { pledgeId = pledge.PledgeId; } } var donationAndDistribution = new MpDonationAndDistributionRecord { DonationAmt = dto.Amount, FeeAmt = fee, DonorId = donor.DonorId, ProgramId = dto.ProgramId, PledgeId = pledgeId, ChargeId = charge.Id, PymtType = dto.PaymentType, ProcessorId = donor.ProcessorId, SetupDate = DateTime.Now, RegisteredDonor = false, Anonymous = dto.Anonymous, PredefinedAmount = dto.PredefinedAmount, SourceUrl = dto.SourceUrl }; var from = dto.Anonymous ? "Anonymous" : donor.Details.FirstName + " " + donor.Details.LastName; var donationId = _mpDonorService.CreateDonationAndDistributionRecord(donationAndDistribution); if (!dto.GiftMessage.IsNullOrWhiteSpace() && pledgeId != null) { SendMessageFromDonor(pledgeId.Value, donationId, dto.GiftMessage, from); } var response = new DonationDTO() { ProgramId = dto.ProgramId, Amount = (int)dto.Amount, Id = donationId.ToString(), Email = donor.Email }; _analyticsService.Track(donor.ContactId.ToString(), "PaymentSucceededServerSide", new EventProperties() { { "Url", dto.SourceUrl }, { "FundingMethod", dto.PaymentType }, { "Email", donor.Email }, { "CheckoutType", "Guest" }, { "Amount", dto.Amount } }); return(Ok(response)); } catch (PaymentProcessorException stripeException) { LogDonationError("CreateDonationAndDistributionUnauthenticated", stripeException, dto, donor); return(stripeException.GetStripeResult()); } catch (Exception exception) { LogDonationError("CreateDonationAndDistributionUnauthenticated", exception, dto, donor); var apiError = new ApiErrorDto("Donation Post Failed", exception); throw new HttpResponseException(apiError.HttpResponseMessage); } }
public int?CreateDonationForBankAccountErrorRefund(StripeRefund refund) { if (refund.Data[0].BalanceTransaction == null || !"payment_failure_refund".Equals(refund.Data[0].BalanceTransaction.Type)) { _logger.Error(string.Format("Balance transaction was not set, or was not a payment_failure_refund for refund ID {0}", refund.Data[0].Id)); return(null); } if (refund.Data[0].Charge == null || string.IsNullOrWhiteSpace(refund.Data[0].Charge.Id)) { _logger.Error(string.Format("No associated Charge for Refund {0}", refund.Data[0].Id)); return(null); } MpDonation donation; try { donation = _mpDonationRepository.GetDonationByProcessorPaymentId(refund.Data[0].Charge.Id, true); } catch (DonationNotFoundException) { _logger.Error(string.Format("No Donation with payment processor ID {0} in MP for Refund {1}", refund.Data[0].Charge.Id, refund.Data[0].Id)); return(null); } var donationAndDist = new MpDonationAndDistributionRecord { Anonymous = false, ChargeId = refund.Data[0].Id, CheckNumber = null, CheckScannerBatchName = null, DonationAmt = -(int.Parse(refund.Data[0].Amount) / Constants.StripeDecimalConversionValue), DonationStatus = (int)DonationStatus.Declined, DonorAcctId = string.Empty, DonorId = _bankErrorRefundDonorId, FeeAmt = refund.Data[0].BalanceTransaction.Fee, PledgeId = null, RecurringGift = false, ProcessorId = string.Empty, ProgramId = donation.Distributions[0].donationDistributionProgram, PymtType = MinistryPlatform.Translation.Enum.PaymentType.GetPaymentType(donation.paymentTypeId).name, RecurringGiftId = null, RegisteredDonor = false, SetupDate = refund.Data[0].BalanceTransaction.Created, Notes = string.Format("Reversed from DonationID {0}", donation.donationId) }; foreach (var distribution in donation.Distributions) { donationAndDist.Distributions.Add(new MpDonationDistribution { donationDistributionAmt = -distribution.donationDistributionAmt, donationDistributionProgram = distribution.donationDistributionProgram, PledgeId = distribution.PledgeId }); } // Create the refund donation and distribution(s), but do NOT send email return(_mpDonorRepository.CreateDonationAndDistributionRecord(donationAndDist, false)); }
public CheckScannerBatch CreateDonationsForBatch(CheckScannerBatch batchDetails) { var checks = _checkScannerDao.GetChecksForBatch(batchDetails.Name); foreach (var check in checks) { if (check.Exported) { var previousError = string.IsNullOrWhiteSpace(check.Error) ? string.Empty : string.Format("Previous Error: {0}", check.Error); var msg = string.Format("Not exporting check {0} on batch {1}, it was already exported. {2}", check.Id, batchDetails.Name, previousError); _logger.Info(msg); check.Error = msg; batchDetails.ErrorChecks.Add(check); continue; } try { var contactDonor = CreateDonor(check); var account = _mpDonorService.DecryptCheckValue(check.AccountNumber); var routing = _mpDonorService.DecryptCheckValue(check.RoutingNumber); var encryptedKey = _mpDonorService.CreateHashedAccountAndRoutingNumber(account, routing); string donorAccountId = ""; if (contactDonor.Account.HasPaymentProcessorInfo() == false) { var stripeCustomer = _paymentService.CreateCustomer(null, contactDonor.DonorId + " Scanned Checks"); var stripeCustomerSource = _paymentService.AddSourceToCustomer(stripeCustomer.id, contactDonor.Account.Token); donorAccountId = _mpDonorService.CreateDonorAccount(null, routing, account.Right(4), encryptedKey, contactDonor.DonorId, stripeCustomerSource.id, stripeCustomer.id).ToString(); contactDonor.Account = new MpDonorAccount { DonorAccountId = int.Parse(donorAccountId), ProcessorId = stripeCustomer.id, ProcessorAccountId = stripeCustomerSource.id }; } else { donorAccountId = contactDonor.Account.DonorAccountId.ToString(); } //Always use the customer ID and source ID from the Donor Account, if it exists var charge = _paymentService.ChargeCustomer(contactDonor.Account.ProcessorId, contactDonor.Account.ProcessorAccountId, check.Amount, contactDonor.DonorId, check.CheckNumber); var fee = charge.BalanceTransaction != null ? charge.BalanceTransaction.Fee : null; // Mark the check as exported now, so we don't double-charge a community member. // If the CreateDonationAndDistributionRecord fails, we'll still consider it exported, but // it will be in error, and will have to be manually resolved. check.Exported = true; var programId = batchDetails.ProgramId == null ? null : batchDetails.ProgramId + ""; var donationAndDistribution = new MpDonationAndDistributionRecord { DonationAmt = check.Amount, FeeAmt = fee, DonorId = contactDonor.DonorId, ProgramId = programId, ChargeId = charge.Id, PymtType = "check", ProcessorId = contactDonor.Account.ProcessorId, SetupDate = check.CheckDate ?? (check.ScanDate ?? DateTime.Now), RegisteredDonor = contactDonor.RegisteredUser, DonorAcctId = donorAccountId, CheckScannerBatchName = batchDetails.Name, CheckNumber = (check.CheckNumber ?? string.Empty).TrimStart(' ', '0').Right(MinistryPlatformCheckNumberMaxLength) }; var donationId = _mpDonorService.CreateDonationAndDistributionRecord(donationAndDistribution, false); check.DonationId = donationId; _checkScannerDao.UpdateCheckStatus(check.Id, true); batchDetails.Checks.Add(check); } catch (Exception e) { check.Error = e.ToString(); check.AccountNumber = _mpDonorService.DecryptCheckValue(check.AccountNumber); check.RoutingNumber = _mpDonorService.DecryptCheckValue(check.RoutingNumber); batchDetails.ErrorChecks.Add(check); _checkScannerDao.UpdateCheckStatus(check.Id, check.Exported, check.Error); } } batchDetails.Status = BatchStatus.Exported; _checkScannerDao.UpdateBatchStatus(batchDetails.Name, batchDetails.Status); return(batchDetails); }