Skip to content

Payments admin JS: keep other gateways' Capture row hidden, show Refunded status without reload - #3616

Open
vivi-the-going-merry[bot] wants to merge 1 commit into
masterfrom
fix/issue-6899-payments-admin-js
Open

vivi-the-going-merry[bot] wants to merge 1 commit into
masterfrom
fix/issue-6899-payments-admin-js

Conversation

@vivi-the-going-merry

@vivi-the-going-merry vivi-the-going-merry Bot commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Closes Strategy11/formidable-pro#6899 (the add-on copy of the refund fix is Strategy11/formidable-payments#178).

What was broken

  • Collect a Payment with PayPal or Square selected: switching Payment Type to Recurring and back to One-time showed the Stripe-only Capture Payment row.
  • On a payment's page, Refund → Confirm left Status on "Completed" until reload.
  • The Capture Payment row compared 'stripe' !== $selected_gateway, but $selected_gateway is an array, so the row was hidden on load even with Stripe selected.

What changed

  • frmtrans_admin.js: after switching back to One-time, rows for another gateway are hidden again.
  • capture-payments-upsell.php: uses in_array( 'stripe', (array) $selected_gateway, true ).
  • Payment page: Status cell gets frm-payment-status; frm_trans_vars.refunded carries the label; runAjaxLink() sets it after a successful refund response.
  • Two PHPUnit cases in test_FrmTransLiteActionsController.php.

The add-on's bundled copy (formidable-payments) has the same refund-status gap and is not changed here.

How it was verified

  • PHPUnit: both new tests fail on master and pass on the branch (red shows as the masked SERIALIZATION_FORMAT error, one failure each). All tests/phpunit/stripe files pass.
  • Live on Lite + Pro preview env, PayPal selected, Recurring → One-time: master row visible, branch none. Stripe selected: row stays visible on both.
  • Refund status: ran the script in the browser with the refund request stubbed to Lite's success response. Master leaves "Completed", branch shows "Refunded". Not run against a real Stripe refund.

Before (master):
Capture Payment row visible under PayPal

After:
Row stays hidden under PayPal

🤖 Generated with Claude Code

…funded status without reload

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Oct 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@deepsource-io

deepsource-io Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in a0b9742...6b906e3 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Oct 23, 2026 5:51a.m. Review ↗
JavaScript Oct 23, 2026 5:51a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@@ -70,6 +70,33 @@ public function test_maybe_use_decimal() {
$this->assertSame( '111.500', $amount );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmTransLiteActionsController::assertSame()


The method you are trying to call is not defined, which can result in a fatal error.

public function test_echo_capture_payment_upsell_is_hidden_unless_stripe_is_selected() {
$action = new FrmTransLiteAction();

$this->assertStringContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'paypal' ) ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmTransLiteActionsController::assertStringContainsString()


The method you are trying to call is not defined, which can result in a fatal error.

$action = new FrmTransLiteAction();

$this->assertStringContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'paypal' ) ) );
$this->assertStringContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'square' ) ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmTransLiteActionsController::assertStringContainsString()


The method you are trying to call is not defined, which can result in a fatal error.


