public static void ValidateCreditCardInfo(ModelStateDictionary modelState, PaymentForm pf) { if (pf.SavePayInfo && pf.CreditCard.HasValue() && pf.CreditCard.StartsWith("X")) return; if (!ValidateCard(pf.CreditCard, pf.SavePayInfo)) { modelState.AddModelError("CreditCard", "The card number is invalid."); } if (!pf.Expires.HasValue()) { modelState.AddModelError("Expires", "The expiration date is required."); return; } var exp = DbUtil.NormalizeExpires(pf.Expires); if (exp == null) modelState.AddModelError("Expires", "The expiration date format is invalid (MMYY)."); if (!pf.CVV.HasValue()) { modelState.AddModelError("CVV", "The CVV is required."); return; } var cvvlen = pf.CVV.GetDigits().Length; if (cvvlen < 3 || cvvlen > 4) modelState.AddModelError("CVV", "The CVV must be a 3 or 4 digit number."); }
public ActionResult ProcessPayment(PaymentForm pf) { Response.NoCache(); #if DEBUG #else if (Session["FormId"] != null) if ((Guid)Session["FormId"] == pf.FormId) return Message("Already submitted"); #endif OnlineRegModel m = null; var ed = DbUtil.Db.RegistrationDatas.SingleOrDefault(e => e.Id == pf.DatumId); if (ed != null) m = Util.DeSerialize<OnlineRegModel>(ed.Data); #if DEBUG #else if (m != null && m.History.Any(h => h.Contains("ProcessPayment"))) return Content("Already submitted"); #endif int? datumid = null; if (m != null) { datumid = m.DatumId; var msg = m.CheckDuplicateGift(pf.AmtToPay); if (msg.HasValue()) return Message(msg); } SetHeaders(pf.OrgId ?? 0); var ret = pf.ProcessPayment(ModelState, m); switch (ret.Route) { case RouteType.ModelAction: return View(ret.View, ret.Model); case RouteType.AmtDue: ViewBag.amtdue = ret.AmtDue; return View(ret.View, ret.Transaction); case RouteType.Error: DbUtil.Db.LogActivity("OnlineReg Error " + ret.Message, pf.OrgId, did: datumid); return Message(ret.Message); case RouteType.ValidationError: return View(ret.View, pf); default: // unexptected Route if (ModelState.IsValid) { ErrorSignal.FromCurrentContext().Raise(new Exception("OnlineReg Unexpected route datum= " + datumid)); DbUtil.Db.LogActivity("OnlineReg Unexpected Route " + ret.Message, oid: pf.OrgId, did: datumid); ModelState.AddModelError("form", "unexpected error in payment processing"); } return View(ret.View ?? "Payment/Process", pf); } }
public ActionResult ApplyCoupon(PaymentForm pf) { OnlineRegModel m = null; if (pf.PayBalance == false) { m = OnlineRegModel.GetRegistrationFromDatum(pf.DatumId); if (m == null) return Json(new {error = "coupon not find your registration"}); m.ParseSettings(); } if (!pf.Coupon.HasValue()) return Json(new {error = "empty coupon"}); var coupon = pf.Coupon.ToUpper().Replace(" ", ""); var admincoupon = DbUtil.Db.Setting("AdminCoupon", "ifj4ijweoij").ToUpper().Replace(" ", ""); if (coupon == admincoupon) if (pf.PayBalance) { var tic = pf.CreateTransaction(DbUtil.Db, pf.AmtToPay); return Json(new {confirm = $"/onlinereg/ConfirmDuePaid/{tic.Id}?TransactionID=AdminCoupon&Amount={tic.Amt}"}); } else return Json(new {confirm = $"/OnlineReg/Confirm/{pf.DatumId}?TransactionId=AdminCoupon"}); var c = DbUtil.Db.Coupons.SingleOrDefault(cp => cp.Id == coupon); if (c == null) return Json(new {error = "coupon not found"}); if (pf.OrgId.HasValue && c.Organization != null && c.Organization.OrgPickList.HasValue()) { var a = c.Organization.OrgPickList.SplitStr(",").Select(ss => ss.ToInt()).ToArray(); if (!a.Contains(pf.OrgId.Value)) return Json(new {error = "coupon and org do not match"}); } else if (pf.OrgId != c.OrgId) return Json(new {error = "coupon and org do not match"}); if (c.Used.HasValue && c.Id.Length == 12) return Json(new {error = "coupon already used"}); if (c.Canceled.HasValue) return Json(new {error = "coupon canceled"}); var ti = pf.CreateTransaction(DbUtil.Db, Math.Min(c.Amount ?? 0m, pf.AmtToPay ?? 0m)); if (m != null) // Start this transaction in the chain { m.HistoryAdd("ApplyCoupon"); m.TranId = ti.OriginalId; m.UpdateDatum(); } var tid = $"Coupon({Util.fmtcoupon(coupon)})"; if (!pf.PayBalance) OnlineRegModel.ConfirmDuePaidTransaction(ti, tid, false); var msg = $"<i class='red'>Your coupon for {c.Amount:n2} has been applied, your balance is now {ti.Amtdue:n2}</i>."; if (ti.Amt < pf.AmtToPay) msg += "You still must complete this transaction with a payment"; if (m != null) m.UseCoupon(ti.TransactionId, ti.Amt ?? 0); else c.UseCoupon(ti.FirstTransactionPeopleId(), ti.Amt ?? 0); DbUtil.Db.SubmitChanges(); if (pf.PayBalance) return Json(new {confirm = $"/onlinereg/ConfirmDuePaid/{ti.Id}?TransactionID=Coupon({Util.fmtcoupon(coupon)})&Amount={ti.Amt}"}); pf.AmtToPay -= ti.Amt; if (pf.AmtToPay <= 0) return Json(new {confirm = $"/OnlineReg/Confirm/{pf.DatumId}?TransactionId={"Coupon"}"}); return Json(new {tiamt = pf.AmtToPay, amtdue = ti.Amtdue, amt = pf.AmtToPay.ToString2("N2"), msg}); }
private static void ClearMaskedNumbers(PaymentForm pf, PaymentInfo pi) { var gateway = DbUtil.Db.Setting("TransactionGateway", ""); var clearBankDetails = false; var clearCreditCardDetails = false; switch (gateway.ToLower()) { case "sage": clearBankDetails = !pi.SageBankGuid.HasValue; clearCreditCardDetails = !pi.SageCardGuid.HasValue; break; case "transnational": clearBankDetails = !pi.TbnBankVaultId.HasValue; clearCreditCardDetails = !pi.TbnCardVaultId.HasValue; break; case "authorizenet": clearBankDetails = !pi.AuNetCustPayBankId.HasValue; clearCreditCardDetails = !pi.AuNetCustPayId.HasValue; break; } if (clearBankDetails) { pf.Account = string.Empty; pf.Routing = string.Empty; } if (clearCreditCardDetails) { pf.CreditCard = string.Empty; pf.CVV = string.Empty; pf.Expires = string.Empty; } }
public static PaymentForm CreatePaymentFormForBalanceDue(Transaction ti, decimal amtdue, string email) { PaymentInfo pi = null; if (ti.Person != null) pi = ti.Person.PaymentInfos.FirstOrDefault(); if (pi == null) pi = new PaymentInfo(); var pf = new PaymentForm { URL = ti.Url, PayBalance = true, AmtToPay = amtdue, Amtdue = 0, AllowCoupon = true, AskDonation = false, Description = ti.Description, OrgId = ti.OrgId, OriginalId = ti.OriginalId, Email = Util.FirstAddress(ti.Emails ?? email).Address, FormId = Guid.NewGuid(), First = ti.First, MiddleInitial = ti.MiddleInitial.Truncate(1) ?? "", Last = ti.Last, Suffix = ti.Suffix, Phone = ti.Phone, Address = ti.Address, Address2 = ti.Address2, City = ti.City, State = ti.State, Country = ti.Country, Zip = ti.Zip, testing = ti.Testing ?? false, TranId = ti.Id }; if (pi.PeopleId == Util.UserPeopleId) // Is this the logged in user? { pf.CreditCard = pi.MaskedCard; pf.Expires = pi.Expires; pf.Account = pi.MaskedAccount; pf.Routing = pi.Routing; pf.SavePayInfo = (pi.MaskedAccount != null && pi.MaskedAccount.StartsWith("X")) || (pi.MaskedCard != null && pi.MaskedCard.StartsWith("X")); } ClearMaskedNumbers(pf, pi); pf.Type = pf.NoEChecksAllowed ? PaymentType.CreditCard : ""; var org = DbUtil.Db.LoadOrganizationById(ti.OrgId); return pf; }
public static PaymentForm CreatePaymentForm(OnlineRegModel m) { var r = m.GetTransactionInfo(); if (r == null) return null; var pf = new PaymentForm { FormId = Guid.NewGuid(), AmtToPay = m.PayAmount() + (m.donation ?? 0), AskDonation = m.AskDonation(), AllowCoupon = !m.OnlineGiving(), PayBalance = false, Amtdue = m.TotalAmount() + (m.donation ?? 0), Donate = m.donation, Description = m.DescriptionForPayment, Email = r.Email, First = r.First, MiddleInitial = r.Middle, Last = r.Last, Suffix = r.Suffix, IsLoggedIn = m.UserPeopleId.HasValue, OrgId = m.List[0].orgid, URL = m.URL, testing = m.testing ?? false, Terms = m.Terms, Address = r.Address, Address2 = r.Address2, City = r.City, State = r.State, Country = r.Country, Zip = r.Zip, Phone = r.Phone, SupportMissionTrip = m.SupportMissionTrip, #if DEBUG2 CreditCard = "4111111111111111", CVV = "123", Expires = "1017", Routing = "056008849", Account = "12345678901234", #endif }; if (r.payinfo.PeopleId == m.UserPeopleId) // Is this the logged in user? { pf.CreditCard = r.payinfo.MaskedCard; pf.Account = r.payinfo.MaskedAccount; pf.Routing = r.payinfo.Routing; pf.Expires = r.payinfo.Expires; pf.SavePayInfo = (r.payinfo.MaskedAccount != null && r.payinfo.MaskedAccount.StartsWith("X")) || (r.payinfo.MaskedCard != null && r.payinfo.MaskedCard.StartsWith("X")); pf.Type = r.payinfo.PreferredPaymentType; } ClearMaskedNumbers(pf, r.payinfo); pf.AllowSaveProgress = m.AllowSaveProgress(); pf.NoCreditCardsAllowed = m.NoCreditCardsAllowed(); if (m.OnlineGiving()) { #if DEBUG pf.NoCreditCardsAllowed = false; #else pf.NoCreditCardsAllowed = DbUtil.Db.Setting("NoCreditCardGiving", "false").ToBool(); #endif pf.IsGiving = true; pf.FinanceOnly = true; pf.Type = r.payinfo.PreferredGivingType; } else if (m.ManageGiving() || m.OnlinePledge()) { pf.FinanceOnly = true; } if (pf.NoCreditCardsAllowed) pf.Type = PaymentType.Ach; // bank account only else if (pf.NoEChecksAllowed) pf.Type = PaymentType.CreditCard; // credit card only pf.Type = pf.NoEChecksAllowed ? PaymentType.CreditCard : pf.Type; pf.DatumId = m.DatumId ?? 0; return pf; }
public static void ConfirmDuePaidTransaction(Transaction ti, string transactionId, bool sendmail, CMSDataContext db) { var org = db.LoadOrganizationById(ti.OrgId); ti.TransactionId = transactionId; if (ti.Testing == true && !ti.TransactionId.Contains("(testing)")) { ti.TransactionId += "(testing)"; } var amt = ti.Amt; var due = PaymentForm.AmountDueTrans(db, ti); foreach (var pi in ti.OriginalTrans.TransactionPeople) { var p = db.LoadPersonById(pi.PeopleId); if (p != null) { var om = db.OrganizationMembers.SingleOrDefault(m => m.OrganizationId == ti.OrgId && m.PeopleId == pi.PeopleId); if (om == null) { continue; } db.SubmitChanges(); if (org.IsMissionTrip == true) { db.GoerSenderAmounts.InsertOnSubmit( new GoerSenderAmount { Amount = ti.Amt, GoerId = pi.PeopleId, Created = DateTime.Now, OrgId = org.OrganizationId, SupporterId = pi.PeopleId, }); var setting = db.CreateRegistrationSettings(org.OrganizationId); var fund = setting.DonationFundId; p.PostUnattendedContribution(db, ti.Amt ?? 0, fund, $"SupportMissionTrip: org={org.OrganizationId}; goer={pi.PeopleId}", typecode: BundleTypeCode.Online); } var pay = amt; if (org.IsMissionTrip == true) { ti.Amtdue = due; } var sb = new StringBuilder(); sb.AppendFormat("{0:g} ----------\n", Util.Now); sb.AppendFormat("{0:c} ({1} id) transaction amount\n", ti.Amt, ti.Id); sb.AppendFormat("{0:c} applied to this registrant\n", pay); sb.AppendFormat("{0:c} total due all registrants\n", due); om.AddToMemberDataBelowComments(sb.ToString()); var reg = p.SetRecReg(); reg.AddToComments(sb.ToString()); reg.AddToComments($"{org.OrganizationName} ({org.OrganizationId})"); amt -= pay; } else { db.Email(db.StaffEmailForOrg(org.OrganizationId), db.PeopleFromPidString(org.NotifyIds), "missing person on payment due", $"Cannot find {pi.Person.Name} ({pi.PeopleId}), payment due completed of {pi.Amt:c} but no record"); } } db.SubmitChanges(); dynamic d = new DynamicData(); d.Name = Transaction.FullName(ti); d.Amt = ti.Amt; d.Description = ti.Description; d.Amtdue = PaymentForm.AmountDueTrans(db, ti); d.names = string.Join(", ", ti.OriginalTrans.TransactionPeople.Select(i => i.Person.Name)); var msg = db.RenderTemplate(@" <p> Thank you {{Name}}, for your payment of {{Fmt Amt 'c'}} on {{Description}}.<br/> {{#if Amtdue}} Your balance is {{Fmt Amtdue 'c'}}<br/> {{/if}} {{names}} </p>", d); var msgstaff = db.RenderTemplate(@" <p> {{Name}} paid {{Fmt Amt 'c'}} on {{Description}}.<br/> {{#if Amtdue}} The balance is {{Fmt Amtdue 'c'}}<br/> {{/if}} {{names}} </p>", d); var pid = ti.FirstTransactionPeopleId(); var p0 = db.LoadPersonById(pid); // question: should we be sending to all TransactionPeople? if (sendmail) { MailAddress staffEmail; if (!Util.TryGetMailAddress(db.StaffEmailForOrg(org.OrganizationId), out staffEmail)) { staffEmail = GetAdminMailAddress(db); } if (p0 == null) { db.SendEmail(staffEmail, "Payment confirmation", msg, Util.ToMailAddressList(Util.FirstAddress(ti.Emails)), pid: pid).Wait(); } else { db.Email(staffEmail, p0, Util.ToMailAddressList(ti.Emails), "Payment confirmation", msg, false); db.Email(p0.FromEmail, db.PeopleFromPidString(org.NotifyIds), "payment received for " + ti.Description, msgstaff); } } }