/**
 * Insert Payment
 *
 * @since 1.0
 * @param array $payment_data
 * @return int|bool Payment ID if payment is inserted, false otherwise
 */
function edd_insert_payment($payment_data = array())
{
    if (empty($payment_data)) {
        return false;
    }
    // Make sure the payment is inserted with the correct timezone
    date_default_timezone_set(edd_get_timezone_id());
    // Construct the payment title
    if (isset($payment_data['user_info']['first_name']) || isset($payment_data['user_info']['last_name'])) {
        $payment_title = $payment_data['user_info']['first_name'] . ' ' . $payment_data['user_info']['last_name'];
    } else {
        $payment_title = $payment_data['user_email'];
    }
    // Retrieve the ID of the discount used, if any
    if ($payment_data['user_info']['discount'] != 'none') {
        $discount = edd_get_discount_by('code', $payment_data['user_info']['discount']);
    }
    // Find the next payment number, if enabled
    if (edd_get_option('enable_sequential')) {
        $number = edd_get_next_payment_number();
    }
    $args = apply_filters('edd_insert_payment_args', array('post_title' => $payment_title, 'post_status' => isset($payment_data['status']) ? $payment_data['status'] : 'pending', 'post_type' => 'edd_payment', 'post_parent' => isset($payment_data['parent']) ? $payment_data['parent'] : null, 'post_date' => isset($payment_data['post_date']) ? $payment_data['post_date'] : null, 'post_date_gmt' => isset($payment_data['post_date']) ? get_gmt_from_date($payment_data['post_date']) : null), $payment_data);
    // Create a blank payment
    $payment = wp_insert_post($args);
    if ($payment) {
        if (isset($payment_data['tax'])) {
            $cart_tax = $payment_data['tax'];
        } else {
            $taxes = $payment_data['cart_details'] ? wp_list_pluck($payment_data['cart_details'], 'tax') : array();
            $cart_tax = array_sum($taxes);
            $cart_tax += edd_get_cart_fee_tax();
        }
        $payment_meta = array('currency' => $payment_data['currency'], 'downloads' => $payment_data['downloads'], 'user_info' => $payment_data['user_info'], 'cart_details' => $payment_data['cart_details']);
        $mode = edd_is_test_mode() ? 'test' : 'live';
        $gateway = !empty($payment_data['gateway']) ? $payment_data['gateway'] : '';
        $gateway = empty($gateway) && isset($_POST['edd-gateway']) ? $_POST['edd-gateway'] : $gateway;
        if (!$payment_data['price']) {
            // Ensures the _edd_payment_total meta key is created for purchases with an amount of 0
            $payment_data['price'] = '0.00';
        }
        // Create or update a customer
        $customer = new EDD_Customer($payment_data['user_email']);
        $customer_data = array('name' => $payment_data['user_info']['first_name'] . ' ' . $payment_data['user_info']['last_name'], 'email' => $payment_data['user_email'], 'user_id' => $payment_data['user_info']['id']);
        if (empty($customer->id)) {
            $customer->create($customer_data);
        } else {
            // Only update the customer if their name or email has changed
            if ($customer_data['email'] !== $customer->email || $customer_data['name'] !== $customer->name) {
                // We shouldn't be updating the User ID here, that is an admin task
                unset($customer_data['user_id']);
                $customer->update($customer_data);
            }
        }
        $customer->attach_payment($payment, false);
        // Record the payment details
        edd_update_payment_meta($payment, '_edd_payment_meta', apply_filters('edd_payment_meta', $payment_meta, $payment_data));
        edd_update_payment_meta($payment, '_edd_payment_user_id', $payment_data['user_info']['id']);
        edd_update_payment_meta($payment, '_edd_payment_customer_id', $customer->id);
        edd_update_payment_meta($payment, '_edd_payment_user_email', $payment_data['user_email']);
        edd_update_payment_meta($payment, '_edd_payment_user_ip', edd_get_ip());
        edd_update_payment_meta($payment, '_edd_payment_purchase_key', $payment_data['purchase_key']);
        edd_update_payment_meta($payment, '_edd_payment_total', $payment_data['price']);
        edd_update_payment_meta($payment, '_edd_payment_mode', $mode);
        edd_update_payment_meta($payment, '_edd_payment_gateway', $gateway);
        edd_update_payment_meta($payment, '_edd_payment_tax', $cart_tax);
        if (!empty($discount)) {
            edd_update_payment_meta($payment, '_edd_payment_discount_id', $discount->ID);
        }
        if (edd_get_option('enable_sequential')) {
            edd_update_payment_meta($payment, '_edd_payment_number', edd_format_payment_number($number));
            update_option('edd_last_payment_number', $number);
        }
        // Clear the user's purchased cache
        delete_transient('edd_user_' . $payment_data['user_info']['id'] . '_purchases');
        do_action('edd_insert_payment', $payment, $payment_data);
        return $payment;
        // Return the ID
    }
    // Return false if no payment was inserted
    return false;
}
/**
 * Process the payment details edit
 *
 * @access      private
 * @since       1.9
 * @return      void
*/
function edd_update_payment_details($data)
{
    if (!current_user_can('edit_shop_payments', $data['edd_payment_id'])) {
        wp_die(__('You do not have permission to edit this payment record', 'easy-digital-downloads'), __('Error', 'easy-digital-downloads'), array('response' => 403));
    }
    check_admin_referer('edd_update_payment_details_nonce');
    // Retrieve the payment ID
    $payment_id = absint($data['edd_payment_id']);
    $payment = new EDD_Payment($payment_id);
    // Retrieve existing payment meta
    $meta = $payment->get_meta();
    $user_info = $payment->user_info;
    $status = $data['edd-payment-status'];
    $unlimited = isset($data['edd-unlimited-downloads']) ? '1' : '';
    $date = sanitize_text_field($data['edd-payment-date']);
    $hour = sanitize_text_field($data['edd-payment-time-hour']);
    // Restrict to our high and low
    if ($hour > 23) {
        $hour = 23;
    } elseif ($hour < 0) {
        $hour = 00;
    }
    $minute = sanitize_text_field($data['edd-payment-time-min']);
    // Restrict to our high and low
    if ($minute > 59) {
        $minute = 59;
    } elseif ($minute < 0) {
        $minute = 00;
    }
    $address = array_map('trim', $data['edd-payment-address'][0]);
    $curr_total = edd_sanitize_amount($payment->total);
    $new_total = edd_sanitize_amount($_POST['edd-payment-total']);
    $tax = isset($_POST['edd-payment-tax']) ? edd_sanitize_amount($_POST['edd-payment-tax']) : 0;
    $date = date('Y-m-d', strtotime($date)) . ' ' . $hour . ':' . $minute . ':00';
    $curr_customer_id = sanitize_text_field($data['edd-current-customer']);
    $new_customer_id = sanitize_text_field($data['customer-id']);
    // Setup purchased Downloads and price options
    $updated_downloads = isset($_POST['edd-payment-details-downloads']) ? $_POST['edd-payment-details-downloads'] : false;
    if ($updated_downloads && !empty($_POST['edd-payment-downloads-changed'])) {
        foreach ($updated_downloads as $download) {
            // If this item doesn't have a log yet, add one for each quantity count
            $has_log = absint($download['has_log']);
            $has_log = empty($has_log) ? false : true;
            if ($has_log) {
                continue;
            }
            if (empty($download['item_price'])) {
                $download['item_price'] = 0.0;
            }
            $item_price = $download['item_price'];
            $download_id = absint($download['id']);
            $quantity = absint($download['quantity']) > 0 ? absint($download['quantity']) : 1;
            $price_id = false;
            if (edd_has_variable_prices($download_id) && isset($download['price_id'])) {
                $price_id = absint($download['price_id']);
            }
            // Set some defaults
            $args = array('quantity' => $quantity, 'item_price' => $item_price, 'price_id' => $price_id);
            $payment->add_download($download_id, $args);
        }
        $deleted_downloads = json_decode(stripcslashes($data['edd-payment-removed']), true);
        foreach ($deleted_downloads as $deleted_download) {
            $deleted_download = $deleted_download[0];
            if (empty($deleted_download['id'])) {
                continue;
            }
            $price_id = empty($deleted_download['price_id']) ? 0 : (int) $deleted_download['price_id'];
            $args = array('quantity' => (int) $deleted_download['quantity'], 'price_id' => (int) $price_id, 'item_price' => (double) $deleted_download['amount']);
            $payment->remove_download($deleted_download['id'], $args);
            do_action('edd_remove_download_from_payment', $payment_id, $deleted_download['id']);
        }
    }
    do_action('edd_update_edited_purchase', $payment_id);
    $payment->date = $date;
    $updated = $payment->save();
    if (0 === $updated) {
        wp_die(__('Error Updating Payment', 'easy-digital-downloads'), __('Error', 'easy-digital-downloads'), array('response' => 400));
    }
    $customer_changed = false;
    if (isset($data['edd-new-customer']) && $data['edd-new-customer'] == '1') {
        $email = isset($data['edd-new-customer-email']) ? sanitize_text_field($data['edd-new-customer-email']) : '';
        $names = isset($data['edd-new-customer-name']) ? sanitize_text_field($data['edd-new-customer-name']) : '';
        if (empty($email) || empty($names)) {
            wp_die(__('New Customers require a name and email address', 'easy-digital-downloads'));
        }
        $customer = new EDD_Customer($email);
        if (empty($customer->id)) {
            $customer_data = array('name' => $names, 'email' => $email);
            $user_id = email_exists($email);
            if (false !== $user_id) {
                $customer_data['user_id'] = $user_id;
            }
            if (!$customer->create($customer_data)) {
                // Failed to crete the new customer, assume the previous customer
                $customer_changed = false;
                $customer = new EDD_Customer($curr_customer_id);
                edd_set_error('edd-payment-new-customer-fail', __('Error creating new customer', 'easy-digital-downloads'));
            }
        }
        $new_customer_id = $customer->id;
        $previous_customer = new EDD_Customer($curr_customer_id);
        $customer_changed = true;
    } elseif ($curr_customer_id !== $new_customer_id) {
        $customer = new EDD_Customer($new_customer_id);
        $email = $customer->email;
        $names = $customer->name;
        $previous_customer = new EDD_Customer($curr_customer_id);
        $customer_changed = true;
    } else {
        $customer = new EDD_Customer($curr_customer_id);
        $email = $customer->email;
        $names = $customer->name;
    }
    // Setup first and last name from input values
    $names = explode(' ', $names);
    $first_name = !empty($names[0]) ? $names[0] : '';
    $last_name = '';
    if (!empty($names[1])) {
        unset($names[0]);
        $last_name = implode(' ', $names);
    }
    if ($customer_changed) {
        // Remove the stats and payment from the previous customer and attach it to the new customer
        $previous_customer->remove_payment($payment_id, false);
        $customer->attach_payment($payment_id, false);
        // If purchase was completed and not ever refunded, adjust stats of customers
        if ('revoked' == $status || 'publish' == $status) {
            $previous_customer->decrease_purchase_count();
            $previous_customer->decrease_value($new_total);
            $customer->increase_purchase_count();
            $customer->increase_value($new_total);
        }
        $payment->customer_id = $customer->id;
    }
    // Set new meta values
    $payment->user_id = $customer->user_id;
    $payment->email = $customer->email;
    $payment->first_name = $first_name;
    $payment->last_name = $last_name;
    $payment->address = $address;
    $payment->total = $new_total;
    $payment->tax = $tax;
    $payment->has_unlimited_downloads = $unlimited;
    // Check for payment notes
    if (!empty($data['edd-payment-note'])) {
        $note = wp_kses($data['edd-payment-note'], array());
        edd_insert_payment_note($payment->ID, $note);
    }
    // Set new status
    $payment->status = $status;
    // Adjust total store earnings if the payment total has been changed
    if ($new_total !== $curr_total && ('publish' == $status || 'revoked' == $status)) {
        if ($new_total > $curr_total) {
            // Increase if our new total is higher
            $difference = $new_total - $curr_total;
            edd_increase_total_earnings($difference);
        } elseif ($curr_total > $new_total) {
            // Decrease if our new total is lower
            $difference = $curr_total - $new_total;
            edd_decrease_total_earnings($difference);
        }
    }
    $payment->save();
    do_action('edd_updated_edited_purchase', $payment_id);
    wp_safe_redirect(admin_url('edit.php?post_type=download&page=edd-payment-history&view=view-order-details&edd-message=payment-updated&id=' . $payment_id));
    exit;
}
 /**
  * Create the base of a payment.
  *
  * @since  2.5
  * @param  array    $payment_data Base payment data.
  * @return int|bool Fale on failure, the payment ID on success.
  */
 private function insert_payment()
 {
     // Make sure the payment is inserted with the correct timezone
     date_default_timezone_set(edd_get_timezone_id());
     // Construct the payment title
     $payment_title = '';
     if (!empty($this->first_name) && !empty($this->last_name)) {
         $payment_title = $this->first_name . ' ' . $this->last_name;
     } else {
         if (!empty($this->first_name) && empty($this->last_name)) {
             $payment_title = $this->first_name;
         } else {
             if (!empty($this->email) && is_email($this->email)) {
                 $payment_title = $this->email;
             }
         }
     }
     if (empty($payment_title)) {
         return false;
     }
     if (empty($this->date)) {
         $this->date = date('Y-m-d H:i:s', current_time('timestamp'));
     }
     if (empty($this->key)) {
         $auth_key = defined('AUTH_KEY') ? AUTH_KEY : '';
         $this->key = strtolower(md5($this->email . date('Y-m-d H:i:s') . $auth_key . uniqid('edd', true)));
         // Unique key
         $this->pending['key'] = $this->key;
     }
     if (empty($this->ip)) {
         $this->ip = edd_get_ip();
         $this->pending['ip'] = $this->ip;
     }
     $payment_data = array('price' => $this->total, 'date' => $this->date, 'user_email' => $this->email, 'purchase_key' => $this->key, 'currency' => $this->currency, 'downloads' => $this->downloads, 'user_info' => array('id' => $this->user_id, 'email' => $this->email, 'first_name' => $this->first_name, 'last_name' => $this->last_name, 'discount' => $this->discounts, 'address' => $this->address), 'cart_details' => $this->cart_details, 'status' => $this->status, 'fees' => $this->fees);
     $args = apply_filters('edd_insert_payment_args', array('post_title' => $payment_title, 'post_status' => $this->status, 'post_type' => 'edd_payment', 'post_parent' => $this->parent_payment, 'post_date' => $this->date, 'post_date_gmt' => get_gmt_from_date($this->date)), $payment_data);
     // Create a blank payment
     $payment_id = wp_insert_post($args);
     if (!empty($payment_id)) {
         $this->ID = $payment_id;
         $this->_ID = $payment_id;
         $customer = new stdClass();
         if (did_action('edd_pre_process_purchase') && is_user_logged_in()) {
             $customer = new EDD_customer(get_current_user_id(), true);
         }
         if (empty($customer->id)) {
             $customer = new EDD_Customer($this->email);
         }
         if (empty($customer->id)) {
             $customer_data = array('name' => !is_email($payment_title) ? $this->first_name . ' ' . $this->last_name : '', 'email' => $this->email, 'user_id' => $this->user_id);
             $customer->create($customer_data);
         }
         $this->customer_id = $customer->id;
         $this->pending['customer_id'] = $this->customer_id;
         $customer->attach_payment($this->ID, false);
         $this->payment_meta = apply_filters('edd_payment_meta', $this->payment_meta, $payment_data);
         if (!empty($this->payment_meta['fees'])) {
             $this->fees = array_merge($this->fees, $this->payment_meta['fees']);
             foreach ($this->fees as $fee) {
                 $this->increase_fees($fee['amount']);
             }
         }
         $this->update_meta('_edd_payment_meta', $this->payment_meta);
         $this->new = true;
     }
     return $this->ID;
 }
