Solve error when coupons are applied to orders that reference deleted products (#46251)

Solve error when coupons are applied to orders that reference deleted products.
This commit is contained in:
Barry Hughes 2024-04-05 03:53:53 -07:00 committed by GitHub
parent 57b8fe8a84
commit d874575c86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 57 additions and 1 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Addresses a fatal error that can occur when applying a coupon within the order editor (where one of the products has been deleted).

View File

@ -906,7 +906,7 @@ class WC_Coupon extends WC_Legacy_Coupon {
* @return bool
*/
public function is_valid_for_product( $product, $values = array() ) {
if ( ! $this->is_type( wc_get_product_coupon_types() ) ) {
if ( ! $this->is_type( wc_get_product_coupon_types() ) || ! is_a( $product, WC_Product::class ) ) {
return apply_filters( 'woocommerce_coupon_is_valid_for_product', false, $product, $this, $values );
}

View File

@ -0,0 +1,52 @@
<?php
/**
* Tests for WC_Coupon.
*
* See also ../../legacy/unit-tests/coupon/coupon.php for other related tests.
*/
class WC_Coupon_Tests extends WC_Unit_Test_Case {
/**
* If a coupon is applied to an order where one or more products have been deleted, the operation should still
* succeed.
*
* However, the coupon will have no impact on any line items referencing the deleted product(s), since in most cases
* the product's eligibility can no longer be assessed (therefore, it is up to the merchant to manually adjust if
* this is problematic).
*
* @see https://github.com/woocommerce/woocommerce/issues/27077
*
* @return void
*/
public function test_deleted_products_do_not_prevent_application_of_coupons(): void {
// Test order will have one product added already (price: 10, quantity: 4).
$order = WC_Helper_Order::create_order();
$extra_product = WC_Helper_Product::create_simple_product();
$coupon = WC_Helper_Coupon::create_coupon(
'look_after_the_pennies',
array(
'discount_type' => 'percent',
'coupon_amount' => 10,
)
);
// Add our further product to the order, but then delete the product itself.
$order->add_product( $extra_product );
$order->save();
wp_delete_post( $extra_product->get_id(), true );
$this->assertTrue(
$order->apply_coupon( $coupon ),
'The coupon was successfully applied to an order containing a deleted product, without triggering an error.'
);
// Both products have a cost of $10. The first item has a quantity of 4 units ($40). So, the 10% discount
// should give an actual discount total of $4 (the second line item is excluded from the calculation, because
// its product was deleted).
$this->assertEquals(
4,
$order->get_discount_total(),
'Line items associated with deleted products are not included in the discount calculation.'
);
}
}