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