public CheckoutResult CheckoutWithPayPalExpressCheckout(Dictionary <string, string> payPalVariables) { string token = payPalVariables["token"]; string payerId = payPalVariables["PayerID"]; PayPalExpressCheckoutPaymentProvider payPalExpress = new PayPalExpressCheckoutPaymentProvider(storeContext.CurrentStore.GetPaymentProviderConfig(PaymentProviderName.PayPalExpressCheckout)); int? orderId = payPalExpress.GetOrderIdForTransactionToken(token); Order pendingOrder = Order.GetOrder(orderId.GetValueOrDefault(-1)); if (pendingOrder != null) { PaymentStatusName paymentStatus = payPalExpress.DoExpressCheckoutPayment(pendingOrder, payPalVariables); OrderStatusName orderStatus = pendingOrder.OrderStatus; if (paymentStatus == PaymentStatusName.Completed) { orderStatus = OrderStatusName.Completed; pendingOrder.CreditCardType = CreditCardType.PayPal.ToString(); } UpdateOrderStatus(pendingOrder, orderStatus, paymentStatus); } return(DoPostCheckoutProcessing(pendingOrder, true)); }
internal void UpdateOrderStatus(Order order, OrderStatusName orderStatusName, PaymentStatusName paymentStatusName) { OrderStatusName oldOrderStatus = order.OrderStatus; PaymentStatusName oldPaymentStatus = order.PaymentStatus; order.PaymentStatus = paymentStatusName; order.OrderStatus = orderStatusName; //if (order.PaymentStatus == PaymentStatusName.Completed && !(order.OrderStatus == OrderStatusName.Paid || order.OrderStatus == OrderStatusName.Completed)) //{ // order.OrderStatus = OrderStatusName.Paid; //} order.Save(); if (oldPaymentStatus != paymentStatusName) { //--- Payment Status has changed... if (paymentStatusName == PaymentStatusName.Completed && WA.Parser.ToBool(storeContext.CurrentStore.GetSetting(StoreSettingNames.SendPaymentCompleteEmail)).GetValueOrDefault(true)) { // send "PaymentCompleted" email EmailController emailController = new EmailController(); TokenHelper tokenHelper = new TokenHelper(storeContext); Dictionary <string, string> emailTokens = tokenHelper.GetOrderTokens(order, true); string emailResponse = emailController.SendEmailTemplate(EmailTemplateNames.PaymentCompleted, emailTokens, order.CustomerEmail, order.UpToStoreByStoreId); } } if (oldOrderStatus != orderStatusName) { // TODO Order Status has changed... send emails ?? } }
public CheckoutResult CheckoutWithOnSitePayment(CheckoutOrderInfo checkoutOrderInfo) { if (!checkoutOrderInfo.RequiresPayment) { checkoutOrderInfo.PaymentProvider = PaymentProviderName.None; } CheckoutOrderValidator checkoutOrderValidator = new CheckoutOrderValidator(); ValidationResult validationResult = checkoutOrderValidator.Validate(checkoutOrderInfo); if (validationResult.IsValid) { Order pendingOrder = CreateOrder(checkoutOrderInfo, OrderStatusName.Processing); if (checkoutOrderInfo.PaymentProvider != PaymentProviderName.None) { PaymentStatusName paymentStatus = pendingOrder.PaymentStatus; if (pendingOrder.PaymentStatus != PaymentStatusName.Completed) { PaymentProvider paymentProcessor = PaymentProviderFactory.GetProvider(checkoutOrderInfo.PaymentProvider, storeContext.CurrentStore); HttpWebResponse response = paymentProcessor.SubmitDirectPaymentRequest(pendingOrder, checkoutOrderInfo.CreditCard); paymentStatus = paymentProcessor.ProcessDirectPaymentResponse(pendingOrder, response); } OrderStatusName orderStatus = (paymentStatus == PaymentStatusName.Completed) ? OrderStatusName.Processing : pendingOrder.OrderStatus; UpdateOrderStatus(pendingOrder, orderStatus, paymentStatus); pendingOrder.Save(); } else { // does not require payment (free order / order total == 0) UpdateOrderStatus(pendingOrder, OrderStatusName.Processing, PaymentStatusName.Completed); } return(DoPostCheckoutProcessing(pendingOrder, true)); } else { // failed validation return(new CheckoutResult() { SubmittedOrder = null, Errors = validationResult.Errors.ToList().ConvertAll(e => e.ErrorMessage) }); } }
public CheckoutResult CheckoutWithPayPalStandardCheckout(HttpRequest request) { Order order = null; PayPalStandardProvider payPalStandard = new PayPalStandardProvider(storeContext.CurrentStore.GetPaymentProviderConfig(PaymentProviderName.PayPalStandard)); int?orderId; if (payPalStandard.IsIpnResponse(request, out orderId)) { // user arrived here through a redirect from PayPal Checkout Page // so we have "IPN" variables in the Request that we can process order = new Order(); if (order.LoadByPrimaryKey(orderId.GetValueOrDefault(-1))) { Exceptions.LogException(new Exception("Loaded order")); PaymentStatusName paymentStatus = payPalStandard.ProcessOffsitePaymentResponse(order, request); Exceptions.LogException(new Exception("paymentStatus:" + paymentStatus)); OrderStatusName orderStatus = order.OrderStatus; Exceptions.LogException(new Exception("orderStatus:" + orderStatus)); if (paymentStatus == PaymentStatusName.Completed) { orderStatus = OrderStatusName.Processing; order.CreditCardType = CreditCardType.PayPal.ToString(); } if (order.PaymentStatus != paymentStatus || order.OrderStatus != orderStatus) { Exceptions.LogException(new Exception("Updating Order Status")); UpdateOrderStatus(order, orderStatus, paymentStatus); Exceptions.LogException(new Exception("Updated Order Status")); return(DoPostCheckoutProcessing(order, true)); } return(DoPostCheckoutProcessing(order, false)); } } else { Exceptions.LogException(new Exception("NOT AN IPN RESPONSE!")); } return(null); }
public override PaymentStatusName ProcessDirectPaymentResponse(Order order, HttpWebResponse response) { string responseString = HttpHelper.WebResponseToString(response); // Decode the response fields from PayPal API string[] encodedPairs = responseString.Split('&'); Dictionary <string, string> fields = new Dictionary <string, string>(encodedPairs.Length); foreach (string field in encodedPairs) { string[] pair = field.Split('='); string name = HttpUtility.UrlDecode(pair[0]); string value = HttpUtility.UrlDecode(pair[1]); fields[name] = value; } // parse response fields into variables string ack = fields["ACK"]; AckValues ackType = WA.Enum <AckValues> .TryParseOrDefault(ack, AckValues.Failure); int? orderId = WA.Parser.ToInt(fields.TryGetValueOrEmpty("CUSTOM")); string transactionId = fields.TryGetValueOrEmpty("TRANSACTIONID"); decimal?amount = WA.Parser.ToDecimal(fields.TryGetValueOrEmpty("AMT")); string error1Code = fields.TryGetValueOrEmpty("L_ERRORCODE0"); string error1ShortMsg = fields.TryGetValueOrEmpty("L_SHORTMESSAGE0"); string error1LongMsg = fields.TryGetValueOrEmpty("L_LONGMESSAGE0"); string error1Severity = fields.TryGetValueOrEmpty("L_SEVERITYCODE0"); PaymentTransaction newTransaction = new PaymentTransaction(); newTransaction.OrderId = order.Id; newTransaction.PaymentProviderId = this.ProviderId; newTransaction.GatewayUrl = ProviderUrl; newTransaction.GatewayTransactionId = transactionId; newTransaction.GatewayDebugResponse = HttpUtility.UrlDecode(responseString); newTransaction.Amount = amount; PaymentStatusName paymentStatus = order.PaymentStatus; if (ackType == AckValues.Success || ackType == AckValues.SuccessWithWarning) { bool paymentAmountMatches = (amount.GetValueOrDefault(-1) == order.Total.Value); if (paymentAmountMatches) { newTransaction.GatewayResponse = ackType.ToString(); paymentStatus = PaymentStatusName.Completed; } else { newTransaction.GatewayResponse = ackType.ToString() + " Amount from Payment Provider does not match the Order amount."; paymentStatus = PaymentStatusName.Pending; } if (ackType == AckValues.SuccessWithWarning) { newTransaction.GatewayError = ackType.ToString() + string.Format(@" ErrorCode: {0}, ShortMsg: {1}, LongMsg: {2}, SeverityCode: {3}", error1Code, error1ShortMsg, error1LongMsg, error1Severity); } } else if (ackType == AckValues.Failure || ackType == AckValues.FailureWithWarning || ackType == AckValues.Warning) { newTransaction.GatewayError = ackType.ToString() + string.Format(@" ErrorCode: {0}, ShortMsg: {1}, LongMsg: {2}, SeverityCode: {3}", error1Code, error1ShortMsg, error1LongMsg, error1Severity); paymentStatus = PaymentStatusName.ProviderError; } else { newTransaction.GatewayError = ack + " Invalid / Unknown Response from Payment Provider"; paymentStatus = PaymentStatusName.ProviderError; } newTransaction.Save(); return(paymentStatus); }
// Step 3. public PaymentStatusName DoExpressCheckoutPayment(Order order, Dictionary <string, string> payPalVariables) { string token = payPalVariables["token"]; string payerId = payPalVariables["PayerID"]; Dictionary <string, string> vars = new Dictionary <string, string>(); vars["METHOD"] = "DoExpressCheckoutPayment"; vars["VERSION"] = "60.0"; vars["USER"] = ApiUsername; vars["PWD"] = ApiPassword; vars["SIGNATURE"] = ApiSignature; vars["TOKEN"] = token; vars["PAYERID"] = payerId; IEnumerable <OrderItem> orderitems = order.OrderItemCollectionByOrderId; int itemNumber = 0; foreach (OrderItem orderItem in orderitems) { string orderItemAttributes = orderItem.GetProductFieldDataPlainTextDisplayString(); vars["L_NAME" + itemNumber] = orderItem.Name.Left(127); vars["L_DESC" + itemNumber] = (!string.IsNullOrEmpty(orderItemAttributes) ? " (" + orderItemAttributes + ")" : "").Left(127); vars["L_AMT" + itemNumber] = orderItem.PriceForSingleItem.ToString("N2"); vars["L_QTY" + itemNumber] = orderItem.Quantity.Value.ToString("N0"); vars["L_NUMBER" + itemNumber] = (!string.IsNullOrEmpty(orderItem.Sku) ? " (" + orderItem.Sku + ")" : ""); itemNumber++; } vars["PAYMENTACTION"] = "Sale"; vars["AMT"] = order.Total.Value.ToString("N2"); vars["CURRENCYCODE"] = order.UpToStoreByStoreId.Currency.Code; // Send Http POST to PayPal HttpWebResponse webResponse = HttpHelper.HttpPost(ProviderUrl, vars); string responseString = HttpHelper.WebResponseToString(webResponse); // Decode the response fields from PayPal API Dictionary <string, string> fields = HttpHelper.DecodeVarsFromHttpString(responseString); // parse response fields into variables string ack = fields["ACK"]; AckValues ackType = WA.Enum <AckValues> .TryParseOrDefault(ack, AckValues.Failure); string correlationId = fields.TryGetValueOrEmpty("CORRELATIONID"); string transactionId = fields.TryGetValueOrEmpty("TOKEN"); decimal?amount = WA.Parser.ToDecimal(fields.TryGetValueOrEmpty("AMT")); decimal?taxAmount = WA.Parser.ToDecimal(fields.TryGetValueOrEmpty("TAXAMT")); // TODO - do we need shipping amount too? PaymentTransaction newTransaction = new PaymentTransaction(); newTransaction.OrderId = order.Id; newTransaction.PaymentProviderId = this.ProviderId; newTransaction.GatewayUrl = ProviderUrl; newTransaction.GatewayTransactionId = transactionId; newTransaction.GatewayResponse = vars["METHOD"] + ": " + ack; newTransaction.GatewayDebugResponse = HttpUtility.UrlDecode(responseString); PaymentStatusName paymentStatus = order.PaymentStatus; if (ackType == AckValues.Success || ackType == AckValues.SuccessWithWarning) { bool paymentAmountMatches = (amount.GetValueOrDefault(-1) == order.Total.Value); if (paymentAmountMatches) { paymentStatus = PaymentStatusName.Completed; newTransaction.Amount = amount; } else { newTransaction.GatewayError = string.Format("Payment amount does not match Order Total. Order total {0:N2}. Payment amount {1:N2}", order.Total, amount); if (amount >= order.Total) { paymentStatus = PaymentStatusName.Completed; newTransaction.Amount = amount; } else { paymentStatus = PaymentStatusName.Pending; } } } else { newTransaction.GatewayError = ack + " Invalid / Unknown Response from Payment Provider"; paymentStatus = PaymentStatusName.ProviderError; } newTransaction.Save(); return(paymentStatus); }
internal void UpdatePaymentStatus(Order order, PaymentStatusName paymentStatus) { UpdateOrderStatus(order, order.OrderStatus, paymentStatus); }
public override PaymentStatusName ProcessDirectPaymentResponse(Order order, HttpWebResponse response) { // returned values are returned as a stream, then read into a string string responseString = HttpHelper.WebResponseToString(response); // the response string is broken into an array // The split character specified here must match the delimiting character specified above string[] fields = responseString.Split(fieldDelimiterChar); ResponseCode responseCode = WA.Enum <ResponseCode> .TryParseOrDefault(fields[0], ResponseCode.Error); string responseSubcode = fields[1]; int? responseReasonCode = WA.Parser.ToInt(fields[2]); string responseReasonText = fields[3]; // could show this to the customer string authorizationCode = fields[4]; string avsResponse = fields[5]; string transactionId = fields[6]; int? orderId = WA.Parser.ToInt(fields[7]); // "Invoice Number" in Auth.Net docs string description = fields[8]; decimal?amount = WA.Parser.ToDecimal(fields[9]); string method = fields[10]; string transactionType = fields[11]; string customerId = fields[12]; //.... fields omitted here.... string md5Hash = fields[37]; string cardCodeResponse = fields[38]; // result of CCV verification string cavvResponse = fields[39]; // Cardholder Authentication Verification Response // Custom Merchant-Defined Fields (Pg. 36/37 of Auth.Net Docs) if (fields.Length >= 69) // custom fields start at position 69 { // grab any add'l merchant-defined fields here... } PaymentTransaction newTransaction = new PaymentTransaction(); newTransaction.OrderId = order.Id; newTransaction.PaymentProviderId = this.ProviderId; newTransaction.GatewayUrl = ProviderUrl; newTransaction.GatewayTransactionId = transactionId; newTransaction.GatewayDebugResponse = responseString; newTransaction.Amount = amount; PaymentStatusName paymentStatus = order.PaymentStatus; if (responseCode == ResponseCode.Approved) { bool paymentAmountMatches = (amount.GetValueOrDefault(-1) == order.Total.Value); if (paymentAmountMatches) { newTransaction.GatewayResponse = "Approved"; paymentStatus = PaymentStatusName.Completed; } else { newTransaction.GatewayResponse = "Payment amount does not match the order amount."; paymentStatus = PaymentStatusName.Pending; } } else if (responseCode == ResponseCode.Declined) { newTransaction.GatewayError = string.Format("Payment was declined. {1} (Response Reason Code: {0}).", responseReasonCode, responseReasonText); paymentStatus = PaymentStatusName.Denied; } else if (responseCode == ResponseCode.Error) { newTransaction.GatewayError = string.Format("{1} (Response Reason Code: {0}).", responseReasonCode, responseReasonText); paymentStatus = PaymentStatusName.ProviderError; } else if (responseCode == ResponseCode.HeldForReview) { newTransaction.GatewayError = string.Format("Payment has been held for review by Authorize.Net. {1} (Response Reason Code: {0}).", responseReasonCode, responseReasonText); paymentStatus = PaymentStatusName.Pending; } else { newTransaction.GatewayError = "Invalid / Unknown Response from Payment Provider"; paymentStatus = PaymentStatusName.ProviderError; } newTransaction.Save(); return(paymentStatus); }
public override PaymentStatusName ProcessOffsitePaymentResponse(Order order, HttpRequest request) { //---- Need to validate the incoming request with PayPal so we know it's authentic Dictionary <string, string> requestParams = HttpHelper.DecodeParamsFromHttpRequest(request); string requestDataString = HttpHelper.EncodeVarsForHttpPostString(requestParams); // send our modified request back to PayPal for validation string postData = requestDataString + "&cmd=_notify-validate"; HttpWebResponse payPalResponse = HttpHelper.HttpPost(ProviderUrl, postData); string payPalResponseString = HttpHelper.WebResponseToString(payPalResponse); // Parse response into some variables NameValueCollection fields = request.Params; string paymentStatus = fields["payment_status"]; string transactionId = fields["txn_id"]; string receiverEmail = fields["receiver_email"]; string businessEmail = fields["business"]; int? orderId = WA.Parser.ToInt(fields["custom"]); decimal?paymentAmount = WA.Parser.ToDecimal(fields["mc_gross"]); // amount before PayPal fee is subtracted decimal?payPalTransactionFee = WA.Parser.ToDecimal(fields["mc_fee"]); decimal shippingAmount = WA.Parser.ToDecimal(fields["mc_shipping"]).GetValueOrDefault(0); decimal handlingAmount = WA.Parser.ToDecimal(fields["mc_handling"]).GetValueOrDefault(0); decimal taxAmount = WA.Parser.ToDecimal(fields["tax"]).GetValueOrDefault(0); string firstName = fields["first_name"] ?? ""; string lastName = fields["last_name"] ?? ""; string email = fields["payer_email"] ?? ""; string phone = fields["contact_phone"] ?? ""; string shipName = fields["address_name"] ?? ""; string shipAddress1 = fields["address_street"] ?? ""; string shipCity = fields["address_city"] ?? ""; string shipRegion = fields["address_state"] ?? ""; string shipPostalCode = fields["address_zip"] ?? ""; string shipCountryCode = fields["address_country_code"] ?? ""; PaymentStatusName paymentStatusName = order.PaymentStatus; bool isValidReceiverEmail = (receiverEmail == EmailAddress) || (businessEmail == EmailAddress); PaymentTransaction newTransaction = new PaymentTransaction(); newTransaction.OrderId = orderId; newTransaction.PaymentProviderId = this.ProviderId; newTransaction.GatewayUrl = ProviderUrl; newTransaction.GatewayTransactionId = transactionId; newTransaction.GatewayResponse = paymentStatus; newTransaction.GatewayDebugResponse = requestDataString; newTransaction.Amount = paymentAmount; if (payPalResponseString != "VERIFIED") { newTransaction.GatewayError = "Invalid/Unknown response or response could not be validated as authentic"; newTransaction.Save(); return(PaymentStatusName.ProviderError); } if (!isValidReceiverEmail) { newTransaction.GatewayError = "Receiver Email does not match PayPal Account"; newTransaction.Save(); return(PaymentStatusName.ProviderError); } //Order pendingOrder = Order.GetOrder(orderId); if (payPalResponseString == "VERIFIED") { // check if we have already processed this transaction successfully // we might already have processed the IPN callback, and the user clicks "return to store" // which would trigger another transaction PaymentTransaction priorTransaction = PaymentTransaction.GetMostRecentByTransactionId(transactionId); if (priorTransaction != null && priorTransaction.OrderId == orderId) { // we have a duplicate transaction, we should NOT process this new one return(order.PaymentStatus); } //check the payment_status is Completed bool paymentStatusComplete = (paymentStatus.ToLower() == "completed"); if (paymentAmount.GetValueOrDefault(-1) < order.Total.Value) { newTransaction.GatewayError = string.Format("Payment amount does not match Order Total. Order total {0:N2}. Payment amount {1:N2}", order.Total, paymentAmount); newTransaction.Save(); return(PaymentStatusName.ProviderError); } //if (paymentStatusComplete && paymentAmountMatches && receiverEmailMatches) if (paymentStatusComplete) { newTransaction.GatewayResponse = "Verified Payment Completed"; if (request.RawUrl.Contains("PayPalIpnHandler.aspx")) { newTransaction.GatewayResponse += " via IPN"; } else if (request.RawUrl.Contains("Checkout-Complete.aspx")) { newTransaction.GatewayResponse += " via return button from PayPal"; } paymentStatusName = PaymentStatusName.Completed; //---- Update the Order order.CustomerFirstName = firstName; order.CustomerLastName = lastName; order.CustomerEmail = email; order.ShipRecipientName = shipName; order.ShipAddress1 = shipAddress1; //order.ShipAddress2 = shipAddress2; order.ShipCity = shipCity; order.ShipRegion = shipRegion; order.ShipPostalCode = shipPostalCode; order.ShipCountryCode = shipCountryCode; order.ShipTelephone = phone; order.BillAddress1 = shipAddress1; //order.BillAddress2 = shipAddress2; order.BillCity = shipCity; order.BillRegion = shipRegion; order.BillPostalCode = shipPostalCode; order.BillCountryCode = shipCountryCode; order.BillTelephone = phone; // PayPal 'paymentAmount' is the total amount paid by customer // so we need to do some basic math to get the other order amounts... order.ShippingAmount = shippingAmount + handlingAmount; order.TaxAmount = taxAmount; order.SubTotal = paymentAmount - (order.ShippingAmount + order.TaxAmount); order.Total = paymentAmount; order.Save(); } newTransaction.Save(); } return(paymentStatusName); }