예제 #1
0
        ///<summary>Creates and returns the HPF URL and validation OTK which can be used to make a payment for an unspecified credit card.  Throws exceptions.</summary>
        public static string GetHpfUrlForPayment(Patient pat, string accountToken, string payNote, bool isMobile, double amount, bool saveToken, CreditCardSource ccSource)
        {
            if (pat == null)
            {
                throw new ODException("No Patient Found", ODException.ErrorCodes.NoPatientFound);
            }
            if (string.IsNullOrWhiteSpace(accountToken))
            {
                throw new ODException("Invalid Account Token", ODException.ErrorCodes.OtkArgsInvalid);
            }
            if (amount < 0.00 || amount > 99999.99)
            {
                throw new ODException("Invalid Amount", ODException.ErrorCodes.OtkArgsInvalid);
            }
            if (string.IsNullOrEmpty(payNote))
            {
                throw new ODException("Invalid PayNote", ODException.ErrorCodes.OtkArgsInvalid);
            }
            PayConnectResponseWeb responseWeb = new PayConnectResponseWeb()
            {
                Amount           = amount,
                AccountToken     = accountToken,
                PatNum           = pat.PatNum,
                ProcessingStatus = PayConnectWebStatus.Created,
                PayNote          = payNote,
                CCSource         = ccSource,
                IsTokenSaved     = saveToken,
            };

            PayConnectResponseWebs.Insert(responseWeb);
            try {
                string url;
                PayConnectREST.PostPaymentRequest(responseWeb, out url);
                PayConnectResponseWebs.Update(responseWeb);
                WakeupWebPaymentsMonitor?.Invoke(url, new EventArgs());
                return(url);
            }
            catch (Exception e) {
                PayConnectResponseWebs.HandleResponseError(responseWeb, "Error calling PostPaymentRequest: " + e.Message);
                PayConnectResponseWebs.Update(responseWeb);
                throw;
            }
        }