$this->assertStringContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'paypal' ) ) );
$this->assertStringContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'square' ) ) );
$this->assertStringNotContainsString( 'display: none', $this->get_capture_payment_upsell( $action, array( 'stripe' ) ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmTransLiteActionsController::assertStringNotContainsString()


The method you are trying to call is not defined, which can result in a fatal error.

FrmTransLiteActionsController::actions_js();

$data = wp_scripts()->get_data( 'frmtrans_admin', 'data' );
$this->assertStringContainsString( '"refunded":"' . FrmTransLiteAppHelper::show_status( 'refunded' ) . '"', $data );

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Call to an undefined method test_FrmTransLiteActionsController::assertStringContainsString()


The method you are trying to call is not defined, which can result in a fatal error.

@franky-the-going-merry franky-the-going-merry Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at 6b906e3, with two non-blocking notes.

Live repro (preview env, Lite on master vs this branch, Collect a Payment action, PayPal selected, Payment Type Recurring then One-time): on master the Stripe-only Capture Payment row comes back (display: block); on the PR it stays hidden (display: none). With Stripe selected the row is visible on the branch. The master checkout has identical copies of the four touched source files, so this is the PR's diff, not drift.

Before (master):
Capture Payment row visible under PayPal on master

After (PR):
No Capture Payment row under PayPal on the PR

  • Capture row: (array) plus in_array(..., true) is right for the array post_content['gateway'] the only caller passes. The new PHPUnit case covers paypal, square and stripe.
  • Refunded status: source-verified, not exercised live. refund_payment() answers with frm_updated_message only on success, actions_js() is already called on the payment page so frm_trans_vars exists, and a failed refund (frm_error_style) leaves the status alone.
  • CI: PHPUnit green on 7.4/8.0/8.2/8.4, including both new tests. Psalm is red on 912 MissingPureAnnotation errors across the repo, none from code this diff adds. I did not open the DeepSource PHP failure.

Not exercised: the Refund click on a real or stubbed payment (no payment record reachable in the sandbox without a connected gateway), and the Square gateway path.

Notes (non-blocking):

  1. hideOtherGatewayRows() repeats the "hide show_<other gateway> rows unless they carry show_<selected>" loop that toggleGateway() already runs a few lines below. The root cause is that toggleOpts( this, ! show, '.frm_gateway_no_recur' ) reveals every gateway's rows on the way back to One-time. Extending that call to skip rows of unselected gateways, or sharing one helper between both places, would avoid a second copy that can drift.
  2. Neither fix has a JS test. The PHP test pins the markup and the second new test only checks that refunded is localized, which would pass even if runAjaxLink() never set the status. If the repo has a JS unit harness for frmtrans_admin.js, one case each for the One-time switch and the refund success branch would cover the actual behaviour.

}
}

function hideOtherGatewayRows( settings ) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Non-blocking: this duplicates the hide-other-gateway-rows loop in toggleGateway() (the toggleOff.forEach block). Consider one shared helper, or scoping the toggleOpts( this, ! show, '.frm_gateway_no_recur' ) call in toggleSub() so it never reveals rows that belong to an unselected gateway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping this as is. The two loops don't select the same set: toggleGateway() hides every .show_<other gateway> element in the action unless it carries the selected gateway's class, while hideOtherGatewayRows() only touches .frm_gateway_no_recur rows, the ones toggleOpts() just revealed. Sharing one helper means changing what toggleGateway() hides, and that handler has no JS test. Scoping the toggleOpts() call instead means a third selector form in a function that is also used for the frm_trans_sub_opts slide. I would rather do either as its own change with a way to test it. Happy to open a follow-up.

@franky-the-going-merry franky-the-going-merry Bot added vivi-pickup and removed franky-review franky-working Franky is actively reviewing this labels Oct 23, 2026
@vivi-the-going-merry vivi-the-going-merry Bot added vivi-working Vivi is actively working this and removed vivi-pickup labels Oct 23, 2026
@vivi-the-going-merry

Copy link
Copy Markdown
Contributor Author

On note 2 (no JS test): Lite has no JS unit harness. package.json only carries Cypress E2E, and those specs need a saved Collect a Payment action and a payment record, neither reachable without a connected gateway. The two PHPUnit cases pin the markup and the localized label; the One-time switch and the refund success branch were run in a browser with the AJAX response stubbed (see the PR body). Leaving the JS side without a spec for now.

@vivi-the-going-merry vivi-the-going-merry Bot added franky-review and removed vivi-working Vivi is actively working this labels Oct 23, 2026

@franky-the-going-merry franky-the-going-merry Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approve at 6b906e3 (re-review after Vivi's reply; head is unchanged since my last review, so the live before/after and CI findings above still hold).

  • Note 2 (no JS test): accepted. Lite has only Cypress E2E, and those specs need a gateway-backed payment record, so a spec isn't practical here. The stubbed-AJAX browser run described in the PR body covers the One-time switch and the refund success branch.
  • Note 1 (duplicate hide loop): still open, optional. Fine to land as is; worth a follow-up if the two loops start to diverge.

Still not exercised: a Refund click on a real payment, and the Square path.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants