Test Failed
Push — backup/issue/4010 ( 70b4ce )
by Ravinder
10:16 queued 10s
created

admin-actions.php ➔ give_stripe_process_refund()   C

Complexity

Conditions 13
Paths 82

Size

Total Lines 78

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
nc 82
nop 3
dl 0
loc 78
rs 5.7733
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Give - Stripe Core Admin Actions
4
 *
5
 * @since 2.5.0
6
 *
7
 * @package    Give
8
 * @subpackage Stripe Core
9
 * @copyright  Copyright (c) 2019, GiveWP
10
 * @license    https://opensource.org/licenses/gpl-license GNU Public License
11
 */
12
13
// Exit, if accessed directly.
14
if ( ! defined( 'ABSPATH' ) ) {
15
    exit;
16
}
17
18
/**
19
 * This function is used to save the parameters returned after successfull connection of Stripe account.
20
 *
21
 * @since 2.5.0
22
 *
23
 * @return void
24
 */
25
function give_stripe_connect_save_options() {
26
27
	$get_vars = give_clean( filter_input_array( INPUT_GET ) );
28
29
	// If we don't have values here, bounce.
30
	if (
31
		! isset( $get_vars['stripe_publishable_key'] )
32
		|| ! isset( $get_vars['stripe_user_id'] )
33
		|| ! isset( $get_vars['stripe_access_token'] )
34
		|| ! isset( $get_vars['stripe_access_token_test'] )
35
		|| ! isset( $get_vars['connected'] )
36
	) {
37
		return false;
38
	}
39
40
	// Update keys.
41
	give_update_option( 'give_stripe_connected', $get_vars['connected'] );
42
	give_update_option( 'give_stripe_user_id', $get_vars['stripe_user_id'] );
43
	give_update_option( 'live_secret_key', $get_vars['stripe_access_token'] );
44
	give_update_option( 'test_secret_key', $get_vars['stripe_access_token_test'] );
45
	give_update_option( 'live_publishable_key', $get_vars['stripe_publishable_key'] );
46
	give_update_option( 'test_publishable_key', $get_vars['stripe_publishable_key_test'] );
47
48
	// Delete option for user API key.
49
	give_delete_option( 'stripe_user_api_keys' );
50
51
}
52
add_action( 'admin_init', 'give_stripe_connect_save_options' );
53
54
/**
55
 * Disconnects user from the Give Stripe Connected App.
56
 */
57
function give_stripe_connect_deauthorize() {
58
59
	$get_vars = give_clean( $_GET ); // WPCS: input var ok.
0 ignored issues
show
introduced by
Detected access of super global var $_GET, probably need manual inspection.
Loading history...
60
61
	// Be sure only to deauthorize when param present.
62
	if ( ! isset( $get_vars['stripe_disconnected'] ) ) {
63
		return false;
64
	}
65
66
	// Show message if NOT disconnected.
67
	if (
68
		'false' === $get_vars['stripe_disconnected']
69
		&& isset( $get_vars['error_code'] )
70
	) {
71
72
		$class   = 'notice notice-warning give-stripe-disconnect-message';
73
		$message = sprintf(
74
			/* translators: %s Error Message */
75
			__( '<strong>Error:</strong> Give could not disconnect from the Stripe API. Reason: %s', 'give' ),
76
			esc_html( $get_vars['error_message'] )
77
		);
78
79
		printf( '<div class="%1$s"><p>%2$s</p></div>', esc_attr( $class ), $message );
80
81
	}
82
83
	// If user disconnects, remove the options regardless.
84
	// They can always click reconnect even if connected.
85
	give_stripe_connect_delete_options();
86
87
}
88
add_action( 'admin_notices', 'give_stripe_connect_deauthorize' );
89
90
/**
91
 * This function will display field to opt for refund in Stripe.
92
 *
93
 * @param int $donation_id Donation ID.
94
 *
95
 * @since 2.5.0
96
 *
97
 * @return void
98
 */
