PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 3.1.2
GiveWP – Donation Plugin and Fundraising Platform v3.1.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
413 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
236 $postData = give_clean($_POST);
237 $formId = absint($postData['give-form-id']);
238 $donorAddress = $this->getDonorAddressFromPostedDataForPaypalOrder($postData);
239
240 $data = [
241 'formId' => $formId,
242 'formTitle' => give_payment_gateway_item_title(['post_data' => $postData], 127),
243 'donationAmount' => isset($postData['give-amount']) ?
244 (float)apply_filters(
245 'give_donation_total',
246 give_maybe_sanitize_amount(
247 $postData['give-amount'],
248 ['currency' => give_get_currency($formId)]
249 )
250 ) :
251 '0.00',
252 'payer' => [
253 'firstName' => $postData['give_first'],
254 'lastName' => $postData['give_last'],
255 'email' => $postData['give_email'],
256 'address' => $donorAddress,
257 ]
258 ];
259
260 try {
261 $result = give(PayPalOrder::class)->createOrder($data);
262
263 wp_send_json_success(
264 [
265 'id' => $result,
266 ]
267 );
268 } catch (\Exception $ex) {
269 wp_send_json_error(
270 [
271 'error' => json_decode($ex->getMessage(), true),
272 ]
273 );
274 }
275 }
276
277 /**
278 * Approve order.
279 *
280 * @todo: handle payment capture error on frontend.
281 *
282 * @unreleased Discover error by checking capture status.
283 * @since 2.9.0
284 */
285 public function approveOrder()
286 {
287 $this->validateFrontendRequest();
288
289 $orderId = give_clean($_GET['order']);
290
291 try {
292 $result = give(PayPalOrder::class)->approveOrder($orderId);
293 // PayPal does not return error in case of invalid cvv. So we need to check capture status and return error.
294 // ref - https://feedback.givewp.com/bug-reports/p/paypal-credit-card-donations-can-generate-a-fatal-error
295 $this->returnErrorOnFailedApproveOrderResponse($result);
296 wp_send_json_success(['order' => $result,]);
297 } catch (\Exception $ex) {
298 wp_send_json_error(['error' => json_decode($ex->getMessage(), true),]);
299 }
300 }
301
302 /**
303 * Return on boarding trouble notice.
304 *
305 * @since 2.9.6
306 */
307 public function onBoardingTroubleNotice()
308 {
309 if (! current_user_can('manage_give_settings')) {
310 wp_die();
311 }
312
313 /* @var AdminSettingFields $adminSettingFields */
314 $adminSettingFields = give(AdminSettingFields::class);
315
316 $actionList = sprintf(
317 '<ol><li>%1$s</li><li>%2$s</li><li>%3$s</li></ol>',
318 esc_html__(
319 'Make sure to complete the entire PayPal process. Do not close the window until you have finished the process.',
320 'give'
321 ),
322 esc_html__(
323 '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.',
324 'give'
325 ),
326 esc_html__(
327 'If you’re still having problems connecting: ',
328 'give'
329 ) . $adminSettingFields->getAdminGuidanceNotice(false)
330 );
331
332 $standardError = sprintf(
333 '<div id="give-paypal-onboarding-trouble-notice" class="give-hidden"><p class="error-message">%1$s</p><p>%2$s</p></div>',
334 esc_html__('Having trouble connecting to PayPal?', 'give'),
335 $actionList
336 );
337
338 wp_send_json_success($standardError);
339 }
340
341 /**
342 * Validate admin ajax request.
343 *
344 * @since 2.9.0
345 */
346 private function validateAdminRequest()
347 {
348 if (! current_user_can('manage_give_settings')) {
349 wp_die();
350 }
351 }
352
353 /**
354 * Validate frontend ajax request.
355 *
356 * @since 2.9.0
357 */
358 private function validateFrontendRequest()
359 {
360 $formId = absint($_POST['give-form-id']);
361
362 if (! $formId || ! give_verify_donation_form_nonce(give_clean($_POST['give-form-hash']), $formId)) {
363 wp_die();
364 }
365 }
366
367 /**
368 * This function should return address array in PayPal rest api accepted format.
369 *
370 * @since 3.1.0 Return address only if setting enabled and has valida country in PayPal accepted formatted.
371 * @since 2.11.1
372 */
373 private function getDonorAddressFromPostedDataForPaypalOrder(array $postedData): array
374 {
375 if (empty($postedData['billing_country'])) {
376 return [];
377 }
378
379 $address['address_line_1'] = ! empty($postedData['card_address']) ? $postedData['card_address'] : '';
380 $address['address_line_2'] = ! empty($postedData['card_address_2']) ? $postedData['card_address_2'] : '';
381 $address['admin_area_2'] = ! empty($postedData['card_city']) ? $postedData['card_city'] : '';
382 $address['admin_area_1'] = ! empty($postedData['card_state']) ? $postedData['card_state'] : '';
383 $address['postal_code'] = ! empty($postedData['card_zip']) ? $postedData['card_zip'] : '';
384 $address['country_code'] = ! empty($postedData['billing_country']) ? $postedData['billing_country'] : '';
385
386 return $address;
387 }
388
389 /**
390 * This function should validate PayPal ApproveOrder response and respond to ajax request on error.
391 *
392 * @unreleased
393 */
394 private function returnErrorOnFailedApproveOrderResponse(\stdClass $response)
395 {
396 // Get capture.
397 // ref - https://developer.paypal.com/docs/api/orders/v2/#orders_capture
398 $capture = $response->purchase_units[0]->payments->captures[0];
399
400 // Check if capture status is failed or declined.
401 if (
402 in_array($capture->status, ['FAILED', 'DECLINED'])
403 && property_exists($capture, 'processor_response')
404 ) {
405 $error = ProcessorResponseError::getError($capture->processor_response);
406
407 if ($error) {
408 wp_send_json_error(['error' => $error]);
409 }
410 }
411 }
412 }
413