PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.12.2
GiveWP – Donation Plugin and Fundraising Platform v3.12.2
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / src / PaymentGateways / PayPalCommerce / AjaxRequestHandler.php
give / src / PaymentGateways / PayPalCommerce Last commit date
Banners 2 years ago DataTransferObjects 4 years ago Exceptions 3 years ago Migrations 2 years ago Models 2 years ago PayPalCheckoutSdk 2 years ago Repositories 2 years ago Webhooks 2 years ago AccountAdminNotices.php 4 years ago AdminSettingFields.php 2 years ago AdvancedCardFields.php 4 years ago AjaxRequestHandler.php 2 years ago DonationDetailsPage.php 4 years ago DonationFormPaymentMethod.php 2 years ago PayPalClient.php 2 years ago PayPalCommerce.php 2 years ago RefreshToken.php 2 years ago RefundPaymentHandler.php 4 years ago ScriptLoader.php 2 years ago Utils.php 2 years ago onBoardingRedirectHandler.php 2 years ago
AjaxRequestHandler.php
443 lines
1 <?php
2
3 namespace Give\PaymentGateways\PayPalCommerce;
4
5 use Give\Framework\Http\ConnectServer\Client\ConnectClient;
6 use Give\PaymentGateways\PayPalCommerce\Models\MerchantDetail;
7 use Give\PaymentGateways\PayPalCommerce\PayPalCheckoutSdk\ProcessorResponseError;
8 use Give\PaymentGateways\PayPalCommerce\Repositories\MerchantDetails;
9 use Give\PaymentGateways\PayPalCommerce\Repositories\PayPalAuth;
10 use Give\PaymentGateways\PayPalCommerce\Repositories\PayPalOrder;
11 use Give\PaymentGateways\PayPalCommerce\Repositories\Settings;
12 use Give\PaymentGateways\PayPalCommerce\Repositories\Webhooks;
13
14 /**
15 * Class AjaxRequestHandler
16 * @package Give\PaymentGateways\PaypalCommerce
17 *
18 * @sicne 2.9.0
19 */
20 class AjaxRequestHandler
21 {
22 /**
23 * @since 2.9.0
24 *
25 * @var Webhooks
26 */
27 private $webhooksRepository;
28
29 /**
30 * @since 2.9.0
31 *
32 * @var MerchantDetail
33 */
34 private $merchantDetails;
35
36 /**
37 * @since 2.9.0
38 *
39 * @var PayPalAuth
40 */
41 private $payPalAuth;
42
43 /**
44 * @since 2.9.0
45 *
46 * @var MerchantDetails
47 */
48 private $merchantRepository;
49
50 /**
51 * @since 2.9.0
52 *
53 * @var ConnectClient
54 */
55 private $refreshToken;
56
57 /**
58 * @since 2.9.0
59 *
60 * @var Settings
61 */
62 private $settings;
63
64 /**
65 * AjaxRequestHandler constructor.
66 *
67 * @since 2.9.0
68 *
69 * @param Webhooks $webhooksRepository
70 * @param MerchantDetail $merchantDetails
71 * @param MerchantDetails $merchantRepository
72 * @param RefreshToken $refreshToken
73 * @param Settings $settings
74 * @param PayPalAuth $payPalAuth
75 */
76 public function __construct(
77 Webhooks $webhooksRepository,
78 MerchantDetail $merchantDetails,
79 MerchantDetails $merchantRepository,
80 RefreshToken $refreshToken,
81 Settings $settings,
82 PayPalAuth $payPalAuth
83 ) {
84 $this->webhooksRepository = $webhooksRepository;
85 $this->merchantDetails = $merchantDetails;
86 $this->merchantRepository = $merchantRepository;
87 $this->refreshToken = $refreshToken;
88 $this->settings = $settings;
89 $this->payPalAuth = $payPalAuth;
90 }
91
92 /**
93 * give_paypal_commerce_user_onboarded ajax action handler
94 *
95 * @since 2.32.0 Return error response on exception when fetch access token from authorization code.
96 * @since 2.9.0
97 */
98 public function onBoardedUserAjaxRequestHandler()
99 {
100 $this->validateAdminRequest();
101
102 if (empty($_GET['mode']) || ! in_array($_GET['mode'], ['sandbox', 'live'])) {
103 wp_send_json_error('Must include valid mode');
104 }
105
106 $mode = sanitize_text_field(wp_unslash($_GET['mode']));
107
108 // Set PayPal client mode.
109 give(PayPalClient::class)->setMode($mode);
110
111 $partnerLinkInfo = $this->settings->getPartnerLinkDetails();
112
113 try {
114 $payPalResponse = $this->payPalAuth->getTokenFromAuthorizationCode(
115 give_clean($_GET['authCode']),
116 give_clean($_GET['sharedId']),
117 $partnerLinkInfo['nonce']
118 );
119 } catch (\Exception $exception) {
120 wp_send_json_error();
121 }
122
123 $this->settings->updateAccessToken($payPalResponse);
124
125 // Set cron job to refresh token.
126 $refreshToken = give(RefreshToken::class);
127 $refreshToken->setMode($mode);
128 $refreshToken->registerCronJobToRefreshToken($payPalResponse['expiresIn']);
129
130 wp_send_json_success();
131 }
132
133 /**
134 * This function handle ajax request with give_paypal_commerce_get_partner_url action.
135 *
136 * @since 3.0.0 Add support for accountType. This param is required to get partner link.
137 * @since 2.30.0 Add support for mode param.
138 * @since 2.9.0
139 */
140 public function onGetPartnerUrlAjaxRequestHandler()
141 {
142 $this->validateAdminRequest();
143
144 if (empty($accountType = $_GET['accountType']) || ! in_array($accountType, ScriptLoader::$accountTypes, true)) {
145 wp_send_json_error('Must include valid account type');
146 }
147
148 if (empty($country = $_GET['countryCode']) || ! isset(give_get_country_list()[$country])) {
149 wp_send_json_error('Must include valid 2-character country code');
150 }
151
152 if (empty($_GET['mode']) || ! in_array($_GET['mode'], ['sandbox', 'live'])) {
153 wp_send_json_error('Must include valid mode');
154 }
155
156 $country = sanitize_text_field(wp_unslash($_GET['countryCode']));
157 $accountType = sanitize_text_field(wp_unslash($_GET['accountType']));
158 $mode = sanitize_text_field(wp_unslash($_GET['mode']));
159 $redirectUrl = add_query_arg(
160 [
161 'tab' => 'gateways',
162 'section' => 'paypal',
163 'group' => 'paypal-commerce',
164 'mode' => $mode,
165 ],
166 admin_url('edit.php?post_type=give_forms&page=give-settings')
167 );
168
169 // Set PayPal client mode.
170 give(PayPalClient::class)->setMode($mode);
171
172 $data = $this->payPalAuth->getSellerPartnerLink($redirectUrl, $accountType);
173
174 if (! $data) {
175 wp_send_json_error();
176 }
177
178 $this->settings->updateAccountCountry($country);
179 $this->settings->updatePartnerLinkDetails($data);
180
181 wp_send_json_success($data);
182 }
183
184 /**
185 * give_paypal_commerce_disconnect_account ajax request handler.
186 *
187 * @since 2.30.0 Add support for mode param.
188 * @since 2.25.0 Remove merchant seller token.
189 * @since 2.9.0
190 */
191 public function removePayPalAccount()
192 {
193 if (! current_user_can('manage_give_settings')) {
194 wp_send_json_error(['error' => esc_html__('You are not allowed to perform this action.', 'give')]);
195 }
196
197 try {
198 $mode = give_clean($_POST['mode']);
199 $this->webhooksRepository->setMode($mode);
200 $this->merchantRepository->setMode($mode);
201 $this->refreshToken->setMode($mode);
202 $this->settings->setMode($mode);
203
204 $this->validateAdminRequest();
205
206 // Remove the webhook from PayPal if there is one
207 if ($webhookConfig = $this->webhooksRepository->getWebhookConfig()) {
208 $this->webhooksRepository->deleteWebhook($this->merchantDetails->accessToken, $webhookConfig->id);
209 $this->webhooksRepository->deleteWebhookConfig();
210 }
211
212 $this->merchantRepository->delete();
213 $this->merchantRepository->deleteAccountErrors();
214 $this->merchantRepository->deleteClientToken();
215 $this->settings->deleteSellerAccessToken();
216 $this->refreshToken->deleteRefreshTokenCronJob();
217
218 wp_send_json_success();
219 } catch (\Exception $exception) {
220 wp_send_json_error(['error' => $exception->getMessage()]);
221 }
222 }
223
224 /**
225 * Create order.
226 *
227 * @todo: handle payment create error on frontend.
228 *
229 * @since 3.1.0 Remove unused variable from createOrder argument.
230 * @since 2.9.0
231 */
232 public function createOrder()
233 {
234 $this->validateFrontendRequest();
235 $data = $this->getOrderData();
236
237 try {
238 $result = give(PayPalOrder::class)->createOrder($data);
239
240 wp_send_json_success(
241 [
242 'id' => $result,
243 ]
244 );
245 } catch (\Exception $ex) {
246 wp_send_json_error(
247 [
248 'error' => json_decode($ex->getMessage(), true),
249 ]
250 );
251 }
252 }
253
254 /**
255 * @since 3.4.2
256 */
257 private function getOrderData(): array
258 {
259 $postData = give_clean($_POST);
260 $formId = absint($postData['give-form-id']);
261 $donorAddress = $this->getDonorAddressFromPostedDataForPaypalOrder($postData);
262
263 return [
264 'formId' => $formId,
265 'formTitle' => give_payment_gateway_item_title(['post_data' => $postData], 127),
266 'donationAmount' => isset($postData['give-amount']) ?
267 (float)apply_filters(
268 'give_donation_total',
269 give_maybe_sanitize_amount(
270 $postData['give-amount'],
271 ['currency' => give_get_currency($formId)]
272 )
273 ) :
274 '0.00',
275 'payer' => [
276 'firstName' => $postData['give_first'],
277 'lastName' => $postData['give_last'],
278 'email' => $postData['give_email'],
279 'address' => $donorAddress,
280 ],
281 ];
282 }
283
284 /**
285 * Approve order.
286 *
287 * @todo: handle payment capture error on frontend.
288 *
289 * @since 3.2.0 Discover error by checking capture status.
290 * @since 2.9.0
291 */
292 public function approveOrder()
293 {
294 $this->validateFrontendRequest();
295
296 $orderId = give_clean($_GET['order']);
297 $updateAmount = filter_var(give_clean($_GET['update_amount']), FILTER_VALIDATE_BOOLEAN);
298
299 try {
300 if ($updateAmount) {
301 give(PayPalOrder::class)->updateOrderAmount($orderId, $this->getOrderData());
302 }
303
304 $result = give(PayPalOrder::class)->approveOrder($orderId);
305 // PayPal does not return error in case of invalid cvv. So we need to check capture status and return error.
306 // ref - https://feedback.givewp.com/bug-reports/p/paypal-credit-card-donations-can-generate-a-fatal-error
307 $this->returnErrorOnFailedApproveOrderResponse($result);
308 wp_send_json_success(['order' => $result,]);
309 } catch (\Exception $ex) {
310 wp_send_json_error(['error' => json_decode($ex->getMessage(), true),]);
311 }
312 }
313
314 /**
315 * @since 3.4.2
316 */
317 public function updateOrderAmount()
318 {
319 $this->validateFrontendRequest();
320
321 $orderId = give_clean($_GET['order']);
322
323 try {
324 give(PayPalOrder::class)->updateOrderAmount($orderId, $this->getOrderData());
325
326 wp_send_json_success(['order' => $orderId,]);
327 } catch (\Exception $ex) {
328 wp_send_json_error(['error' => json_decode($ex->getMessage(), true),]);
329 }
330 }
331
332 /**
333 * Return on boarding trouble notice.
334 *
335 * @since 2.9.6
336 */
337 public function onBoardingTroubleNotice()
338 {
339 if (! current_user_can('manage_give_settings')) {
340 wp_die();
341 }
342
343 /* @var AdminSettingFields $adminSettingFields */
344 $adminSettingFields = give(AdminSettingFields::class);
345
346 $actionList = sprintf(
347 '<ol><li>%1$s</li><li>%2$s</li><li>%3$s</li></ol>',
348 esc_html__(
349 'Make sure to complete the entire PayPal process. Do not close the window until you have finished the process.',
350 'give'
351 ),
352 esc_html__(
353 'The last screen of the PayPal connect process includes a button to be sent back to your site. It is important you click this and do not close the window yourself.',
354 'give'
355 ),
356 esc_html__(
357 'If you’re still having problems connecting: ',
358 'give'
359 ) . $adminSettingFields->getAdminGuidanceNotice(false)
360 );
361
362 $standardError = sprintf(
363 '<div id="give-paypal-onboarding-trouble-notice" class="give-hidden"><p class="error-message">%1$s</p><p>%2$s</p></div>',
364 esc_html__('Having trouble connecting to PayPal?', 'give'),
365 $actionList
366 );
367
368 wp_send_json_success($standardError);
369 }
370
371 /**
372 * Validate admin ajax request.
373 *
374 * @since 2.9.0
375 */
376 private function validateAdminRequest()
377 {
378 if (! current_user_can('manage_give_settings')) {
379 wp_die();
380 }
381 }
382
383 /**
384 * Validate frontend ajax request.
385 *
386 * @since 2.9.0
387 */
388 private function validateFrontendRequest()
389 {
390 $formId = absint($_POST['give-form-id']);
391
392 if (! $formId || ! give_verify_donation_form_nonce(give_clean($_POST['give-form-hash']), $formId)) {
393 wp_die();
394 }
395 }
396
397 /**
398 * This function should return address array in PayPal rest api accepted format.
399 *
400 * @since 3.1.0 Return address only if setting enabled and has valida country in PayPal accepted formatted.
401 * @since 2.11.1
402 */
403 private function getDonorAddressFromPostedDataForPaypalOrder(array $postedData): array
404 {
405 if (empty($postedData['billing_country'])) {
406 return [];
407 }
408
409 $address['address_line_1'] = ! empty($postedData['card_address']) ? $postedData['card_address'] : '';
410 $address['address_line_2'] = ! empty($postedData['card_address_2']) ? $postedData['card_address_2'] : '';
411 $address['admin_area_2'] = ! empty($postedData['card_city']) ? $postedData['card_city'] : '';
412 $address['admin_area_1'] = ! empty($postedData['card_state']) ? $postedData['card_state'] : '';
413 $address['postal_code'] = ! empty($postedData['card_zip']) ? $postedData['card_zip'] : '';
414 $address['country_code'] = ! empty($postedData['billing_country']) ? $postedData['billing_country'] : '';
415
416 return $address;
417 }
418
419 /**
420 * This function should validate PayPal ApproveOrder response and respond to ajax request on error.
421 *
422 * @since 3.2.0
423 */
424 private function returnErrorOnFailedApproveOrderResponse(\stdClass $response)
425 {
426 // Get capture.
427 // ref - https://developer.paypal.com/docs/api/orders/v2/#orders_capture
428 $capture = $response->purchase_units[0]->payments->captures[0];
429
430 // Check if capture status is failed or declined.
431 if (
432 in_array($capture->status, ['FAILED', 'DECLINED'])
433 && property_exists($capture, 'processor_response')
434 ) {
435 $error = ProcessorResponseError::getError($capture->processor_response);
436
437 if ($error) {
438 wp_send_json_error(['error' => $error]);
439 }
440 }
441 }
442 }
443