This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | if ( ! defined( 'ABSPATH' ) ) { |
||
3 | exit; |
||
4 | } |
||
5 | |||
6 | /** |
||
7 | * Compatibility class for Subscriptions. |
||
8 | * |
||
9 | * @extends WC_Gateway_Stripe |
||
10 | */ |
||
11 | class WC_Stripe_Subs_Compat extends WC_Gateway_Stripe { |
||
12 | /** |
||
13 | * Constructor |
||
14 | */ |
||
15 | public function __construct() { |
||
16 | parent::__construct(); |
||
17 | |||
18 | if ( class_exists( 'WC_Subscriptions_Order' ) ) { |
||
19 | add_action( 'woocommerce_scheduled_subscription_payment_' . $this->id, array( $this, 'scheduled_subscription_payment' ), 10, 2 ); |
||
20 | add_action( 'wcs_resubscribe_order_created', array( $this, 'delete_resubscribe_meta' ), 10 ); |
||
21 | add_action( 'wcs_renewal_order_created', array( $this, 'delete_renewal_meta' ), 10 ); |
||
22 | add_action( 'woocommerce_subscription_failing_payment_method_updated_stripe', array( $this, 'update_failing_payment_method' ), 10, 2 ); |
||
23 | add_action( 'wc_stripe_cards_payment_fields', array( $this, 'display_update_subs_payment_checkout' ) ); |
||
24 | add_action( 'wc_stripe_add_payment_method_' . $this->id . '_success', array( $this, 'handle_add_payment_method_success' ), 10, 2 ); |
||
25 | add_action( 'woocommerce_subscriptions_change_payment_before_submit', array( $this, 'differentiate_change_payment_method_form' ) ); |
||
26 | |||
27 | // display the credit card used for a subscription in the "My Subscriptions" table |
||
28 | add_filter( 'woocommerce_my_subscriptions_payment_method', array( $this, 'maybe_render_subscription_payment_method' ), 10, 2 ); |
||
29 | |||
30 | // allow store managers to manually set Stripe as the payment method on a subscription |
||
31 | add_filter( 'woocommerce_subscription_payment_meta', array( $this, 'add_subscription_payment_meta' ), 10, 2 ); |
||
32 | add_filter( 'woocommerce_subscription_validate_payment_meta', array( $this, 'validate_subscription_payment_meta' ), 10, 2 ); |
||
33 | add_filter( 'wc_stripe_display_save_payment_method_checkbox', array( $this, 'maybe_hide_save_checkbox' ) ); |
||
34 | |||
35 | /* |
||
36 | * WC subscriptions hooks into the "template_redirect" hook with priority 100. |
||
37 | * If the screen is "Pay for order" and the order is a subscription renewal, it redirects to the plain checkout. |
||
38 | * See: https://github.com/woocommerce/woocommerce-subscriptions/blob/99a75687e109b64cbc07af6e5518458a6305f366/includes/class-wcs-cart-renewal.php#L165 |
||
39 | * If we are in the "You just need to authorize SCA" flow, we don't want that redirection to happen. |
||
40 | */ |
||
41 | add_action( 'template_redirect', array( $this, 'remove_order_pay_var' ), 99 ); |
||
42 | add_action( 'template_redirect', array( $this, 'restore_order_pay_var' ), 101 ); |
||
43 | } |
||
44 | } |
||
45 | |||
46 | /** |
||
47 | * Checks to see if we need to hide the save checkbox field. |
||
48 | * Because when cart contains a subs product, it will save regardless. |
||
49 | * |
||
50 | * @since 4.0.0 |
||
51 | * @version 4.0.0 |
||
52 | */ |
||
53 | public function maybe_hide_save_checkbox( $display_tokenization ) { |
||
54 | if ( WC_Subscriptions_Cart::cart_contains_subscription() ) { |
||
55 | return false; |
||
56 | } |
||
57 | |||
58 | return $display_tokenization; |
||
59 | } |
||
60 | |||
61 | /** |
||
62 | * Is $order_id a subscription? |
||
63 | * @param int $order_id |
||
64 | * @return boolean |
||
65 | */ |
||
66 | public function has_subscription( $order_id ) { |
||
67 | return ( function_exists( 'wcs_order_contains_subscription' ) && ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) ); |
||
68 | } |
||
69 | |||
70 | /** |
||
71 | * Checks if page is pay for order and change subs payment page. |
||
72 | * |
||
73 | * @since 4.0.4 |
||
74 | * @return bool |
||
75 | */ |
||
76 | public function is_subs_change_payment() { |
||
77 | return ( isset( $_GET['pay_for_order'] ) && isset( $_GET['change_payment_method'] ) ); |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Displays a checkbox to allow users to update all subs payments with new |
||
82 | * payment. |
||
83 | * |
||
84 | * @since 4.1.11 |
||
85 | */ |
||
86 | View Code Duplication | public function display_update_subs_payment_checkout() { |
|
0 ignored issues
–
show
|
|||
87 | $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) ); |
||
88 | if ( |
||
89 | apply_filters( 'wc_stripe_display_update_subs_payment_method_card_checkbox', true ) && |
||
90 | wcs_user_has_subscription( get_current_user_id(), '', $subs_statuses ) && |
||
91 | is_add_payment_method_page() |
||
92 | ) { |
||
93 | $label = esc_html( apply_filters( 'wc_stripe_save_to_subs_text', __( 'Update the Payment Method used for all of my active subscriptions.', 'woocommerce-gateway-stripe' ) ) ); |
||
94 | $id = sprintf( 'wc-%1$s-update-subs-payment-method-card', $this->id ); |
||
95 | woocommerce_form_field( |
||
96 | $id, |
||
97 | array( |
||
98 | 'type' => 'checkbox', |
||
99 | 'label' => $label, |
||
100 | 'default' => apply_filters( 'wc_stripe_save_to_subs_checked', false ), |
||
101 | ) |
||
102 | ); |
||
103 | } |
||
104 | } |
||
105 | |||
106 | /** |
||
107 | * Updates all active subscriptions payment method. |
||
108 | * |
||
109 | * @since 4.1.11 |
||
110 | * @param string $source_id |
||
111 | * @param object $source_object |
||
112 | */ |
||
113 | View Code Duplication | public function handle_add_payment_method_success( $source_id, $source_object ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
114 | if ( isset( $_POST[ 'wc-' . $this->id . '-update-subs-payment-method-card' ] ) ) { |
||
115 | $all_subs = wcs_get_users_subscriptions(); |
||
116 | $subs_statuses = apply_filters( 'wc_stripe_update_subs_payment_method_card_statuses', array( 'active' ) ); |
||
117 | $stripe_customer = new WC_Stripe_Customer( get_current_user_id() ); |
||
118 | |||
119 | if ( ! empty( $all_subs ) ) { |
||
120 | foreach ( $all_subs as $sub ) { |
||
121 | if ( $sub->has_status( $subs_statuses ) ) { |
||
122 | WC_Subscriptions_Change_Payment_Gateway::update_payment_method( |
||
123 | $sub, |
||
124 | $this->id, |
||
125 | array( |
||
126 | 'post_meta' => array( |
||
127 | '_stripe_source_id' => array( 'value' => $source_id ), |
||
128 | '_stripe_customer_id' => array( 'value' => $stripe_customer->get_id() ), |
||
129 | ), |
||
130 | ) |
||
131 | ); |
||
132 | } |
||
133 | } |
||
134 | } |
||
135 | } |
||
136 | } |
||
137 | |||
138 | /** |
||
139 | * Render a dummy element in the "Change payment method" form (that does not appear in the "Pay for order" form) |
||
140 | * which can be checked to determine proper SCA handling to apply for each form. |
||
141 | * |
||
142 | * @since 4.6.1 |
||
143 | */ |
||
144 | public function differentiate_change_payment_method_form() { |
||
145 | echo '<input type="hidden" id="wc-stripe-change-payment-method" />'; |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * Process the payment method change for subscriptions. |
||
150 | * |
||
151 | * @since 4.0.4 |
||
152 | * @since 4.1.11 Remove 3DS check as it is not needed. |
||
153 | * @param int $order_id |
||
154 | */ |
||
155 | public function change_subs_payment_method( $order_id ) { |
||
156 | try { |
||
157 | $subscription = wc_get_order( $order_id ); |
||
158 | $prepared_source = $this->prepare_source( get_current_user_id(), true ); |
||
159 | |||
160 | $this->maybe_disallow_prepaid_card( $prepared_source ); |
||
161 | $this->check_source( $prepared_source ); |
||
162 | $this->save_source_to_order( $subscription, $prepared_source ); |
||
163 | |||
164 | do_action( 'wc_stripe_change_subs_payment_method_success', $prepared_source->source, $prepared_source ); |
||
165 | |||
166 | return array( |
||
167 | 'result' => 'success', |
||
168 | 'redirect' => $this->get_return_url( $subscription ), |
||
169 | ); |
||
170 | } catch ( WC_Stripe_Exception $e ) { |
||
171 | wc_add_notice( $e->getLocalizedMessage(), 'error' ); |
||
172 | WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() ); |
||
173 | } |
||
174 | } |
||
175 | |||
176 | /** |
||
177 | * Process the payment based on type. |
||
178 | * @param int $order_id |
||
179 | * @return array |
||
180 | */ |
||
181 | View Code Duplication | public function process_payment( $order_id, $retry = true, $force_save_source = false, $previous_error = false, $use_order_source = false ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
182 | if ( $this->has_subscription( $order_id ) ) { |
||
183 | if ( $this->is_subs_change_payment() ) { |
||
184 | return $this->change_subs_payment_method( $order_id ); |
||
185 | } |
||
186 | |||
187 | // Regular payment with force customer enabled |
||
188 | return parent::process_payment( $order_id, $retry, true, $previous_error, $use_order_source ); |
||
189 | } else { |
||
190 | return parent::process_payment( $order_id, $retry, $force_save_source, $previous_error, $use_order_source ); |
||
191 | } |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * Overloads WC_Stripe_Payment_Gateway::generate_create_intent_request() in order to |
||
196 | * include additional flags, used when setting payment intents up for off-session usage. |
||
197 | * |
||
198 | * @param WC_Order $order The order that is being paid for. |
||
199 | * @param object $prepared_source The source that is used for the payment. |
||
200 | * @return array The arguments for the request. |
||
201 | */ |
||
202 | public function generate_create_intent_request( $order, $prepared_source ) { |
||
203 | $request = parent::generate_create_intent_request( $order, $prepared_source ); |
||
204 | |||
205 | // Non-subscription orders do not need any additional parameters. |
||
206 | if ( ! $this->has_subscription( $order ) ) { |
||
207 | return $request; |
||
208 | } |
||
209 | |||
210 | // Let Stripe know that the payment should be prepared for future usage. |
||
211 | $request['setup_future_usage'] = 'off_session'; |
||
212 | |||
213 | return $request; |
||
214 | } |
||
215 | |||
216 | /** |
||
217 | * Scheduled_subscription_payment function. |
||
218 | * |
||
219 | * @param $amount_to_charge float The amount to charge. |
||
220 | * @param $renewal_order WC_Order A WC_Order object created to record the renewal payment. |
||
221 | */ |
||
222 | public function scheduled_subscription_payment( $amount_to_charge, $renewal_order ) { |
||
223 | $this->process_subscription_payment( $amount_to_charge, $renewal_order, true, false ); |
||
224 | } |
||
225 | |||
226 | /** |
||
227 | * Process_subscription_payment function. |
||
228 | * |
||
229 | * @since 3.0 |
||
230 | * @since 4.0.4 Add third parameter flag to retry. |
||
231 | * @since 4.1.0 Add fourth parameter to log previous errors. |
||
232 | * @param float $amount |
||
233 | * @param mixed $renewal_order |
||
234 | * @param bool $retry Should we retry the process? |
||
235 | * @param object $previous_error |
||
236 | */ |
||
237 | public function process_subscription_payment( $amount, $renewal_order, $retry = true, $previous_error = false ) { |
||
238 | try { |
||
239 | View Code Duplication | if ( $amount * 100 < WC_Stripe_Helper::get_minimum_amount() ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
240 | /* translators: minimum amount */ |
||
241 | $message = sprintf( __( 'Sorry, the minimum allowed order total is %1$s to use this payment method.', 'woocommerce-gateway-stripe' ), wc_price( WC_Stripe_Helper::get_minimum_amount() / 100 ) ); |
||
242 | throw new WC_Stripe_Exception( |
||
243 | 'Error while processing renewal order ' . $renewal_order->get_id() . ' : ' . $message, |
||
244 | $message |
||
245 | ); |
||
246 | } |
||
247 | |||
248 | $order_id = $renewal_order->get_id(); |
||
249 | |||
250 | $this->ensure_subscription_has_customer_id( $order_id ); |
||
251 | |||
252 | // Unlike regular off-session subscription payments, early renewals are treated as on-session payments, involving the customer. |
||
253 | if ( isset( $_REQUEST['process_early_renewal'] ) ) { // wpcs: csrf ok. |
||
254 | $response = parent::process_payment( $order_id, true, false, $previous_error, true ); |
||
0 ignored issues
–
show
It seems like you call parent on a different method (
process_payment() instead of process_subscription_payment() ). Are you sure this is correct? If so, you might want to change this to $this->process_payment() .
This check looks for a call to a parent method whose name is different than the method from which it is called. Consider the following code: class Daddy
{
protected function getFirstName()
{
return "Eidur";
}
protected function getSurName()
{
return "Gudjohnsen";
}
}
class Son
{
public function getFirstName()
{
return parent::getSurname();
}
}
The ![]() |
|||
255 | |||
256 | if( 'success' === $response['result'] && isset( $response['payment_intent_secret'] ) ) { |
||
257 | $verification_url = add_query_arg( |
||
258 | array( |
||
259 | 'order' => $order_id, |
||
260 | 'nonce' => wp_create_nonce( 'wc_stripe_confirm_pi' ), |
||
261 | 'redirect_to' => remove_query_arg( array( 'process_early_renewal', 'subscription_id', 'wcs_nonce' ) ), |
||
262 | 'early_renewal' => true, |
||
263 | ), |
||
264 | WC_AJAX::get_endpoint( 'wc_stripe_verify_intent' ) |
||
265 | ); |
||
266 | |||
267 | echo wp_json_encode( array( |
||
268 | 'stripe_sca_required' => true, |
||
269 | 'intent_secret' => $response['payment_intent_secret'], |
||
270 | 'redirect_url' => $verification_url, |
||
271 | ) ); |
||
272 | |||
273 | exit; |
||
274 | } |
||
275 | |||
276 | // Hijack all other redirects in order to do the redirection in JavaScript. |
||
277 | add_action( 'wp_redirect', array( $this, 'redirect_after_early_renewal' ), 100 ); |
||
278 | |||
279 | return; |
||
280 | } |
||
281 | |||
282 | // Check for an existing intent, which is associated with the order. |
||
283 | if ( $this->has_authentication_already_failed( $renewal_order ) ) { |
||
284 | return; |
||
285 | } |
||
286 | |||
287 | // Get source from order |
||
288 | $prepared_source = $this->prepare_order_source( $renewal_order ); |
||
289 | $source_object = $prepared_source->source_object; |
||
290 | |||
291 | View Code Duplication | if ( ! $prepared_source->customer ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
292 | throw new WC_Stripe_Exception( |
||
293 | 'Failed to process renewal for order ' . $renewal_order->get_id() . '. Stripe customer id is missing in the order', |
||
294 | __( 'Customer not found', 'woocommerce-gateway-stripe' ) |
||
295 | ); |
||
296 | } |
||
297 | |||
298 | WC_Stripe_Logger::log( "Info: Begin processing subscription payment for order {$order_id} for the amount of {$amount}" ); |
||
299 | |||
300 | /* If we're doing a retry and source is chargeable, we need to pass |
||
301 | * a different idempotency key and retry for success. |
||
302 | */ |
||
303 | View Code Duplication | if ( is_object( $source_object ) && empty( $source_object->error ) && $this->need_update_idempotency_key( $source_object, $previous_error ) ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
304 | add_filter( 'wc_stripe_idempotency_key', array( $this, 'change_idempotency_key' ), 10, 2 ); |
||
305 | } |
||
306 | |||
307 | View Code Duplication | if ( ( $this->is_no_such_source_error( $previous_error ) || $this->is_no_linked_source_error( $previous_error ) ) && apply_filters( 'wc_stripe_use_default_customer_source', true ) ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
308 | // Passing empty source will charge customer default. |
||
309 | $prepared_source->source = ''; |
||
310 | } |
||
311 | |||
312 | $this->lock_order_payment( $renewal_order ); |
||
313 | |||
314 | $response = $this->create_and_confirm_intent_for_off_session( $renewal_order, $prepared_source, $amount ); |
||
315 | $is_authentication_required = $this->is_authentication_required_for_payment( $response ); |
||
316 | |||
317 | // It's only a failed payment if it's an error and it's not of the type 'authentication_required'. |
||
318 | // If it's 'authentication_required', then we should email the user and ask them to authenticate. |
||
319 | View Code Duplication | if ( ! empty( $response->error ) && ! $is_authentication_required ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
320 | // We want to retry. |
||
321 | if ( $this->is_retryable_error( $response->error ) ) { |
||
322 | if ( $retry ) { |
||
323 | // Don't do anymore retries after this. |
||
324 | if ( 5 <= $this->retry_interval ) { |
||
325 | return $this->process_subscription_payment( $amount, $renewal_order, false, $response->error ); |
||
326 | } |
||
327 | |||
328 | sleep( $this->retry_interval ); |
||
329 | |||
330 | $this->retry_interval++; |
||
331 | |||
332 | return $this->process_subscription_payment( $amount, $renewal_order, true, $response->error ); |
||
333 | } else { |
||
334 | $localized_message = __( 'Sorry, we are unable to process your payment at this time. Please retry later.', 'woocommerce-gateway-stripe' ); |
||
335 | $renewal_order->add_order_note( $localized_message ); |
||
336 | throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message ); |
||
337 | } |
||
338 | } |
||
339 | |||
340 | $localized_messages = WC_Stripe_Helper::get_localized_messages(); |
||
341 | |||
342 | if ( 'card_error' === $response->error->type ) { |
||
343 | $localized_message = isset( $localized_messages[ $response->error->code ] ) ? $localized_messages[ $response->error->code ] : $response->error->message; |
||
344 | } else { |
||
345 | $localized_message = isset( $localized_messages[ $response->error->type ] ) ? $localized_messages[ $response->error->type ] : $response->error->message; |
||
346 | } |
||
347 | |||
348 | $renewal_order->add_order_note( $localized_message ); |
||
349 | |||
350 | throw new WC_Stripe_Exception( print_r( $response, true ), $localized_message ); |
||
351 | } |
||
352 | |||
353 | // Either the charge was successfully captured, or it requires further authentication. |
||
354 | |||
355 | if ( $is_authentication_required ) { |
||
356 | do_action( 'wc_gateway_stripe_process_payment_authentication_required', $renewal_order, $response ); |
||
357 | |||
358 | $error_message = __( 'This transaction requires authentication.', 'woocommerce-gateway-stripe' ); |
||
359 | $renewal_order->add_order_note( $error_message ); |
||
360 | |||
361 | $charge = end( $response->error->payment_intent->charges->data ); |
||
362 | $id = $charge->id; |
||
363 | $order_id = $renewal_order->get_id(); |
||
0 ignored issues
–
show
$order_id is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
364 | |||
365 | $renewal_order->set_transaction_id( $id ); |
||
366 | $renewal_order->update_status( 'failed', sprintf( __( 'Stripe charge awaiting authentication by user: %s.', 'woocommerce-gateway-stripe' ), $id ) ); |
||
367 | if ( is_callable( array( $renewal_order, 'save' ) ) ) { |
||
368 | $renewal_order->save(); |
||
369 | } |
||
370 | } else { |
||
371 | // The charge was successfully captured |
||
372 | do_action( 'wc_gateway_stripe_process_payment', $response, $renewal_order ); |
||
373 | |||
374 | $this->process_response( end( $response->charges->data ), $renewal_order ); |
||
375 | } |
||
376 | |||
377 | $this->unlock_order_payment( $renewal_order ); |
||
378 | } catch ( WC_Stripe_Exception $e ) { |
||
379 | WC_Stripe_Logger::log( 'Error: ' . $e->getMessage() ); |
||
380 | |||
381 | do_action( 'wc_gateway_stripe_process_payment_error', $e, $renewal_order ); |
||
382 | |||
383 | /* translators: error message */ |
||
384 | $renewal_order->update_status( 'failed' ); |
||
385 | } |
||
386 | } |
||
387 | |||
388 | /** |
||
389 | * Updates other subscription sources. |
||
390 | * |
||
391 | * @since 3.1.0 |
||
392 | * @version 4.0.0 |
||
393 | */ |
||
394 | View Code Duplication | public function save_source_to_order( $order, $source ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
395 | parent::save_source_to_order( $order, $source ); |
||
396 | |||
397 | $order_id = $order->get_id(); |
||
398 | |||
399 | // Also store it on the subscriptions being purchased or paid for in the order |
||
400 | if ( function_exists( 'wcs_order_contains_subscription' ) && wcs_order_contains_subscription( $order_id ) ) { |
||
401 | $subscriptions = wcs_get_subscriptions_for_order( $order_id ); |
||
402 | } elseif ( function_exists( 'wcs_order_contains_renewal' ) && wcs_order_contains_renewal( $order_id ) ) { |
||
403 | $subscriptions = wcs_get_subscriptions_for_renewal_order( $order_id ); |
||
404 | } else { |
||
405 | $subscriptions = array(); |
||
406 | } |
||
407 | |||
408 | foreach ( $subscriptions as $subscription ) { |
||
409 | $subscription_id = $subscription->get_id(); |
||
410 | update_post_meta( $subscription_id, '_stripe_customer_id', $source->customer ); |
||
411 | update_post_meta( $subscription_id, '_stripe_source_id', $source->source ); |
||
412 | } |
||
413 | } |
||
414 | |||
415 | /** |
||
416 | * Don't transfer Stripe customer/token meta to resubscribe orders. |
||
417 | * @param int $resubscribe_order The order created for the customer to resubscribe to the old expired/cancelled subscription |
||
418 | */ |
||
419 | View Code Duplication | public function delete_resubscribe_meta( $resubscribe_order ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
420 | delete_post_meta( $resubscribe_order->get_id(), '_stripe_customer_id' ); |
||
0 ignored issues
–
show
|
|||
421 | delete_post_meta( $resubscribe_order->get_id(), '_stripe_source_id' ); |
||
0 ignored issues
–
show
|
|||
422 | // For BW compat will remove in future |
||
423 | delete_post_meta( $resubscribe_order->get_id(), '_stripe_card_id' ); |
||
0 ignored issues
–
show
|
|||
424 | // delete payment intent ID |
||
425 | delete_post_meta( $resubscribe_order->get_id(), '_stripe_intent_id' ); |
||
0 ignored issues
–
show
|
|||
426 | $this->delete_renewal_meta( $resubscribe_order ); |
||
427 | } |
||
428 | |||
429 | /** |
||
430 | * Don't transfer Stripe fee/ID meta to renewal orders. |
||
431 | * @param int $resubscribe_order The order created for the customer to resubscribe to the old expired/cancelled subscription |
||
0 ignored issues
–
show
There is no parameter named
$resubscribe_order . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
432 | */ |
||
433 | public function delete_renewal_meta( $renewal_order ) { |
||
434 | WC_Stripe_Helper::delete_stripe_fee( $renewal_order ); |
||
435 | WC_Stripe_Helper::delete_stripe_net( $renewal_order ); |
||
436 | |||
437 | // delete payment intent ID |
||
438 | delete_post_meta( $renewal_order->get_id(), '_stripe_intent_id' ); |
||
439 | |||
440 | return $renewal_order; |
||
441 | } |
||
442 | |||
443 | /** |
||
444 | * Update the customer_id for a subscription after using Stripe to complete a payment to make up for |
||
445 | * an automatic renewal payment which previously failed. |
||
446 | * |
||
447 | * @access public |
||
448 | * @param WC_Subscription $subscription The subscription for which the failing payment method relates. |
||
449 | * @param WC_Order $renewal_order The order which recorded the successful payment (to make up for the failed automatic payment). |
||
450 | * @return void |
||
451 | */ |
||
452 | public function update_failing_payment_method( $subscription, $renewal_order ) { |
||
453 | update_post_meta( $subscription->get_id(), '_stripe_customer_id', $renewal_order->get_meta( '_stripe_customer_id', true ) ); |
||
454 | update_post_meta( $subscription->get_id(), '_stripe_source_id', $renewal_order->get_meta( '_stripe_source_id', true ) ); |
||
455 | } |
||
456 | |||
457 | /** |
||
458 | * Include the payment meta data required to process automatic recurring payments so that store managers can |
||
459 | * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+. |
||
460 | * |
||
461 | * @since 2.5 |
||
462 | * @param array $payment_meta associative array of meta data required for automatic payments |
||
463 | * @param WC_Subscription $subscription An instance of a subscription object |
||
464 | * @return array |
||
465 | */ |
||
466 | public function add_subscription_payment_meta( $payment_meta, $subscription ) { |
||
467 | $subscription_id = $subscription->get_id(); |
||
468 | $source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); |
||
469 | |||
470 | // For BW compat will remove in future. |
||
471 | if ( empty( $source_id ) ) { |
||
472 | $source_id = get_post_meta( $subscription_id, '_stripe_card_id', true ); |
||
473 | |||
474 | // Take this opportunity to update the key name. |
||
475 | update_post_meta( $subscription_id, '_stripe_source_id', $source_id ); |
||
476 | delete_post_meta( $subscription_id, '_stripe_card_id', $source_id ); |
||
477 | } |
||
478 | |||
479 | $payment_meta[ $this->id ] = array( |
||
480 | 'post_meta' => array( |
||
481 | '_stripe_customer_id' => array( |
||
482 | 'value' => get_post_meta( $subscription_id, '_stripe_customer_id', true ), |
||
483 | 'label' => 'Stripe Customer ID', |
||
484 | ), |
||
485 | '_stripe_source_id' => array( |
||
486 | 'value' => $source_id, |
||
487 | 'label' => 'Stripe Source ID', |
||
488 | ), |
||
489 | ), |
||
490 | ); |
||
491 | |||
492 | return $payment_meta; |
||
493 | } |
||
494 | |||
495 | /** |
||
496 | * Validate the payment meta data required to process automatic recurring payments so that store managers can |
||
497 | * manually set up automatic recurring payments for a customer via the Edit Subscriptions screen in 2.0+. |
||
498 | * |
||
499 | * @since 2.5 |
||
500 | * @since 4.0.4 Stripe sourd id field no longer needs to be required. |
||
501 | * @param string $payment_method_id The ID of the payment method to validate |
||
502 | * @param array $payment_meta associative array of meta data required for automatic payments |
||
503 | * @return array |
||
504 | */ |
||
505 | View Code Duplication | public function validate_subscription_payment_meta( $payment_method_id, $payment_meta ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
506 | if ( $this->id === $payment_method_id ) { |
||
507 | |||
508 | if ( ! isset( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) || empty( $payment_meta['post_meta']['_stripe_customer_id']['value'] ) ) { |
||
509 | |||
510 | // Allow empty stripe customer id during subscription renewal. It will be added when processing payment if required. |
||
511 | if ( ! isset( $_POST['wc_order_action'] ) || 'wcs_process_renewal' !== $_POST['wc_order_action'] ) { |
||
512 | throw new Exception( __( 'A "Stripe Customer ID" value is required.', 'woocommerce-gateway-stripe' ) ); |
||
513 | } |
||
514 | } elseif ( 0 !== strpos( $payment_meta['post_meta']['_stripe_customer_id']['value'], 'cus_' ) ) { |
||
515 | throw new Exception( __( 'Invalid customer ID. A valid "Stripe Customer ID" must begin with "cus_".', 'woocommerce-gateway-stripe' ) ); |
||
516 | } |
||
517 | |||
518 | if ( |
||
519 | ! empty( $payment_meta['post_meta']['_stripe_source_id']['value'] ) && ( |
||
520 | 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'card_' ) |
||
521 | && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'src_' ) |
||
522 | && 0 !== strpos( $payment_meta['post_meta']['_stripe_source_id']['value'], 'pm_' ) |
||
523 | ) |
||
524 | ) { |
||
525 | throw new Exception( __( 'Invalid source ID. A valid source "Stripe Source ID" must begin with "src_", "pm_", or "card_".', 'woocommerce-gateway-stripe' ) ); |
||
526 | } |
||
527 | } |
||
528 | } |
||
529 | |||
530 | /** |
||
531 | * Render the payment method used for a subscription in the "My Subscriptions" table |
||
532 | * |
||
533 | * @since 1.7.5 |
||
534 | * @param string $payment_method_to_display the default payment method text to display |
||
535 | * @param WC_Subscription $subscription the subscription details |
||
536 | * @return string the subscription payment method |
||
537 | */ |
||
538 | public function maybe_render_subscription_payment_method( $payment_method_to_display, $subscription ) { |
||
539 | $customer_user = $subscription->get_customer_id(); |
||
540 | |||
541 | // bail for other payment methods |
||
542 | if ( $subscription->get_payment_method() !== $this->id || ! $customer_user ) { |
||
543 | return $payment_method_to_display; |
||
544 | } |
||
545 | |||
546 | $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_source_id', true ); |
||
547 | |||
548 | // For BW compat will remove in future. |
||
549 | if ( empty( $stripe_source_id ) ) { |
||
550 | $stripe_source_id = get_post_meta( $subscription->get_id(), '_stripe_card_id', true ); |
||
551 | |||
552 | // Take this opportunity to update the key name. |
||
553 | update_post_meta( $subscription->get_id(), '_stripe_source_id', $stripe_source_id ); |
||
554 | } |
||
555 | |||
556 | $stripe_customer = new WC_Stripe_Customer(); |
||
557 | $stripe_customer_id = get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ); |
||
558 | |||
559 | // If we couldn't find a Stripe customer linked to the subscription, fallback to the user meta data. |
||
560 | View Code Duplication | if ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
561 | $user_id = $customer_user; |
||
562 | $stripe_customer_id = get_user_option( '_stripe_customer_id', $user_id ); |
||
563 | $stripe_source_id = get_user_option( '_stripe_source_id', $user_id ); |
||
564 | |||
565 | // For BW compat will remove in future. |
||
566 | if ( empty( $stripe_source_id ) ) { |
||
567 | $stripe_source_id = get_user_option( '_stripe_card_id', $user_id ); |
||
568 | |||
569 | // Take this opportunity to update the key name. |
||
570 | update_user_option( $user_id, '_stripe_source_id', $stripe_source_id, false ); |
||
571 | } |
||
572 | } |
||
573 | |||
574 | // If we couldn't find a Stripe customer linked to the account, fallback to the order meta data. |
||
575 | View Code Duplication | if ( ( ! $stripe_customer_id || ! is_string( $stripe_customer_id ) ) && false !== $subscription->order ) { |
|
0 ignored issues
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
576 | $stripe_customer_id = get_post_meta( $subscription->get_parent_id(), '_stripe_customer_id', true ); |
||
577 | $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_source_id', true ); |
||
578 | |||
579 | // For BW compat will remove in future. |
||
580 | if ( empty( $stripe_source_id ) ) { |
||
581 | $stripe_source_id = get_post_meta( $subscription->get_parent_id(), '_stripe_card_id', true ); |
||
582 | |||
583 | // Take this opportunity to update the key name. |
||
584 | update_post_meta( $subscription->get_parent_id(), '_stripe_source_id', $stripe_source_id ); |
||
585 | } |
||
586 | } |
||
587 | |||
588 | $stripe_customer->set_id( $stripe_customer_id ); |
||
589 | |||
590 | $sources = $stripe_customer->get_sources(); |
||
591 | $payment_method_to_display = __( 'N/A', 'woocommerce-gateway-stripe' ); |
||
592 | |||
593 | if ( $sources ) { |
||
0 ignored issues
–
show
The expression
$sources of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||
594 | $card = false; |
||
595 | |||
596 | foreach ( $sources as $source ) { |
||
597 | if ( isset( $source->type ) && 'card' === $source->type ) { |
||
598 | $card = $source->card; |
||
599 | } elseif ( isset( $source->object ) && 'card' === $source->object ) { |
||
600 | $card = $source; |
||
601 | } |
||
602 | |||
603 | if ( $source->id === $stripe_source_id ) { |
||
604 | if ( $card ) { |
||
605 | /* translators: 1) card brand 2) last 4 digits */ |
||
606 | $payment_method_to_display = sprintf( __( 'Via %1$s card ending in %2$s', 'woocommerce-gateway-stripe' ), ( isset( $card->brand ) ? $card->brand : __( 'N/A', 'woocommerce-gateway-stripe' ) ), $card->last4 ); |
||
607 | } |
||
608 | |||
609 | break; |
||
610 | } |
||
611 | } |
||
612 | } |
||
613 | |||
614 | return $payment_method_to_display; |
||
615 | } |
||
616 | |||
617 | /** |
||
618 | * If this is the "Pass the SCA challenge" flow, remove a variable that is checked by WC Subscriptions |
||
619 | * so WC Subscriptions doesn't redirect to the checkout |
||
620 | */ |
||
621 | public function remove_order_pay_var() { |
||
622 | global $wp; |
||
623 | if ( isset( $_GET['wc-stripe-confirmation'] ) ) { |
||
624 | $this->order_pay_var = $wp->query_vars['order-pay']; |
||
625 | $wp->query_vars['order-pay'] = null; |
||
626 | } |
||
627 | } |
||
628 | |||
629 | /** |
||
630 | * Restore the variable that was removed in remove_order_pay_var() |
||
631 | */ |
||
632 | public function restore_order_pay_var() { |
||
633 | global $wp; |
||
634 | if ( isset( $this->order_pay_var ) ) { |
||
635 | $wp->query_vars['order-pay'] = $this->order_pay_var; |
||
636 | } |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * Checks if a renewal already failed because a manual authentication is required. |
||
641 | * |
||
642 | * @param WC_Order $renewal_order The renewal order. |
||
643 | * @return boolean |
||
644 | */ |
||
645 | public function has_authentication_already_failed( $renewal_order ) { |
||
646 | $existing_intent = $this->get_intent_from_order( $renewal_order ); |
||
647 | |||
648 | if ( |
||
649 | ! $existing_intent |
||
650 | || 'requires_payment_method' !== $existing_intent->status |
||
651 | || empty( $existing_intent->last_payment_error ) |
||
652 | || 'authentication_required' !== $existing_intent->last_payment_error->code |
||
653 | ) { |
||
654 | return false; |
||
655 | } |
||
656 | |||
657 | // Make sure all emails are instantiated. |
||
658 | WC_Emails::instance(); |
||
659 | |||
660 | /** |
||
661 | * A payment attempt failed because SCA authentication is required. |
||
662 | * |
||
663 | * @param WC_Order $renewal_order The order that is being renewed. |
||
664 | */ |
||
665 | do_action( 'wc_gateway_stripe_process_payment_authentication_required', $renewal_order ); |
||
666 | |||
667 | // Fail the payment attempt (order would be currently pending because of retry rules). |
||
668 | $charge = end( $existing_intent->charges->data ); |
||
669 | $charge_id = $charge->id; |
||
670 | $renewal_order->update_status( 'failed', sprintf( __( 'Stripe charge awaiting authentication by user: %s.', 'woocommerce-gateway-stripe' ), $charge_id ) ); |
||
671 | |||
672 | return true; |
||
673 | } |
||
674 | |||
675 | /** |
||
676 | * Hijacks `wp_redirect` in order to generate a JS-friendly object with the URL. |
||
677 | * |
||
678 | * @param string $url The URL that Subscriptions attempts a redirect to. |
||
679 | * @return void |
||
680 | */ |
||
681 | public function redirect_after_early_renewal( $url ) { |
||
682 | echo wp_json_encode( |
||
683 | array( |
||
684 | 'stripe_sca_required' => false, |
||
685 | 'redirect_url' => $url, |
||
686 | ) |
||
687 | ); |
||
688 | |||
689 | exit; |
||
690 | } |
||
691 | |||
692 | /** |
||
693 | * Once an intent has been verified, perform some final actions for early renewals. |
||
694 | * |
||
695 | * @param WC_Order $order The renewal order. |
||
696 | * @param stdClass $intent The Payment Intent object. |
||
697 | */ |
||
698 | View Code Duplication | protected function handle_intent_verification_success( $order, $intent ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
699 | parent::handle_intent_verification_success( $order, $intent ); |
||
700 | |||
701 | if ( isset( $_GET['early_renewal'] ) ) { // wpcs: csrf ok. |
||
702 | wcs_update_dates_after_early_renewal( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ), $order ); |
||
703 | wc_add_notice( __( 'Your early renewal order was successful.', 'woocommerce-gateway-stripe' ), 'success' ); |
||
704 | } |
||
705 | } |
||
706 | |||
707 | /** |
||
708 | * During early renewals, instead of failing the renewal order, delete it and let Subs redirect to the checkout. |
||
709 | * |
||
710 | * @param WC_Order $order The renewal order. |
||
711 | * @param stdClass $intent The Payment Intent object (unused). |
||
712 | */ |
||
713 | View Code Duplication | protected function handle_intent_verification_failure( $order, $intent ) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository. ![]() |
|||
714 | if ( isset( $_GET['early_renewal'] ) ) { |
||
715 | $order->delete( true ); |
||
716 | wc_add_notice( __( 'Payment authorization for the renewal order was unsuccessful, please try again.', 'woocommerce-gateway-stripe' ), 'error' ); |
||
717 | $renewal_url = wcs_get_early_renewal_url( wcs_get_subscription( $order->get_meta( '_subscription_renewal' ) ) ); |
||
718 | wp_redirect( $renewal_url ); exit; |
||
719 | } |
||
720 | } |
||
721 | } |
||
722 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.