Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: add

Add evidence matrix entry for product not received × physical product dispute combination
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,34 @@ describe( 'Cover Letter Generator', () => {
expect( result ).toContain( 'Other documents (Attachment E)' );
} );

it( 'should order all product_not_received attachments correctly with full evidence and physical_product product type', () => {
const productNotReceivedDispute: ExtendedDispute = {
...mockDispute,
reason: 'product_not_received' as DisputeReason,
evidence: {
receipt: 'receipt_url',
customer_communication: 'customer_communication_url',
customer_signature: 'customer_signature_url',
refund_policy: 'refund_policy_url',
shipping_documentation: 'shipping_documentation_url',
uncategorized_file: 'uncategorized_file_url',
},
};
const result = generateAttachments(
productNotReceivedDispute,
undefined,
'physical_product'
);
expect( result ).toContain( 'Order receipt (Attachment A)' );
expect( result ).toContain(
'Customer communication (Attachment B)'
);
expect( result ).toContain( "Customer's signature (Attachment C)" );
expect( result ).toContain( 'Store refund policy (Attachment D)' );
expect( result ).toContain( 'Proof of shipping (Attachment E)' );
expect( result ).toContain( 'Other documents (Attachment F)' );
} );

it( 'should include "Customer\'s signature" only for physical_product product type', () => {
const disputeWithSignature: ExtendedDispute = {
...mockDispute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@
* - duplicate × booking_reservation (is_not_duplicate scenario)
* - credit_not_processed × booking_reservation (refund_was_not_owed scenario)
* - credit_not_processed × booking_reservation (refund_has_been_issued scenario)
* - product_not_received × physical_product
*
* ⏳ Not yet implemented (in backlog):
* - All combinations with physical_product
* - All combinations with physical_product (except product_not_received)
* - All combinations with digital_product_or_service
* - All combinations with offline_service
* - All combinations with event
Expand Down Expand Up @@ -155,6 +156,50 @@ const implementedCombinations: CombinationSpec[] = [
},
},

// ============================================
// PRODUCT NOT RECEIVED × PHYSICAL PRODUCT
// ============================================
{
reason: 'product_not_received',
productType: 'physical_product',
description:
'Product not received for physical product - needs receipt, signature, refund policy',
uiFields: {
shouldInclude: [
DOCUMENT_FIELD_KEYS.RECEIPT,
DOCUMENT_FIELD_KEYS.CUSTOMER_COMMUNICATION,
DOCUMENT_FIELD_KEYS.CUSTOMER_SIGNATURE,
DOCUMENT_FIELD_KEYS.REFUND_POLICY,
DOCUMENT_FIELD_KEYS.UNCATEGORIZED_FILE,
],
shouldExclude: [
DOCUMENT_FIELD_KEYS.SHIPPING_DOCUMENTATION, // Shown separately in shipping step
DOCUMENT_FIELD_KEYS.SERVICE_DOCUMENTATION, // Not for physical products
DOCUMENT_FIELD_KEYS.CANCELLATION_REBUTTAL, // Not in spec for physical product
],
expectedLabels: {
[ DOCUMENT_FIELD_KEYS.RECEIPT ]: 'Order receipt',
[ DOCUMENT_FIELD_KEYS.CUSTOMER_COMMUNICATION ]:
'Customer communication',
[ DOCUMENT_FIELD_KEYS.CUSTOMER_SIGNATURE ]:
"Customer's signature",
[ DOCUMENT_FIELD_KEYS.REFUND_POLICY ]: 'Refund policy',
[ DOCUMENT_FIELD_KEYS.UNCATEGORIZED_FILE ]: 'Other documents',
},
},
coverLetterAttachments: {
// Note: Cover letter uses "Store refund policy" label
shouldInclude: [
'Order receipt',
'Customer communication',
"Customer's signature",
'Store refund policy',
'Other documents',
],
shouldExclude: [],
},
},

// ============================================
// PRODUCT UNACCEPTABLE × BOOKING/RESERVATION
// ============================================
Expand Down Expand Up @@ -773,7 +818,7 @@ describe( 'Evidence Matrix Specification Validation', () => {
* - other (needs: Prior history, Other)
*
* Product Not Received:
* - physical_product (needs: Order receipt, Customer communication, Customer's signature, Refund policy, Other)
* - physical_product ✅ Implemented
* - digital_product_or_service (needs: Order receipt, Login/usage records, Other)
* - offline_service (needs: Order receipt, Proof of service completion, Other)
* - event (needs: Order receipt, Attendance confirmation, Other)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -542,7 +542,7 @@ describe( 'Recommended Documents', () => {
expect( result[ 4 ].label ).toBe( 'Other documents' );
} );

it( 'should fall back to trunk product_not_received fields for physical_product when feature flag is enabled', () => {
it( 'should return matrix fields for product_not_received + physical_product when feature flag is enabled', () => {
global.wcpaySettings.featureFlags.isDisputeAdditionalEvidenceTypesEnabled = true;

const result = getRecommendedDocumentFields(
Expand All @@ -552,13 +552,18 @@ describe( 'Recommended Documents', () => {
'physical_product'
);

// Should fall back to trunk product_not_received fields since no matrix entry for physical_product
// Matrix entry for product_not_received + physical_product
expect( result ).toHaveLength( 5 );
expect( result[ 0 ].key ).toBe( 'receipt' );
expect( result[ 0 ].label ).toBe( 'Order receipt' );
expect( result[ 1 ].key ).toBe( 'customer_communication' );
expect( result[ 1 ].label ).toBe( 'Customer communication' );
expect( result[ 2 ].key ).toBe( 'customer_signature' );
expect( result[ 2 ].label ).toBe( "Customer's signature" );
expect( result[ 3 ].key ).toBe( 'refund_policy' );
expect( result[ 3 ].label ).toBe( 'Refund policy' );
expect( result[ 4 ].key ).toBe( 'uncategorized_file' );
expect( result[ 4 ].label ).toBe( 'Other documents' );
} );
} );

Expand Down
39 changes: 39 additions & 0 deletions client/disputes/new-evidence/evidence-matrix.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,45 @@ const getSubscriptionCanceledMatrix = (): {
const getProductNotReceivedMatrix = (): {
[ productType: string ]: Array< RecommendedDocument >;
} => ( {
// Physical Product product type
physical_product: [
{
key: DOCUMENT_FIELD_KEYS.RECEIPT,
label: __( 'Order receipt', 'woocommerce-payments' ),
description: __(
"A copy of the customer's receipt, which can be found in the receipt history for this transaction.",
'woocommerce-payments'
),
order: 10,
},
{
key: DOCUMENT_FIELD_KEYS.CUSTOMER_SIGNATURE,
label: __( "Customer's signature", 'woocommerce-payments' ),
description: __(
"Any relevant documents showing the customer's signature, such as signed proof of delivery.",
'woocommerce-payments'
),
order: 25,
},
{
key: DOCUMENT_FIELD_KEYS.REFUND_POLICY,
label: __( 'Refund policy', 'woocommerce-payments' ),
description: __(
"A screenshot of your store's refund policy.",
'woocommerce-payments'
),
order: 30,
},
{
key: DOCUMENT_FIELD_KEYS.UNCATEGORIZED_FILE,
label: __( 'Other documents', 'woocommerce-payments' ),
description: __(
'Any other relevant documents that will support your case.',
'woocommerce-payments'
),
order: 100,
},
],
// Booking/Reservation product type
booking_reservation: [
{
Expand Down
Loading