Skip to content

Commit 6045fc4

Browse files
committed
PayPal Plus: Testing... Cancel URL ambiguous. Getting undocumented pseudo message flag over cancel URL when buyer clicks 'continue' at PayPal (ELV or CC in sandbox).
1 parent 6e8982e commit 6045fc4

6 files changed

Lines changed: 67 additions & 47 deletions

File tree

src/Plugins/SmartStore.PayPal/Controllers/PayPalPlusController.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ public ActionResult PaymentWall()
218218
model.UseSandbox = settings.UseSandbox;
219219
model.HasPaymentFee = (settings.AdditionalFee > decimal.Zero);
220220
model.LanguageCulture = (language.LanguageCulture ?? "de_DE").Replace("-", "_");
221+
model.PayPalPlusPseudoMessageFlag = TempData["PayPalPlusPseudoMessageFlag"] as string;
221222

222223
if (customer.BillingAddress != null && customer.BillingAddress.Country != null)
223224
{
@@ -321,6 +322,17 @@ public ActionResult CheckoutReturn(string systemName, string paymentId, string P
321322
[ValidateInput(false)]
322323
public ActionResult CheckoutCancel()
323324
{
325+
// Request.QueryString:
326+
// token: EC-6JM38216F6718012L, ppp_msg: 1
327+
328+
// undocumented
329+
var pseudoMessageFlag = Request.QueryString["ppp_msg"] as string;
330+
331+
if (pseudoMessageFlag.HasValue())
332+
{
333+
TempData["PayPalPlusPseudoMessageFlag"] = pseudoMessageFlag;
334+
}
335+
324336
// back to where he came from
325337
return RedirectToAction("PaymentMethod", "Checkout", new { area = "" });
326338
}

src/Plugins/SmartStore.PayPal/Localization/resources.de-de.xml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Value>API Zugang;Datenaustausch;Sonstiges</Value>
1212
</LocaleResource>
1313
<LocaleResource Name="OrderNoteStrings">
14-
<Value><![CDATA[Antwort von PayPal:<br />{0}]]></Value>
14+
<Value><![CDATA[Mitteilung von PayPal:<br />{0}]]></Value>
1515
</LocaleResource>
1616
<LocaleResource Name="MessageStrings">
1717
<Value>Mitteilung;Ereignis;Ereignis-ID;Status;Betrag;Zahlungs-ID</Value>
@@ -28,15 +28,15 @@
2828
<LocaleResource Name="PaymentInstructionStrings">
2929
<Value>Referenz;Bankleitzahl;Bank;BIC;IBAN;Kontoinhaber;Kontonummer;Betrag;Zahlung fällig am;Details</Value>
3030
</LocaleResource>
31-
<LocaleResource Name="MissingPaymentId">
32-
<Value>Fehlende Payment-ID.</Value>
33-
</LocaleResource>
3431
<LocaleResource Name="FoundOrderForPayment">
35-
<Value>Keine Statusaktualisierung, da {0} Aufträge mit der Payment-ID {1} gefunden wurden.</Value>
32+
<Value>Mitteilung wurde ignoriert, da {0} Aufträge mit der Payment-ID {1} gefunden wurden.</Value>
3633
</LocaleResource>
3734
<LocaleResource Name="CurrencyNotEqual">
3835
<Value>Währung {0} entspricht nicht der Leitwährung des Shops {1}.</Value>
3936
</LocaleResource>
37+
<LocaleResource Name="NoApprovalUrlReturned">
38+
<Value>Keine Weiterleitungs-URL von PayPal erhalten.</Value>
39+
</LocaleResource>
4040

4141
<LocaleResource Name="ClientId">
4242
<Value>Client-ID</Value>
@@ -413,13 +413,16 @@ Die Bezahlung auf Rechnung steht möglicherweise nicht allen Händlern zur Verf
413413
Unter <a href="https://developer.paypal.com/docs/integration/admin/manage-apps/" target="paypal">Manage your applications</a> finden Sie weitere Informationen zum Thema PayPal Anwendungen (Englisch).</li>
414414
<li>Klicken Sie auf den Namen der Anwendung und tragen Sie <b>Client-ID</b> und <b>Secret</b> weiter unten auf dieser Seite ein. Speichern.</li>
415415
<li>Optional: Klicken Sie unten bei <b>Experience Profil-ID</b> auf <b>Hinzufügen</b>, um ein Profil zu erstellen. Ihre Shop-Daten (Name, Logo etc.) werden Käufern dadurch beim Bezahlen auf den PayPal-Seiten angezeigt.</li>
416-
<li>Optional: Klicken Sie unten bei <b>Webhook-ID</b> auf <b>Hinzufügen</b>, um einen Webhook zu erstellen. Über einen Webhook wird der Zahlungsstatus Ihrer Aufträge aktualisiert.</li>
416+
<li>Optional: Klicken Sie unten bei <b>Webhook-ID</b> auf <b>Hinzufügen</b>, um einen Webhook zu erstellen. Über einen Webhook empfängt der Shop PayPal-Mitteilungen und aktualisiert u.U. den Zahlungsstatus Ihrer Aufträge.</li>
417417
</ol></p>]]>
418418
</Value>
419419
</LocaleResource>
420420
<LocaleResource Name="MethodUnavailable">
421421
<Value>Wir können Ihnen leider keine PayPal PLUS Zahlungsart anbieten. Bitte versuchen Sie er später erneut.</Value>
422422
</LocaleResource>
423+
<LocaleResource Name="SorryFailure">
424+
<Value>Entschuldigung, das hat gerade nicht funktioniert. Bitte versuchen Sie es erneut oder wählen Sie eine andere Zahlungsmethode.</Value>
425+
</LocaleResource>
423426
<LocaleResource Name="ThirdPartyPaymentMethods">
424427
<Value>Weitere Zahlarten</Value>
425428
</LocaleResource>

