PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.19.8
GiveWP – Donation Plugin and Fundraising Platform v2.19.8
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 / onBoardingRedirectHandler.php
give / src / PaymentGateways / PayPalCommerce Last commit date
Actions 4 years ago DataTransferObjects 4 years ago Exceptions 4 years ago Migrations 4 years ago Models 4 years ago Repositories 4 years ago Webhooks 4 years ago AccountAdminNotices.php 4 years ago AdminSettingFields.php 4 years ago AdvancedCardFields.php 4 years ago AjaxRequestHandler.php 4 years ago DonationDetailsPage.php 4 years ago DonationFormPaymentMethod.php 4 years ago PayPalClient.php 4 years ago PayPalCommerce.php 4 years ago RefreshToken.php 4 years ago RefundPaymentHandler.php 4 years ago ScriptLoader.php 4 years ago Utils.php 4 years ago onBoardingRedirectHandler.php 4 years ago
onBoardingRedirectHandler.php
462 lines
1 <?php
2
3 namespace Give\PaymentGateways\PayPalCommerce;
4
5 use Exception;
6 use Give\PaymentGateways\PayPalCommerce\Models\MerchantDetail;
7 use Give\PaymentGateways\PayPalCommerce\Repositories\MerchantDetails;
8 use Give\PaymentGateways\PayPalCommerce\Repositories\PayPalAuth;
9 use Give\PaymentGateways\PayPalCommerce\Repositories\Settings;
10 use Give\PaymentGateways\PayPalCommerce\Repositories\Webhooks;
11 use Give_Admin_Settings;
12
13 /**
14 * Class PayPalOnBoardingRedirectHandler
15 * @package Give\PaymentGateways\PayPalCommerce
16 *
17 * @since 2.9.0
18 */
19 class onBoardingRedirectHandler
20 {
21 /**
22 * @since 2.9.0
23 *
24 * @var PayPalAuth
25 */
26 private $payPalAuth;
27
28 /**
29 * @since 2.9.0
30 *
31 * @var Webhooks
32 */
33 private $webhooksRepository;
34
35 /**
36 * @since 2.9.0
37 *
38 * @var MerchantDetails
39 */
40 private $merchantRepository;
41
42 /**
43 * @since 2.9.0
44 *
45 * @var Settings
46 */
47 private $settings;
48
49 /**
50 * onBoardingRedirectHandler constructor.
51 *
52 * @since 2.9.0
53 *
54 * @param Webhooks $webhooks
55 * @param MerchantDetails $merchantRepository
56 * @param Settings $settings
57 * @param PayPalAuth $payPalAuth
58 */
59 public function __construct(
60 Webhooks $webhooks,
61 MerchantDetails $merchantRepository,
62 Settings $settings,
63 PayPalAuth $payPalAuth
64 ) {
65 $this->webhooksRepository = $webhooks;
66 $this->merchantRepository = $merchantRepository;
67 $this->settings = $settings;
68 $this->payPalAuth = $payPalAuth;
69 }
70
71 /**
72 * Bootstrap class
73 *
74 * @since 2.9.0
75 */
76 public function boot()
77 {
78 if ($this->isPayPalUserRedirected()) {
79 $details = $this->savePayPalMerchantDetails();
80 $this->setUpWebhook($details);
81 $this->redirectAccountConnected();
82 }
83
84 if ($this->isPayPalAccountDetailsSaved()) {
85 $this->registerPayPalSSLNotice();
86 $this->registerPayPalAccountConnectedNotice();
87 }
88
89 if ($this->isStatusRefresh()) {
90 $this->refreshAccountStatus();
91 }
92 }
93
94 /**
95 * Save PayPal merchant details
96 *
97 * @since 2.9.0
98 *
99 * @return MerchantDetail
100 */
101 private function savePayPalMerchantDetails()
102 {
103 $paypalGetData = wp_parse_args($_SERVER['QUERY_STRING']);
104 $partnerLinkInfo = $this->settings->getPartnerLinkDetails();
105 $tokenInfo = $this->settings->getAccessToken();
106
107 $allowedPayPalData = [
108 'merchantId',
109 'merchantIdInPayPal',
110 ];
111
112 $payPalAccount = array_intersect_key($paypalGetData, array_flip($allowedPayPalData));
113
114 if ( ! array_key_exists('merchantIdInPayPal', $payPalAccount) || empty($payPalAccount['merchantIdInPayPal'])) {
115 $errors[] = [
116 'type' => 'url',
117 'message' => esc_html__(
118 'There was a problem with PayPal return url and we could not find valid merchant ID. Paypal return URL is:',
119 'give'
120 ) . "\n",
121 'value' => urlencode($_SERVER['QUERY_STRING']),
122 ];
123
124 $this->merchantRepository->saveAccountErrors($errors);
125 $this->redirectWhenOnBoardingFail();
126 }
127
128 $restApiCredentials = (array)$this->payPalAuth->getSellerRestAPICredentials(
129 $tokenInfo ? $tokenInfo['accessToken'] : ''
130 );
131 $this->didWeGetValidSellerRestApiCredentials($restApiCredentials);
132
133 $tokenInfo = $this->payPalAuth->getTokenFromClientCredentials(
134 $restApiCredentials['client_id'],
135 $restApiCredentials['client_secret']
136 );
137 $this->settings->updateAccessToken($tokenInfo);
138
139 $payPalAccount['clientId'] = $restApiCredentials['client_id'];
140 $payPalAccount['clientSecret'] = $restApiCredentials['client_secret'];
141 $payPalAccount['token'] = $tokenInfo;
142 $payPalAccount['supportsCustomPayments'] = 'PPCP' === $partnerLinkInfo['product'];
143 $payPalAccount['accountIsReady'] = true;
144 $payPalAccount['accountCountry'] = $this->settings->getAccountCountry();
145
146 $merchantDetails = MerchantDetail::fromArray($payPalAccount);
147 $this->merchantRepository->save($merchantDetails);
148
149 $this->deleteTempOptions();
150
151 return $merchantDetails;
152 }
153
154 /**
155 * Redirects the user to the account connected url
156 *
157 * @since 2.9.0
158 */
159 private function redirectAccountConnected()
160 {
161 $this->refreshAccountStatus();
162
163 wp_redirect(
164 admin_url(
165 'edit.php?post_type=give_forms&page=give-settings&tab=gateways&section=paypal&group=paypal-commerce&paypal-commerce-account-connected=1'
166 )
167 );
168
169 exit();
170 }
171
172 /**
173 * Sets up the webhook for the connected account
174 *
175 * @since 2.9.0
176 *
177 * @param MerchantDetail $merchant_details
178 */
179 private function setUpWebhook(MerchantDetail $merchant_details)
180 {
181 if ( ! is_ssl()) {
182 return;
183 }
184
185 try {
186 $webhookConfig = $this->webhooksRepository->createWebhook($merchant_details->accessToken);
187 $this->webhooksRepository->saveWebhookConfig($webhookConfig);
188 } catch (Exception $ex) {
189 $errors[] = esc_html__(
190 'There was a problem with creating webhook on PayPal. A gateway error log also added to get details information about PayPal response.',
191 'give'
192 );
193
194 $this->merchantRepository->saveAccountErrors($errors);
195 $this->redirectWhenOnBoardingFail();
196 }
197 }
198
199 /**
200 * Delete temp data
201 *
202 * @since 2.9.0
203 * @return void
204 */
205 private function deleteTempOptions()
206 {
207 $this->settings->deletePartnerLinkDetails();
208 $this->settings->deleteAccessToken();
209 }
210
211 /**
212 * Register notice if account connect success fully.
213 *
214 * @since 2.9.0
215 */
216 private function registerPayPalAccountConnectedNotice()
217 {
218 Give_Admin_Settings::add_message(
219 'paypal-commerce-account-connected',
220 esc_html__('PayPal account connected successfully.', 'give')
221 );
222 }
223
224 /**
225 * Returns whether or not the current request is for refreshing the account status
226 *
227 * @since 2.9.0
228 *
229 * @return bool
230 */
231 private function isStatusRefresh()
232 {
233 return isset($_GET['paypalStatusCheck']) && Give_Admin_Settings::is_setting_page('gateways', 'paypal');
234 }
235
236 /**
237 * Return whether or not PayPal user redirect to GiveWP setting page after successful onboarding.
238 *
239 * @since 2.9.0
240 *
241 * @return bool
242 */
243 private function isPayPalUserRedirected()
244 {
245 return isset($_GET['merchantIdInPayPal']) && Give_Admin_Settings::is_setting_page('gateways', 'paypal');
246 }
247
248 /**
249 * Return whether or not PayPal account details saved.
250 *
251 * @since 2.9.0
252 *
253 * @return bool
254 */
255 private function isPayPalAccountDetailsSaved()
256 {
257 return isset($_GET['paypal-commerce-account-connected']) && Give_Admin_Settings::is_setting_page(
258 'gateways',
259 'paypal'
260 );
261 }
262
263 /**
264 * validate rest api credential.
265 *
266 * @since 2.9.0
267 *
268 * @param array $array
269 *
270 */
271 private function didWeGetValidSellerRestApiCredentials($array)
272 {
273 $required = ['client_id', 'client_secret'];
274 $array = array_filter($array); // Remove empty values.
275
276 if (array_diff($required, array_keys($array))) {
277 $errors[] = [
278 'type' => 'json',
279 'message' => esc_html__('PayPal client access token API request response is:', 'give'),
280 'value' => wp_json_encode($this->settings->getAccessToken()),
281 ];
282
283 $errors[] = [
284 'type' => 'json',
285 'message' => esc_html__('PayPal client rest api credentials API request response is:', 'give'),
286 'value' => wp_json_encode($array),
287 ];
288
289 $errors[] = esc_html__(
290 'There was a problem with PayPal client rest API request and we could not find valid client id and secret.',
291 'give'
292 );
293
294 $this->merchantRepository->saveAccountErrors($errors);
295 $this->redirectWhenOnBoardingFail();
296 }
297 }
298
299 /**
300 * Handles the request for refreshing the account status
301 *
302 * @since 2.9.0
303 */
304 private function refreshAccountStatus()
305 {
306 $merchantDetails = $this->merchantRepository->getDetails();
307
308 $statusErrors = $this->isAdminSuccessfullyOnBoarded(
309 $merchantDetails->merchantIdInPayPal,
310 $merchantDetails->accessToken,
311 $merchantDetails->supportsCustomPayments
312 );
313 if ($statusErrors !== true) {
314 $merchantDetails->accountIsReady = false;
315 $this->merchantRepository->saveAccountErrors($statusErrors);
316 } else {
317 $merchantDetails->accountIsReady = true;
318 $this->merchantRepository->deleteAccountErrors();
319 }
320
321 $this->merchantRepository->save($merchantDetails);
322 }
323
324 /**
325 * Validate seller on Boarding status
326 *
327 * @since 2.9.0
328 *
329 * @param string $merchantId
330 * @param string $accessToken
331 * @param bool $usesCustomPayments
332 *
333 * @return true|string[]
334 */
335 private function isAdminSuccessfullyOnBoarded($merchantId, $accessToken, $usesCustomPayments)
336 {
337 $onBoardedData = (array)$this->payPalAuth->getSellerOnBoardingDetailsFromPayPal($merchantId, $accessToken);
338 $onBoardedData = array_filter($onBoardedData); // Remove empty values.
339 $errorMessages[] = [
340 'type' => 'json',
341 'message' => esc_html__('PayPal merchant status check API request response is:', 'give'),
342 'value' => wp_json_encode($onBoardedData),
343 ];
344
345 if ( ! is_ssl()) {
346 $errorMessages[] = esc_html__(
347 'A valid SSL certificate is required to accept donations and set up your PayPal account. Once a
348 certificate is installed and the site is using https, please disconnect and reconnect your account.',
349 'give'
350 );
351 }
352
353 if (array_diff(['payments_receivable', 'primary_email_confirmed'], array_keys($onBoardedData))) {
354 $errorMessages[] = esc_html__(
355 'There was a problem with the status check for your account. Please try disconnecting and connecting again. If the problem persists, please contact support.',
356 'give'
357 );
358
359 // Return here since the rest of the validations will definitely fail
360 return $errorMessages;
361 }
362
363 if ( ! $onBoardedData['payments_receivable']) {
364 $errorMessages[] = esc_html__('Set up an account to receive payment from PayPal', 'give');
365 }
366
367 if ( ! $onBoardedData['primary_email_confirmed']) {
368 $errorMessage[] = esc_html__('Confirm your primary email address', 'give');
369 }
370
371 if ( ! $usesCustomPayments) {
372 return count($errorMessages) > 1 ? $errorMessages : true;
373 }
374
375 if (array_diff(['products', 'capabilities'], array_keys($onBoardedData))) {
376 $errorMessages[] = esc_html__(
377 'Your account was expected to be able to accept custom payments, but is not. Please make sure your
378 account country matches the country setting. If the problem persists, please contact PayPal.',
379 'give'
380 );
381
382 // Return here since the rest of the validations will definitely fail
383 return $errorMessages;
384 }
385
386 // Grab the PPCP_CUSTOM product from the status data
387 $customProduct = current(
388 array_filter(
389 $onBoardedData['products'],
390 function ($product) {
391 return $product['name'] === 'PPCP_CUSTOM';
392 }
393 )
394 );
395
396 if (empty($customProduct) || $customProduct['vetting_status'] !== 'SUBSCRIBED') {
397 $errorMessages[] = esc_html__('Reach out to PayPal to enable PPCP_CUSTOM for your account', 'give');
398 }
399
400 // Loop through the capabilities and see if any are not active
401 $invalidCapabilities = [];
402 foreach ($onBoardedData['capabilities'] as $capability) {
403 if ($capability['status'] !== 'ACTIVE') {
404 $invalidCapabilities[] = $capability['name'];
405 }
406 }
407
408 if ( ! empty($invalidCapabilities)) {
409 $errorMessages[] = esc_html__(
410 'Reach out to PayPal to resolve the following capabilities:',
411 'give'
412 ) . ' ' . implode(', ', $invalidCapabilities);
413 }
414
415 // If there were errors then redirect the user with notices
416 return count($errorMessages) > 1 ? $errorMessages : true;
417 }
418
419 /**
420 * Redirect admin to setting section with error.
421 *
422 * @since 2.9.0
423 */
424 private function redirectWhenOnBoardingFail()
425 {
426 wp_redirect(
427 admin_url(
428 'edit.php?post_type=give_forms&page=give-settings&tab=gateways&section=paypal&group=paypal-commerce&paypal-error=1'
429 )
430 );
431
432 exit();
433 }
434
435 /**
436 * Displays a notice of the site is not using SSL
437 *
438 * @since 2.9.0
439 */
440 private function registerPayPalSSLNotice()
441 {
442 if (is_ssl() && empty($this->webhooksRepository->getWebhookConfig())) {
443 $logLink = sprintf(
444 '<a href="%1$s">%2$s</a>',
445 admin_url('/edit.php?post_type=give_forms&page=give-tools&tab=logs'),
446 esc_html__('logs data', 'give')
447 );
448
449 Give_Admin_Settings::add_error(
450 'paypal-webhook-error',
451 sprintf(
452 esc_html__(
453 'There was a problem setting up the webhooks for your PayPal account. Please try disconnecting and reconnecting your PayPal account. If the problem persists, please contact support and provide them with the latest %1$s',
454 'give'
455 ),
456 $logLink
457 )
458 );
459 }
460 }
461 }
462