Bug: [REFACTOR] payment link's flow



An expected high level payment link's lifecycle is mentioned below

- Create payment link
- Render payment link
- Confirm via payment widget
- If 3DS [always perform top redirection]
    - Redirect to external page
    - Once actions are performed, submit on page
    - External page redirects back to HS
    - HS redirects back to merchant's `return_url`
- If No3DS
    - Redirect to status page (current window)
    - Wait for 5 seconds
    - Redirect to merchant's `return_url` [always perform top redirection]

Current behavior is similar expect for the last step in No3DS - instead of redirecting to merchant's page in top, it performs a redirection in current window. This needs to be updated to perform a top redirection.
diff --git a/crates/router/src/core/payment_link/payment_link_status/status.js b/crates/router/src/core/payment_link/payment_link_status/status.js
index 371fdf1d2df..863c4239757 100644
--- a/crates/router/src/core/payment_link/payment_link_status/status.js
+++ b/crates/router/src/core/payment_link/payment_link_status/status.js
@@ -360,7 +360,7 @@ function renderStatusDetails(paymentDetails) {
             url.search = params.toString();
             setTimeout(function () {
               // Finally redirect
-              window.location.href = url.toString();
+              window.top.location.href = url.toString();
             }, 1000);
           }
         }, i * 1000);

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
This PR updates the behavior of final redirection to use top redirection when payment link's status page is present in the flow as well.

Explained in https://github.com/juspay/hyperswitch/issues/8639

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
Helps keep the behavior of payment links consistent.

## How did you test it?
<details>
    <summary>1. Create a default payment link</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_l9cbI5mKxdcSM5xnj2wiPTQGwO0lXCXDnHBeiCL9v9mbgQfYPdNcxSyEO8EHhaQN' \
        --data '{"payment_id":"25c03e52-2ed0-4ca9-9841-5554f1857d8b","authentication_type":"three_ds","customer_id":"cus_UWxTZBStM3s2FzdDGGun","profile_id":"pro_gSujWAfJukk8ammz6aft","customer_acceptance":{"acceptance_type":"online","accepted_at":"1963-05-03T04:07:52.723Z","online":{"ip_address":"127.0.0.1","user_agent":"amet irure esse"}},"setup_future_usage":"off_session","amount":1,"currency":"EUR","confirm":false,"payment_link":true,"session_expiry":2629800,"payment_link_config":{},"return_url":"https://www.example.com"}'

Response

    {"payment_id":"fdb4c32a-c9ff-4742-a3f4-0cdc03d04f52","merchant_id":"merchant_1752567879","status":"requires_payment_method","amount":1,"net_amount":1,"shipping_cost":null,"amount_capturable":0,"amount_received":null,"connector":null,"client_secret":"fdb4c32a-c9ff-4742-a3f4-0cdc03d04f52_secret_YM3fNu32vNuM3v8lrJzR","created":"2025-07-15T08:28:36.362Z","currency":"EUR","customer_id":"cus_UWxTZBStM3s2FzdDGGun","customer":{"id":"cus_UWxTZBStM3s2FzdDGGun","name":null,"email":null,"phone":null,"phone_country_code":null},"description":null,"refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":"off_session","off_session":null,"capture_on":null,"capture_method":null,"payment_method":null,"payment_method_data":null,"payment_token":null,"shipping":null,"billing":null,"order_details":null,"email":null,"name":null,"phone":null,"return_url":"https://www.example.com/","authentication_type":"three_ds","statement_descriptor_name":null,"statement_descriptor_suffix":null,"next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":null,"connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_UWxTZBStM3s2FzdDGGun","created_at":1752568116,"expires":1752571716,"secret":"epk_06cd3c6510724493aee541a72cb1a5c2"},"manual_retry_allowed":null,"connector_transaction_id":null,"frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":null,"reference_id":null,"payment_link":{"link":"http://localhost:8080/payment_link/merchant_1752567879/fdb4c32a-c9ff-4742-a3f4-0cdc03d04f52?locale=en","secure_link":null,"payment_link_id":"plink_NkEB0uKH4Tg5baxkU7NF"},"profile_id":"pro_gSujWAfJukk8ammz6aft","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":null,"incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-14T18:58:36.361Z","fingerprint":null,"browser_info":null,"payment_method_id":null,"payment_method_status":null,"updated":"2025-07-15T08:28:36.369Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":null,"force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null}

</details>

<details>
    <summary>2. Open payment link inside an and process using a non 3DS card</summary>

Iframe template

    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <style>
                html, body {
                    margin: 0;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    background-color: black;
                    height: 100vh;
                    width: 100vw;
                }
                iframe {
                    border-radius: 4px;
                    height: 90vh;
                    width: 90vw;
                    background-color: white;
                }

            </style>
        </head>
        <body>
            <iframe
                allow="payment"
                src="http://localhost:8080/payment_link/merchant_1752567879/12883fad-a7ce-4535-a327-7eccabb1258c?locale=en"
                frameborder="0"
                ></iframe>
        </body>
        <!-- <script src="https://6498-49-207-207-180.ngrok-free.app/HyperLoader.js" ></script> -->
    </html>

Test cards
https://docs.adyen.com/development-resources/testing/test-card-numbers/#visa

Behavior
- Redirection to status page happens inside an iframe
- Redirection to return_url happens in top

<img width="949" height="938" alt="Screenshot 2025-07-15 at 2 08 07 PM" src="https://github.com/user-attachments/assets/66846803-9dba-48e8-a843-a3ddcfdaac20" />
<img width="947" height="939" alt="Screenshot 2025-07-15 at 2 08 11 PM" src="https://github.com/user-attachments/assets/7c5435f0-ac8f-4b49-8a12-34c8032f2269" />


