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