Completed
Push — master ( 4cfe42...efc364 )
by Roy
04:30 queued 02:18
created

WC_Stripe_Privacy::maybe_handle_subscription()   C

Complexity

Conditions 7
Paths 7

Size

Total Lines 44
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 24
nc 7
nop 1
dl 0
loc 44
rs 6.7272
c 0
b 0
f 0
1
<?php
2
if ( ! class_exists( 'WC_Abstract_Privacy' ) ) {
3
	return;
4
}
5
6
class WC_Stripe_Privacy extends WC_Abstract_Privacy {
7
	/**
8
	 * Constructor
9
	 *
10
	 */
11
	public function __construct() {
12
		parent::__construct( __( 'Stripe', 'woocommerce-gateway-stripe' ) );
13
14
		$this->add_exporter( 'woocommerce-gateway-stripe-order-data', __( 'WooCommerce Stripe Order Data', 'woocommerce-gateway-stripe' ), array( $this, 'order_data_exporter' ) );
15
16
		if ( function_exists( 'wcs_get_subscriptions' ) ) {
17
			$this->add_exporter( 'woocommerce-gateway-stripe-subscriptions-data', __( 'WooCommerce Stripe Subscriptions Data', 'woocommerce-gateway-stripe' ), array( $this, 'subscriptions_data_exporter' ) );
18
		}
19
20
		$this->add_exporter( 'woocommerce-gateway-stripe-customer-data', __( 'WooCommerce Stripe Customer Data', 'woocommerce-gateway-stripe' ), array( $this, 'customer_data_exporter' ) );
21
22
		$this->add_eraser( 'woocommerce-gateway-stripe-customer-data', __( 'WooCommerce Stripe Customer Data', 'woocommerce-gateway-stripe' ), array( $this, 'customer_data_eraser' ) );
23
		$this->add_eraser( 'woocommerce-gateway-stripe-order-data', __( 'WooCommerce Stripe Data', 'woocommerce-gateway-stripe' ), array( $this, 'order_data_eraser' ) );
24
	}
25
26
	/**
27
	 * Returns a list of orders that are using one of Stripe's payment methods.
28
	 *
29
	 * @param string  $email_address
30
	 * @param int     $page
31
	 *
32
	 * @return array WP_Post
33
	 */
34
	protected function get_stripe_orders( $email_address, $page ) {
35
		$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
36
37
		$order_query    = array(
38
			'payment_method' => array( 'stripe', 'stripe_alipay', 'stripe_bancontact', 'stripe_eps', 'stripe_giropay', 'stripe_ideal', 'stripe_multibanco', 'stripe_p24', 'stripe_sepa', 'stripe_sofort' ),
39
			'limit'          => 10,
40
			'page'           => $page,
41
		);
42
43
		if ( $user instanceof WP_User ) {
0 ignored issues
show
Bug introduced by
The class WP_User does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
44
			$order_query['customer_id'] = (int) $user->ID;
45
		} else {
46
			$order_query['billing_email'] = $email_address;
47
		}
48
49
		return wc_get_orders( $order_query );
50
	}
51
52
	/**
53
	 * Gets the message of the privacy to display.
54
	 *
55
	 */
56
	public function get_privacy_message() {
57
		return wpautop( sprintf( __( 'By using this extension, you may be storing personal data or sharing data with an external service. <a href="%s" target="_blank">Learn more about how this works, including what you may want to include in your privacy policy.</a>', 'woocommerce-gateway-stripe' ), 'https://docs.woocommerce.com/privacy/?woocommerce-gateway-stripe' ) );
58
	}
59
60
	/**
61
	 * Handle exporting data for Orders.
62
	 *
63
	 * @param string $email_address E-mail address to export.
64
	 * @param int    $page          Pagination of data.
65
	 *
66
	 * @return array
67
	 */
68
	public function order_data_exporter( $email_address, $page = 1 ) {
69
		$done           = false;
0 ignored issues
show
Unused Code introduced by
$done 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
70
		$data_to_export = array();
71
72
		$orders = $this->get_stripe_orders( $email_address, (int) $page );
73
74
		$done = true;
75
76 View Code Duplication
		if ( 0 < count( $orders ) ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
77
			foreach ( $orders as $order ) {
78
				$data_to_export[] = array(
79
					'group_id'    => 'woocommerce_orders',
80
					'group_label' => __( 'Orders', 'woocommerce-gateway-stripe' ),
81
					'item_id'     => 'order-' . $order->get_id(),
82
					'data'        => array(
83
						array(
84
							'name'  => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ),
85
							'value' => get_post_meta( $order->get_id(), '_stripe_source_id', true ),
86
						),
87
						array(
88
							'name'  => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ),
89
							'value' => get_post_meta( $order->get_id(), '_stripe_customer_id', true ),
90
						),
91
					),
92
				);
93
			}
94
95
			$done = 10 > count( $orders );
96
		}