</details>

<details>
    <summary>3. Create a payment link skipping the status screen</summary>

cURL

    curl --location --request POST 'http://localhost:8080/payments' \
        --header 'Content-Type: application/json' \
        --header 'Accept: application/json' \
        --header 'api-key: dev_l9cbI5mKxdcSM5xnj2wiPTQGwO0lXCXDnHBeiCL9v9mbgQfYPdNcxSyEO8EHhaQN' \
        --data '{"payment_id":"d60872e7-104d-493d-a88b-1030ccde869d","authentication_type":"three_ds","customer_id":"cus_UWxTZBStM3s2FzdDGGun","profile_id":"pro_gSujWAfJukk8ammz6aft","customer_acceptance":{"acceptance_type":"online","accepted_at":"1963-05-03T04:07:52.723Z","online":{"ip_address":"127.0.0.1","user_agent":"amet irure esse"}},"setup_future_usage":"off_session","amount":1,"currency":"EUR","confirm":false,"payment_link":true,"session_expiry":2629800,"payment_link_config":{"skip_status_screen":true},"return_url":"https://www.example.com"}'

Response

    {"payment_id":"d69f0158-a3bc-44ac-80d7-931f60eb102e","merchant_id":"merchant_1752567879","status":"requires_payment_method","amount":1,"net_amount":1,"shipping_cost":null,"amount_capturable":0,"amount_received":null,"connector":null,"client_secret":"d69f0158-a3bc-44ac-80d7-931f60eb102e_secret_sj4ENrQbMcZM87VvlwSg","created":"2025-07-15T08:34:22.075Z","currency":"EUR","customer_id":"cus_UWxTZBStM3s2FzdDGGun","customer":{"id":"cus_UWxTZBStM3s2FzdDGGun","name":null,"email":null,"phone":null,"phone_country_code":null},"description":null,"refunds":null,"disputes":null,"mandate_id":null,"mandate_data":null,"setup_future_usage":"off_session","off_session":null,"capture_on":null,"capture_method":null,"payment_method":null,"payment_method_data":null,"payment_token":null,"shipping":null,"billing":null,"order_details":null,"email":null,"name":null,"phone":null,"return_url":"https://www.example.com/","authentication_type":"three_ds","statement_descriptor_name":null,"statement_descriptor_suffix":null,"next_action":null,"cancellation_reason":null,"error_code":null,"error_message":null,"unified_code":null,"unified_message":null,"payment_experience":null,"payment_method_type":null,"connector_label":null,"business_country":null,"business_label":"default","business_sub_label":null,"allowed_payment_method_types":null,"ephemeral_key":{"customer_id":"cus_UWxTZBStM3s2FzdDGGun","created_at":1752568462,"expires":1752572062,"secret":"epk_c474ec1928d4487799a10fdec281d647"},"manual_retry_allowed":null,"connector_transaction_id":null,"frm_message":null,"metadata":null,"connector_metadata":null,"feature_metadata":null,"reference_id":null,"payment_link":{"link":"http://localhost:8080/payment_link/merchant_1752567879/d69f0158-a3bc-44ac-80d7-931f60eb102e?locale=en","secure_link":null,"payment_link_id":"plink_AG81wLnXtkzSLv1D499u"},"profile_id":"pro_gSujWAfJukk8ammz6aft","surcharge_details":null,"attempt_count":1,"merchant_decision":null,"merchant_connector_id":null,"incremental_authorization_allowed":null,"authorization_count":null,"incremental_authorizations":null,"external_authentication_details":null,"external_3ds_authentication_attempted":false,"expires_on":"2025-08-14T19:04:22.073Z","fingerprint":null,"browser_info":null,"payment_method_id":null,"payment_method_status":null,"updated":"2025-07-15T08:34:22.081Z","split_payments":null,"frm_metadata":null,"extended_authorization_applied":null,"capture_before":null,"merchant_order_reference_id":null,"order_tax_amount":null,"connector_mandate_id":null,"card_discovery":null,"force_3ds_challenge":false,"force_3ds_challenge_trigger":false,"issuer_error_code":null,"issuer_error_message":null,"is_iframe_redirection_enabled":null,"whole_connector_response":null}

</details>

<details>
    <summary>4. Open payment link inside an and process using a non 3DS card</summary>

Iframe template

    <html lang="en">
        <head>
            <meta charset="UTF-8">
            <meta name="viewport" content="width=device-width, initial-scale=1.0">
            <title>Document</title>
            <style>
                html, body {
                    margin: 0;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    background-color: black;
                    height: 100vh;
                    width: 100vw;
                }
                iframe {
                    border-radius: 4px;
                    height: 90vh;
                    width: 90vw;
                    background-color: white;
                }

            </style>
        </head>
        <body>
            <iframe
                allow="payment"
                src="http://localhost:8080/payment_link/merchant_1752567879/12883fad-a7ce-4535-a327-7eccabb1258c?locale=en"
                frameborder="0"
                ></iframe>
        </body>
        <!-- <script src="https://6498-49-207-207-180.ngrok-free.app/HyperLoader.js" ></script> -->
    </html>

Test cards
https://docs.adyen.com/development-resources/testing/test-card-numbers/#visa

Behavior
- Status screen is skipped
- Redirection to return_url happens in top

<img width="946" height="936" alt="Screenshot 2025-07-15 at 2 04 05 PM" src="https://github.com/user-attachments/assets/16291a93-a167-4195-9e5c-93f709050578" />
<img width="949" height="943" alt="Screenshot 2025-07-15 at 2 04 16 PM" src="https://github.com/user-attachments/assets/1f50ee1f-ca71-41f6-9db7-806dbdb5cf8a" />


</details>

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
