Cherry pick #367 into release/9.2 (#50804)

* Init: Revoke download parmission for partially refunded items

* fix failing tests

* fix failing tests

* added tests

* Added changelog

* review changes

* Drop changelog

* Address PHPCS violation

---------

Co-authored-by: Naman Malhotra <naman03malhotra@gmail.com>
This commit is contained in:
Jorge A. Torres 2024-08-20 17:38:38 -03:00 committed by GitHub
parent 3625a4f55d
commit 60bea63fe8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 108 additions and 6 deletions

View File

@ -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.
*

View File

@ -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() );
}
}

View File

@ -1,6 +1,7 @@
<?php
use Automattic\WooCommerce\RestApi\UnitTests\HPOSToggleTrait;
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
/**
* Tests for the WC_User class.
@ -62,4 +63,82 @@ class WC_User_Functions_Tests extends WC_Unit_Test_Case {
$this->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'] );
}
}