99
function give_stripe_opt_refund( $donation_id ) {
100
101
	$processed_gateway = Give()->payment_meta->get_meta( $donation_id, '_give_payment_gateway', true );
102
103
	// Bail out, if the donation is not processed with Stripe payment gateway.
104
	if ( 'stripe' !== $processed_gateway ) {
105
		return;
106
	}
107
	?>
108
	<div id="give-stripe-opt-refund-wrap" class="give-stripe-opt-refund give-admin-box-inside give-hidden">
109
		<p>
110
			<input type="checkbox" id="give-stripe-opt-refund" name="give_stripe_opt_refund" value="1"/>
111
			<label for="give-stripe-opt-refund">
112
				<?php esc_html_e( 'Refund Charge in Stripe?', 'give' ); ?>
113
			</label>
114
		</p>
115
	</div>
116
117
	<?php
118
}
119
120
add_action( 'give_view_donation_details_totals_after', 'give_stripe_opt_refund', 10, 1 );
121
122
/**
123
 * Process refund in Stripe.
124
 *
125
 * @since  2.5.0
126
 * @access public
127
 *
128
 * @param int    $donation_id Donation ID.
129
 * @param string $new_status  New Donation Status.
130
 * @param string $old_status  Old Donation Status.
131
 *
132
 * @return void
133
 */
134
function give_stripe_process_refund( $donation_id, $new_status, $old_status ) {
135
136
	// Only move forward if refund requested.
137
	$can_process_refund = ! empty( $_POST['give_stripe_opt_refund'] ) ? give_clean( $_POST['give_stripe_opt_refund'] ) : false;
0 ignored issues
show
introduced by
Detected access of super global var $_POST, probably need manual inspection.
Loading history...
introduced by
Detected usage of a non-sanitized input variable: $_POST
Loading history...
138
	if ( ! $can_process_refund ) {
139
		return;
140
	}
141
142
	// Verify statuses.
143
	$should_process_refund = 'publish' !== $old_status ? false : true;
144
	$should_process_refund = apply_filters( 'give_stripe_should_process_refund', $should_process_refund, $donation_id, $new_status, $old_status );
145
146
	if ( false === $should_process_refund ) {
147
		return;
148
	}
149
150
	if ( 'refunded' !== $new_status ) {
151
		return;
152
	}
153
154
	$charge_id = give_get_payment_transaction_id( $donation_id );
155
156
	// If no charge ID, look in the payment notes.
157
	if ( empty( $charge_id ) || $charge_id == $donation_id ) {
158
		$charge_id = give_stripe_get_payment_txn_id_fallback( $donation_id );
159
	}
160
161
	// Bail if no charge ID was found.
162
	if ( empty( $charge_id ) ) {
163
		return;
164
	}
165
166
	try {
167
168
		$refund = \Stripe\Refund::create( array(
169
			'charge' => $charge_id,
170
		) );
171
172
		if ( isset( $refund->id ) ) {
173
			give_insert_payment_note(
174
				$donation_id,
175
				sprintf(
176
					/* translators: 1. Refund ID */
177
					esc_html__( 'Charge refunded in Stripe: %s', 'give' ),
178
					$refund->id
179
				)
180
			);
181
		}
182
	} catch ( \Stripe\Error\Base $e ) {
183
		// Refund issue occurred.
184
		$log_message = __( 'The Stripe payment gateway returned an error while refunding a donation.', 'give' ) . '<br><br>';
185
		$log_message .= sprintf( esc_html__( 'Message: %s', 'give' ), $e->getMessage() ) . '<br><br>';
186
		$log_message .= sprintf( esc_html__( 'Code: %s', 'give' ), $e->getCode() );
187
188
		// Log it with DB.
189
		give_record_gateway_error( __( 'Stripe Error', 'give' ), $log_message );
190
191
	} catch ( Exception $e ) {
192
193
		// some sort of other error.
194
		$body = $e->getJsonBody();
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Exception as the method getJsonBody() does only exist in the following sub-classes of Exception: Stripe\Error\Api, Stripe\Error\ApiConnection, Stripe\Error\Authentication, Stripe\Error\Base, Stripe\Error\Card, Stripe\Error\Idempotency, Stripe\Error\InvalidRequest, Stripe\Error\OAuth\InvalidClient, Stripe\Error\OAuth\InvalidGrant, Stripe\Error\OAuth\InvalidRequest, Stripe\Error\OAuth\InvalidScope, Stripe\Error\OAuth\OAuthBase, Stripe\Error\OAuth\UnsupportedGrantType, Stripe\Error\OAuth\UnsupportedResponseType, Stripe\Error\Permission, Stripe\Error\RateLimit, Stripe\Error\SignatureVerification. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
195
		$err  = $body['error'];
196
197
		if ( isset( $err['message'] ) ) {
198
			$error = $err['message'];
199
		} else {
200
			$error = esc_html__( 'Something went wrong while refunding the charge in Stripe.', 'give' );
201
		}
202
203
		wp_die( $error, esc_html__( 'Error', 'give' ), array(
204
			'response' => 400,
205
		) );
206
207
	} // End try().
208
209
	do_action( 'give_stripe_donation_refunded', $donation_id );
210
211
}
212
213
add_action( 'give_update_payment_status', 'give_stripe_process_refund', 200, 3 );
214
215
/**
216
 * Displays the "Give Connect" banner.
217
 *
218
 * @since 2.5.0
219
 *
220
 * @see: https://stripe.com/docs/connect/reference
221
 *
222
 * @return bool
223
 */
224
function give_stripe_show_connect_banner() {
225
226
	$status = true;
227
228
	// Don't show if already connected.
229
	if ( give_stripe_is_connected() ) {
230
		$status = false;
231
	}
232
233
	$hide_on_pages = array( 'give-about', 'give-getting-started', 'give-credits', 'give-addons' );
234
235
	// Don't show if on the about page.
236
	if ( in_array( give_get_current_setting_page(), $hide_on_pages, true ) ) {
237
		$status = false;
238
	}
239
240
	$hide_on_sections = array( 'stripe-settings', 'gateways-settings' );
241
242
	// Don't show if on the payment settings section.
243
	if ( in_array( give_get_current_setting_section(), $hide_on_sections, true ) ) {
244
		$status = false;
245
	}
246
247
	// Don't show for non-admins.
248
	if ( ! current_user_can( 'update_plugins' ) ) {
249
		$status = false;
250
	}
251
252
	// Is the notice temporarily dismissed?
253
	if ( give_stripe_is_connect_banner_dismissed() ) {
254
		$status = false;
255
	}
256
257
	/**
258
	 * This filter hook is used to decide whether the connect button banner need to be displayed or not.
259
	 *
260
	 * @since 2.5.0
261
	 */
262
	$status = apply_filters( 'give_stripe_connect_banner_status', $status );
263
264
	// Bailout, if status is false.
265
	if ( false === $status ) {
266
		return $status;
267
	}
268
269
	$connect_link = give_stripe_connect_button();
270
271
	// Default message.
272
	$main_text = __( 'The Stripe gateway is enabled but you\'re not connected. Connect to Stripe to start accepting credit card donations directly on your website. <a href="#" class="give-stripe-connect-temp-dismiss">Not right now <span class="dashicons dashicons-dismiss"></span></a>', 'give' );
273
274
	/**
275
	 * This filter hook is used to change the text of the connect banner.
276
	 *
277
	 * @param string $main_text Text to be displayed on the connect banner.
278
	 *
279
	 * @since 2.5.0
280
	 */
281
	$main_text = apply_filters( 'give_stripe_change_connect_banner_text', $main_text );
282
283
	$message = sprintf(
284
		/* translators: 1. Main Text, 2. Connect Link */
285
		__( '<strong>Stripe Connect:</strong> %1$s %2$s', 'give' ),
286
		$main_text,
287
		$connect_link
288
	);
289
290
	?>
291
	<div class="notice notice-warning give-stripe-connect-message">
292
		<p>
293
			<?php echo $message; ?>
0 ignored issues
show
introduced by
Expected next thing to be a escaping function, not '$message'
Loading history...
294
		</p>
295
	</div>
296
	<?php
297
}
298
299
add_action( 'admin_notices', 'give_stripe_show_connect_banner' );
300
301
/**
302
 * Dismiss connect banner temporarily.
303
 *
304
 * Sets transient via AJAX callback.
305
 *
306
 * @since 2.5.0
307
 */
308
function give_stripe_connect_dismiss_banner() {
309
310
	$user_id = get_current_user_id();
311
	set_transient( "give_hide_stripe_connect_notice_{$user_id}", '1', DAY_IN_SECONDS );
312
313
	return true;
314
315
}
316
317
add_action( 'give_stripe_connect_dismiss', 'give_stripe_connect_dismiss_banner' );
318
319