97
98
		return array(
99
			'data' => $data_to_export,
100
			'done' => $done,
101
		);
102
	}
103
104
	/**
105
	 * Handle exporting data for Subscriptions.
106
	 *
107
	 * @param string $email_address E-mail address to export.
108
	 * @param int    $page          Pagination of data.
109
	 *
110
	 * @return array
111
	 */
112
	public function subscriptions_data_exporter( $email_address, $page = 1 ) {
113
		$done           = false;
0 ignored issues
show
Unused Code introduced by
$done 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
114
		$page           = (int) $page;
115
		$data_to_export = array();
116
117
		$meta_query = array(
118
			'relation'    => 'AND',
119
			array(
120
				'key'     => '_payment_method',
121
				'value'   => array( 'stripe', 'stripe_alipay', 'stripe_bancontact', 'stripe_eps', 'stripe_giropay', 'stripe_ideal', 'stripe_multibanco', 'stripe_p24', 'stripe_sepa', 'stripe_sofort' ),
122
				'compare' => 'IN',
123
			),
124
			array(
125
				'key'     => '_billing_email',
126
				'value'   => $email_address,
127
				'compare' => '=',
128
			),
129
		);
130
131
		$subscription_query    = array(
132
			'posts_per_page'  => 10,
133
			'page'            => $page,
134
			'meta_query'      => $meta_query,
135
		);
136
137
		$subscriptions = wcs_get_subscriptions( $subscription_query );
138
139
		$done = true;
140
141 View Code Duplication
		if ( 0 < count( $subscriptions ) ) {
0 ignored issues
show
Duplication introduced by
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.

Loading history...
142
			foreach ( $subscriptions as $subscription ) {
143
				$data_to_export[] = array(
144
					'group_id'    => 'woocommerce_subscriptions',
145
					'group_label' => __( 'Subscriptions', 'woocommerce-gateway-stripe' ),
146
					'item_id'     => 'subscription-' . $subscription->get_id(),
147
					'data'        => array(
148
						array(
149
							'name'  => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ),
150
							'value' => get_post_meta( $subscription->get_id(), '_stripe_source_id', true ),
151
						),
152
						array(
153
							'name'  => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ),
154
							'value' => get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ),
155
						),
156
					),
157
				);
158
			}
159
160
			$done = 10 > count( $subscriptions );
161
		}
162
163
		return array(
164
			'data' => $data_to_export,
165
			'done' => $done,
166
		);
167
	}
168
169
	/**
170
	 * Finds and exports customer data by email address.
171
	 *
172
	 * @param string $email_address The user email address.
173
	 * @param int    $page  Page.
174
	 * @return array An array of personal data in name value pairs
175
	 */
176
	public function customer_data_exporter( $email_address, $page ) {
177
		$user           = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
178
		$data_to_export = array();
179
180
		if ( $user instanceof WP_User ) {
0 ignored issues
show
Bug introduced by
The class WP_User does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
181
			$stripe_user = new WC_Stripe_Customer( $user->ID );
182
183
			$data_to_export[] = array(
184
				'group_id'    => 'woocommerce_customer',
185
				'group_label' => __( 'Customer Data', 'woocommerce-gateway-stripe' ),
186
				'item_id'     => 'user',
187
				'data'        => array(
188
					array(
189
						'name'  => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ),
190
						'value' => get_user_meta( $user->ID, '_stripe_source_id', true ),
191
					),
192
					array(
193
						'name'  => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ),
194
						'value' => $stripe_user->get_id(),
195
					),
196
				),
197
			);
198
		}
199
200
		return array(
201
			'data' => $data_to_export,
202
			'done' => true,
203
		);
204
	}
205
206
	/**
207
	 * Finds and erases customer data by email address.
208
	 *
209
	 * @param string $email_address The user email address.
210
	 * @param int    $page  Page.
211
	 * @return array An array of personal data in name value pairs
212
	 */
213
	public function customer_data_eraser( $email_address, $page ) {
214
		$page = (int) $page;
0 ignored issues
show
Unused Code introduced by
$page 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 $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
215
		$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data.
216
217
		$stripe_customer_id = get_user_meta( $user->ID, '_stripe_customer_id', true );
218
		$stripe_source_id   = get_user_meta( $user->ID, '_stripe_source_id', true );
219
220
		$items_removed  = false;
221
		$messages       = array();
222
223
		if ( ! empty( $stripe_customer_id ) || ! empty( $stripe_source_id ) ) {
224
			$items_removed = true;
225
			delete_user_meta( $user->ID, '_stripe_customer_id' );
226
			delete_user_meta( $user->ID, '_stripe_source_id' );
227
			$messages[] = __( 'Stripe User Data Erased.', 'woocommerce-gateway-stripe' );
228
		}
229
230
		return array(
231
			'items_removed'  => $items_removed,
232
			'items_retained' => false,
233
			'messages'       => $messages,
234
			'done'           => true,
235
		);
236
	}