예제 #2
0
 ///<summary>Poll the existing PayConnectResponseWeb for status changes.
 ///This method will update the ResponseJSON/ProcessingStatus with any changes</summary>
 public static void GetPaymentStatus(PayConnectResponseWeb responseWeb)
 {
     #region Response Object
     var resObj = new {
         Amount            = -1.00,
         TransactionType   = "",
         TransactionStatus = "",
         TransactionDate   = DateTime.MinValue,
         StatusDescription = "",
         //Used to poll for getting the payment status to see if the user has made a payment.
         PayToken             = "",
         CreditCardNumber     = "",
         CreditCardExpireDate = "",
         TransactionID        = -1,
         RefNumber            = "",
         Pending = true,
         Status  = new {
             code        = -1,
             description = "",
         },
         Messages = new {
             Message = new string[0]
         },
         //Used for future payments with this card.  Do not confuse this with PayToken.
         PaymentToken = new {
             TokenId    = "",
             Expiration = new {
                 month = "",
                 year  = "",
             },
             Messages = new {
                 Message = new string[0]
             },
         },
     };
     #endregion
     List <string> listHeaders = GetClientRequestHeadersForWebURL();
     listHeaders.Add("AccountToken: " + responseWeb.AccountToken);
     try {
         var res = Request(ApiRoute.PaymentStatus, HttpMethod.Get, listHeaders, "", resObj, $"?payToken={responseWeb.PayToken}");
         if (res == null)
         {
             PayConnectResponseWebs.HandleResponseError(responseWeb, JsonConvert.SerializeObject(res));
             throw new ODException("Invalid response from PayConnect.");
         }
         int    code    = -1;
         string codeMsg = "";
         if (res.Status != null)
         {
             code    = res.Status.code;
             codeMsg = "Response code: " + res.Status.code + "\r\n";
         }
         if (code > 0)
         {
             string err = "Invalid response from PayConnect.\r\nResponse code: " + code;
             if (res.Messages != null && res.Messages.Message != null && res.Messages.Message.Length > 0)
             {
                 err += "\r\nError retrieving payment status.\r\nResponse message(s):\r\n" + string.Join("\r\n", res.Messages.Message);
             }
             PayConnectResponseWebs.HandleResponseError(responseWeb, JsonConvert.SerializeObject(res));
             throw new ODException(err);
         }
         if (res.Pending)
         {
             HandleResponseSuccess(responseWeb, JsonConvert.SerializeObject(res), true);
         }
         else if (res.TransactionStatus != null &&
                  (res.TransactionStatus.Contains("Timeout") || res.TransactionStatus.Contains("Cancelled") || res.TransactionStatus.Contains("Declined")))
         {
             responseWeb.LastResponseStr  = JsonConvert.SerializeObject(res);
             responseWeb.ProcessingStatus = res.TransactionStatus.Contains("Declined") ? PayConnectWebStatus.Declined
                                         : (res.TransactionStatus.Contains("Cancelled") ? PayConnectWebStatus.Cancelled : PayConnectWebStatus.Expired);
             responseWeb.DateTimeExpired = MiscData.GetNowDateTime();
         }
         else if (res.TransactionStatus != null && res.TransactionStatus.Contains("Approved"))
         {
             string expYear  = res.PaymentToken.Expiration.year.Substring(res.PaymentToken.Expiration.year.Length - 2); //Last 2 digits only
             string expMonth = res.PaymentToken.Expiration.month.PadLeft(2, '0');                                       //2 digit month with leading 0 if needed
             responseWeb.PaymentToken = res.PaymentToken.TokenId;
             responseWeb.ExpDateToken = expYear + expMonth;                                                             //yyMM format
             responseWeb.RefNumber    = res.RefNumber;
             responseWeb.TransType    = PayConnectService.transType.SALE;
             HandleResponseSuccess(responseWeb, JsonConvert.SerializeObject(res), res.Pending);
         }
         else
         {
             responseWeb.LastResponseStr   = JsonConvert.SerializeObject(res);
             responseWeb.ProcessingStatus  = PayConnectWebStatus.Unknown;
             responseWeb.DateTimeLastError = MiscData.GetNowDateTime();
         }
     }
     catch (Exception ex) {
         PayConnectResponseWebs.HandleResponseError(responseWeb, ex.Message);
         throw;
     }
 }
