__( 'ReturnKit returns and withdrawals', 'returnkit' ), 'callback' => array( __CLASS__, 'export' ), ); return $exporters; } /** * Register the eraser. * * @param array $erasers Erasers. * @return array */ public static function erasers( $erasers ) { $erasers['returnkit'] = array( 'eraser_friendly_name' => __( 'ReturnKit returns and withdrawals', 'returnkit' ), 'callback' => array( __CLASS__, 'erase' ), ); return $erasers; } /** * Export a person's requests. * * @param string $email Email. * @param int $page Page. * @return array */ public static function export( $email, $page = 1 ) { $requests = self::requests_of( $email, $page ); $items = array(); foreach ( $requests as $request ) { $data = array( array( 'name' => __( 'Request', 'returnkit' ), 'value' => $request->number(), ), array( 'name' => __( 'Type', 'returnkit' ), 'value' => Labels::type( $request->type() ), ), array( 'name' => __( 'Status', 'returnkit' ), 'value' => Labels::status( $request->status(), $request->type() ), ), array( 'name' => __( 'Submitted', 'returnkit' ), 'value' => Labels::local( $request->created_gmt() ), ), array( 'name' => __( 'Name', 'returnkit' ), 'value' => $request->name(), ), array( 'name' => __( 'Email', 'returnkit' ), 'value' => $request->email(), ), array( 'name' => __( 'IP address', 'returnkit' ), 'value' => (string) $request->get( 'ip' ), ), array( 'name' => __( 'Note', 'returnkit' ), 'value' => $request->note(), ), ); $lines = array(); foreach ( $request->items() as $item ) { $lines[] = (int) $item['qty'] . ' × ' . $item['name']; } if ( $lines ) { $data[] = array( 'name' => __( 'Items', 'returnkit' ), 'value' => implode( ', ', $lines ), ); } $items[] = array( 'group_id' => 'returnkit', 'group_label' => __( 'Returns and withdrawals', 'returnkit' ), 'item_id' => 'rtkt-request-' . $request->id(), 'data' => $data, ); } $done = count( $requests ) < self::PAGE; if ( $done ) { foreach ( self::credit_rows( $email ) as $row ) { $items[] = array( 'group_id' => 'returnkit-credit', 'group_label' => __( 'Store credit', 'returnkit' ), 'item_id' => 'rtkt-credit-' . $row['id'], 'data' => array( array( 'name' => __( 'Date', 'returnkit' ), 'value' => $row['created_at'], ), array( 'name' => __( 'Amount', 'returnkit' ), 'value' => $row['amount'], ), array( 'name' => __( 'Note', 'returnkit' ), 'value' => $row['note'], ), ), ); } } return array( 'data' => $items, 'done' => $done, ); } /** * A person's requests: by email, plus those made with their account. * * @param string $email Email. * @param int $page Page. * @return \ReturnKit\Domain\Request[] */ private static function requests_of( $email, $page = 1 ) { $requests = Requests::by_email( $email, self::PAGE, $page ); $user = get_user_by( 'email', $email ); if ( $user && 1 === (int) $page ) { foreach ( Requests::query( array( 'customer_id' => $user->ID ), 500 ) as $request ) { $requests[ $request->id() ] = $request; } } $out = array(); foreach ( $requests as $request ) { $out[ $request->id() ] = $request; } return array_values( $out ); } /** * Store credit ledger rows for an email (Pro table, when it exists). * * @param string $email Email. * @return array[] */ private static function credit_rows( $email ) { global $wpdb; $table = $wpdb->prefix . 'rtkt_credit'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $table ) ) !== $table ) { return array(); } $user = get_user_by( 'email', $email ); $rows = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i WHERE email = %s OR ( user_id > 0 AND user_id = %d )', $table, strtolower( (string) $email ), $user ? $user->ID : 0 ), ARRAY_A ); return $rows ? $rows : array(); } /** * Anonymize a person's requests. * * @param string $email Email. * @param int $page Page (always 1: anonymized rows drop out of the query). * @return array */ public static function erase( $email, $page = 1 ) { unset( $page ); global $wpdb; $requests = self::requests_of( $email, 1 ); $removed = false; foreach ( $requests as $request ) { $meta = $request->all_meta(); if ( isset( $meta['statement'] ) && is_array( $meta['statement'] ) ) { $meta['statement']['name'] = ''; $meta['statement']['email'] = ''; $meta['statement']['note'] = ''; $meta['statement']['details'] = ''; } if ( ! empty( $meta['label']['file'] ) && preg_match( '/^[a-f0-9]{32}\.(pdf|png|jpe?g|gif)$/', (string) $meta['label']['file'] ) ) { // Labels carry the customer's address. $uploads = wp_upload_dir( null, false ); $file = trailingslashit( $uploads['basedir'] ) . 'returnkit-labels/' . $meta['label']['file']; if ( file_exists( $file ) ) { wp_delete_file( $file ); } unset( $meta['label'] ); } $meta['anonymized'] = time(); Requests::update( $request->id(), array( 'email' => 'deleted-' . $request->id() . '@anonymized.invalid', 'name' => '', 'ip' => '', 'note' => '', 'meta' => $meta, ) ); $wpdb->query( $wpdb->prepare( 'UPDATE %i SET data = NULL WHERE request_id = %d', Log::table(), $request->id() ) ); // Notes and messages are free text that may name the customer. $wpdb->query( $wpdb->prepare( "UPDATE %i SET message = %s WHERE request_id = %d AND event IN ('note', 'message')", Log::table(), __( '[erased]', 'returnkit' ), $request->id() ) ); Log::add( $request->id(), 'anonymized', __( 'Personal data erased on request.', 'returnkit' ), 'admin' ); $removed = true; } $credit = $wpdb->prefix . 'rtkt_credit'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $credit ) ) === $credit ) { // Amounts stay for the books; the email goes. $wpdb->query( $wpdb->prepare( "UPDATE %i SET email = '', note = '' WHERE email = %s", $credit, strtolower( (string) $email ) ) ); } return array( 'items_removed' => $removed, 'items_retained' => false, 'messages' => array(), 'done' => count( Requests::by_email( $email, self::PAGE, 1 ) ) < self::PAGE, ); } /** * Suggested privacy-policy text. * * @return void */ public static function policy() { if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) { return; } if ( Settings::get( 'anonymize_ip' ) ) { $text = __( 'When you request a return, an exchange or withdraw from a purchase, we store your name, email address, the order and items concerned, your reason and comments, the date and time, and a shortened (anonymized) IP address. We use this to handle your request, to send you the confirmations and updates about it, and, for withdrawals, as the record of when your withdrawal was received. These records are kept as long as your order records.', 'returnkit' ); } else { $text = __( 'When you request a return, an exchange or withdraw from a purchase, we store your name, email address, the order and items concerned, your reason and comments, the date and time, and your IP address. We use this to handle your request, to send you the confirmations and updates about it, and, for withdrawals, as the record of when your withdrawal was received. These records are kept as long as your order records.', 'returnkit' ); } wp_add_privacy_policy_content( __( 'ReturnKit', 'returnkit' ), wp_kses_post( '
' . $text . '
' ) ); } }