/**
 * Process web accept (one time) payment IPNs
 *
 * @since 1.3.4
 * @param array   $data IPN Data
 * @return void
 */
function edd_process_paypal_web_accept_and_cart($data, $payment_id)
{
    if ($data['txn_type'] != 'web_accept' && $data['txn_type'] != 'cart' && $data['payment_status'] != 'Refunded') {
        return;
    }
    if (empty($payment_id)) {
        return;
    }
    $payment = new EDD_Payment($payment_id);
    // Collect payment details
    $purchase_key = isset($data['invoice']) ? $data['invoice'] : $data['item_number'];
    $paypal_amount = $data['mc_gross'];
    $payment_status = strtolower($data['payment_status']);
    $currency_code = strtolower($data['mc_currency']);
    $business_email = isset($data['business']) && is_email($data['business']) ? trim($data['business']) : trim($data['receiver_email']);
    if ($payment->gateway != 'paypal') {
        return;
        // this isn't a PayPal standard IPN
    }
    // Verify payment recipient
    if (strcasecmp($business_email, trim(edd_get_option('paypal_email', false))) != 0) {
        edd_record_gateway_error(__('IPN Error', 'easy-digital-downloads'), sprintf(__('Invalid business email in IPN response. IPN data: %s', 'easy-digital-downloads'), json_encode($data)), $payment_id);
        edd_update_payment_status($payment_id, 'failed');
        edd_insert_payment_note($payment_id, __('Payment failed due to invalid PayPal business email.', 'easy-digital-downloads'));
        return;
    }
    // Verify payment currency
    if ($currency_code != strtolower($payment->currency)) {
        edd_record_gateway_error(__('IPN Error', 'easy-digital-downloads'), sprintf(__('Invalid currency in IPN response. IPN data: %s', 'easy-digital-downloads'), json_encode($data)), $payment_id);
        edd_update_payment_status($payment_id, 'failed');
        edd_insert_payment_note($payment_id, __('Payment failed due to invalid currency in PayPal IPN.', 'easy-digital-downloads'));
        return;
    }
    if (empty($payment->email)) {
        // This runs when a Buy Now purchase was made. It bypasses checkout so no personal info is collected until PayPal
        // Setup and store the customers's details
        $address = array();
        $address['line1'] = !empty($data['address_street']) ? sanitize_text_field($data['address_street']) : false;
        $address['city'] = !empty($data['address_city']) ? sanitize_text_field($data['address_city']) : false;
        $address['state'] = !empty($data['address_state']) ? sanitize_text_field($data['address_state']) : false;
        $address['country'] = !empty($data['address_country_code']) ? sanitize_text_field($data['address_country_code']) : false;
        $address['zip'] = !empty($data['address_zip']) ? sanitize_text_field($data['address_zip']) : false;
        $payment->email = sanitize_text_field($data['payer_email']);
        $payment->first_name = sanitize_text_field($data['first_name']);
        $payment->last_name = sanitize_text_field($data['last_name']);
        $payment->address = $address;
        if (empty($payment->customer_id)) {
            $customer = new EDD_Customer($payment->email);
            if (!$customer || $customer->id < 1) {
                $customer->create(array('email' => $payment->email, 'name' => $payment->first_name . ' ' . $payment->last_name, 'user_id' => $payment->user_id));
            }
            $payment->customer_id = $customer->id;
        }
        $payment->save();
    }
    if ($payment_status == 'refunded' || $payment_status == 'reversed') {
        // Process a refund
        edd_process_paypal_refund($data, $payment_id);
    } else {
        if (get_post_status($payment_id) == 'publish') {
            return;
            // Only complete payments once
        }
        // Retrieve the total purchase amount (before PayPal)
        $payment_amount = edd_get_payment_amount($payment_id);
        if (number_format((double) $paypal_amount, 2) < number_format((double) $payment_amount, 2)) {
            // The prices don't match
            edd_record_gateway_error(__('IPN Error', 'easy-digital-downloads'), sprintf(__('Invalid payment amount in IPN response. IPN data: %s', 'easy-digital-downloads'), json_encode($data)), $payment_id);
            edd_update_payment_status($payment_id, 'failed');
            edd_insert_payment_note($payment_id, __('Payment failed due to invalid amount in PayPal IPN.', 'easy-digital-downloads'));
            return;
        }
        if ($purchase_key != edd_get_payment_key($payment_id)) {
            // Purchase keys don't match
            edd_record_gateway_error(__('IPN Error', 'easy-digital-downloads'), sprintf(__('Invalid purchase key in IPN response. IPN data: %s', 'easy-digital-downloads'), json_encode($data)), $payment_id);
            edd_update_payment_status($payment_id, 'failed');
            edd_insert_payment_note($payment_id, __('Payment failed due to invalid purchase key in PayPal IPN.', 'easy-digital-downloads'));
            return;
        }
        if ('completed' == $payment_status || edd_is_test_mode()) {
            edd_insert_payment_note($payment_id, sprintf(__('PayPal Transaction ID: %s', 'easy-digital-downloads'), $data['txn_id']));
            edd_set_payment_transaction_id($payment_id, $data['txn_id']);
            edd_update_payment_status($payment_id, 'publish');
        } else {
            if ('pending' == $payment_status && isset($data['pending_reason'])) {
                // Look for possible pending reasons, such as an echeck
                $note = '';
                switch (strtolower($data['pending_reason'])) {
                    case 'echeck':
                        $note = __('Payment made via eCheck and will clear automatically in 5-8 days', 'easy-digital-downloads');
                        break;
                    case 'address':
                        $note = __('Payment requires a confirmed customer address and must be accepted manually through PayPal', 'easy-digital-downloads');
                        break;
                    case 'intl':
                        $note = __('Payment must be accepted manually through PayPal due to international account regulations', 'easy-digital-downloads');
                        break;
                    case 'multi-currency':
                        $note = __('Payment received in non-shop currency and must be accepted manually through PayPal', 'easy-digital-downloads');
                        break;
                    case 'paymentreview':
                    case 'regulatory_review':
                        $note = __('Payment is being reviewed by PayPal staff as high-risk or in possible violation of government regulations', 'easy-digital-downloads');
                        break;
                    case 'unilateral':
                        $note = __('Payment was sent to non-confirmed or non-registered email address.', 'easy-digital-downloads');
                        break;
                    case 'upgrade':
                        $note = __('PayPal account must be upgraded before this payment can be accepted', 'easy-digital-downloads');
                        break;
                    case 'verify':
                        $note = __('PayPal account is not verified. Verify account in order to accept this payment', 'easy-digital-downloads');
                        break;
                    case 'other':
                        $note = __('Payment is pending for unknown reasons. Contact PayPal support for assistance', 'easy-digital-downloads');
                        break;
                }
                if (!empty($note)) {
                    edd_insert_payment_note($payment_id, $note);
                }
            }
        }
    }
}
Example #5
0
/**
 * Process the payment details edit
 *
 * @access      private
 * @since       1.9
 * @return      void
*/
function edd_update_payment_details($data)
{
    if (!current_user_can('edit_shop_payments', $data['edd_payment_id'])) {
        wp_die(__('You do not have permission to edit this payment record', 'edd'), __('Error', 'edd'), array('response' => 403));
    }
    check_admin_referer('edd_update_payment_details_nonce');
    // Retrieve the payment ID
    $payment_id = absint($data['edd_payment_id']);
    // Retrieve existing payment meta
    $meta = edd_get_payment_meta($payment_id);
    $user_info = edd_get_payment_meta_user_info($payment_id);
    $status = $data['edd-payment-status'];
    $unlimited = isset($data['edd-unlimited-downloads']) ? '1' : '';
    $date = sanitize_text_field($data['edd-payment-date']);
    $hour = sanitize_text_field($data['edd-payment-time-hour']);
    // Restrict to our high and low
    if ($hour > 23) {
        $hour = 23;
    } elseif ($hour < 0) {
        $hour = 00;
    }
    $minute = sanitize_text_field($data['edd-payment-time-min']);
    // Restrict to our high and low
    if ($minute > 59) {
        $minute = 59;
    } elseif ($minute < 0) {
        $minute = 00;
    }
    $address = array_map('trim', $data['edd-payment-address'][0]);
    $curr_total = edd_sanitize_amount(edd_get_payment_amount($payment_id));
    $new_total = edd_sanitize_amount($_POST['edd-payment-total']);
    $tax = isset($_POST['edd-payment-tax']) ? edd_sanitize_amount($_POST['edd-payment-tax']) : 0;
    $date = date('Y-m-d', strtotime($date)) . ' ' . $hour . ':' . $minute . ':00';
    $curr_customer_id = sanitize_text_field($data['edd-current-customer']);
    $new_customer_id = sanitize_text_field($data['customer-id']);
    // Setup purchased Downloads and price options
    $updated_downloads = isset($_POST['edd-payment-details-downloads']) ? $_POST['edd-payment-details-downloads'] : false;
    if ($updated_downloads && !empty($_POST['edd-payment-downloads-changed'])) {
        $downloads = array();
        $cart_details = array();
        $i = 0;
        foreach ($updated_downloads as $download) {
            if (empty($download['amount'])) {
                $download['amount'] = '0.00';
            }
            $item = array();
            $item['id'] = absint($download['id']);
            $item['quantity'] = absint($download['quantity']) > 0 ? absint($download['quantity']) : 1;
            $price_id = (int) $download['price_id'];
            $has_log = absint($download['has_log']);
            if ($price_id !== false && edd_has_variable_prices($item['id'])) {
                $item['options'] = array('price_id' => $price_id);
            }
            $downloads[] = $item;
            $cart_item = array();
            $cart_item['item_number'] = $item;
            $item_price = round($download['amount'] / $item['quantity'], edd_currency_decimal_filter());
            $cart_details[$i] = array('name' => get_the_title($download['id']), 'id' => $download['id'], 'item_number' => $item, 'price' => $download['amount'], 'item_price' => $item_price, 'subtotal' => $download['amount'], 'quantity' => $download['quantity'], 'discount' => 0, 'tax' => 0);
            // If this item doesn't have a log yet, add one for each quantity count
            if (empty($has_log)) {
                $log_date = date('Y-m-d G:i:s', current_time('timestamp', true));
                $price_id = $price_id !== false ? $price_id : 0;
                $y = 0;
                while ($y < $download['quantity']) {
                    edd_record_sale_in_log($download['id'], $payment_id, $price_id, $log_date);
                    $y++;
                }
                edd_increase_purchase_count($download['id'], $download['quantity']);
                edd_increase_earnings($download['id'], $download['amount']);
            }
            $i++;
        }
        $meta['downloads'] = $downloads;
        $meta['cart_details'] = $cart_details;
        $deleted_downloads = json_decode(stripcslashes($data['edd-payment-removed']), true);
        foreach ($deleted_downloads as $deleted_download) {
            $deleted_download = $deleted_download[0];
            if (empty($deleted_download['id'])) {
                continue;
            }
            $price_id = empty($deleted_download['price_id']) ? 0 : (int) $deleted_download['price_id'];
            $log_args = array('post_type' => 'edd_log', 'post_parent' => $deleted_download['id'], 'numberposts' => $deleted_download['quantity'], 'meta_query' => array(array('key' => '_edd_log_payment_id', 'value' => $payment_id, 'compare' => '='), array('key' => '_edd_log_price_id', 'value' => $price_id, 'compare' => '=')));
            $found_logs = get_posts($log_args);
            foreach ($found_logs as $log) {
                wp_delete_post($log->ID, true);
            }
            edd_decrease_purchase_count($deleted_download['id'], $deleted_download['quantity']);
            edd_decrease_earnings($deleted_download['id'], $deleted_download['amount']);
            do_action('edd_remove_download_from_payment', $payment_id, $deleted_download['id']);
        }
    }
    do_action('edd_update_edited_purchase', $payment_id);
    // Update main payment record
    $updated = wp_update_post(array('ID' => $payment_id, 'post_date' => $date));
    if (0 === $updated) {
        wp_die(__('Error Updating Payment', 'edd'), __('Error', 'edd'), array('response' => 400));
    }
    $customer_changed = false;
    if (isset($data['edd-new-customer']) && $data['edd-new-customer'] == '1') {
        $email = isset($data['edd-new-customer-email']) ? sanitize_text_field($data['edd-new-customer-email']) : '';
        $names = isset($data['edd-new-customer-name']) ? sanitize_text_field($data['edd-new-customer-name']) : '';
        if (empty($email) || empty($names)) {
            wp_die(__('New Customers require a name and email address', 'edd'));
        }
        $customer = new EDD_Customer($email);
        if (empty($customer->id)) {
            $customer_data = array('name' => $names, 'email' => $email);
            $user_id = email_exists($email);
            if (false !== $user_id) {
                $customer_data['user_id'] = $user_id;
            }
            if (!$customer->create($customer_data)) {
                // Failed to crete the new customer, assume the previous customer
                $customer_changed = false;
                $customer = new EDD_Customer($curr_customer_id);
                edd_set_error('edd-payment-new-customer-fail', __('Error creating new customer', 'edd'));
            }
        }
        $new_customer_id = $customer->id;
        $previous_customer = new EDD_Customer($curr_customer_id);
        $customer_changed = true;
    } elseif ($curr_customer_id !== $new_customer_id) {
        $customer = new EDD_Customer($new_customer_id);
        $email = $customer->email;
        $names = $customer->name;
        $previous_customer = new EDD_Customer($curr_customer_id);
        $customer_changed = true;
    } else {
        $customer = new EDD_Customer($curr_customer_id);
        $email = $customer->email;
        $names = $customer->name;
    }
    // Setup first and last name from input values
    $names = explode(' ', $names);
    $first_name = !empty($names[0]) ? $names[0] : '';
    $last_name = '';
    if (!empty($names[1])) {
        unset($names[0]);
        $last_name = implode(' ', $names);
    }
    if ($customer_changed) {
        // Remove the stats and payment from the previous customer and attach it to the new customer
        $previous_customer->remove_payment($payment_id, false);
        $customer->attach_payment($payment_id, false);
        // If purchase was completed and not ever refunded, adjust stats of customers
        if ('revoked' == $status || 'publish' == $status) {
            $previous_customer->decrease_purchase_count();
            $previous_customer->decrease_value($new_total);
            $customer->increase_purchase_count();
            $customer->increase_value($new_total);
        }
        update_post_meta($payment_id, '_edd_payment_customer_id', $customer->id);
    }
    // Set new meta values
    $user_info['id'] = $customer->user_id;
    $user_info['email'] = $customer->email;
    $user_info['first_name'] = $first_name;
    $user_info['last_name'] = $last_name;
    $user_info['address'] = $address;
    $meta['user_info'] = $user_info;
    $meta['tax'] = $tax;
    // Check for payment notes
    if (!empty($data['edd-payment-note'])) {
        $note = wp_kses($data['edd-payment-note'], array());
        edd_insert_payment_note($payment_id, $note);
    }
    // Set new status
    edd_update_payment_status($payment_id, $status);
    edd_update_payment_meta($payment_id, '_edd_payment_user_id', $customer->user_id);
    edd_update_payment_meta($payment_id, '_edd_payment_user_email', $customer->email);
    edd_update_payment_meta($payment_id, '_edd_payment_meta', $meta);
    edd_update_payment_meta($payment_id, '_edd_payment_total', $new_total);
    // Adjust total store earnings if the payment total has been changed
    if ($new_total !== $curr_total && ('publish' == $status || 'revoked' == $status)) {
        if ($new_total > $curr_total) {
            // Increase if our new total is higher
            $difference = $new_total - $curr_total;
            edd_increase_total_earnings($difference);
        } elseif ($curr_total > $new_total) {
            // Decrease if our new total is lower
            $difference = $curr_total - $new_total;
            edd_decrease_total_earnings($difference);
        }
    }
    edd_update_payment_meta($payment_id, '_edd_payment_downloads', $new_total);
    edd_update_payment_meta($payment_id, '_edd_payment_unlimited_downloads', $unlimited);
    do_action('edd_updated_edited_purchase', $payment_id);
    wp_safe_redirect(admin_url('edit.php?post_type=download&page=edd-payment-history&view=view-order-details&edd-message=payment-updated&id=' . $payment_id));
    exit;
}
 public static function create_payment($data)
 {
     if (wp_verify_nonce($data['edd_create_payment_nonce'], 'edd_create_payment_nonce')) {
         global $edd_options;
         $data['downloads'] = array_values($data['downloads']);
         if ($data['downloads'][0]['id'] == 0) {
             wp_die(sprintf(__('Please select at least one %s to add to the payment.', 'edd-manual-purchases'), edd_get_label_singular()));
         }
         $by_user_id = false;
         if (!empty($data['email'])) {
             $user = strip_tags(trim($data['email']));
             $by_user_id = false;
         } elseif (empty($data['email']) && !empty($data['customer'])) {
             $user = strip_tags(trim($data['customer']));
         } else {
             $user = null;
         }
         if (null == $user) {
             wp_die(__('Please select a customer or create a new one.', 'edd-manual-purchases'));
         }
         $payment = new EDD_Payment();
         $customer = new EDD_Customer($user, $by_user_id);
         $user_id = $by_user_id == true ? $user : 0;
         $email = $by_user_id == false ? $user : '';
         $first = isset($data['first']) ? sanitize_text_field($data['first']) : '';
         $last = isset($data['last']) ? sanitize_text_field($data['last']) : '';
         if (!$customer->id > 0) {
             $user = $by_user_id == false ? get_user_by('email', $user) : get_user_by('id', $user);
             if ($user) {
                 $user_id = $user->ID;
                 $email = $user->user_email;
             }
             $customer->create(array('email' => $email, 'name' => $first . ' ' . $last, 'user_id' => $user_id));
         } else {
             $email = $customer->email;
         }
         $total = 0.0;
         $payment->customer_id = $customer->id;
         $payment->user_id = $user_id;
         $payment->first_name = $first;
         $payment->last_name = $last;
         $payment->email = $email;
         // Make sure the user info data is set
         $payment->user_info = array('first_name' => $first, 'last_name' => $last, 'id' => $user_id, 'email' => $email);
         $cart_details = array();
         $total = 0;
         foreach ($data['downloads'] as $key => $download) {
             // calculate total purchase cost
             if (isset($download['price_id']) && empty($download['amount'])) {
                 $prices = get_post_meta($download['id'], 'edd_variable_prices', true);
                 $price_key = $download['options']['price_id'];
                 $item_price = $prices[$download['price_id']]['amount'];
             } elseif (empty($download['amount'])) {
                 $item_price = edd_get_download_price($download['id']);
             }
             $item_tax = $args = array('quantity' => !empty($download['quantity']) ? absint($download['quantity']) : 1, 'price_id' => isset($download['price_id']) ? $download['price_id'] : null, 'item_price' => !empty($download['amount']) ? edd_sanitize_amount($download['amount']) : $item_price);
             $args['tax'] = !empty($download['tax']) ? edd_sanitize_amount($download['tax'] * $args['quantity']) : 0;
             $payment->add_download($download['id'], $args);
             $total += $args['item_price'] * $args['quantity'];
         }
         if (!empty($data['amount'])) {
             $total = edd_sanitize_amount(strip_tags(trim($data['amount'])));
             $payment->total = $total;
         }
         // if we are using Wallet, ensure the customer can afford this purchase
         if (!empty($data['wallet']) && class_exists('EDD_Wallet') && $user_id > 0) {
             $wallet_value = edd_wallet()->wallet->balance($user_id);
             if ($wallet_value < $total) {
                 wp_die(__('The customer does not have sufficient funds in their wallet to pay for this purchase.', 'edd-manual-purchases'));
             }
         }
         $date = !empty($data['date']) ? date('Y-m-d H:i:s', strtotime(strip_tags(trim($data['date'])))) : false;
         if (!$date) {
             $date = date('Y-m-d H:i:s', current_time('timestamp'));
         }
         if (strtotime($date, time()) > time()) {
             $date = date('Y-m-d H:i:s', current_time('timestamp'));
         }
         $payment->date = $date;
         $payment->status = 'pending';
         $payment->currency = edd_get_currency();
         $payment->gateway = sanitize_text_field($_POST['gateway']);
         $payment->mode = edd_is_test_mode() ? 'test' : 'live';
         if (!empty($_POST['transaction_id'])) {
             $payment->transaction_id = sanitize_text_field($_POST['transaction_id']);
         }
         $payment->save();
         if (!isset($data['receipt'])) {
             remove_action('edd_complete_purchase', 'edd_trigger_purchase_receipt', 999);
         }
         if (isset($_POST['status']) && 'pending' !== $_POST['status']) {
             $payment->status = $_POST['status'];
             $payment->save();
         }
         if (!empty($data['wallet']) && class_exists('EDD_Wallet') && $user_id > 0) {
             // Update the user wallet
             edd_wallet()->wallet->withdraw($user_id, $total, 'withdrawal', $payment->ID);
         }
         if (!empty($data['shipped'])) {
             update_post_meta($payment->ID, '_edd_payment_shipping_status', '2');
         }
         wp_redirect(admin_url('edit.php?post_type=download&page=edd-payment-history&edd-message=payment_created'));
         exit;
     }
 }
 private function set_customer($row)
 {
     global $wpdb;
     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['customer_id']) && !empty($row[$this->field_mapping['customer_id']])) {
         $canonical_id = absint($row[$this->field_mapping['customer_id']]);
         $mapped_id = $wpdb->get_var($wpdb->prepare("SELECT customer_id FROM {$wpdb->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['customer_id']) && !empty($row[$this->field_mapping['customer_id']])) {
             $customer_id = absint($row[$this->field_mapping['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_id) || $customer_by_id->id !== $customer_by_email->id) && !empty($customer_by_email)) {
             $customer = $customer_by_email;
         } else {
             if (!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 (!is_a($customer, 'EDD_Customer')) {
                 $customer = new EDD_Customer();
             }
             $first_name = '';
             $last_name = '';
             if (!empty($this->field_mapping['first_name']) && !empty($row[$this->field_mapping['first_name']])) {
                 $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']])) {
                 $last_name = sanitize_text_field($row[$this->field_mapping['last_name']]);
             }
             $customer->create(array('name' => $first_name . ' ' . $last_name, 'email' => $email));
             if (!empty($canonical_id) && (int) $canonical_id !== (int) $customer->id) {
                 $customer->update_meta('_canonical_import_id', $canonical_id);
             }
         }
     }
     if ($email && $email != $customer->email) {
         $customer->add_email($email);
     }
     return $customer->id;
 }