From d2104e107927d67c524ddaa153419a61c1bb0cdf Mon Sep 17 00:00:00 2001 From: "Jorge A. Torres" Date: Tue, 20 Aug 2024 20:45:13 -0300 Subject: [PATCH] Cherry pick PR#50804 into trunk (#50812) --- .../includes/wc-order-functions.php | 32 +++++++- .../php/includes/wc-order-functions-test.php | 3 +- .../php/includes/wc-user-functions-test.php | 79 +++++++++++++++++++ 3 files changed, 108 insertions(+), 6 deletions(-) diff --git a/plugins/woocommerce/includes/wc-order-functions.php b/plugins/woocommerce/includes/wc-order-functions.php index 420f2da080d..972705ab078 100644 --- a/plugins/woocommerce/includes/wc-order-functions.php +++ b/plugins/woocommerce/includes/wc-order-functions.php @@ -540,10 +540,11 @@ function wc_create_refund( $args = array() ) { throw new Exception( __( 'Invalid order ID.', 'woocommerce' ) ); } - $remaining_refund_amount = $order->get_remaining_refund_amount(); - $remaining_refund_items = $order->get_remaining_refund_items(); - $refund_item_count = 0; - $refund = new WC_Order_Refund( $args['refund_id'] ); + $remaining_refund_amount = $order->get_remaining_refund_amount(); + $remaining_refund_items = $order->get_remaining_refund_items(); + $refund_item_count = 0; + $refund = new WC_Order_Refund( $args['refund_id'] ); + $refunded_order_and_products = array(); if ( 0 > $args['amount'] || $args['amount'] > $remaining_refund_amount ) { throw new Exception( __( 'Invalid refund amount.', 'woocommerce' ) ); @@ -576,6 +577,16 @@ function wc_create_refund( $args = array() ) { continue; } + // array of order id and product id which were refunded. + // later to be used for revoking download permission. + // checking if the item is a product, as we only need to revoke download permission for products. + if ( $item->is_type( 'line_item' ) ) { + $refunded_order_and_products[ $item_id ] = array( + 'order_id' => $order->get_id(), + 'product_id' => $item->get_product_id(), + ); + } + $class = get_class( $item ); $refunded_item = new $class( $item ); $refunded_item->set_id( 0 ); @@ -635,6 +646,19 @@ function wc_create_refund( $args = array() ) { wc_restock_refunded_items( $order, $args['line_items'] ); } + // delete downloads that were refunded using order and product id, if present. + if ( ! empty( $refunded_order_and_products ) ) { + foreach ( $refunded_order_and_products as $refunded_order_and_product ) { + $download_data_store = WC_Data_Store::load( 'customer-download' ); + $downloads = $download_data_store->get_downloads( $refunded_order_and_product ); + if ( ! empty( $downloads ) ) { + foreach ( $downloads as $download ) { + $download_data_store->delete_by_id( $download->get_id() ); + } + } + } + } + /** * Trigger notification emails. * diff --git a/plugins/woocommerce/tests/php/includes/wc-order-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-order-functions-test.php index 75d99e32986..3ef3723e4ad 100644 --- a/plugins/woocommerce/tests/php/includes/wc-order-functions-test.php +++ b/plugins/woocommerce/tests/php/includes/wc-order-functions-test.php @@ -39,7 +39,7 @@ class WC_Order_Functions_Test extends \WC_Unit_Test_Case { $line_item = reset( $items ); // Force a restock of one item. - $refunded_items = array(); + $refunded_items = array(); $refunded_items[ $line_item->get_id() ] = array( 'qty' => 1, ); @@ -174,5 +174,4 @@ class WC_Order_Functions_Test extends \WC_Unit_Test_Case { $this->assertEquals( 1, $order->get_data_store()->get_recorded_coupon_usage_counts( $order ) ); $this->assertEquals( 1, ( new WC_Coupon( $coupon ) )->get_usage_count() ); } - } diff --git a/plugins/woocommerce/tests/php/includes/wc-user-functions-test.php b/plugins/woocommerce/tests/php/includes/wc-user-functions-test.php index a2149955f27..163e977a555 100644 --- a/plugins/woocommerce/tests/php/includes/wc-user-functions-test.php +++ b/plugins/woocommerce/tests/php/includes/wc-user-functions-test.php @@ -1,6 +1,7 @@ assertFalse( wc_customer_bought_product( 'test@example.com', $customer_id_1, $product_id_2 ) ); $this->assertFalse( wc_customer_bought_product( 'test2@example.com', $customer_id_2, $product_id_1 ) ); } + + /** + * Test test_wc_get_customer_available_downloads_for_partial_refunds. + * + * @since 9.3 + */ + public function test_wc_get_customer_available_downloads_for_partial_refunds(): void { + /** @var Download_Directories $download_directories */ + $download_directories = wc_get_container()->get( Download_Directories::class ); + $download_directories->set_mode( Download_Directories::MODE_ENABLED ); + $download_directories->add_approved_directory( 'https://always.trusted' ); + + $test_file = 'https://always.trusted/123.pdf'; + + $customer_id = wc_create_new_customer( 'test@example.com', 'testuser', 'testpassword' ); + + $prod_download = new WC_Product_Download(); + $prod_download->set_file( $test_file ); + $prod_download->set_id( 1 ); + + $prod_download2 = new WC_Product_Download(); + $prod_download2->set_file( $test_file ); + $prod_download2->set_id( 2 ); + + $product = new WC_Product_Simple(); + $product->set_regular_price( 10 ); + $product->set_downloadable( 'yes' ); + $product->set_downloads( array( $prod_download ) ); + $product->save(); + + $product2 = new WC_Product_Simple(); + $product2->set_regular_price( 20 ); + $product2->set_downloadable( 'yes' ); + $product2->set_downloads( array( $prod_download2 ) ); + $product2->save(); + + $order = new WC_Order(); + $order->set_customer_id( $customer_id ); + + $item = new WC_Order_Item_Product(); + $item->set_product( $product ); + $item->set_order_id( $order->get_id() ); + $item->set_total( 10 ); + $item->save(); + $order->add_item( $item ); + + $item2 = new WC_Order_Item_Product(); + $item2->set_product( $product2 ); + $item2->set_order_id( $order->get_id() ); + $item->set_total( 20 ); + $item2->save(); + $order->add_item( $item2 ); + + $order->set_total( 30 ); // 10 + 20 + $order->set_status( 'completed' ); + $order->save(); + + $args = array( + 'amount' => 10, + 'order_id' => $order->get_id(), + 'line_items' => array( + $item->get_id() => array( + 'qty' => 1, + 'refund_total' => 10, + ), + ), + ); + + wc_create_refund( $args ); + + $downloads = wc_get_customer_available_downloads( $customer_id ); + $this->assertEquals( 1, count( $downloads ) ); + + $download = current( $downloads ); + $this->assertEquals( $prod_download2->get_id(), $download['download_id'] ); + $this->assertEquals( $order->get_id(), $download['order_id'] ); + $this->assertEquals( $product2->get_id(), $download['product_id'] ); + } }