Skip to content

Commit

Permalink
Update inquiry order notes to use inquiry specific content (#9828)
Browse files Browse the repository at this point in the history
Co-authored-by: Nagesh Pai <[email protected]>
Co-authored-by: Nagesh Pai <[email protected]>
  • Loading branch information
3 people authored Dec 2, 2024
1 parent 8091bae commit f500790
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 10 deletions.
4 changes: 4 additions & 0 deletions changelog/fix-9612-inquiry-order-note
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: fix

Order notes for inquiries have clearer content.
48 changes: 42 additions & 6 deletions includes/class-wc-payments-order-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -314,15 +314,17 @@ public function mark_order_blocked_for_fraud( $order, $intent_id, $intent_status
* @param string $amount The disputed amount – formatted currency value.
* @param string $reason The reason for the dispute – human-readable text.
* @param string $due_by The deadline for responding to the dispute - formatted date string.
* @param string $status The status of the dispute.
*
* @return void
*/
public function mark_payment_dispute_created( $order, $charge_id, $amount, $reason, $due_by ) {
public function mark_payment_dispute_created( $order, $charge_id, $amount, $reason, $due_by, $status = '' ) {
if ( ! is_a( $order, 'WC_Order' ) ) {
return;
}

$note = $this->generate_dispute_created_note( $charge_id, $amount, $reason, $due_by );
$is_inquiry = strpos( $status, 'warning_' ) === 0;
$note = $this->generate_dispute_created_note( $charge_id, $amount, $reason, $due_by, $is_inquiry );
if ( $this->order_note_exists( $order, $note ) ) {
return;
}
Expand All @@ -346,7 +348,8 @@ public function mark_payment_dispute_closed( $order, $charge_id, $status ) {
return;
}

$note = $this->generate_dispute_closed_note( $charge_id, $status );
$is_inquiry = strpos( $status, 'warning_' ) === 0;
$note = $this->generate_dispute_closed_note( $charge_id, $status, $is_inquiry );

if ( $this->order_note_exists( $order, $note ) ) {
return;
Expand Down Expand Up @@ -1643,15 +1646,32 @@ private function generate_fraud_blocked_note( $order ): string {
* @param string $amount The disputed amount – formatted currency value.
* @param string $reason The reason for the dispute – human-readable text.
* @param string $due_by The deadline for responding to the dispute - formatted date string.
* @param bool $is_inquiry Whether the dispute is an inquiry or not.
*
* @return string Note content.
*/
private function generate_dispute_created_note( $charge_id, $amount, $reason, $due_by ) {
private function generate_dispute_created_note( $charge_id, $amount, $reason, $due_by, $is_inquiry = false ) {
$dispute_url = $this->compose_dispute_url( $charge_id );

// Get merchant-friendly dispute reason description.
$reason = WC_Payments_Utils::get_dispute_reason_description( $reason );

if ( $is_inquiry ) {
return sprintf(
WC_Payments_Utils::esc_interpolated_html(
/* translators: %1: the disputed amount and currency; %2: the dispute reason; %3 the deadline date for responding to the inquiry */
__( 'A payment inquiry has been raised for %1$s with reason "%2$s". <a>Response due by %3$s</a>.', 'woocommerce-payments' ),
[
'a' => '<a href="%4$s" target="_blank" rel="noopener noreferrer">',
]
),
$amount,
$reason,
$due_by,
$dispute_url
);
}

return sprintf(
WC_Payments_Utils::esc_interpolated_html(
/* translators: %1: the disputed amount and currency; %2: the dispute reason; %3 the deadline date for responding to dispute */
Expand All @@ -1672,15 +1692,31 @@ private function generate_dispute_created_note( $charge_id, $amount, $reason, $d
*
* @param string $charge_id The ID of the disputed charge associated with this order.
* @param string $status The status of the dispute.
* @param bool $is_inquiry Whether the dispute is an inquiry or not.
*
* @return string Note content.
*/
private function generate_dispute_closed_note( $charge_id, $status ) {
private function generate_dispute_closed_note( $charge_id, $status, $is_inquiry = false ) {
$dispute_url = $this->compose_dispute_url( $charge_id );

if ( $is_inquiry ) {
return sprintf(
WC_Payments_Utils::esc_interpolated_html(
/* translators: %1: the dispute status */
__( 'Payment inquiry has been closed with status %1$s. See <a>payment status</a> for more details.', 'woocommerce-payments' ),
[
'a' => '<a href="%2$s" target="_blank" rel="noopener noreferrer">',
]
),
$status,
$dispute_url
);
}

return sprintf(
WC_Payments_Utils::esc_interpolated_html(
/* translators: %1: the dispute status */
__( 'Payment dispute has been closed with status %1$s. See <a>dispute overview</a> for more details.', 'woocommerce-payments' ),
__( 'Dispute has been closed with status %1$s. See <a>dispute overview</a> for more details.', 'woocommerce-payments' ),
[
'a' => '<a href="%2$s" target="_blank" rel="noopener noreferrer">',
]
Expand Down
3 changes: 2 additions & 1 deletion includes/class-wc-payments-webhook-processing-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ private function process_webhook_dispute_created( $event_body ) {
$reason = $this->read_webhook_property( $event_object, 'reason' );
$amount_raw = $this->read_webhook_property( $event_object, 'amount' );
$evidence = $this->read_webhook_property( $event_object, 'evidence_details' );
$status = $this->read_webhook_property( $event_object, 'status' );
$due_by = $this->read_webhook_property( $evidence, 'due_by' );

$order = $this->wcpay_db->order_from_charge_id( $charge_id );
Expand All @@ -558,7 +559,7 @@ private function process_webhook_dispute_created( $event_body ) {
);
}

$this->order_service->mark_payment_dispute_created( $order, $charge_id, $amount, $reason, $due_by );
$this->order_service->mark_payment_dispute_created( $order, $charge_id, $amount, $reason, $due_by, $status );

// Clear dispute caches to trigger a fetch of new data.
$this->database_cache->delete( DATABASE_CACHE::DISPUTE_STATUS_COUNTS_KEY );
Expand Down
71 changes: 69 additions & 2 deletions tests/unit/test-class-wc-payments-order-service.php
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,44 @@ public function test_mark_payment_dispute_created() {
$this->assertCount( 2, $notes_2 );
}


/**
* Tests if the payment was updated to show inquiry created.
*/
public function test_mark_payment_dispute_created_for_inquiry() {
// Arrange: Set the charge_id and reason, and the order status.
$charge_id = 'ch_123';
$amount = '$123.45';
$reason = 'product_not_received';
$deadline = 'June 7, 2023';
$order_status = Order_Status::ON_HOLD;
$dispute_status = 'warning_needs_response';

// Act: Attempt to mark payment dispute created.
$this->order_service->mark_payment_dispute_created( $this->order, $charge_id, $amount, $reason, $deadline, $dispute_status );

// Assert: Check that the order status was updated to on-hold status.
$this->assertTrue( $this->order->has_status( [ $order_status ] ) );

$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );

// Assert: Check that dispute order note was added with relevant info and link to dispute detail.
$this->assertStringNotContainsString( 'Payment has been disputed', $notes[0]->content );
$this->assertStringContainsString( 'inquiry', $notes[0]->content );
$this->assertStringContainsString( $amount, $notes[0]->content );
$this->assertStringContainsString( 'Product not received', $notes[0]->content );
$this->assertStringContainsString( $deadline, $notes[0]->content );
$this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">Response due by', $notes[0]->content );

// Assert: Check that order status change note was added.
$this->assertStringContainsString( 'Pending payment to On hold', $notes[1]->content );

// Assert: Applying the same data multiple times does not cause duplicate actions.
$this->order_service->mark_payment_dispute_created( $this->order, $charge_id, $amount, $reason, $deadline, $dispute_status );
$notes_2 = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertCount( 2, $notes_2 );
}

/**
* Tests to make sure mark_payment_dispute_created exits if the order is invalid.
*/
Expand Down Expand Up @@ -909,7 +947,7 @@ public function test_mark_payment_dispute_closed_with_status_won() {
// Assert: Check that the notes were updated.
$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertStringContainsString( 'Pending payment to Completed', $notes[1]->content );
$this->assertStringContainsString( 'Payment dispute has been closed with status won', $notes[0]->content );
$this->assertStringContainsString( 'Dispute has been closed with status won', $notes[0]->content );
$this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );

// Assert: Applying the same data multiple times does not cause duplicate actions.
Expand Down Expand Up @@ -937,7 +975,7 @@ public function test_mark_payment_dispute_closed_with_status_lost() {
// Assert: Check that the notes were updated.
$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertStringContainsString( 'On hold to Refunded', $notes[1]->content );
$this->assertStringContainsString( 'Payment dispute has been closed with status lost', $notes[0]->content );
$this->assertStringContainsString( 'Dispute has been closed with status lost', $notes[0]->content );
$this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">dispute overview', $notes[0]->content );

// Assert: Check for created refund, and the amount is correct.
Expand All @@ -951,6 +989,35 @@ public function test_mark_payment_dispute_closed_with_status_lost() {
$this->assertCount( 3, $notes_2 );
}


/**
* Tests if the order note was added to show inquiry closed.
*/
public function test_mark_payment_dispute_closed_with_status_warning_closed() {
// Arrange: Set the charge_id, dispute status, the order status, and update the order status.
$charge_id = 'ch_123';
$status = 'warning_closed';
$order_status = Order_Status::COMPLETED;
$this->order->update_status( Order_Status::ON_HOLD ); // When a dispute is created, the order status is changed to On Hold.

// Act: Attempt to mark payment dispute created.
$this->order_service->mark_payment_dispute_closed( $this->order, $charge_id, $status );

// Assert: Check that the order status was left in on-hold status.
$this->assertTrue( $this->order->has_status( [ $order_status ] ) );

// Assert: Check that the notes were updated.
$notes = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertStringNotContainsString( 'Dispute has been closed with status won', $notes[0]->content );
$this->assertStringContainsString( 'inquiry', $notes[0]->content );
$this->assertStringContainsString( '%2Fpayments%2Ftransactions%2Fdetails&id=ch_123" target="_blank" rel="noopener noreferrer">payment status', $notes[0]->content );

// Assert: Applying the same data multiple times does not cause duplicate actions.
$this->order_service->mark_payment_dispute_closed( $this->order, $charge_id, $status );
$notes_2 = wc_get_order_notes( [ 'order_id' => $this->order->get_id() ] );
$this->assertCount( 3, $notes_2 );
}

/**
* Tests to make sure mark_payment_dispute_closed exits if the order is invalid.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,7 @@ public function test_dispute_created_order_note() {
'charge' => 'test_charge_id',
'reason' => 'test_reason',
'amount' => 9900,
'status' => 'test_status',
'evidence_details' => [
'due_by' => 'test_due_by',
],
Expand Down Expand Up @@ -1289,7 +1290,7 @@ public function test_dispute_closed_order_note() {
->method( 'add_order_note' )
->with(
$this->matchesRegularExpression(
'/Payment dispute has been closed with status test_status/'
'/Dispute has been closed with status test_status/'
)
);

Expand Down

0 comments on commit f500790

Please sign in to comment.