'edd-payment-history', 'view' => 'view-order-details', 'id' => absint( $request['id'] ) ) ) ); } } add_action( 'edd_handle_order_item_change', 'edd_handle_order_item_change' ); /** * Process the changes from the `View Order Details` page. * * @since 1.9 * @since 3.0 Refactored to use new core objects and query methods. * * @param array $data Order data. */ function edd_update_payment_details( $data = array() ) { // Bail if an empty array is passed. if ( empty( $data ) ) { wp_die( esc_html__( 'You do not have permission to edit this payment record', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); } // Bail if the user does not have the correct permissions. if ( ! current_user_can( 'edit_shop_payments', $data['edd_payment_id'] ) ) { wp_die( esc_html__( 'You do not have permission to edit this payment record', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); } check_admin_referer( 'edd_update_payment_details_nonce' ); // Retrieve the order ID and set up the order. $order_id = absint( $data['edd_payment_id'] ); $order = edd_get_order( $order_id ); $order_update_args = array(); $unlimited = isset( $data['edd-unlimited-downloads'] ) ? '1' : null; $new_status = sanitize_key( $data['edd-payment-status'] ); $date_string = EDD()->utils->get_date_string( sanitize_text_field( $data['edd-payment-date'] ), sanitize_text_field( $data['edd-payment-time-hour'] ), sanitize_text_field( $data['edd-payment-time-min'] ) ); // The date is entered in the WP timezone. We need to convert it to UTC prior to saving now. $date = edd_get_utc_equivalent_date( EDD()->utils->date( $date_string, edd_get_timezone_id(), false ) ); $date = $date->format( 'Y-m-d H:i:s' ); $order_update_args['date_created'] = $date; // Customer $curr_customer_id = sanitize_text_field( $data['current-customer-id'] ); $new_customer_id = sanitize_text_field( $data['customer-id'] ); // Create a new customer. if ( isset( $data['edd-new-customer'] ) && 1 === (int) $data['edd-new-customer'] ) { $email = isset( $data['edd-new-customer-email'] ) ? sanitize_text_field( $data['edd-new-customer-email'] ) : ''; // Sanitize first name $first_name = isset( $data['edd-new-customer-first-name'] ) ? sanitize_text_field( $data['edd-new-customer-first-name'] ) : ''; // Sanitize last name $last_name = isset( $data['edd-new-customer-last-name'] ) ? sanitize_text_field( $data['edd-new-customer-last-name'] ) : ''; // Combine $name = $first_name . ' ' . $last_name; if ( empty( $email ) || empty( $name ) ) { wp_die( esc_html__( 'New Customers require a name and email address', 'easy-digital-downloads' ) ); } $customer = new EDD_Customer( $email ); if ( empty( $customer->id ) ) { $customer_data = array( 'name' => $name, 'email' => $email, ); $user_id = email_exists( $email ); if ( false !== $user_id ) { $customer_data['user_id'] = $user_id; } if ( ! $customer->create( $customer_data ) ) { $customer = new EDD_Customer( $curr_customer_id ); edd_set_error( 'edd-payment-new-customer-fail', __( 'Error creating new customer', 'easy-digital-downloads' ) ); } } else { wp_die( sprintf( __( 'A customer with the email address %s already exists. Please go back and assign this payment to them.', 'easy-digital-downloads' ), $email ) ); } $previous_customer = new EDD_Customer( $curr_customer_id ); } elseif ( $curr_customer_id !== $new_customer_id ) { $customer = new EDD_Customer( $new_customer_id ); $previous_customer = new EDD_Customer( $curr_customer_id ); } else { $customer = new EDD_Customer( $curr_customer_id ); } // Remove the stats and payment from the previous customer and attach it to the new customer if ( isset( $previous_customer ) ) { $previous_customer->remove_payment( $order_id, false ); $customer->attach_payment( $order_id, false ); // If purchase was completed and not ever refunded, adjust stats of customers if ( 'revoked' === $new_status || 'complete' === $new_status ) { $previous_customer->recalculate_stats(); if ( ! empty( $customer ) ) { $customer->recalculate_stats(); } } $order_update_args['customer_id'] = $customer->id; } $order_update_args['user_id'] = $customer->user_id; $order_update_args['email'] = $customer->email; // Address. $address = $data['edd_order_address']; $order_address_id = absint( $address['address_id'] ); $order_address_details = array( 'name' => $customer->name, 'address' => $address['address'], 'address2' => $address['address2'], 'city' => $address['city'], 'region' => $address['region'], 'postal_code' => $address['postal_code'], 'country' => $address['country'], ); if ( empty( $order_address_id ) ) { // Unset the address_id which is 0. unset( $address['address_id'] ); // Add the $order_id to the arguments to create this order address. $order_address_details['order_id'] = $order_id; edd_add_order_address( $order_address_details ); } else { edd_update_order_address( $order_address_id, $order_address_details ); } // Unlimited downloads. if ( 1 === (int) $unlimited ) { edd_update_order_meta( $order_id, 'unlimited_downloads', $unlimited ); } else { edd_delete_order_meta( $order_id, 'unlimited_downloads' ); } // Don't set the status in the update call (for back compat) unset( $order_update_args['status'] ); // Attempt to update the order $updated = edd_update_order( $order_id, $order_update_args ); // Bail if an error occurred if ( false === $updated ) { wp_die( __( 'Error updating order.', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 400 ) ); } // Check if the status has changed, if so, we need to invoke the pertinent // status processing method (for back compat) if ( $new_status !== $order->status ) { edd_update_order_status( $order_id, $new_status ); } do_action( 'edd_updated_edited_purchase', $order_id ); edd_redirect( edd_get_admin_url( array( 'page' => 'edd-payment-history', 'view' => 'view-order-details', 'edd-message' => 'payment-updated', 'id' => absint( $order_id ), ) ) ); } add_action( 'edd_update_payment_details', 'edd_update_payment_details' ); /** * New in 3.0, permanently destroys an order, and all its data, and related data. * * @since 3.0 * * @param array $data Arguments passed. */ function edd_trigger_destroy_order( $data ) { if ( wp_verify_nonce( $data['_wpnonce'], 'edd_payment_nonce' ) ) { $payment_id = absint( $data['purchase_id'] ); if ( ! current_user_can( 'delete_shop_payments', $payment_id ) ) { wp_die( esc_html__( 'You do not have permission to edit this order.', 'easy-digital-downloads' ), esc_html__( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); } edd_destroy_order( $payment_id ); $redirect_link = add_query_arg( array( 'page' => 'edd-payment-history', 'edd-message' => 'payment_deleted', 'status' => 'trash', ), edd_get_admin_base_url() ); edd_redirect( $redirect_link ); } } add_action( 'edd_delete_order', 'edd_trigger_destroy_order' ); /** * Trigger the action of moving an order to the 'trash' status * * @since 3.0 * * @param $data * @return void */ function edd_trigger_trash_order( $data ) { if ( wp_verify_nonce( $data['_wpnonce'], 'edd_payment_nonce' ) ) { $payment_id = absint( $data['purchase_id'] ); if ( ! current_user_can( 'delete_shop_payments', $payment_id ) ) { wp_die( __( 'You do not have permission to edit this payment record', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); } edd_trash_order( $payment_id ); $redirect = edd_get_admin_url( array( 'page' => 'edd-payment-history', 'edd-message' => 'order_trashed', 'order_type' => esc_attr( $data['order_type'] ), ) ); edd_redirect( $redirect ); } } add_action( 'edd_trash_order', 'edd_trigger_trash_order' ); /** * Trigger the action of restoring an order from the 'trash' status * * @since 3.0 * * @param $data * @return void */ function edd_trigger_restore_order( $data ) { if ( wp_verify_nonce( $data['_wpnonce'], 'edd_payment_nonce' ) ) { $payment_id = absint( $data['purchase_id'] ); if ( ! current_user_can( 'delete_shop_payments', $payment_id ) ) { wp_die( __( 'You do not have permission to edit this payment record', 'easy-digital-downloads' ), __( 'Error', 'easy-digital-downloads' ), array( 'response' => 403 ) ); } edd_restore_order( $payment_id ); $redirect = edd_get_admin_url( array( 'page' => 'edd-payment-history', 'edd-message' => 'order_restored', 'order_type' => esc_attr( $data['order_type'] ), ) ); edd_redirect( $redirect ); } } add_action( 'edd_restore_order', 'edd_trigger_restore_order' ); /** * Retrieves a new download link for a purchased file * * @since 2.0 * @return string */ function edd_ajax_generate_file_download_link() { $customer_view_role = apply_filters( 'edd_view_customers_role', 'view_shop_reports' ); if ( ! current_user_can( $customer_view_role ) ) { die( '-1' ); } $payment_id = absint( $_POST['payment_id'] ); $download_id = absint( $_POST['download_id'] ); $price_id = isset( $_POST['price_id'] ) && is_numeric( $_POST['price_id'] ) ? absint( $_POST['price_id'] ) : null; if ( empty( $payment_id ) ) { die( '-2' ); } if ( empty( $download_id ) ) { die( '-3' ); } $limit = edd_get_file_download_limit( $download_id ); if ( ! empty( $limit ) ) { // Increase the file download limit when generating new links edd_set_file_download_limit_override( $download_id, $payment_id ); } $files = edd_get_download_files( $download_id, $price_id ); if ( ! $files ) { die( '-4' ); } $order = edd_get_order( $payment_id ); $file_urls = ''; foreach ( $files as $file_key => $file ) { $file_urls .= edd_get_download_file_url( $order, $order->email, $file_key, $download_id, $price_id ); $file_urls .= "\n\n"; } die( $file_urls ); } add_action( 'wp_ajax_edd_get_file_download_link', 'edd_ajax_generate_file_download_link' ); /** * Renders the refund form that is used to process a refund. * * @since 3.0 * * @return void */ function edd_ajax_generate_refund_form() { // Verify we have a logged user. if ( ! is_user_logged_in() ) { $return = array( 'success' => false, 'message' => __( 'You must be logged in to perform this action.', 'easy-digital-downloads' ), ); wp_send_json( $return, 401 ); } // Verify the logged in user has permission to edit shop payments. if ( ! current_user_can( 'edit_shop_payments' ) ) { $return = array( 'success' => false, 'message' => __( 'Your account does not have permission to perform this action.', 'easy-digital-downloads' ), ); wp_send_json( $return, 401 ); } $order_id = isset( $_POST['order_id'] ) && is_numeric( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : false; if ( empty( $order_id ) ) { $return = array( 'success' => false, 'message' => __( 'Invalid order ID', 'easy-digital-downloads' ), ); wp_send_json( $return, 400 ); } $order = edd_get_order( $order_id ); if ( empty( $order ) ) { $return = array( 'success' => false, 'message' => __( 'Invalid order', 'easy-digital-downloads' ), ); wp_send_json( $return, 404 ); } if ( 'refunded' === $order->status ) { $return = array( 'success' => false, 'message' => __( 'Order is already refunded', 'easy-digital-downloads' ), ); wp_send_json( $return, 404 ); } if ( 'refund' === $order->type ) { $return = array( 'success' => false, 'message' => __( 'Cannot refund an order that is already refunded.', 'easy-digital-downloads' ), ); wp_send_json( $return, 404 ); } // Output buffer the form before we include it in the JSON response. ob_start(); ?>
prepare_items(); $refund_items->display(); ?>
true, 'html' => $html, ); wp_send_json( $return, 200 ); } add_action( 'wp_ajax_edd_generate_refund_form', 'edd_ajax_generate_refund_form' ); /** * Processes the results from the Submit Refund form * * @since 3.0 * @return void */ function edd_ajax_process_refund_form() { // Verify we have a logged user. if ( ! is_user_logged_in() ) { wp_send_json_error( __( 'You must be logged in to perform this action.', 'easy-digital-downloads' ), 401 ); } // Verify the logged in user has permission to edit shop payments. if ( ! current_user_can( 'edit_shop_payments' ) ) { wp_send_json_error( __( 'Your account does not have permission to perform this action.', 'easy-digital-downloads' ), 401 ); } if ( empty( $_POST['data'] ) || empty( $_POST['order_id'] ) ) { wp_send_json_error( __( 'Missing form data or order ID.', 'easy-digital-downloads' ), 400 ); } // Get our data out of the serialized string. parse_str( $_POST['data'], $form_data ); // Verify the nonce. $nonce = ! empty( $form_data['edd_process_refund'] ) ? sanitize_text_field( $form_data['edd_process_refund'] ) : false; if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'edd_process_refund' ) ) { wp_send_json_error( __( 'Nonce validation failed when submitting refund.', 'easy-digital-downloads' ), 401 ); } // Collect selected order items. $order_items = array(); if ( ! empty( $form_data['refund_order_item'] ) && is_array( $form_data['refund_order_item'] ) ) { foreach( $form_data['refund_order_item'] as $order_item_id => $order_item ) { // If there's no quantity or subtotal - bail. if ( empty( $order_item['quantity'] ) || empty( $order_item['subtotal'] ) ) { continue; } $order_items[] = array( 'order_item_id' => absint( $order_item_id ), 'quantity' => intval( $order_item['quantity'] ), 'subtotal' => edd_sanitize_amount( $order_item['subtotal'] ), 'tax' => ! empty( $order_item['tax'] ) ? edd_sanitize_amount( $order_item['tax'] ) : 0.00 ); } } // Collect selected adjustments. $adjustments = array(); if ( ! empty( $form_data['refund_order_adjustment'] ) && is_array( $form_data['refund_order_adjustment'] ) ) { foreach( $form_data['refund_order_adjustment'] as $adjustment_id => $adjustment ) { // If there's no quantity or subtotal - bail. if ( empty( $adjustment['quantity'] ) || empty( $adjustment['subtotal'] ) ) { continue; } $adjustments[] = array( 'adjustment_id' => absint( $adjustment_id ), 'quantity' => intval( $adjustment['quantity'] ), 'subtotal' => floatval( edd_sanitize_amount( $adjustment['subtotal'] ) ), 'tax' => ! empty( $adjustment['tax'] ) ? floatval( edd_sanitize_amount( $adjustment['tax'] ) ) : 0.00 ); } } $order_id = absint( $_POST['order_id'] ); $refund_id = edd_refund_order( $order_id, $order_items, $adjustments ); if ( is_wp_error( $refund_id ) ) { wp_send_json_error( $refund_id->get_error_message() ); } elseif ( ! empty( $refund_id ) ) { $return = array( 'refund_id' => $refund_id, 'message' => sprintf( __( 'Refund successfully processed.', 'easy-digital-downloads' ) ), 'refund_url' => edd_get_admin_url( array( 'page' => 'edd-payment-history', 'view' => 'view-refund-details', 'id' => urlencode( $refund_id ), ) ) ); wp_send_json_success( $return, 200 ); } else { wp_send_json_error( __( 'Unable to process refund.', 'easy-digital-downloads' ), 401 ); } } add_action( 'wp_ajax_edd_process_refund_form', 'edd_ajax_process_refund_form' ); /** * Process Orders list table bulk actions. This is necessary because we need to * redirect to ensure filters do not get applied when bulk actions are being * processed. This processing cannot happen within the `EDD_Payment_History_Table` * class as at that point, it is too late to do a redirect. * * @since 3.0 */ function edd_orders_list_table_process_bulk_actions() { // Bail if this method was called directly. if ( 'load-download_page_edd-payment-history' !== current_action() ) { _doing_it_wrong( __FUNCTION__, 'This method is not meant to be called directly.', 'EDD 3.0' ); } $action = isset( $_REQUEST['action'] ) // WPCS: CSRF ok. ? sanitize_text_field( $_REQUEST['action'] ) : ''; // If this is a 'delete' action, the capability changes from edit to delete. $cap = 'delete' === $action ? 'delete_shop_payments' : 'edit_shop_payments'; // Check the current user's capability. if ( ! current_user_can( $cap ) ) { return; } // Bail if we aren't processing bulk actions. if ( '-1' === $action ) { return; } $ids = isset( $_GET['order'] ) // WPCS: CSRF ok. ? $_GET['order'] : false; if ( ! is_array( $ids ) ) { $ids = array( $ids ); } if ( empty( $action ) ) { return; } check_admin_referer( 'bulk-orders' ); $ids = wp_parse_id_list( $ids ); foreach ( $ids as $id ) { switch ( $action ) { case 'trash': edd_trash_order( $id ); break; case 'restore': edd_restore_order( $id ); break; case 'delete': edd_destroy_order( $id ); break; case 'set-status-complete': edd_update_payment_status( $id, 'complete' ); break; case 'set-status-pending': edd_update_payment_status( $id, 'pending' ); break; case 'set-status-processing': edd_update_payment_status( $id, 'processing' ); break; case 'set-status-revoked': edd_update_payment_status( $id, 'revoked' ); break; case 'set-status-failed': edd_update_payment_status( $id, 'failed' ); break; case 'set-status-abandoned': edd_update_payment_status( $id, 'abandoned' ); break; case 'set-status-preapproval': edd_update_payment_status( $id, 'preapproval' ); break; case 'set-status-cancelled': edd_update_payment_status( $id, 'cancelled' ); break; case 'resend-receipt': edd_email_purchase_receipt( $id, false ); break; } do_action( 'edd_payments_table_do_bulk_action', $id, $action ); } wp_safe_redirect( wp_get_referer() ); } add_action( 'load-download_page_edd-payment-history', 'edd_orders_list_table_process_bulk_actions' );