src/Plugins/SmartStore.PayPal/Localization/resources.en-us.xml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<Value>API access;Data exchange;Miscellaneous</Value>
1212
</LocaleResource>
1313
<LocaleResource Name="OrderNoteStrings">
14-
<Value><![CDATA[Response from PayPal:<br />{0}]]></Value>
14+
<Value><![CDATA[Message from PayPal:<br />{0}]]></Value>
1515
</LocaleResource>
1616
<LocaleResource Name="MessageStrings">
1717
<Value>Message;Event;Event-ID;State;Amount;Payment-ID</Value>
@@ -31,15 +31,15 @@
3131
<LocaleResource Name="PaymentInstructionStrings">
3232
<Value>Reference;Bank routing number;Bank;BIC;IBAN;Account holder;Account number;Amount;Payment due date;Details</Value>
3333
</LocaleResource>
34-
<LocaleResource Name="MissingPaymentId">
35-
<Value>Missing payment ID.</Value>
36-
</LocaleResource>
3734
<LocaleResource Name="FoundOrderForPayment">
38-
<Value>No status update because {0} orders with payment ID {1} found.</Value>
35+
<Value>Message has been ignored because {0} orders with payment ID {1} found.</Value>
3936
</LocaleResource>
4037
<LocaleResource Name="CurrencyNotEqual">
4138
<Value>Currency {0} does not equal primary store currency {1}.</Value>
4239
</LocaleResource>
40+
<LocaleResource Name="NoApprovalUrlReturned">
41+
<Value>No redirect URL received from PayPal.</Value>
42+
</LocaleResource>
4343