예제 #3
0
            ///<summary>Returns number of pending transactions remaining after completion.</summary>
            private static int ProcessOutstandingTransactions()
            {
                OnLoggerEvent("Checking for outstanding PaymentTokens.");
                List <PayConnectResponseWeb> listPendingPaymentsAll = PayConnectResponseWebs.GetAllPending();
                //Only process if it's been >= 5 seconds.
                List <PayConnectResponseWeb> listPendingDue = listPendingPaymentsAll.FindAll(x => DateTime.Now.Subtract(x.GetLastPendingUpdateDateTime()) > TimeSpan.FromSeconds(5));

                OnLoggerEvent("Found " + listPendingPaymentsAll.Count + " PaymentTokens. " + listPendingDue.Count.ToString() + " are due to be processed.");
                if (listPendingDue.Count <= 0)                //None are due this time around but we may have some still pending, return count of those.
                {
                    return(listPendingPaymentsAll.Count);
                }
                OnLoggerEvent("Processing " + listPendingDue.Count.ToString() + " outstanding PaymentTokens.", LogLevel.Information);
                //Seed total remaining with any that we won't be processing this time around.
                int remaining = listPendingPaymentsAll.Count - listPendingDue.Count;

                foreach (PayConnectResponseWeb responseWebCur in listPendingDue)
                {
                    try {
                        //This method will update the responseWebCur with all of the data from the /paymentStatus API call
                        PayConnectREST.GetPaymentStatus(responseWebCur);
                        switch (responseWebCur.ProcessingStatus)
                        {
                        case PayConnectWebStatus.Pending:
                            //No new status to report. Try again next time.
                            OnLoggerEvent("PaymentToken still pending: " + responseWebCur.PayToken, LogLevel.Information);
                            if (DateTime.Now.AddMinutes(30) < responseWebCur.GetLastPendingUpdateDateTime())
                            {
                                //Expire this transaction ourselves after 30 minutes.  In testing, PayConnect expires them after 15 minutes.
                                responseWebCur.ProcessingStatus = PayConnectWebStatus.Expired;
                                responseWebCur.DateTimeExpired  = MiscData.GetNowDateTime();
                                OnLoggerEvent("PaymentToken has expired: " + responseWebCur.PayToken, LogLevel.Information);
                            }
                            break;

                        case PayConnectWebStatus.CreatedError:
                        case PayConnectWebStatus.PendingError:
                            OnLoggerEvent("PaymentToken returned an error when retreiving a status update: " + responseWebCur.PayToken, LogLevel.Information);
                            break;

                        case PayConnectWebStatus.Expired:
                            OnLoggerEvent("PaymentToken has expired: " + responseWebCur.PayToken, LogLevel.Information);
                            break;

                        case PayConnectWebStatus.Completed:
                            OnLoggerEvent("PaymentToken has been completed: " + responseWebCur.PayToken, LogLevel.Information);
                            if (responseWebCur.IsTokenSaved)
                            {
                                CreditCards.InsertFromPayConnect(responseWebCur);
                            }
                            Patient pat       = Patients.GetPat(responseWebCur.PatNum);
                            long    clinicNum = 0;
                            if (PrefC.HasClinicsEnabled)
                            {
                                clinicNum = pat.ClinicNum;
                            }
                            string receipt = "";
                            if (!string.IsNullOrWhiteSpace(responseWebCur.LastResponseStr))
                            {
                                var pcInfo = Newtonsoft.Json.JsonConvert.DeserializeAnonymousType(responseWebCur.LastResponseStr,
                                                                                                  new { Amount = (decimal)0.0, CreditCardNumber = "", Messages = new { Message = new string[0] }, RefNumber = "", Status = new { description = "" }, }
                                                                                                  );
                                receipt = BuildReceiptString(PayConnectService.transType.SALE, pcInfo.RefNumber, "", pcInfo.CreditCardNumber, "", "", pcInfo.Status?.description ?? "", pcInfo.Messages.Message.ToList(), pcInfo.Amount, 0, clinicNum);
                            }
                            responseWebCur.PayNum = Payments.InsertFromPayConnect(pat.PatNum, pat.PriProv, clinicNum, responseWebCur.Amount, responseWebCur.GetFormattedNote(true), receipt, responseWebCur.CCSource);
                            break;

                        case PayConnectWebStatus.Cancelled:
                            OnLoggerEvent("PaymentToken has been cancelled: " + responseWebCur.PayToken, LogLevel.Information);
                            break;

                        case PayConnectWebStatus.Declined:
                            OnLoggerEvent("PaymentToken has been declined: " + responseWebCur.PayToken, LogLevel.Information);
                            break;

                        case PayConnectWebStatus.Created:
                        case PayConnectWebStatus.Unknown:
                        case PayConnectWebStatus.UnknownError:
                        default:
                            OnLoggerEvent($"PaymentToken {responseWebCur.PayToken} returned unsupported state: {responseWebCur.ProcessingStatus.ToString()}", LogLevel.Information);
                            break;
                        }
                    }
                    catch (Exception e) {
                        e.DoNothing();
                    }
                    finally {
                        PayConnectResponseWebs.Update(responseWebCur);
                    }
                }
                remaining = listPendingPaymentsAll.FindAll(x => x.ProcessingStatus == PayConnectWebStatus.Pending).Count;
                OnLoggerEvent(remaining.ToString() + " PaymentTokens still pending after processing.", LogLevel.Information);
                return(remaining);
            }
