Skip to content

Commit 6c3d3cb

Browse files
committed
PayPal Plus: Void and capturing
1 parent a8be8ce commit 6c3d3cb

3 files changed

Lines changed: 164 additions & 40 deletions

File tree

src/Plugins/SmartStore.PayPal/Providers/PayPalRestApiProviderBase.cs

Lines changed: 67 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -93,41 +93,41 @@ public override ProcessPaymentResult ProcessPayment(ProcessPaymentRequest proces
9393
if (apiResult.Success && apiResult.Json != null)
9494
{
9595
var state = (string)apiResult.Json.state;
96+
string reasonCode = null;
97+
dynamic relatedObject = null;
9698

9799
if (!state.IsCaseInsensitiveEqual("failed"))
98100
{
99101
// intent: "sale" for immediate payment, "authorize" for pre-authorized payments and "order" for an order.
100102
// info required cause API has different endpoints for different intents.
101103
result.AuthorizationTransactionCode = (string)apiResult.Json.intent;
102104

103-
var sale = apiResult.Json.transactions[0].related_resources[0].sale;
105+
if (result.AuthorizationTransactionCode.IsCaseInsensitiveEqual("sale"))
106+
{
107+
relatedObject = apiResult.Json.transactions[0].related_resources[0].sale;
104108

105-
if (sale != null)
109+
session.PaymentInstruction = PayPalService.ParsePaymentInstruction(apiResult.Json.payment_instruction) as PayPalPaymentInstruction;
110+
}
111+
else
106112
{
107-
state = (string)sale.state;
113+
relatedObject = apiResult.Json.transactions[0].related_resources[0].authorization;
114+
}
108115

109-
result.AuthorizationTransactionResult = state;
110-
result.AuthorizationTransactionId = (string)sale.id;
116+
if (relatedObject != null)
117+
{
118+
state = (string)relatedObject.state;
119+
reasonCode = (string)relatedObject.reason_code;
111120

112-
result.NewPaymentStatus = PaymentStatus.Authorized;
121+
result.AuthorizationTransactionResult = state;
122+
result.AuthorizationTransactionId = (string)relatedObject.id;
113123

114-
if (state.IsCaseInsensitiveEqual("completed") || state.IsCaseInsensitiveEqual("processed"))
115-
{
116-
result.CaptureTransactionResult = state;
117-
result.CaptureTransactionId = (string)sale.id;
124+
result.NewPaymentStatus = PayPalService.GetPaymentStatus(state, reasonCode, PaymentStatus.Authorized);
118125

119-
result.NewPaymentStatus = PaymentStatus.Paid;
120-
}
121-
else if (state.IsCaseInsensitiveEqual("pending"))
126+
if (result.NewPaymentStatus == PaymentStatus.Paid)
122127
{
123-
var reasonCode = (string)sale.reason_code;
124-
if (reasonCode.IsCaseInsensitiveEqual("ECHECK"))
125-
{
126-
result.NewPaymentStatus = PaymentStatus.Pending;
127-
}
128+
result.CaptureTransactionResult = result.AuthorizationTransactionResult;
129+
result.CaptureTransactionId = result.AuthorizationTransactionId;
128130
}
129-
130-
session.PaymentInstruction = PayPalService.ParsePaymentInstruction(apiResult.Json.payment_instruction) as PayPalPaymentInstruction;
131131
}
132132
}
133133
else
@@ -168,33 +168,48 @@ public override CapturePaymentResult Capture(CapturePaymentRequest capturePaymen
168168
};
169169

170170
var settings = Services.Settings.LoadSetting<TSetting>(capturePaymentRequest.Order.StoreId);
171-
var currencyCode = Services.WorkContext.WorkingCurrency.CurrencyCode ?? "EUR";
171+
var session = new PayPalSessionData();
172+
173+
var apiResult = PayPalService.EnsureAccessToken(session, settings);
174+
if (result.Success)
175+
{
176+
apiResult = PayPalService.Capture(settings, session, capturePaymentRequest);
172177

173-
var authorizationId = capturePaymentRequest.Order.AuthorizationTransactionId;
174-
175-
// TODO
178+
if (apiResult.Success)
179+
{
180+
result.NewPaymentStatus = PaymentStatus.Paid;
181+
}
182+
else
183+
{
184+
result.Errors.Add(apiResult.ErrorMessage);
185+
}
186+
}
187+
else
188+
{
189+
result.Errors.Add(apiResult.ErrorMessage);
190+
}
176191

177-
return result;
192+
return result;
178193
}
179194

180-
public override RefundPaymentResult Refund(RefundPaymentRequest request)
195+
public override RefundPaymentResult Refund(RefundPaymentRequest refundPaymentRequest)
181196
{
182197
var result = new RefundPaymentResult
183198
{
184-
NewPaymentStatus = request.Order.PaymentStatus
199+
NewPaymentStatus = refundPaymentRequest.Order.PaymentStatus
185200
};
186201

187-
var settings = Services.Settings.LoadSetting<TSetting>(request.Order.StoreId);
202+
var settings = Services.Settings.LoadSetting<TSetting>(refundPaymentRequest.Order.StoreId);
188203
var session = new PayPalSessionData();
189204

190205
var apiResult = PayPalService.EnsureAccessToken(session, settings);
191206
if (result.Success)
192207
{
193-
apiResult = PayPalService.Refund(settings, session, request);
208+
apiResult = PayPalService.Refund(settings, session, refundPaymentRequest);
194209

195-
if (apiResult.Success && apiResult.Json != null)
210+
if (apiResult.Success)
196211
{
197-
if (request.IsPartialRefund)
212+
if (refundPaymentRequest.IsPartialRefund)
198213
result.NewPaymentStatus = PaymentStatus.PartiallyRefunded;
199214
else
200215
result.NewPaymentStatus = PaymentStatus.Refunded;
@@ -212,21 +227,33 @@ public override RefundPaymentResult Refund(RefundPaymentRequest request)
212227
return result;
213228
}
214229

215-
public override VoidPaymentResult Void(VoidPaymentRequest request)
230+
public override VoidPaymentResult Void(VoidPaymentRequest voidPaymentRequest)
216231
{
217232
var result = new VoidPaymentResult
218233
{
219-
NewPaymentStatus = request.Order.PaymentStatus
234+
NewPaymentStatus = voidPaymentRequest.Order.PaymentStatus
220235
};
221236

222-
var settings = Services.Settings.LoadSetting<TSetting>(request.Order.StoreId);
223-
224-
var transactionId = request.Order.AuthorizationTransactionId;
225-
226-
if (transactionId.IsEmpty())
227-
transactionId = request.Order.CaptureTransactionId;
237+
var settings = Services.Settings.LoadSetting<TSetting>(voidPaymentRequest.Order.StoreId);
238+
var session = new PayPalSessionData();
228239

229-
// TODO
240+
var apiResult = PayPalService.EnsureAccessToken(session, settings);
241+
if (result.Success)
242+
{
243+
apiResult = PayPalService.Void(settings, session, voidPaymentRequest);
244+
if (apiResult.Success)
245+
{
246+
result.NewPaymentStatus = PaymentStatus.Voided;
247+
}
248+
else
249+
{
250+
result.Errors.Add(apiResult.ErrorMessage);
251+
}
252+
}
253+
else
254+
{
255+
result.Errors.Add(apiResult.ErrorMessage);
256+
}
230257

231258
return result;
232259
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using SmartStore.Core.Domain.Orders;
4+
using SmartStore.Core.Domain.Payments;
45
using SmartStore.Core.Domain.Stores;
56
using SmartStore.PayPal.Settings;
67
using SmartStore.Services.Payments;
@@ -17,6 +18,8 @@ public interface IPayPalService
1718

1819
string CreatePaymentInstruction(PayPalPaymentInstruction instruct);
1920

21+
PaymentStatus GetPaymentStatus(string state, string reasonCode, PaymentStatus defaultStatus);
22+
2023
PayPalResponse CallApi(string method, string path, string accessToken, PayPalApiSettingsBase settings, string data, IList<string> errors = null);
2124

2225
PayPalResponse EnsureAccessToken(PayPalSessionData session, PayPalApiSettingsBase settings);
@@ -36,5 +39,9 @@ PayPalResponse CreatePayment(
3639
PayPalResponse ExecutePayment(PayPalApiSettingsBase settings, PayPalSessionData session);
3740

3841
PayPalResponse Refund(PayPalApiSettingsBase settings, PayPalSessionData session, RefundPaymentRequest request);
42+
43+
PayPalResponse Capture(PayPalApiSettingsBase settings, PayPalSessionData session, CapturePaymentRequest request);
44+
45+
PayPalResponse Void(PayPalApiSettingsBase settings, PayPalSessionData session, VoidPaymentRequest request);
3946
}
4047
}

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

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using SmartStore.Core.Domain.Discounts;
1313
using SmartStore.Core.Domain.Logging;
1414
using SmartStore.Core.Domain.Orders;
15+
using SmartStore.Core.Domain.Payments;
1516
using SmartStore.Core.Domain.Stores;
1617
using SmartStore.Core.Domain.Tax;
1718
using SmartStore.Core.Localization;
@@ -309,6 +310,56 @@ public string CreatePaymentInstruction(PayPalPaymentInstruction instruct)
309310
return sb.ToString();
310311
}
311312

313+
public PaymentStatus GetPaymentStatus(string state, string reasonCode, PaymentStatus defaultStatus)
314+
{
315+
var result = defaultStatus;
316+
317+
if (state == null)
318+
state = string.Empty;
319+
320+
if (reasonCode == null)
321+
reasonCode = string.Empty;
322+
323+
switch (state.ToLowerInvariant())
324+
{
325+
case "authorized":
326+
result = PaymentStatus.Authorized;
327+
break;
328+
case "pending":
329+
switch (reasonCode.ToLowerInvariant())
330+
{
331+
case "authorization":
332+
result = PaymentStatus.Authorized;
333+
break;
334+
default:
335+
result = PaymentStatus.Pending;
336+
break;
337+
}
338+
break;
339+
case "completed":
340+
case "captured":
341+
case "partially_captured":
342+
case "canceled_reversal":
343+
result = PaymentStatus.Paid;
344+
break;
345+
case "denied":
346+
case "expired":
347+
case "failed":
348+
case "voided":
349+
result = PaymentStatus.Voided;
350+
break;
351+
case "reversed":
352+
case "refunded":
353+
result = PaymentStatus.Refunded;
354+
break;
355+
case "partially_refunded":
356+
result = PaymentStatus.PartiallyRefunded;
357+
break;
358+
}
359+
360+
return result;
361+
}
362+
312363
public PayPalResponse CallApi(string method, string path, string accessToken, PayPalApiSettingsBase settings, string data, IList<string> errors = null)
313364
{
314365
var isJson = (data.HasValue() && data.StartsWith("{"));
@@ -749,6 +800,45 @@ public PayPalResponse Refund(PayPalApiSettingsBase settings, PayPalSessionData s
749800

750801
return result;
751802
}
803+
804+
public PayPalResponse Capture(PayPalApiSettingsBase settings, PayPalSessionData session, CapturePaymentRequest request)
805+
{
806+
var data = new Dictionary<string, object>();
807+
//var isAuthorize = request.Order.AuthorizationTransactionCode.IsCaseInsensitiveEqual("authorize");
808+
809+
var path = "/v1/payments/authorization/{0}/capture".FormatInvariant(request.Order.AuthorizationTransactionId);
810+
811+
var store = _services.StoreService.GetStoreById(request.Order.StoreId);
812+
813+
var amount = new Dictionary<string, object>();
814+
amount.Add("total", Math.Round(request.Order.OrderTotal, 2));
815+
amount.Add("currency", store.PrimaryStoreCurrency.CurrencyCode);
816+
817+
data.Add("amount", amount);
818+
819+
var result = CallApi("POST", path, session.AccessToken, settings, JsonConvert.SerializeObject(data));
820+
821+
if (result.Success && result.Json != null)
822+
{
823+
result.Id = (string)result.Json.id;
824+
}
825+
826+
return result;
827+
}
828+
829+
public PayPalResponse Void(PayPalApiSettingsBase settings, PayPalSessionData session, VoidPaymentRequest request)
830+
{
831+
var path = "/v1/payments/authorization/{0}/void".FormatInvariant(request.Order.AuthorizationTransactionId);
832+
833+
var result = CallApi("POST", path, session.AccessToken, settings, null);
834+
835+
if (result.Success && result.Json != null)
836+
{
837+
result.Id = (string)result.Json.id;
838+
}
839+
840+
return result;
841+
}
752842
}
753843

754844

0 commit comments

Comments
 (0)