Skip to content

Commit 2fa9d38

Browse files
authored
Add feature flag and backend support for additional dispute evidence types (#11129)
1 parent 59c5b9c commit 2fa9d38

File tree

4 files changed

+93
-20
lines changed

4 files changed

+93
-20
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Significance: patch
2+
Type: add
3+
4+
Add backend support for additional dispute evidence types (event, booking, other) behind feature flag.

includes/class-wc-payments-features.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class WC_Payments_Features {
2727
const WOOPAY_FIRST_PARTY_AUTH_FLAG_NAME = '_wcpay_feature_woopay_first_party_auth';
2828
const WOOPAY_DIRECT_CHECKOUT_FLAG_NAME = '_wcpay_feature_woopay_direct_checkout';
2929
const DISPUTE_ISSUER_EVIDENCE = '_wcpay_feature_dispute_issuer_evidence';
30+
const DISPUTE_ADDITIONAL_EVIDENCE_TYPES = '_wcpay_feature_dispute_additional_evidence_types';
3031
const WOOPAY_GLOBAL_THEME_SUPPORT_FLAG_NAME = '_wcpay_feature_woopay_global_theme_support';
3132
const WCPAY_DYNAMIC_CHECKOUT_PLACE_ORDER_BUTTON_FLAG_NAME = '_wcpay_feature_dynamic_checkout_place_order_button';
3233
const ACCOUNT_DETAILS_FLAG_NAME = '_wcpay_feature_account_details';
@@ -324,6 +325,17 @@ public static function is_dispute_issuer_evidence_enabled(): bool {
324325
return '1' === get_option( self::DISPUTE_ISSUER_EVIDENCE, '0' );
325326
}
326327

328+
/**
329+
* Checks whether Dispute Additional Evidence Types feature should be enabled. Disabled by default.
330+
*
331+
* This gates the new evidence form types (event, booking_reservation, other) for dispute challenges.
332+
*
333+
* @return bool
334+
*/
335+
public static function is_dispute_additional_evidence_types_enabled(): bool {
336+
return '1' === get_option( self::DISPUTE_ADDITIONAL_EVIDENCE_TYPES, '0' );
337+
}
338+
327339
/**
328340
* Checks whether the next deposit notice on the deposits list screen has been dismissed.
329341
*
@@ -373,6 +385,7 @@ public static function to_array() {
373385
'documents' => self::is_documents_section_enabled(),
374386
'woopayExpressCheckout' => self::is_woopay_express_checkout_enabled(),
375387
'isDisputeIssuerEvidenceEnabled' => self::is_dispute_issuer_evidence_enabled(),
388+
'isDisputeAdditionalEvidenceTypesEnabled' => self::is_dispute_additional_evidence_types_enabled(),
376389
'isFRTReviewFeatureActive' => self::is_frt_review_feature_active(),
377390
'isDynamicCheckoutPlaceOrderButtonEnabled' => self::is_dynamic_checkout_place_order_button_enabled(),
378391
'isAccountDetailsEnabled' => self::is_account_details_enabled(),

includes/wc-payment-api/class-wc-payments-api-client.php

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2962,9 +2962,9 @@ private function determine_suggested_product_type( WC_Order $order ): string {
29622962
return 'physical_product';
29632963
}
29642964

2965-
$virtual_products = 0;
2966-
$physical_products = 0;
2967-
$product_count = 0;
2965+
$virtual_products = 0;
2966+
$product_count = 0;
2967+
$product_type = null;
29682968

29692969
foreach ( $items as $item ) {
29702970
// Only process product items.
@@ -2979,20 +2979,34 @@ private function determine_suggested_product_type( WC_Order $order ): string {
29792979

29802980
++$product_count;
29812981

2982+
// Capture first product's type (only used for single-product orders).
2983+
if ( null === $product_type ) {
2984+
$product_type = $product->get_type();
2985+
}
2986+
29822987
if ( $product->is_virtual() ) {
29832988
++$virtual_products;
2984-
} else {
2985-
++$physical_products;
29862989
}
29872990
}
29882991

2992+
// If no valid products found, default to physical.
2993+
if ( 0 === $product_count ) {
2994+
return 'physical_product';
2995+
}
2996+
29892997
// If more than one product, suggest multiple.
29902998
if ( $product_count > 1 ) {
29912999
return 'multiple';
29923000
}
29933001

2994-
// If only one product and it's virtual, suggest digital.
2995-
if ( 1 === $product_count && 1 === $virtual_products ) {
3002+
// At this point, we know there's exactly one product.
3003+
// Check for specific product types (gated by feature flag).
3004+
if ( WC_Payments_Features::is_dispute_additional_evidence_types_enabled() && 'booking' === $product_type ) {
3005+
return 'booking_reservation';
3006+
}
3007+
3008+
// Check if it's virtual (digital product or service).
3009+
if ( 1 === $virtual_products ) {
29963010
return 'digital_product_or_service';
29973011
}
29983012

tests/unit/wc-payment-api/test-class-wc-payments-api-client.php

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1304,7 +1304,10 @@ private function create_woocommerce_default_pages(): array {
13041304
*
13051305
* @dataProvider data_determine_suggested_product_type
13061306
*/
1307-
public function test_determine_suggested_product_type( $order_items, $expected_product_type ) {
1307+
public function test_determine_suggested_product_type( $order_items, $expected_product_type, $evidence_types_flag_enabled = true ) {
1308+
// Set the feature flag option.
1309+
update_option( WC_Payments_Features::DISPUTE_ADDITIONAL_EVIDENCE_TYPES, $evidence_types_flag_enabled ? '1' : '0' );
1310+
13081311
// Create a mock order.
13091312
$mock_order = $this->getMockBuilder( 'WC_Order' )
13101313
->disableOriginalConstructor()
@@ -1328,73 +1331,112 @@ public function test_determine_suggested_product_type( $order_items, $expected_p
13281331
*/
13291332
public function data_determine_suggested_product_type() {
13301333
return [
1331-
'empty_order' => [
1334+
'empty_order' => [
13321335
'order_items' => [],
13331336
'expected_product_type' => 'physical_product',
13341337
],
1335-
'single_physical_product' => [
1338+
'single_physical_product' => [
13361339
'order_items' => [
13371340
$this->create_mock_order_item_product( false ), // not virtual.
13381341
],
13391342
'expected_product_type' => 'physical_product',
13401343
],
1341-
'single_virtual_product' => [
1344+
'single_virtual_product' => [
13421345
'order_items' => [
13431346
$this->create_mock_order_item_product( true ), // virtual.
13441347
],
13451348
'expected_product_type' => 'digital_product_or_service',
13461349
],
1347-
'multiple_products_mixed' => [
1350+
'multiple_products_mixed' => [
13481351
'order_items' => [
13491352
$this->create_mock_order_item_product( false ), // physical.
13501353
$this->create_mock_order_item_product( true ), // virtual.
13511354
],
13521355
'expected_product_type' => 'multiple',
13531356
],
1354-
'multiple_physical_products' => [
1357+
'multiple_physical_products' => [
13551358
'order_items' => [
13561359
$this->create_mock_order_item_product( false ), // physical.
13571360
$this->create_mock_order_item_product( false ), // physical.
13581361
],
13591362
'expected_product_type' => 'multiple',
13601363
],
1361-
'multiple_virtual_products' => [
1364+
'multiple_virtual_products' => [
13621365
'order_items' => [
13631366
$this->create_mock_order_item_product( true ), // virtual.
13641367
$this->create_mock_order_item_product( true ), // virtual.
13651368
],
13661369
'expected_product_type' => 'multiple',
13671370
],
1368-
'order_with_non_product_items' => [
1371+
'order_with_non_product_items' => [
13691372
'order_items' => [
13701373
$this->create_mock_order_item_product( true ), // virtual product.
13711374
$this->create_mock_order_item_shipping(), // shipping item (not a product).
13721375
],
13731376
'expected_product_type' => 'digital_product_or_service',
13741377
],
1375-
'order_with_invalid_product' => [
1378+
'order_with_invalid_product' => [
13761379
'order_items' => [
13771380
$this->create_mock_order_item_product( true, false ), // virtual but invalid product.
13781381
],
13791382
'expected_product_type' => 'physical_product',
13801383
],
1384+
'single_booking_product' => [
1385+
'order_items' => [
1386+
$this->create_mock_order_item_product( true, true, 'booking' ), // booking product.
1387+
],
1388+
'expected_product_type' => 'booking_reservation',
1389+
'evidence_types_flag_enabled' => true,
1390+
],
1391+
'single_booking_product_flag_off' => [
1392+
'order_items' => [
1393+
$this->create_mock_order_item_product( true, true, 'booking' ), // booking product (virtual).
1394+
],
1395+
'expected_product_type' => 'digital_product_or_service', // Falls back to virtual detection.
1396+
'evidence_types_flag_enabled' => false,
1397+
],
1398+
'single_booking_product_physical_flag_off' => [
1399+
'order_items' => [
1400+
$this->create_mock_order_item_product( false, true, 'booking' ), // booking product (not virtual).
1401+
],
1402+
'expected_product_type' => 'physical_product', // Falls back to physical detection.
1403+
'evidence_types_flag_enabled' => false,
1404+
],
1405+
'multiple_booking_products' => [
1406+
'order_items' => [
1407+
$this->create_mock_order_item_product( true, true, 'booking' ), // booking.
1408+
$this->create_mock_order_item_product( true, true, 'booking' ), // booking.
1409+
],
1410+
'expected_product_type' => 'multiple',
1411+
'evidence_types_flag_enabled' => true,
1412+
],
1413+
'booking_physical_mixed' => [
1414+
'order_items' => [
1415+
$this->create_mock_order_item_product( true, true, 'booking' ), // booking.
1416+
$this->create_mock_order_item_product( false, true, 'simple' ), // physical.
1417+
],
1418+
'expected_product_type' => 'multiple',
1419+
'evidence_types_flag_enabled' => true,
1420+
],
13811421
];
13821422
}
13831423

13841424
/**
13851425
* Create a mock order item product for testing.
13861426
*
1387-
* @param bool $is_virtual Whether the product is virtual.
1388-
* @param bool $is_valid Whether the product is valid (can be retrieved).
1427+
* @param bool $is_virtual Whether the product is virtual.
1428+
* @param bool $is_valid Whether the product is valid (can be retrieved).
1429+
* @param string $product_type The product type (e.g., 'simple', 'booking', 'variable').
13891430
* @return MockObject
13901431
*/
1391-
private function create_mock_order_item_product( $is_virtual = false, $is_valid = true ) {
1432+
private function create_mock_order_item_product( $is_virtual = false, $is_valid = true, $product_type = 'simple' ) {
13921433
$mock_product = $this->getMockBuilder( 'WC_Product' )
13931434
->disableOriginalConstructor()
1394-
->setMethods( [ 'is_virtual' ] )
1435+
->setMethods( [ 'is_virtual', 'get_type' ] )
13951436
->getMock();
13961437

13971438
$mock_product->method( 'is_virtual' )->willReturn( $is_virtual );
1439+
$mock_product->method( 'get_type' )->willReturn( $product_type );
13981440

13991441
$mock_order_item = $this->getMockBuilder( 'WC_Order_Item_Product' )
14001442
->disableOriginalConstructor()

0 commit comments

Comments
 (0)