예제 #4
0
 ///<summary>Make a payment using HPF directly.  Throws exceptions.</summary>
 public static void MakePaymentWithAlias(Patient pat, string payNote, double amount, CreditCard cc)
 {
     if (pat == null)
     {
         throw new ODException("No Patient Found", ODException.ErrorCodes.NoPatientFound);
     }
     if (amount < 0.00 || amount > 99999.99)
     {
         throw new ODException("Invalid Amount", ODException.ErrorCodes.OtkArgsInvalid);
     }
     if (string.IsNullOrEmpty(payNote))
     {
         throw new ODException("Invalid PayNote", ODException.ErrorCodes.OtkArgsInvalid);
     }
     if (cc == null)
     {
         throw new ODException("No Credit Card Found", ODException.ErrorCodes.OtkArgsInvalid);
     }
     if (string.IsNullOrEmpty(cc.PayConnectToken))
     {
         throw new ODException("Invalid CC Alias", ODException.ErrorCodes.OtkArgsInvalid);
     }
     //request a PayConnect token, if a token was already saved PayConnect will return the same token,
     //otherwise replace CCNumberMasked with the returned token if the sale successful
     PayConnectService.creditCardRequest payConnectRequest = PayConnect.BuildSaleRequest(
         (decimal)amount, cc.PayConnectToken, cc.CCExpiration.Year, cc.CCExpiration.Month,
         pat.GetNameFLnoPref(), "", cc.Zip, null,
         PayConnectService.transType.SALE, "", true);
     //clinicNumCur could be 0, and the practice level or 'Headquarters' PayConnect credentials would be used for this charge
     PayConnectService.transResponse payConnectResponse = PayConnect.ProcessCreditCard(payConnectRequest, pat.ClinicNum,
                                                                                       x => throw new ODException(x));
     if (payConnectRequest != null && payConnectResponse.Status.code == 0)         //Success
     {
         string receipt = BuildReceiptString(payConnectRequest.TransType, payConnectResponse.RefNumber, payConnectRequest.NameOnCard, payConnectRequest.CardNumber,
                                             payConnectRequest.MagData, payConnectResponse.AuthCode, payConnectResponse.Status.description, payConnectResponse.Messages.ToList(), payConnectRequest.Amount,
                                             0, pat.ClinicNum);
         DateTime dateTimeProcessed = DateTime.Now;
         string   formattedNote     = Lans.g("PayConnect", "Amount:") + " " + amount.ToString("f") + "\r\n"
                                      + Lans.g("PayConnect", "Card Number:") + " " + cc.CCNumberMasked + "\r\n"
                                      + Lans.g("PayConnect", "Transaction ID:") + " " + payConnectRequest.RefNumber + "\r\n"
                                      + Lans.g("PayConnect", "Processed:") + " " + dateTimeProcessed.ToShortDateString() + " " + dateTimeProcessed.ToShortTimeString() + "\r\n"
                                      + Lans.g("PayConnect", "Note:") + " " + payNote;
         long payNum = Payments.InsertFromPayConnect(pat.PatNum, pat.PriProv, pat.ClinicNum, amount, formattedNote, receipt, CreditCardSource.PayConnectPortal);
         PayConnectResponseWeb responseWeb = new PayConnectResponseWeb()
         {
             Amount            = amount,
             PatNum            = pat.PatNum,
             ProcessingStatus  = PayConnectWebStatus.Completed,
             PayNote           = payNote,
             CCSource          = cc.CCSource,
             IsTokenSaved      = true,
             PayNum            = payNum,
             DateTimeCompleted = MiscData.GetNowDateTime(),
             RefNumber         = payConnectResponse.RefNumber,
             TransType         = PayConnectService.transType.SALE,
             PaymentToken      = cc.PayConnectToken,
         };
         //Insert a new payconnectresponse row for historical record in the transaction window.
         PayConnectResponseWebs.Insert(responseWeb);
     }
     else              //Failed
     {
         throw new ODException("Unable to process payment for this credit card: " + (payConnectResponse == null ? "Unknown error" : payConnectResponse.Status.description));
     }
 }