awesomemotive / easy-digital-downloads

Sell digital downloads through WordPress
https://easydigitaldownloads.com
GNU General Public License v2.0
863 stars 474 forks source link

Discount code amount is shown but total shows non-discount price so transaction fails #9698

Open WildeWebMarketing opened 10 months ago

WildeWebMarketing commented 10 months ago

This issue remains, please see for reference => https://github.com/awesomemotive/easy-digital-downloads/issues/9594

Using the add_download function is not calculating applied discounts correctly.

The following function checks to see if the user has already received a freebie item and, if not, adds the item to their order. The item is free, but is it recalculating the total and not taking possible discounts into consideration.

To reproduce:

  1. Install EDD

  2. Create dummy product (Awesome Product) for $9.99 (price irrelevant)

  3. Create dummy product (Free Product) for $0.00 (again, price irrelevant)

  4. Create discount code for 40% off (Code: BLACK)

  5. Add the following to functions.php (changing product IDs to Free Product ID :

function add_chained_product($payment_id, $data){
  $payment = new EDD_Payment($payment_id);
  $customer = new EDD_Customer( $payment->user_info['email'] );
  //error_log(print_r($payment->total, true));

  $user_id = $payment->user_info['id'];
  if($user_id == 0 && $customer->user_id !== 0){
      $user_id = $customer->user_id;
  }
  if(!edd_has_user_purchased($user_id, 1334)){
    $payment->add_download( 1334 );
  }
  //error_log(print_r($payment->total, true));
  $payment->save();
}
add_action( 'edd_insert_payment', 'add_chained_product', 100, 2 );
  1. Add Awesome Product $9.99 to Cart

  2. Add discount code BLACK to order (discount will be reflected in order)

  3. Complete Checkout

Now order will complete. Chained download is successfully added to order. But if you look at the order, the discount shows, but the total is incorrect, regardless if the product is free or not, which causes payment failed on production.

I added error_log(print_r($payment->total, true)); in two places in the function (currently commented out), which prints the total before and after the add_download into the error log. The first total is correct, the second is missing the discount.

I have also tested by adding $args and changing the price from 0.00 to 1.00, with the same result.

robincornett commented 10 months ago

A better way to do this would be to add the free product to the order using the order object and methods, because the EDD_Payment class is, as you have discovered, fairly involved.

Here's an example of what I would suggest instead, which is working for me without affecting the discount or total:

/**
 * Add a free product to an order.
 *
 * @param int $order_id The order ID.
 * @return void
 */
function prefix_add_free_product_to_order( $order_id ) {
    $free_product_id = 38111;
    $order           = edd_get_order( $order_id );
    if ( ! empty( $order->user_id ) && edd_has_user_purchased( $order->user_id, $free_product_id ) ) {
        return;
    }

    $order_item = edd_add_order_item(
        array(
            'order_id'     => $order_id,
            'product_id'   => $free_product_id,
            'price_id'     => null,
            'product_name' => edd_get_download_name( $free_product_id ),
            'cart_index'   => 1,
            'quantity'     => 1,
        )
    );
}
add_action( 'edd_built_order', 'prefix_add_free_product_to_order' );

Note that edd_built_order fires immediately after edd_insert_payment, which may eventually be deprecated.