4444
<LocaleResource Name="ClientId">
4545
<Value>Client ID</Value>
@@ -413,13 +413,16 @@ Pay upon invoice may not be available for all merchants. PayPal PLUS only suppor
413413
Go to <a href="https://developer.paypal.com/docs/integration/admin/manage-apps/" target="paypal">Manage your applications</a> to get more information about PayPal applications.</li>
414414
<li>Click the name of the application and enter <b>Client-ID</b> and <b>Secret</b> below on this page. Save.</li>
415415
<li>Optional: Click <b>Add</b> next to <b>Experience profile ID</b> to create a new profile. Your shop data (name, logo etc.) can now be displayed to customers when paying on PayPal pages.</li>
416-
<li>Optional: Click <b>Add</b> next to <b>Webhook-ID</b> to create a webhook. The payment state of your orders can be updated through a webhook.</li>
416+
<li>Optional: Click <b>Add</b> next to <b>Webhook-ID</b> to create a webhook. Through a webhook the shop receives PayPal messages und possibly updates the payment state of your orders.</li>
417417
</ol></p>]]>
418418
</Value>
419419
</LocaleResource>
420420
<LocaleResource Name="MethodUnavailable">
421421
<Value>Unfortunately we cannot offer you a PayPal PLUS payment method. Please try again later.</Value>
422422
</LocaleResource>
423+
<LocaleResource Name="SorryFailure">
424+
<Value>I'm sorry, that just didn't work. Please try again or select another payment method.</Value>
425+
</LocaleResource>
423426
<LocaleResource Name="ThirdPartyPaymentMethods">
424427
<Value>More payment methods</Value>
425428
</LocaleResource>

src/Plugins/SmartStore.PayPal/Models/PayPalPlusCheckoutModel.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public class PayPalPlusCheckoutModel : ModelBase
1111
public string LanguageCulture { get; set; }
1212
public string ApprovalUrl { get; set; }
1313
public string ErrorMessage { get; set; }
14+
public string PayPalPlusPseudoMessageFlag { get; set; }
1415

1516
public List<ThirdPartyPaymentMethod> ThirdPartyPaymentMethods { get; set; }
1617

src/Plugins/SmartStore.PayPal/Services/PayPalService.cs

Lines changed: 26 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
using Newtonsoft.Json.Linq;
1212
using SmartStore.Core.Data;
1313
using SmartStore.Core.Domain.Common;
14+
using SmartStore.Core.Domain.Customers;
1415
using SmartStore.Core.Domain.Discounts;
1516
using SmartStore.Core.Domain.Logging;
1617
using SmartStore.Core.Domain.Orders;
@@ -79,7 +80,7 @@ public PayPalService(
7980
public Localizer T { get; set; }
8081
public ILogger Logger { get; set; }
8182

82-
private Dictionary<string, object> CreateAddress(Address addr)
83+
private Dictionary<string, object> CreateAddress(Address addr, bool addRecipientName)
8384
{
8485
var dic = new Dictionary<string, object>();
8586

@@ -104,7 +105,10 @@ private Dictionary<string, object> CreateAddress(Address addr)
104105
dic.Add("state", addr.StateProvince.Abbreviation.Truncate(100));
105106
}
106107

107-
dic.Add("recipient_name", addr.GetFullName().Truncate(50));
108+
if (addRecipientName)
109+
{
110+
dic.Add("recipient_name", addr.GetFullName().Truncate(50));
111+
}
108112

109113
return dic;
110114
}
@@ -595,6 +599,8 @@ public PayPalResponse CreatePayment(
595599
var language = _services.WorkContext.WorkingLanguage;
596600
var currencyCode = store.PrimaryStoreCurrency.CurrencyCode;
597601

602+
var dateOfBirth = customer.GetAttribute<DateTime?>(SystemCustomerAttributeNames.DateOfBirth);
603+
598604
Discount orderAppliedDiscount;
599605
List<AppliedGiftCard> appliedGiftCards;
600606
int redeemedRewardPoints = 0;
@@ -611,7 +617,6 @@ public PayPalResponse CreatePayment(
611617
var total = (_orderTotalCalculationService.GetShoppingCartTotal(cart, out orderDiscountInclTax, out orderAppliedDiscount, out appliedGiftCards,
612618
out redeemedRewardPoints, out redeemedRewardPointsAmount) ?? decimal.Zero);
613619

614-
var path = "/v1/payments/payment";
615620
var data = new Dictionary<string, object>();
616621
var redirectUrls = new Dictionary<string, object>();
617622
var payer = new Dictionary<string, object>();
@@ -622,9 +627,6 @@ public PayPalResponse CreatePayment(
622627
var items = new List<Dictionary<string, object>>();
623628
var itemList = new Dictionary<string, object>();
624629

625-
if (session.PaymentId.HasValue())
626-
path = string.Concat(path, "/", HttpUtility.UrlPathEncode(session.PaymentId));
627-
628630
// "PayPal PLUS only supports transaction type “Sale” (instant settlement)"
629631
if (providerSystemName == PayPalPlusProvider.SystemName)
630632
data.Add("intent", "sale");
@@ -644,16 +646,18 @@ public PayPalResponse CreatePayment(
644646
if (redirectUrls.Any())
645647
data.Add("redirect_urls", redirectUrls);
646648

647-
// payer
648-
payer.Add("payment_method", "paypal");
649-
649+
// payer, payer_info
650+
if (dateOfBirth.HasValue)
651+
{
652+
payerInfo.Add("birth_date", dateOfBirth.Value.ToString("yyyy-MM-dd"));
653+
}
650654
if (customer.BillingAddress != null)
651655
{
652-
payerInfo.Add("billing_address", CreateAddress(customer.BillingAddress));
653-
654-
payer.Add("payer_info", payerInfo);
656+
payerInfo.Add("billing_address", CreateAddress(customer.BillingAddress, false));
655657
}
656658

659+
payer.Add("payment_method", "paypal");
660+
payer.Add("payer_info", payerInfo);
657661
data.Add("payer", payer);
658662

659663
// line items
@@ -691,7 +695,7 @@ public PayPalResponse CreatePayment(
691695
itemList.Add("items", items);
692696
if (customer.ShippingAddress != null)
693697
{
694-
itemList.Add("shipping_address", CreateAddress(customer.ShippingAddress));
698+
itemList.Add("shipping_address", CreateAddress(customer.ShippingAddress, true));
695699
}
696700

697701
// transactions
@@ -724,15 +728,15 @@ public PayPalResponse CreatePayment(
724728

725729
data.Add("transactions", new List<Dictionary<string, object>> { transaction });
726730

727-
var result = CallApi("POST", path, session.AccessToken, settings, JsonConvert.SerializeObject(data));
731+
var result = CallApi("POST", "/v1/payments/payment", session.AccessToken, settings, JsonConvert.SerializeObject(data));
728732

729733
if (result.Success && result.Json != null)
730734
{
731735
result.Id = (string)result.Json.id;
732-
733-
//Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + result.Json.ToString());
734736
}
735737

738+
Logger.InsertLog(LogLevel.Information, "PayPal PLUS", JsonConvert.SerializeObject(data, Formatting.Indented) + "\r\n\r\n" + (result.Json != null ? result.Json.ToString() : ""));
739+
736740
return result;
737741
}
738742

@@ -756,24 +760,16 @@ public PayPalResponse ExecutePayment(PayPalApiSettingsBase settings, PayPalSessi
756760
public PayPalResponse Refund(PayPalApiSettingsBase settings, PayPalSessionData session, RefundPaymentRequest request)
757761
{
758762
var data = new Dictionary<string, object>();
763+
var store = _services.StoreService.GetStoreById(request.Order.StoreId);
759764
var isSale = request.Order.AuthorizationTransactionResult.Contains("(sale)");
760765

761766
var path = "/v1/payments/{0}/{1}/refund".FormatInvariant(isSale ? "sale" : "capture", request.Order.CaptureTransactionId);
762767

763-
if (isSale && !request.IsPartialRefund)
764-
{
765-
// no body required
766-
}
767-
else
768-
{
769-
var store = _services.StoreService.GetStoreById(request.Order.StoreId);
770-
771-
var amount = new Dictionary<string, object>();
772-
amount.Add("total", Math.Round(request.AmountToRefund, 2));
773-
amount.Add("currency", store.PrimaryStoreCurrency.CurrencyCode);
768+
var amount = new Dictionary<string, object>();
769+
amount.Add("total", Math.Round(request.AmountToRefund, 2));
770+
amount.Add("currency", store.PrimaryStoreCurrency.CurrencyCode);
774771

775-
data.Add("amount", amount);
776-
}
772+
data.Add("amount", amount);
777773

778774
var result = CallApi("POST", path, session.AccessToken, settings, data.Any() ? JsonConvert.SerializeObject(data) : null);
779775

@@ -955,8 +951,6 @@ public HttpStatusCode ProcessWebhook(
955951
//foreach (var key in headers.AllKeys)"{0}: {1}".FormatInvariant(key, headers[key]).Dump();
956952
//string data = JsonConvert.SerializeObject(json, Formatting.Indented);data.Dump();
957953

958-
if (eventType.IsEmpty() || json.resource == null)
959-
return HttpStatusCode.OK;
960954

961955
// validating against PayPal SDK failing using sandbox, so better we do not use it:
962956
//var apiContext = new global::PayPal.Api.APIContext
@@ -976,7 +970,7 @@ public HttpStatusCode ProcessWebhook(
976970
var paymentId = (string)json.resource.parent_payment;
977971
if (paymentId.IsEmpty())
978972
{
979-
LogError(null, T("Plugins.SmartStore.PayPal.MissingPaymentId"), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true);
973+
LogError(null, T("Plugins.SmartStore.PayPal.FoundOrderForPayment", 0, "".NaIfEmpty()), JsonConvert.SerializeObject(json, Formatting.Indented), isWarning: true);
980974
return HttpStatusCode.OK;
981975
}
982976

src/Plugins/SmartStore.PayPal/Views/PayPalPlus/PaymentWall.cshtml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
@{
55
Layout = "~/Views/Shared/_Checkout.cshtml";
66
Html.AddTitleParts(T("PageTitle.Checkout").Text);
7-
//Html.AddCssFileParts(true, Url.Content("~/Plugins/SmartStore.PayPal/Content/smartstore.paypal.css"));
87
}
98
@section orderProgress
109
{
@@ -27,9 +26,19 @@
2726
<div class="alert alert-error">
2827
@Html.Raw(T("Plugins.Payments.PayPalPlus.MethodUnavailable"))
2928
<br />
29+
@if (!Model.ApprovalUrl.HasValue())
30+
{
31+
@T("Plugins.SmartStore.PayPal.NoApprovalUrlReturned")
32+
}
3033
@Model.ErrorMessage
3134
</div>
3235
}
36+
else if (Model.PayPalPlusPseudoMessageFlag.HasValue() && Model.PayPalPlusPseudoMessageFlag == "1")
37+
{
38+
<div class="alert alert-error">
39+
@Html.Raw(T("Plugins.Payments.PayPalPlus.SorryFailure"))
40+
</div>
41+
}
3342

3443
<div id="PayPalPlusPaymentWall"></div>
3544

@@ -38,8 +47,6 @@
3847
<i class="fa fa-caret-left"></i>&nbsp;@T("Common.Back")
3948
</a>
4049

41-
@*TODO: reward points*@
42-
4350
<button id="PayPalPlusNextCheckoutStep" class="btn btn-warning pull-right payment-method-next-step-button hide">
4451
@T("Checkout.NextButton")&nbsp;<i class="fa fa-caret-right"></i>
4552
</button>

0 commit comments

Comments
 (0)