-
Notifications
You must be signed in to change notification settings - Fork 206
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #649 from woocommerce/feature/stripe-privacy
Feature/stripe privacy
- Loading branch information
Showing
3 changed files
with
358 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,352 @@ | ||
<?php | ||
if ( ! class_exists( 'WC_Abstract_Privacy' ) ) { | ||
return; | ||
} | ||
|
||
class WC_Stripe_Privacy extends WC_Abstract_Privacy { | ||
/** | ||
* Constructor | ||
* | ||
*/ | ||
public function __construct() { | ||
parent::__construct( __( 'Stripe', 'woocommerce-gateway-stripe' ) ); | ||
|
||
$this->add_exporter( 'woocommerce-gateway-stripe-order-data', __( 'WooCommerce Stripe Order Data', 'woocommerce-gateway-stripe' ), array( $this, 'order_data_exporter' ) ); | ||
|
||
if ( function_exists( 'wcs_get_subscriptions' ) ) { | ||
$this->add_exporter( 'woocommerce-gateway-stripe-subscriptions-data', __( 'WooCommerce Stripe Subscriptions Data', 'woocommerce-gateway-stripe' ), array( $this, 'subscriptions_data_exporter' ) ); | ||
} | ||
|
||
$this->add_exporter( 'woocommerce-gateway-stripe-customer-data', __( 'WooCommerce Stripe Customer Data', 'woocommerce-gateway-stripe' ), array( $this, 'customer_data_exporter' ) ); | ||
|
||
$this->add_eraser( 'woocommerce-gateway-stripe-customer-data', __( 'WooCommerce Stripe Customer Data', 'woocommerce-gateway-stripe' ), array( $this, 'customer_data_eraser' ) ); | ||
$this->add_eraser( 'woocommerce-gateway-stripe-order-data', __( 'WooCommerce Stripe Data', 'woocommerce-gateway-stripe' ), array( $this, 'order_data_eraser' ) ); | ||
} | ||
|
||
/** | ||
* Returns a list of orders that are using one of Stripe's payment methods. | ||
* | ||
* @param string $email_address | ||
* @param int $page | ||
* | ||
* @return array WP_Post | ||
*/ | ||
protected function get_stripe_orders( $email_address, $page ) { | ||
$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data. | ||
|
||
$order_query = array( | ||
'payment_method' => array( 'stripe', 'stripe_alipay', 'stripe_bancontact', 'stripe_eps', 'stripe_giropay', 'stripe_ideal', 'stripe_multibanco', 'stripe_p24', 'stripe_sepa', 'stripe_sofort' ), | ||
'limit' => 10, | ||
'page' => $page, | ||
); | ||
|
||
if ( $user instanceof WP_User ) { | ||
$order_query['customer_id'] = (int) $user->ID; | ||
} else { | ||
$order_query['billing_email'] = $email_address; | ||
} | ||
|
||
return wc_get_orders( $order_query ); | ||
} | ||
|
||
/** | ||
* Gets the message of the privacy to display. | ||
* | ||
*/ | ||
public function get_privacy_message() { | ||
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' ) ); | ||
} | ||
|
||
/** | ||
* Handle exporting data for Orders. | ||
* | ||
* @param string $email_address E-mail address to export. | ||
* @param int $page Pagination of data. | ||
* | ||
* @return array | ||
*/ | ||
public function order_data_exporter( $email_address, $page = 1 ) { | ||
$done = false; | ||
$data_to_export = array(); | ||
|
||
$orders = $this->get_stripe_orders( $email_address, (int) $page ); | ||
|
||
$done = true; | ||
|
||
if ( 0 < count( $orders ) ) { | ||
foreach ( $orders as $order ) { | ||
$data_to_export[] = array( | ||
'group_id' => 'woocommerce_orders', | ||
'group_label' => __( 'Orders', 'woocommerce-gateway-stripe' ), | ||
'item_id' => 'order-' . $order->get_id(), | ||
'data' => array( | ||
array( | ||
'name' => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ), | ||
'value' => get_post_meta( $order->get_id(), '_stripe_source_id', true ), | ||
), | ||
array( | ||
'name' => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ), | ||
'value' => get_post_meta( $order->get_id(), '_stripe_customer_id', true ), | ||
), | ||
), | ||
); | ||
} | ||
|
||
$done = 10 > count( $orders ); | ||
} | ||
|
||
return array( | ||
'data' => $data_to_export, | ||
'done' => $done, | ||
); | ||
} | ||
|
||
/** | ||
* Handle exporting data for Subscriptions. | ||
* | ||
* @param string $email_address E-mail address to export. | ||
* @param int $page Pagination of data. | ||
* | ||
* @return array | ||
*/ | ||
public function subscriptions_data_exporter( $email_address, $page = 1 ) { | ||
$done = false; | ||
$page = (int) $page; | ||
$data_to_export = array(); | ||
|
||
$meta_query = array( | ||
'relation' => 'AND', | ||
array( | ||
'key' => '_payment_method', | ||
'value' => array( 'stripe', 'stripe_alipay', 'stripe_bancontact', 'stripe_eps', 'stripe_giropay', 'stripe_ideal', 'stripe_multibanco', 'stripe_p24', 'stripe_sepa', 'stripe_sofort' ), | ||
'compare' => 'IN', | ||
), | ||
array( | ||
'key' => '_billing_email', | ||
'value' => $email_address, | ||
'compare' => '=', | ||
), | ||
); | ||
|
||
$subscription_query = array( | ||
'posts_per_page' => 10, | ||
'page' => $page, | ||
'meta_query' => $meta_query, | ||
); | ||
|
||
$subscriptions = wcs_get_subscriptions( $subscription_query ); | ||
|
||
$done = true; | ||
|
||
if ( 0 < count( $subscriptions ) ) { | ||
foreach ( $subscriptions as $subscription ) { | ||
$data_to_export[] = array( | ||
'group_id' => 'woocommerce_subscriptions', | ||
'group_label' => __( 'Subscriptions', 'woocommerce-gateway-stripe' ), | ||
'item_id' => 'subscription-' . $subscription->get_id(), | ||
'data' => array( | ||
array( | ||
'name' => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ), | ||
'value' => get_post_meta( $subscription->get_id(), '_stripe_source_id', true ), | ||
), | ||
array( | ||
'name' => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ), | ||
'value' => get_post_meta( $subscription->get_id(), '_stripe_customer_id', true ), | ||
), | ||
), | ||
); | ||
} | ||
|
||
$done = 10 > count( $subscriptions ); | ||
} | ||
|
||
return array( | ||
'data' => $data_to_export, | ||
'done' => $done, | ||
); | ||
} | ||
|
||
/** | ||
* Finds and exports customer data by email address. | ||
* | ||
* @param string $email_address The user email address. | ||
* @param int $page Page. | ||
* @return array An array of personal data in name value pairs | ||
*/ | ||
public function customer_data_exporter( $email_address, $page ) { | ||
$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data. | ||
$data_to_export = array(); | ||
|
||
if ( $user instanceof WP_User ) { | ||
$stripe_user = new WC_Stripe_Customer( $user->ID ); | ||
|
||
$data_to_export[] = array( | ||
'group_id' => 'woocommerce_customer', | ||
'group_label' => __( 'Customer Data', 'woocommerce-gateway-stripe' ), | ||
'item_id' => 'user', | ||
'data' => array( | ||
array( | ||
'name' => __( 'Stripe payment id', 'woocommerce-gateway-stripe' ), | ||
'value' => get_user_meta( $user->ID, '_stripe_source_id', true ), | ||
), | ||
array( | ||
'name' => __( 'Stripe customer id', 'woocommerce-gateway-stripe' ), | ||
'value' => $stripe_user->get_id(), | ||
), | ||
), | ||
); | ||
} | ||
|
||
return array( | ||
'data' => $data_to_export, | ||
'done' => true, | ||
); | ||
} | ||
|
||
/** | ||
* Finds and erases customer data by email address. | ||
* | ||
* @param string $email_address The user email address. | ||
* @param int $page Page. | ||
* @return array An array of personal data in name value pairs | ||
*/ | ||
public function customer_data_eraser( $email_address, $page ) { | ||
$page = (int) $page; | ||
$user = get_user_by( 'email', $email_address ); // Check if user has an ID in the DB to load stored personal data. | ||
|
||
$stripe_customer_id = get_user_meta( $user->ID, '_stripe_customer_id', true ); | ||
$stripe_source_id = get_user_meta( $user->ID, '_stripe_source_id', true ); | ||
|
||
$items_removed = false; | ||
$messages = array(); | ||
|
||
if ( ! empty( $stripe_customer_id ) || ! empty( $stripe_source_id ) ) { | ||
$items_removed = true; | ||
delete_user_meta( $user->ID, '_stripe_customer_id' ); | ||
delete_user_meta( $user->ID, '_stripe_source_id' ); | ||
$messages[] = __( 'Stripe User Data Erased.', 'woocommerce-gateway-stripe' ); | ||
} | ||
|
||
return array( | ||
'items_removed' => $items_removed, | ||
'items_retained' => false, | ||
'messages' => $messages, | ||
'done' => true, | ||
); | ||
} | ||
|
||
/** | ||
* Finds and erases order data by email address. | ||
* | ||
* @param string $email_address The user email address. | ||
* @param int $page Page. | ||
* @return array An array of personal data in name value pairs | ||
*/ | ||
public function order_data_eraser( $email_address, $page ) { | ||
$orders = $this->get_stripe_orders( $email_address, (int) $page ); | ||
|
||
$items_removed = false; | ||
$items_retained = false; | ||
$messages = array(); | ||
|
||
foreach ( (array) $orders as $order ) { | ||
$order = wc_get_order( $order->get_id() ); | ||
|
||
list( $removed, $retained, $msgs ) = $this->maybe_handle_order( $order ); | ||
$items_removed |= $removed; | ||
$items_retained |= $retained; | ||
$messages = array_merge( $messages, $msgs ); | ||
|
||
list( $removed, $retained, $msgs ) = $this->maybe_handle_subscription( $order ); | ||
$items_removed |= $removed; | ||
$items_retained |= $retained; | ||
$messages = array_merge( $messages, $msgs ); | ||
} | ||
|
||
// Tell core if we have more orders to work on still | ||
$done = count( $orders ) < 10; | ||
|
||
return array( | ||
'items_removed' => $items_removed, | ||
'items_retained' => $items_retained, | ||
'messages' => $messages, | ||
'done' => $done, | ||
); | ||
} | ||
|
||
/** | ||
* Handle eraser of data tied to Subscriptions | ||
* | ||
* @param WC_Order $order | ||
* @return array | ||
*/ | ||
protected function maybe_handle_subscription( $order ) { | ||
if ( ! class_exists( 'WC_Subscriptions' ) ) { | ||
return array( false, false, array() ); | ||
} | ||
|
||
if ( ! wcs_order_contains_subscription( $order ) ) { | ||
return array( false, false, array() ); | ||
} | ||
|
||
$subscription = current( wcs_get_subscriptions_for_order( $order->get_id() ) ); | ||
$subscription_id = $subscription->get_id(); | ||
|
||
$stripe_source_id = get_post_meta( $subscription_id, '_stripe_source_id', true ); | ||
|
||
if ( empty( $stripe_source_id ) ) { | ||
return array( false, false, array() ); | ||
} | ||
|
||
$order_age = strtotime( 'now' ) - $order->get_date_created()->getTimestamp(); | ||
|
||
// If order age is longer than specified days, don't do anything to it | ||
// TODO: Figure out if 180 is the real number | ||
if ( $order_age < DAY_IN_SECONDS * 180 ) { | ||
return array( false, true, array( sprintf( __( 'Order ID %d is less than 180 days (Stripe)' ), $order->get_id() ) ) ); | ||
} | ||
|
||
if ( $subscription->has_status( apply_filters( 'wc_stripe_privacy_eraser_subs_statuses', array( 'on-hold', 'active' ) ) ) ) { | ||
return array( false, true, array( sprintf( __( 'Order ID %d contains an active Subscription' ), $order->get_id() ) ) ); | ||
} | ||
|
||
$renewal_orders = WC_Subscriptions_Renewal_Order::get_renewal_orders( $order->get_id() ); | ||
|
||
foreach ( $renewal_orders as $renewal_order_id ) { | ||
delete_post_meta( $renewal_order_id, '_stripe_source_id' ); | ||
delete_post_meta( $renewal_order_id, '_stripe_refund_id' ); | ||
delete_post_meta( $renewal_order_id, '_stripe_customer_id' ); | ||
} | ||
|
||
delete_post_meta( $subscription_id, '_stripe_source_id' ); | ||
delete_post_meta( $subscription_id, '_stripe_refund_id' ); | ||
delete_post_meta( $subscription_id, '_stripe_customer_id' ); | ||
|
||
return array( true, false, array( __( 'Stripe Subscription Data Erased.', 'woocommerce-gateway-stripe' ) ) ); | ||
} | ||
|
||
/** | ||
* Handle eraser of data tied to Orders | ||
* | ||
* @param WC_Order $order | ||
* @return array | ||
*/ | ||
protected function maybe_handle_order( $order ) { | ||
$order_id = $order->get_id(); | ||
$stripe_source_id = get_post_meta( $order_id, '_stripe_source_id', true ); | ||
$stripe_refund_id = get_post_meta( $order_id, '_stripe_refund_id', true ); | ||
$stripe_customer_id = get_post_meta( $order_id, '_stripe_customer_id', true ); | ||
|
||
if ( empty( $stripe_source_id ) && empty( $stripe_refund_id ) && empty( $stripe_customer_id ) ) { | ||
return array( false, false, array() ); | ||
} | ||
|
||
delete_post_meta( $order_id, '_stripe_source_id' ); | ||
delete_post_meta( $order_id, '_stripe_refund_id' ); | ||
delete_post_meta( $order_id, '_stripe_customer_id' ); | ||
|
||
return array( true, false, array( __( 'Stripe personal data erased.', 'woocommerce-gateway-stripe' ) ) ); | ||
} | ||
} | ||
|
||
new WC_Stripe_Privacy(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters