laipower/wp-content/plugins/easy-digital-downloads/includes/admin/import/class-batch-import-payments.php

637 lines
15 KiB
PHP

<?php
/**
* Payment Import Class
*
* This class handles importing payments with the batch processing API
*
* @package EDD
* @subpackage Admin/Import
* @copyright Copyright (c) 2018, Easy Digital Downloads, LLC
* @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
* @since 2.6
*/
// Exit if accessed directly
defined( 'ABSPATH' ) || exit;
/**
* EDD_Batch_Import Class
*
* @since 2.6
*/
class EDD_Batch_Payments_Import extends EDD_Batch_Import {
/**
* Set up our import config.
*
* @since 2.6
* @return void
*/
public function init() {
$this->per_step = 5;
// Set up default field map values
$this->field_mapping = array(
'total' => '',
'subtotal' => '',
'tax' => 'draft',
'number' => '',
'mode' => '',
'gateway' => '',
'date' => '',
'status' => '',
'email' => '',
'name' => '',
'first_name' => '',
'last_name' => '',
'edd_customer_id' => '',
'user_id' => '',
'discounts' => '',
'key' => '',
'transaction_id' => '',
'ip' => '',
'currency' => '',
'parent_payment_id' => '',
'downloads' => '',
'line1' => '',
'line2' => '',
'city' => '',
'state' => '',
'zip' => '',
'country' => '',
);
}
/**
* Process a step
*
* @since 2.6
* @return bool
*/
public function process_step() {
$more = false;
if ( ! $this->can_import() ) {
wp_die( __( 'You do not have permission to import data.', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) );
}
// Remove certain actions to ensure they don't fire when creating the payments
remove_action( 'edd_complete_purchase', 'edd_trigger_purchase_receipt', 999 );
remove_action( 'edd_admin_sale_notice', 'edd_admin_email_notice', 10 );
$i = 1;
$offset = $this->step > 1 ? ( $this->per_step * ( $this->step - 1 ) ) : 0;
if( $offset > $this->total ) {
$this->done = true;
// Clean up the temporary records in the payment import process
global $wpdb;
$sql = "DELETE FROM {$wpdb->prefix}edd_customermeta WHERE meta_key = '_canonical_import_id'";
$wpdb->query( $sql );
// Delete the uploaded CSV file.
unlink( $this->file );
}
if( ! $this->done && $this->csv ) {
$more = true;
foreach( $this->csv as $key => $row ) {
// Skip all rows until we pass our offset
if( $key + 1 <= $offset ) {
continue;
}
// Done with this batch
if( $i > $this->per_step ) {
break;
}
// Import payment
$this->create_payment( $row );
$i++;
}
}
return $more;
}
/**
* Set up and store a payment record from a CSV row
*
* @since 2.6
* @return void
*/
public function create_payment( $row = array() ) {
$payment = new EDD_Payment;
$payment->status = 'pending';
if( ! empty( $this->field_mapping['number'] ) && ! empty( $row[ $this->field_mapping['number'] ] ) ) {
$payment->number = sanitize_text_field( $row[ $this->field_mapping['number'] ] );
}
if( ! empty( $this->field_mapping['mode'] ) && ! empty( $row[ $this->field_mapping['mode'] ] ) ) {
$mode = strtolower( sanitize_text_field( $row[ $this->field_mapping['mode'] ] ) );
$mode = 'test' != $mode && 'live' != $mode ? false : $mode;
if( ! $mode ) {
$mode = edd_is_test_mode() ? 'test' : 'live';
}
$payment->mode = $mode;
}
if( ! empty( $this->field_mapping['date'] ) && ! empty( $row[ $this->field_mapping['date'] ] ) ) {
$date = sanitize_text_field( $row[ $this->field_mapping['date'] ] );
if( ! strtotime( $date ) ) {
$date = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
} else {
$date = date( 'Y-m-d H:i:s', strtotime( $date ) );
}
$payment->date = $date;
}
$payment->customer_id = $this->set_customer( $row );
if( ! empty( $this->field_mapping['email'] ) && ! empty( $row[ $this->field_mapping['email'] ] ) ) {
$payment->email = sanitize_text_field( $row[ $this->field_mapping['email'] ] );
}
if ( ! empty( $this->field_mapping['name'] ) && ! empty( $row[ $this->field_mapping['name'] ] ) ) {
$payment->name = sanitize_text_field( $row[ $this->field_mapping['name'] ] );
} else {
if ( ! empty( $this->field_mapping['first_name'] ) && ! empty( $row[ $this->field_mapping['first_name'] ] ) ) {
$payment->first_name = sanitize_text_field( $row[ $this->field_mapping['first_name'] ] );
}
if ( ! empty( $this->field_mapping['last_name'] ) && ! empty( $row[ $this->field_mapping['last_name'] ] ) ) {
$payment->last_name = sanitize_text_field( $row[ $this->field_mapping['last_name'] ] );
}
}
if( ! empty( $this->field_mapping['user_id'] ) && ! empty( $row[ $this->field_mapping['user_id'] ] ) ) {
$user_id = sanitize_text_field( $row[ $this->field_mapping['user_id'] ] );
if( is_numeric( $user_id ) ) {
$user_id = absint( $row[ $this->field_mapping['user_id'] ] );
$user = get_userdata( $user_id );
} elseif( is_email( $user_id ) ) {
$user = get_user_by( 'email', $user_id );
} else {
$user = get_user_by( 'login', $user_id );
}
if( $user ) {
$payment->user_id = $user->ID;
$customer = new EDD_Customer( $payment->customer_id );
if( empty( $customer->user_id ) ) {
$customer->update( array( 'user_id' => $user->ID ) );
}
}
}
if( ! empty( $this->field_mapping['discounts'] ) && ! empty( $row[ $this->field_mapping['discounts'] ] ) ) {
$payment->discounts = sanitize_text_field( $row[ $this->field_mapping['discounts'] ] );
}
if( ! empty( $this->field_mapping['transaction_id'] ) && ! empty( $row[ $this->field_mapping['transaction_id'] ] ) ) {
$payment->transaction_id = sanitize_text_field( $row[ $this->field_mapping['transaction_id'] ] );
}
if( ! empty( $this->field_mapping['ip'] ) && ! empty( $row[ $this->field_mapping['ip'] ] ) ) {
$payment->ip = sanitize_text_field( $row[ $this->field_mapping['ip'] ] );
}
if( ! empty( $this->field_mapping['gateway'] ) && ! empty( $row[ $this->field_mapping['gateway'] ] ) ) {
$gateways = edd_get_payment_gateways();
$gateway = strtolower( sanitize_text_field( $row[ $this->field_mapping['gateway'] ] ) );
if( ! array_key_exists( $gateway, $gateways ) ) {
foreach( $gateways as $key => $enabled_gateway ) {
if( $enabled_gateway['checkout_label'] == $gateway ) {
$gateway = $key;
break;
}
}
}
$payment->gateway = $gateway;
}
if( ! empty( $this->field_mapping['currency'] ) && ! empty( $row[ $this->field_mapping['currency'] ] ) ) {
$payment->currency = strtoupper( sanitize_text_field( $row[ $this->field_mapping['currency'] ] ) );
}
if( ! empty( $this->field_mapping['key'] ) && ! empty( $row[ $this->field_mapping['key'] ] ) ) {
$payment->key = sanitize_text_field( $row[ $this->field_mapping['key'] ] );
}
if( ! empty( $this->field_mapping['parent_payment_id'] ) && ! empty( $row[ $this->field_mapping['parent_payment_id'] ] ) ) {
$payment->parent_payment_id = absint( $row[ $this->field_mapping['parent_payment_id'] ] );
}
if( ! empty( $this->field_mapping['downloads'] ) && ! empty( $row[ $this->field_mapping['downloads'] ] ) ) {
if( __( 'Products (Raw)', 'easy-digital-downloads' ) == $this->field_mapping['downloads'] ) {
// This is an EDD export so we can extract prices
$downloads = $this->get_downloads_from_edd( $row[ $this->field_mapping['downloads'] ] );
} else {
$downloads = $this->str_to_array( $row[ $this->field_mapping['downloads'] ] );
}
if( is_array( $downloads ) ) {
$download_count = count( $downloads );
foreach( $downloads as $download ) {
if( is_array( $download ) ) {
$download_name = $download['download'];
$price = $download['price'];
$tax = $download['tax'];
$price_id = $download['price_id'];
} else {
$download_name = $download;
}
$download_id = $this->maybe_create_download( $download_name );
if( ! $download_id ) {
continue;
}
$item_price = ! isset( $price ) ? edd_get_download_price( $download_id ) : $price;
$item_tax = ! isset( $tax ) ? ( $download_count > 1 ? 0.00 : $payment->tax ) : $tax;
$price_id = ! isset( $price_id ) ? false : $price_id;
$args = array(
'item_price' => $item_price,
'tax' => $item_tax,
'price_id' => $price_id,
);
$payment->add_download( $download_id, $args );
}
}
}
if( ! empty( $this->field_mapping['total'] ) && ! empty( $row[ $this->field_mapping['total'] ] ) ) {
$payment->total = edd_sanitize_amount( $row[ $this->field_mapping['total'] ] );
}
if( ! empty( $this->field_mapping['tax'] ) && ! empty( $row[ $this->field_mapping['tax'] ] ) ) {
$payment->tax = edd_sanitize_amount( $row[ $this->field_mapping['tax'] ] );
}
if( ! empty( $this->field_mapping['subtotal'] ) && ! empty( $row[ $this->field_mapping['subtotal'] ] ) ) {
$payment->subtotal = edd_sanitize_amount( $row[ $this->field_mapping['subtotal'] ] );
} else {
$payment->subtotal = $payment->total - $payment->tax;
}
$address = array( 'line1' => '', 'line2' => '', 'city' => '', 'state' => '', 'zip' => '', 'country' => '' );
foreach( $address as $key => $address_field ) {
if( ! empty( $this->field_mapping[ $key ] ) && ! empty( $row[ $this->field_mapping[ $key ] ] ) ) {
$address[ $key ] = sanitize_text_field( $row[ $this->field_mapping[ $key ] ] );
}
}
$payment->address = $address;
$payment->save();
// The status has to be set after payment is created to ensure status update properly
if( ! empty( $this->field_mapping['status'] ) && ! empty( $row[ $this->field_mapping['status'] ] ) ) {
$payment->status = strtolower( sanitize_text_field( $row[ $this->field_mapping['status'] ] ) );
} else {
$payment->status = 'complete';
}
// Save a second time to update stats
$payment->save();
}
private function set_customer( $row ) {
global $wpdb;
$customer = false;
$customer = false;
$email = '';
if( ! empty( $this->field_mapping['email'] ) && ! empty( $row[ $this->field_mapping['email'] ] ) ) {
$email = sanitize_text_field( $row[ $this->field_mapping['email'] ] );
}
// Look for a customer from the canonical source, if any
if( ! empty( $this->field_mapping['edd_customer_id'] ) && ! empty( $row[ $this->field_mapping['edd_customer_id'] ] ) ) {
$canonical_id = absint( $row[ $this->field_mapping['edd_customer_id'] ] );
$mapped_id = $wpdb->get_var( $wpdb->prepare( "SELECT edd_customer_id FROM $wpdb->edd_customermeta WHERE meta_key = '_canonical_import_id' AND meta_value = %d LIMIT 1", $canonical_id ) );
}
if( ! empty( $mapped_id ) ) {
$customer = new EDD_Customer( $mapped_id );
}
if( empty( $mapped_id ) || ! $customer->id > 0 ) {
// Look for a customer based on provided ID, if any
if ( ! empty( $this->field_mapping['edd_customer_id'] ) && ! empty( $row[ $this->field_mapping['edd_customer_id'] ] ) ) {
$customer_id = absint( $row[ $this->field_mapping['edd_customer_id'] ] );
$customer_by_id = new EDD_Customer( $customer_id );
}
// Now look for a customer based on provided email
if( ! empty( $email ) ) {
$customer_by_email = new EDD_Customer( $email );
}
// Now compare customer records. If they don't match, customer_id will be stored in meta and we will use the customer that matches the email
if ( ! empty( $customer_by_email ) && ( empty( $customer_by_id ) || $customer_by_id->id !== $customer_by_email->id ) ) {
$customer = $customer_by_email;
} elseif ( ! empty( $customer_by_id ) ) {
$customer = $customer_by_id;
if( ! empty( $email ) ) {
$customer->add_email( $email );
}
}
// Make sure we found a customer. Create one if not.
if ( empty( $customer->id ) ) {
if ( ! $customer instanceof EDD_Customer ) {
$customer = new EDD_Customer();
}
}
if ( ! empty( $this->field_mapping['name'] ) && ! empty( $row[ $this->field_mapping['name'] ] ) ) {
$name = $row[ $this->field_mapping['name'] ];
} else {
$first_name = '';
$last_name = '';
if ( ! empty( $this->field_mapping['first_name'] ) && ! empty( $row[ $this->field_mapping['first_name'] ] ) ) {
$first_name = $row[ $this->field_mapping['first_name'] ];
}
if ( ! empty( $this->field_mapping['last_name'] ) && ! empty( $row[ $this->field_mapping['last_name'] ] ) ) {
$last_name = $row[ $this->field_mapping['last_name'] ];
}
$name = $first_name . ' ' . $last_name;
}
$customer->create(
array(
'name' => sanitize_text_field( $name ),
'email' => empty( $email ) ? '' : $email,
)
);
if( ! empty( $canonical_id ) && (int) $canonical_id !== (int) $customer->id ) {
$customer->update_meta( '_canonical_import_id', $canonical_id );
}
}
if ( ! empty( $email ) && $email !== $customer->email ) {
$customer->add_email( $email );
}
return $customer->id;
}
/**
* Look up Download by title and create one if none is found
*
* @since 2.6
* @return int Download ID
*/
private function maybe_create_download( $title = '' ) {
if( ! is_string( $title ) ) {
return false;
}
$download = get_page_by_title( $title, OBJECT, 'download' );
if( $download ) {
$download_id = $download->ID;
} else {
$args = array(
'post_type' => 'download',
'post_title' => $title,
'post_author' => get_current_user_id()
);
$download_id = wp_insert_post( $args );
}
return $download_id;
}
/**
* Return the calculated completion percentage
*
* @since 2.6
* @return int
*/
public function get_downloads_from_edd( $data_str ) {
// Break string into separate products
$d_array = array();
$downloads = (array) explode( '/', $data_str );
if( $downloads ) {
foreach( $downloads as $key => $download ) {
$d = (array) explode( '|', $download );
if ( ! array_key_exists( 1, $d ) ) {
continue;
}
preg_match_all( '/\{(\d|(\d+(\.\d+|\d+)))\}/', $d[1], $matches );
if( false !== strpos( $d[1], '{' ) ) {
$price = trim( substr( $d[1], 0, strpos( $d[1], '{' ) ) );
} else {
$price = trim( $d[1] );
}
$price = floatval( $price );
$tax = isset( $matches[1][0] ) ? floatval( trim( $matches[1][0] ) ) : 0;
$price_id = isset( $matches[1][1] ) ? trim( $matches[1][1] ) : false;
$d_array[] = array(
'download' => trim( $d[0] ),
'price' => $price - $tax,
'tax' => $tax,
'price_id' => $price_id,
);
}
}
return $d_array;
}
/**
* Return the calculated completion percentage
*
* @since 2.6
* @return int
*/
public function get_percentage_complete() {
$total = count( $this->csv );
if( $total > 0 ) {
$percentage = ( $this->step * $this->per_step / $total ) * 100;
}
if( $percentage > 100 ) {
$percentage = 100;
}
return $percentage;
}
/**
* Retrieve the URL to the payments list table
*
* @since 2.6
* @return string
*/
public function get_list_table_url() {
return admin_url( 'edit.php?post_type=download&page=edd-payment-history' );
}
/**
* Retrieve the payments labels
*
* @since 2.6
* @return string
*/
public function get_import_type_label() {
return __( 'payments', 'easy-digital-downloads' );
}
}