237
238
	/**
239
	 * Finds and erases order data by email address.
240
	 *
241
	 * @param string $email_address The user email address.
242
	 * @param int    $page  Page.
243
	 * @return array An array of personal data in name value pairs
244
	 */
245
	public function order_data_eraser( $email_address, $page ) {
246
		$orders = $this->get_stripe_orders( $email_address, (int) $page );
247
248
		$items_removed  = false;
249
		$items_retained = false;
250
		$messages       = array();
251
252
		foreach ( (array) $orders as $order ) {
253
			$order = wc_get_order( $order->get_id() );
254
255
			list( $removed, $retained, $msgs ) = $this->maybe_handle_order( $order );
256
			$items_removed  |= $removed;
257
			$items_retained |= $retained;
258
			$messages        = array_merge( $messages, $msgs );
259
260
			list( $removed, $retained, $msgs ) = $this->maybe_handle_subscription( $order );
261
			$items_removed  |= $removed;
262
			$items_retained |= $retained;
263
			$messages        = array_merge( $messages, $msgs );
264
		}
265
266
		// Tell core if we have more orders to work on still
267
		$done = count( $orders ) < 10;
268
269
		return array(
270
			'items_removed'  => $items_removed,
271
			'items_retained' => $items_retained,
272
			'messages'       => $messages,
273
			'done'           => $done,
274
		);
275
	}
276
277
	/**
278
	 * Handle eraser of data tied to Subscriptions
279
	 *
280
	 * @param WC_Order $order
281
	 * @return array
282
	 */
283
	protected function maybe_handle_subscription( $order ) {
284
		if ( ! class_exists( 'WC_Subscriptions' ) ) {
285
			return array( false, false, array() );
286
		}
287
288
		if ( ! wcs_order_contains_subscription( $order ) ) {
289
			return array( false, false, array() );
290
		}
291
292
		$subscription    = current( wcs_get_subscriptions_for_order( $order->get_id() ) );
293
		$subscription_id = $subscription->get_id();
294
295
		$stripe_source_id = get_post_meta( $subscription_id, '_stripe_source_id', true );
296
297
		if ( empty( $stripe_source_id ) ) {
298
			return array( false, false, array() );
299
		}
300
301
		$order_age = strtotime( 'now' ) - $order->get_date_created()->getTimestamp();
302
303
		// If order age is longer than specified days, don't do anything to it
304
		// TODO: Figure out if 180 is the real number
305
		if ( $order_age < DAY_IN_SECONDS * 180 ) {
306
			return array( false, true, array( sprintf( __( 'Order ID %d is less than 180 days (Stripe)' ), $order->get_id() ) ) );
307
		}
308
309
		if ( $subscription->has_status( apply_filters( 'wc_stripe_privacy_eraser_subs_statuses', array( 'on-hold', 'active' ) ) ) ) {
310
			return array( false, true, array( sprintf( __( 'Order ID %d contains an active Subscription' ), $order->get_id() ) ) );
311
		}
312
313
		$renewal_orders = WC_Subscriptions_Renewal_Order::get_renewal_orders( $order->get_id() );
314
315
		foreach ( $renewal_orders as $renewal_order_id ) {
316
			delete_post_meta( $renewal_order_id, '_stripe_source_id' );
317
			delete_post_meta( $renewal_order_id, '_stripe_refund_id' );
318
			delete_post_meta( $renewal_order_id, '_stripe_customer_id' );
319
		}
320
321
		delete_post_meta( $subscription_id, '_stripe_source_id' );
322
		delete_post_meta( $subscription_id, '_stripe_refund_id' );
323
		delete_post_meta( $subscription_id, '_stripe_customer_id' );
324
325
		return array( true, false, array( __( 'Stripe Subscription Data Erased.', 'woocommerce-gateway-stripe' ) ) );
326
	}
327
328
	/**
329
	 * Handle eraser of data tied to Orders
330
	 *
331
	 * @param WC_Order $order
332
	 * @return array
333
	 */
334
	protected function maybe_handle_order( $order ) {
335
		$order_id           = $order->get_id();
336
		$stripe_source_id   = get_post_meta( $order_id, '_stripe_source_id', true );
337
		$stripe_refund_id   = get_post_meta( $order_id, '_stripe_refund_id', true );
338
		$stripe_customer_id = get_post_meta( $order_id, '_stripe_customer_id', true );
339
340
		if ( empty( $stripe_source_id ) && empty( $stripe_refund_id ) && empty( $stripe_customer_id ) ) {
341
			return array( false, false, array() );
342
		}
343
344
		delete_post_meta( $order_id, '_stripe_source_id' );
345
		delete_post_meta( $order_id, '_stripe_refund_id' );
346
		delete_post_meta( $order_id, '_stripe_customer_id' );
347
348
		return array( true, false, array( __( 'Stripe personal data erased.', 'woocommerce-gateway-stripe' ) ) );
349
	}
350
}
351
352
new WC_Stripe_Privacy();
353