- - -

## 2024.11.07.0

### Features

- **analytics:** Implement currency conversion to power multi-currency aggregation ([#6418](https://github.com/juspay/hyperswitch/pull/6418)) ([`01c5216`](https://github.com/juspay/hyperswitch/commit/01c5216fdd6f1d841082868cccea6054b64e9e07))

### Bug Fixes

- **core:** PMD Not Getting Populated for Saved Card Transactions ([#6497](https://github.com/juspay/hyperswitch/pull/6497)) ([`b8b2060`](https://github.com/juspay/hyperswitch/commit/b8b206057c5b464420a6d115a1116ef5cc695bf7))

**Full Changelog:** [`2024.11.06.0...2024.11.07.0`](https://github.com/juspay/hyperswitch/compare/2024.11.06.0...2024.11.07.0)

- - -

## 2024.11.06.0

### Features

- **config:** Update vector config ([#6365](https://github.com/juspay/hyperswitch/pull/6365)) ([`2919db8`](https://github.com/juspay/hyperswitch/commit/2919db874bd84372663228f2531ba18338e039c0))
- **connector:**
  - [ELAVON] Template PR ([#6309](https://github.com/juspay/hyperswitch/pull/6309)) ([`b481e5c`](https://github.com/juspay/hyperswitch/commit/b481e5cb8ffe417591a2fb917f37ba72667f2fcd))
  - [Paypal] implement vaulting for paypal wallet and cards while purchasing ([#5323](https://github.com/juspay/hyperswitch/pull/5323)) ([`22ba2db`](https://github.com/juspay/hyperswitch/commit/22ba2dbb2870471315d688147b3b53c432ce15dc))
  - [JP MORGAN] Added Template code for cards integration ([#6467](https://github.com/juspay/hyperswitch/pull/6467)) ([`b048e39`](https://github.com/juspay/hyperswitch/commit/b048e39b5c4213752da7765834915cca6bf776f6))
- **db:** Implement `MerchantAccountInteraface` for `Mockdb` ([#6283](https://github.com/juspay/hyperswitch/pull/6283)) ([`5f493a5`](https://github.com/juspay/hyperswitch/commit/5f493a5166aa0a0a29f9aed538cad03def657c22))
- **nix:** Add support for running external services through services-flake ([#6377](https://github.com/juspay/hyperswitch/pull/6377)) ([`95f2e0b`](https://github.com/juspay/hyperswitch/commit/95f2e0b8c51bfe116241fc486069e10e578a5ff8))
- **users:** Add `force_two_factor_auth` environment variable ([#6466](https://github.com/juspay/hyperswitch/pull/6466)) ([`6b66ccc`](https://github.com/juspay/hyperswitch/commit/6b66cccd02c2589bb2dad38b46f4da7e1455ca0b))

### Bug Fixes

- **connector:**
  - Expiration Year Incorrectly Populated as YYYY Format in Paybox Mandates ([#6474](https://github.com/juspay/hyperswitch/pull/6474)) ([`e457ccd`](https://github.com/juspay/hyperswitch/commit/e457ccd91e60d5168e0a3283dfa325097f455076))
  - [Cybersource] remove newline in billing address with space ([#6478](https://github.com/juspay/hyperswitch/pull/6478)) ([`7f1d345`](https://github.com/juspay/hyperswitch/commit/7f1d34571f72f63b8bb52aff995ad093e3b6d856))
- **refunds:** Remove to schema from refund aggregate response and exclude it from open api documentation ([#6405](https://github.com/juspay/hyperswitch/pull/6405)) ([`449c9cf`](https://github.com/juspay/hyperswitch/commit/449c9cfe557b3540e4ad25e48e012b531eb232fd))
- Replace deprecated backticks with $(...) for command substitution ([#6337](https://github.com/juspay/hyperswitch/pull/6337)) ([`1c92f58`](https://github.com/juspay/hyperswitch/commit/1c92f5843009db42778f94bc9fd915b411a93f76))
- Lazy connection pools for dynamic routing service ([#6437](https://github.com/juspay/hyperswitch/pull/6437)) ([`71d9933`](https://github.com/juspay/hyperswitch/commit/71d99332204ddfbb3cf305c7d3bc8840d508bf47))

**Full Changelog:** [`2024.11.05.0...2024.11.06.0`](https://github.com/juspay/hyperswitch/compare/2024.11.05.0...2024.11.06.0)

- - -

## 2024.11.05.0

### Features

- Add macro to generate ToEncryptable trait ([#6313](https://github.com/juspay/hyperswitch/pull/6313)) ([`19cf0f7`](https://github.com/juspay/hyperswitch/commit/19cf0f7437a8d16ee4da254d2a3e2659879be68c))

### Bug Fixes

- **analytics:** Add dynamic limit by clause in failure reasons metric query ([#6462](https://github.com/juspay/hyperswitch/pull/6462)) ([`8825378`](https://github.com/juspay/hyperswitch/commit/88253780d708bc1c005a87c186c4b0b14325c8a0))

### Refactors

- **connector:** [AIRWALLEX, MULTISAFEPAY, RAZORPAY, SHIFT4, WORLDPAY, ZSL] Move connectors from `router` to `hyperswitch_connectors` crate ([#6369](https://github.com/juspay/hyperswitch/pull/6369)) ([`72ee434`](https://github.com/juspay/hyperswitch/commit/72ee434003eef744d516343a2f803264f226d92a))

**Full Changelog:** [`2024.11.04.0...2024.11.05.0`](https://github.com/juspay/hyperswitch/compare/2024.11.04.0...2024.11.05.0)

- - -

## 2024.11.04.0

### Features

- **analytics:** Add `customer_id` as filter for payment intents ([#6344](https://github.com/juspay/hyperswitch/pull/6344)) ([`d697def`](https://github.com/juspay/hyperswitch/commit/d697def0b7cad3743db9fd70d09a45921dcbea61))
- **authz:** Make info APIs support `ParentGroup` ([#6440](https://github.com/juspay/hyperswitch/pull/6440)) ([`7dcffcc`](https://github.com/juspay/hyperswitch/commit/7dcffccf3f16de5e40f61a302beb318035c3e88b))
- **connector:** [Paybox] Add mandates Flow for Paybox ([#6378](https://github.com/juspay/hyperswitch/pull/6378)) ([`37513e0`](https://github.com/juspay/hyperswitch/commit/37513e0f1e78f99da0accf0fee263c10ca4e03c6))
- **cypress-test:** Include worldpay's request / response structure for test suite ([#6420](https://github.com/juspay/hyperswitch/pull/6420)) ([`8372389`](https://github.com/juspay/hyperswitch/commit/8372389671c4aefeb625365d198390df5d8f35a5))
- **router:** Add payments get-intent API for v2 ([#6396](https://github.com/juspay/hyperswitch/pull/6396)) ([`c514608`](https://github.com/juspay/hyperswitch/commit/c514608594ebbe9894de47747b0d9fb573ab2503))

### Refactors

- **connector:** Add amount conversion framework to rapyd ([#6414](https://github.com/juspay/hyperswitch/pull/6414)) ([`33bc83f`](https://github.com/juspay/hyperswitch/commit/33bc83fce47c579457f1b9be0a91bb4fa13585ff))
- **connnector:** Structure connector enums in separate files for improved team ownership ([#6459](https://github.com/juspay/hyperswitch/pull/6459)) ([`bb246e2`](https://github.com/juspay/hyperswitch/commit/bb246e27b72e9e4168c89b94e8d07d63a544b586))

### Documentation

- **README:** Updated the icon and repositioned the hero image ([#6445](https://github.com/juspay/hyperswitch/pull/6445)) ([`35bf5a9`](https://github.com/juspay/hyperswitch/commit/35bf5a91d9a5b2d5e476c995e679b445242218e0))

### Miscellaneous Tasks

- **users:** Change entity_type column of roles to non-optional ([#6435](https://github.com/juspay/hyperswitch/pull/6435)) ([`62067e4`](https://github.com/juspay/hyperswitch/commit/62067e406a01d3a17ef94a04b0ef0304ebd05a70))

**Full Changelog:** [`2024.10.30.0...2024.11.04.0`](https://github.com/juspay/hyperswitch/compare/2024.10.30.0...2024.11.04.0)

- - -

## 2024.10.30.0

### Refactors

- **connector:** Add amount conversion framework to payu ([#6199](https://github.com/juspay/hyperswitch/pull/6199)) ([`11ce389`](https://github.com/juspay/hyperswitch/commit/11ce389000bf53c7f740d069f7ad2262bf5b70d6))

### Documentation

- Added desc. for wallets other than AP, GP ([#6452](https://github.com/juspay/hyperswitch/pull/6452)) ([`55a81eb`](https://github.com/juspay/hyperswitch/commit/55a81eb4692979036d0bfd43e445d3e1db6601e7))

**Full Changelog:** [`2024.10.29.0...2024.10.30.0`](https://github.com/juspay/hyperswitch/compare/2024.10.29.0...2024.10.30.0)

- - -

## 2024.10.29.0

### Bug Fixes

- **multitenancy:** Consistently use tenant nomenclature everywhere ([#6389](https://github.com/juspay/hyperswitch/pull/6389)) ([`aecd5ee`](https://github.com/juspay/hyperswitch/commit/aecd5eea3d2dce3ccdd4784f60d076b641104b67))

**Full Changelog:** [`2024.10.28.2...2024.10.29.0`](https://github.com/juspay/hyperswitch/compare/2024.10.28.2...2024.10.29.0)

- - -

## 2024.10.28.2

### Bug Fixes

- **connector:**
  - [Novalnet] Remove webhook placeholder connector config ([#6451](https://github.com/juspay/hyperswitch/pull/6451)) ([`e33340e`](https://github.com/juspay/hyperswitch/commit/e33340e70b59e9e4f18e92fc27d8c90b3df5768b))
  - [Adyen] Add MYR currency config ([#6442](https://github.com/juspay/hyperswitch/pull/6442)) ([`925e424`](https://github.com/juspay/hyperswitch/commit/925e4240e4ad6da1d243769b184842c0d8251a7d))

**Full Changelog:** [`2024.10.28.1...2024.10.28.2`](https://github.com/juspay/hyperswitch/compare/2024.10.28.1...2024.10.28.2)

- - -

## 2024.10.28.1

### Bug Fixes

- **core:** Fix setup mandate payments to store connector mandate details ([#6446](https://github.com/juspay/hyperswitch/pull/6446)) ([`cee84cd`](https://github.com/juspay/hyperswitch/commit/cee84cdcfd6c323e8db80163f462d8e286aae600))

**Full Changelog:** [`2024.10.28.0...2024.10.28.1`](https://github.com/juspay/hyperswitch/compare/2024.10.28.0...2024.10.28.1)

- - -

## 2024.10.28.0

### Features

- **connector:**
  - [Rapyd] Use connector_response_reference_id ([#6302](https://github.com/juspay/hyperswitch/pull/6302)) ([`a845d46`](https://github.com/juspay/hyperswitch/commit/a845d46899d87ba7f3ca4386719c1934ce3da90e))
  - [Rapyd] Use connector_request_reference_id ([#6296](https://github.com/juspay/hyperswitch/pull/6296)) ([`4105d98`](https://github.com/juspay/hyperswitch/commit/4105d98d7aca885f9c622d5b56c6dbacb85a688b))
  - [Novalnet] Integrate Applepay wallet token flow ([#6409](https://github.com/juspay/hyperswitch/pull/6409)) ([`1d24b04`](https://github.com/juspay/hyperswitch/commit/1d24b04596e6d2f7c44b93501d56fc4fb950bd3b))
  - [PayU] Use connector_request_reference_id ([#6360](https://github.com/juspay/hyperswitch/pull/6360)) ([`acd1530`](https://github.com/juspay/hyperswitch/commit/acd153042062dd14d5e6e266fdc73d82b78213fe))
  - [Fiuu] Add support for cards recurring payments ([#6361](https://github.com/juspay/hyperswitch/pull/6361)) ([`4647a2f`](https://github.com/juspay/hyperswitch/commit/4647a2f6aece6b9479395fa3622b51b50d3091ee))
- **euclid:** Add dynamic routing in core flows ([#6333](https://github.com/juspay/hyperswitch/pull/6333)) ([`ce732db`](https://github.com/juspay/hyperswitch/commit/ce732db9b2f98924a2b1d44ea5eb1000b6cbb498))
- **router:** Move organization_id to request header from request body for v2 ([#6277](https://github.com/juspay/hyperswitch/pull/6277)) ([`aaac9aa`](https://github.com/juspay/hyperswitch/commit/aaac9aa97d1b00d50bec4e02efb0658956463398))
- **sample_data:** Generate random disputes for sample data ([#6341](https://github.com/juspay/hyperswitch/pull/6341)) ([`e36ea18`](https://github.com/juspay/hyperswitch/commit/e36ea184ae6d1363fb1af55c790162df9f8b451c))
- Add amount, currency and email to paze session response ([#6412](https://github.com/juspay/hyperswitch/pull/6412)) ([`a3ea62f`](https://github.com/juspay/hyperswitch/commit/a3ea62f88524a360b666cacfbc1cf239f6be8797))

### Bug Fixes

- **analytics:** Fix refund status filter on dashboard ([#6431](https://github.com/juspay/hyperswitch/pull/6431)) ([`d58f706`](https://github.com/juspay/hyperswitch/commit/d58f706dc3fdd5ea277eeef6de9c224fe6097b46))
- **router:** Update request body for migrate-batch api ([#6429](https://github.com/juspay/hyperswitch/pull/6429)) ([`5307579`](https://github.com/juspay/hyperswitch/commit/53075792b372a7ca574b94058c7d72033c014bc8))

### Refactors

- **connector:**
  - Add amount conversion framework to tsys ([#6282](https://github.com/juspay/hyperswitch/pull/6282)) ([`90765be`](https://github.com/juspay/hyperswitch/commit/90765bece1b12b208192e7ae4d54f4c70a301cea))
  - [Paypal] Add support for passing shipping_cost in Payment request ([#6423](https://github.com/juspay/hyperswitch/pull/6423)) ([`b0d5c96`](https://github.com/juspay/hyperswitch/commit/b0d5c96b9918549663125681259a598698ec705c))
  - Added amount conversion framework for klarna and change type of amount to MinorUnit for OrderDetailsWithAmount ([#4979](https://github.com/juspay/hyperswitch/pull/4979)) ([`2807622`](https://github.com/juspay/hyperswitch/commit/2807622ba671f77892a0fde42febbcffcb6c2238))

**Full Changelog:** [`2024.10.25.0...2024.10.28.0`](https://github.com/juspay/hyperswitch/compare/2024.10.25.0...2024.10.28.0)

- - -

## 2024.10.25.0

### Features

- **authz:** Create a permission generator ([#6394](https://github.com/juspay/hyperswitch/pull/6394)) ([`4a0afb8`](https://github.com/juspay/hyperswitch/commit/4a0afb8213cce47cabe9e3f5d22ad1dccb02c20f))
- **connector:**
  - [Airwallex] Use connector_response_reference_id as reference to merchant ([#2747](https://github.com/juspay/hyperswitch/pull/2747)) ([`4b569c9`](https://github.com/juspay/hyperswitch/commit/4b569c9d5eb9b6403175c958b887d7ace4d9cbbb))
  - [Novalnet] Integrate wallets Paypal and Googlepay ([#6370](https://github.com/juspay/hyperswitch/pull/6370)) ([`673b869`](https://github.com/juspay/hyperswitch/commit/673b8691e092e145ba211050db4f5c7e021a0ce2))
- **payments_v2:** Add payment_confirm_intent api endpoint ([#6263](https://github.com/juspay/hyperswitch/pull/6263)) ([`c7c1e1a`](https://github.com/juspay/hyperswitch/commit/c7c1e1adabceeb0a03659bf8feb9aa06d85960ea))

### Bug Fixes

- **core:** Populate billing_address for payment with pm_id ([#6411](https://github.com/juspay/hyperswitch/pull/6411)) ([`8e58b56`](https://github.com/juspay/hyperswitch/commit/8e58b56b43ad2f823c51943c34aa8837297c70d6))
- **payment_methods:** Fix merchant payment method list to retain a mca based on connector_name and mca_id ([#6408](https://github.com/juspay/hyperswitch/pull/6408)) ([`842c4a2`](https://github.com/juspay/hyperswitch/commit/842c4a2f47d4cc7b850a16abbe5431fe575f7a86))
- **payments:** Filter total count by card-network value ([#6397](https://github.com/juspay/hyperswitch/pull/6397)) ([`ca325e9`](https://github.com/juspay/hyperswitch/commit/ca325e969b24fbbb5aa7edcdf86d5b3022291db1))

### Refactors

- **connector:**
  - Add amount conversion framework to Shift4 ([#6250](https://github.com/juspay/hyperswitch/pull/6250)) ([`fbe3951`](https://github.com/juspay/hyperswitch/commit/fbe395198aea7252e9c4e3fad97956a548d07002))
  - Add amount conversion framework to Wellsfargo ([#6298](https://github.com/juspay/hyperswitch/pull/6298)) ([`c3b0f7c`](https://github.com/juspay/hyperswitch/commit/c3b0f7c1d6ad95034535048aa50ff6abe9ed6aa0))

### Documentation

- **cypress:** Refactor cypress documentation for more clarity ([#6415](https://github.com/juspay/hyperswitch/pull/6415)) ([`26e0c32`](https://github.com/juspay/hyperswitch/commit/26e0c32f4da5689a1c01fbb456ac008a0b831710))
- **openapi:** Improve `rust_locker_open_api_spec` ([#6322](https://github.com/juspay/hyperswitch/pull/6322)) ([`a31d164`](https://github.com/juspay/hyperswitch/commit/a31d1641fb9e1c9efd652c6f191f6b29c75dc69b))

### Miscellaneous Tasks

- Add samsung pay payment method support for cybersource ([#6424](https://github.com/juspay/hyperswitch/pull/6424)) ([`ecaf700`](https://github.com/juspay/hyperswitch/commit/ecaf70099671950287e9a6b7d30ffd02c0c5f51e))
- Address Rust 1.82.0 clippy lints ([#6401](https://github.com/juspay/hyperswitch/pull/6401)) ([`8708a5c`](https://github.com/juspay/hyperswitch/commit/8708a5cb8f7d64a382b2fe061c725d4854ba9e92))

**Full Changelog:** [`2024.10.24.0...2024.10.25.0`](https://github.com/juspay/hyperswitch/compare/2024.10.24.0...2024.10.25.0)

- - -

## 2024.10.24.0

### Features

- **analytics:** Remove additional filters from PaymentIntentFilters ([#6403](https://github.com/juspay/hyperswitch/pull/6403)) ([`4ef48c3`](https://github.com/juspay/hyperswitch/commit/4ef48c39b3ed7c1fcda9c850da766a0bdb701335))
- **router:** Add api_models and openapi changes for refunds create api v2 ([#6385](https://github.com/juspay/hyperswitch/pull/6385)) ([`5a10e58`](https://github.com/juspay/hyperswitch/commit/5a10e5867a0f3097a40c8a6868454ff06630ed2c))

### Bug Fixes

- **connector_config:** Include the `payment_processing_details_at` `Hyperswitch` option only if apple pay token decryption flow is supported for the connector ([#6386](https://github.com/juspay/hyperswitch/pull/6386)) ([`af0aeee`](https://github.com/juspay/hyperswitch/commit/af0aeeea53014d8fe5c955cbad3fe8b371c44889))
- **deployment-config:** Remove invalid currencies from worldpay filters ([#6400](https://github.com/juspay/hyperswitch/pull/6400)) ([`aee11c5`](https://github.com/juspay/hyperswitch/commit/aee11c560e427195a0d321dff19c0d33ec60ba64))

### Refactors

- **connector:** Move connectors Forte, Nexinets, Payeezy, Payu and Zen from Router to Hyperswitch Connector Trait ([#6261](https://github.com/juspay/hyperswitch/pull/6261)) ([`829a20c`](https://github.com/juspay/hyperswitch/commit/829a20cc933267551e49565d06eb08e03e5f13bb))

**Full Changelog:** [`2024.10.23.0...2024.10.24.0`](https://github.com/juspay/hyperswitch/compare/2024.10.23.0...2024.10.24.0)

- - -

## 2024.10.23.0

### Features

- **cypress:** Execute cypress tests in parallel ([#6225](https://github.com/juspay/hyperswitch/pull/6225)) ([`f247978`](https://github.com/juspay/hyperswitch/commit/f24797834553794f341bd4f3be3afe5fcba693ed))

### Refactors

- **connector:** [WorldPay] propagate refusal codes as error code and messages ([#6392](https://github.com/juspay/hyperswitch/pull/6392)) ([`3d1a3cd`](https://github.com/juspay/hyperswitch/commit/3d1a3cdc8f942a3dca2e6a200bf9200366bd62f1))
- **permissions:** Remove permissions field from permission info API response ([#6376](https://github.com/juspay/hyperswitch/pull/6376)) ([`e5710fa`](https://github.com/juspay/hyperswitch/commit/e5710fa084ed5b0a4969a63b14a7f8e3433a3c64))

**Full Changelog:** [`2024.10.22.0...2024.10.23.0`](https://github.com/juspay/hyperswitch/compare/2024.10.22.0...2024.10.23.0)

- - -

## 2024.10.22.0

### Features

- **connector:** Add 3DS flow for Worldpay ([#6374](https://github.com/juspay/hyperswitch/pull/6374)) ([`b93c849`](https://github.com/juspay/hyperswitch/commit/b93c849623c46ad00fe8dfe5bed85a43c700b3c8))

### Bug Fixes


pub struct OrgAuthenticationMethodUpdateInternal {
    pub private_config: Option<Encryption>,
    pub public_config: Option<serde_json::Value>,
    pub last_modified_at: PrimitiveDateTime,
    pub email_domain: Option<String>,
}


File: crates/router/src/routes/authentication.rs
 Public functions: 5

use actix_web::{web, HttpRequest, Responder};
use api_models::authentication::{AuthenticationAuthenticateRequest, AuthenticationCreateRequest};
#[cfg(feature = "v1")]
use api_models::authentication::{
    AuthenticationEligibilityRequest, AuthenticationSyncPostUpdateRequest,
    AuthenticationSyncRequest,
};
use router_env::{instrument, tracing, Flow};

use crate::{
    core::{api_locking, unified_authentication_service},
    routes::app::{self},
    services::{api, authentication as auth},
    types::domain,
};

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::AuthenticationCreate))]
pub async fn authentication_create(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    json_payload: web::Json<AuthenticationCreateRequest>,
) -> impl Responder {
    let flow = Flow::AuthenticationCreate;

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        json_payload.into_inner(),
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            unified_authentication_service::authentication_create_core(state, merchant_context, req)
        },
        &auth::HeaderAuth(auth::ApiKeyAuth {
            is_connected_allowed: false,
            is_platform_allowed: false,
        }),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::AuthenticationEligibility))]
pub async fn authentication_eligibility(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    json_payload: web::Json<AuthenticationEligibilityRequest>,
    path: web::Path<common_utils::id_type::AuthenticationId>,
) -> impl Responder {
    let flow = Flow::AuthenticationEligibility;

    let api_auth = auth::ApiKeyAuth::default();
    let payload = json_payload.into_inner();

    let (auth, _) = match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth)
    {
        Ok((auth, _auth_flow)) => (auth, _auth_flow),
        Err(e) => return api::log_and_return_error_response(e),
    };

    let authentication_id = path.into_inner();
    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            unified_authentication_service::authentication_eligibility_core(
                state,
                merchant_context,
                req,
                authentication_id.clone(),
            )
        },
        &*auth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::AuthenticationAuthenticate))]
pub async fn authentication_authenticate(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    json_payload: web::Json<AuthenticationAuthenticateRequest>,
    path: web::Path<common_utils::id_type::AuthenticationId>,
) -> impl Responder {
    let flow = Flow::AuthenticationAuthenticate;
    let authentication_id = path.into_inner();
    let api_auth = auth::ApiKeyAuth::default();
    let payload = AuthenticationAuthenticateRequest {
        authentication_id,
        ..json_payload.into_inner()
    };

    let (auth, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok((auth, auth_flow)) => (auth, auth_flow),
            Err(e) => return api::log_and_return_error_response(e),
        };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            unified_authentication_service::authentication_authenticate_core(
                state,
                merchant_context,
                req,
                auth_flow,
            )
        },
        &*auth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::AuthenticationSync))]
pub async fn authentication_sync(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::AuthenticationId,
    )>,
    json_payload: web::Query<AuthenticationSyncRequest>,
) -> impl Responder {
    let flow = Flow::AuthenticationSync;
    let api_auth = auth::ApiKeyAuth::default();
    let (_merchant_id, authentication_id) = path.into_inner();
    let payload = AuthenticationSyncRequest {
        authentication_id,
        ..json_payload.into_inner()
    };
    let (auth, auth_flow) =
        match auth::check_client_secret_and_get_auth(req.headers(), &payload, api_auth) {
            Ok((auth, auth_flow)) => (auth, auth_flow),
            Err(e) => return api::log_and_return_error_response(e),
        };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            unified_authentication_service::authentication_sync_core(
                state,
                merchant_context,
                auth_flow,
                req,
            )
        },
        &*auth,
        api_locking::LockAction::NotApplicable,
    ))
    .await
}

#[cfg(feature = "v1")]
#[instrument(skip_all, fields(flow = ?Flow::AuthenticationSyncPostUpdate))]
pub async fn authentication_sync_post_update(
    state: web::Data<app::AppState>,
    req: HttpRequest,
    path: web::Path<(
        common_utils::id_type::MerchantId,
        common_utils::id_type::AuthenticationId,
    )>,
) -> impl Responder {
    let flow = Flow::AuthenticationSyncPostUpdate;
    let (merchant_id, authentication_id) = path.into_inner();
    let payload = AuthenticationSyncPostUpdateRequest { authentication_id };

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, auth: auth::AuthenticationData, req, _| {
            let merchant_context = domain::MerchantContext::NormalMerchant(Box::new(
                domain::Context(auth.merchant_account, auth.key_store),
            ));
            unified_authentication_service::authentication_post_sync_core(
                state,
                merchant_context,
                req,
            )
        },
        &auth::MerchantIdAuth(merchant_id),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl api::RefundSync for Authorizedotnet {}

impl api::RefundSync for for Authorizedotnet


pub async fn get_vault_data(
        &self,
        state: &SessionState,
        merchant_context: domain::MerchantContext,
    ) -> RouterResult<Value> {
        match self {
            Self::PaymentMethodRecord(_) => {
                let vault_resp = vault::retrieve_payment_method_from_vault_internal(
                    state,
                    &merchant_context,
                    &self.get_vault_id()?,
                    &self.get_customer_id(),
                )
                .await
                .change_context(errors::ApiErrorResponse::InternalServerError)
                .attach_printable("Error while fetching data from vault")?;

                Ok(vault_resp
                    .data
                    .encode_to_value()
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to serialize vault data")?)
            }
            Self::TokenizationRecord(_) => {
                let vault_request = pm_types::VaultRetrieveRequest {
                    entity_id: self.get_customer_id(),
                    vault_id: self.get_vault_id()?,
                };

                let vault_data = vault::retrieve_value_from_vault(state, vault_request)
                    .await
                    .change_context(errors::ApiErrorResponse::InternalServerError)
                    .attach_printable("Failed to retrieve vault data")?;

                Ok(vault_data.get("data").cloned().unwrap_or(Value::Null))
            }
        }
    }


impl api::ConnectorAccessToken for Mpgs {}

impl api::ConnectorAccessToken for for Mpgs


pub struct PaymentMethodSessionConfirmRequest {
    /// The payment method type
    #[schema(value_type = PaymentMethod, example = "card")]
    pub payment_method_type: common_enums::PaymentMethod,

    /// The payment method subtype
    #[schema(value_type = PaymentMethodType, example = "google_pay")]
    pub payment_method_subtype: common_enums::PaymentMethodType,

    /// The payment instrument data to be used for the payment
    #[schema(value_type = PaymentMethodDataRequest)]
    pub payment_method_data: payments::PaymentMethodDataRequest,

    /// The return url to which the customer should be redirected to after adding the payment method
    #[schema(value_type = Option<String>)]
    pub return_url: Option<common_utils::types::Url>,
}


pub async fn delete_merchant_account(
    state: web::Data<AppState>,
    req: HttpRequest,
    mid: web::Path<common_utils::id_type::MerchantId>,
) -> HttpResponse {
    let flow = Flow::MerchantsAccountDelete;
    let mid = mid.into_inner();

    let payload = web::Json(admin::MerchantId { merchant_id: mid }).into_inner();
    api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, req, _| merchant_account_delete(state, req.merchant_id),
        &auth::V2AdminApiAuth,
        api_locking::LockAction::NotApplicable,
    )
    .await
}


File: crates/api_models/src/open_router.rs
 Public functions: 6
 Public structs: 23

use std::{collections::HashMap, fmt::Debug};

use common_utils::{errors, id_type, types::MinorUnit};
pub use euclid::{
    dssa::types::EuclidAnalysable,
    frontend::{
        ast,
        dir::{DirKeyKind, EuclidDirFilter},
    },
};
use serde::{Deserialize, Serialize};
use utoipa::ToSchema;

use crate::{
    enums::{Currency, PaymentMethod},
    payment_methods,
};

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct OpenRouterDecideGatewayRequest {
    pub payment_info: PaymentInfo,
    #[schema(value_type = String)]
    pub merchant_id: id_type::ProfileId,
    pub eligible_gateway_list: Option<Vec<String>>,
    pub ranking_algorithm: Option<RankingAlgorithm>,
    pub elimination_enabled: Option<bool>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct DecideGatewayResponse {
    pub decided_gateway: Option<String>,
    pub gateway_priority_map: Option<serde_json::Value>,
    pub filter_wise_gateways: Option<serde_json::Value>,
    pub priority_logic_tag: Option<String>,
    pub routing_approach: Option<String>,
    pub gateway_before_evaluation: Option<String>,
    pub priority_logic_output: Option<PriorityLogicOutput>,
    pub reset_approach: Option<String>,
    pub routing_dimension: Option<String>,
    pub routing_dimension_level: Option<String>,
    pub is_scheduled_outage: Option<bool>,
    pub is_dynamic_mga_enabled: Option<bool>,
    pub gateway_mga_id_map: Option<serde_json::Value>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct PriorityLogicOutput {
    pub is_enforcement: Option<bool>,
    pub gws: Option<Vec<String>>,
    pub priority_logic_tag: Option<String>,
    pub gateway_reference_ids: Option<HashMap<String, String>>,
    pub primary_logic: Option<PriorityLogicData>,
    pub fallback_logic: Option<PriorityLogicData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
pub struct PriorityLogicData {
    pub name: Option<String>,
    pub status: Option<String>,
    pub failure_reason: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum RankingAlgorithm {
    SrBasedRouting,
    PlBasedRouting,
    NtwBasedRouting,
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct PaymentInfo {
    #[schema(value_type = String)]
    pub payment_id: id_type::PaymentId,
    pub amount: MinorUnit,
    pub currency: Currency,
    // customerId: Option<ETCu::CustomerId>,
    // preferredGateway: Option<ETG::Gateway>,
    pub payment_type: String,
    pub metadata: Option<String>,
    // internalMetadata: Option<String>,
    // isEmi: Option<bool>,
    // emiBank: Option<String>,
    // emiTenure: Option<i32>,
    pub payment_method_type: String,
    pub payment_method: PaymentMethod,
    // paymentSource: Option<String>,
    // authType: Option<ETCa::txn_card_info::AuthType>,
    // cardIssuerBankName: Option<String>,
    pub card_isin: Option<String>,
    // cardType: Option<ETCa::card_type::CardType>,
    // cardSwitchProvider: Option<Secret<String>>,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct DecidedGateway {
    pub gateway_priority_map: Option<HashMap<String, f64>>,
    pub debit_routing_output: Option<DebitRoutingOutput>,
    pub routing_approach: String,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct DebitRoutingOutput {
    pub co_badged_card_networks_info: CoBadgedCardNetworks,
    pub issuer_country: common_enums::CountryAlpha2,
    pub is_regulated: bool,
    pub regulated_name: Option<common_enums::RegulatedName>,
    pub card_type: common_enums::CardType,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct CoBadgedCardNetworksInfo {
    pub network: common_enums::CardNetwork,
    pub saving_percentage: f64,
}

#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
pub struct CoBadgedCardNetworks(pub Vec<CoBadgedCardNetworksInfo>);

impl CoBadgedCardNetworks {
    pub fn get_card_networks(&self) -> Vec<common_enums::CardNetwork> {
        self.0.iter().map(|info| info.network.clone()).collect()
    }

    pub fn get_signature_network(&self) -> Option<common_enums::CardNetwork> {
        self.0
            .iter()
            .find(|info| info.network.is_signature_network())
            .map(|info| info.network.clone())
    }
}

impl From<&DebitRoutingOutput> for payment_methods::CoBadgedCardData {
    fn from(output: &DebitRoutingOutput) -> Self {
        Self {
            co_badged_card_networks_info: output.co_badged_card_networks_info.clone(),
            issuer_country_code: output.issuer_country,
            is_regulated: output.is_regulated,
            regulated_name: output.regulated_name.clone(),
        }
    }
}

impl TryFrom<(payment_methods::CoBadgedCardData, String)> for DebitRoutingRequestData {
    type Error = error_stack::Report<errors::ParsingError>;

    fn try_from(
        (output, card_type): (payment_methods::CoBadgedCardData, String),
    ) -> Result<Self, Self::Error> {
        let parsed_card_type = card_type.parse::<common_enums::CardType>().map_err(|_| {
            error_stack::Report::new(errors::ParsingError::EnumParseFailure("CardType"))
        })?;

        Ok(Self {
            co_badged_card_networks_info: output.co_badged_card_networks_info.get_card_networks(),
            issuer_country: output.issuer_country_code,
            is_regulated: output.is_regulated,
            regulated_name: output.regulated_name,
            card_type: parsed_card_type,
        })
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CoBadgedCardRequest {
    pub merchant_category_code: common_enums::DecisionEngineMerchantCategoryCode,
    pub acquirer_country: common_enums::CountryAlpha2,
    pub co_badged_card_data: Option<DebitRoutingRequestData>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct DebitRoutingRequestData {
    pub co_badged_card_networks_info: Vec<common_enums::CardNetwork>,
    pub issuer_country: common_enums::CountryAlpha2,
    pub is_regulated: bool,
    pub regulated_name: Option<common_enums::RegulatedName>,
    pub card_type: common_enums::CardType,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct ErrorResponse {
    pub status: String,
    pub error_code: String,
    pub error_message: String,
    pub priority_logic_tag: Option<String>,
    pub filter_wise_gateways: Option<serde_json::Value>,
    pub error_info: UnifiedError,
    pub is_dynamic_mga_enabled: bool,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct UnifiedError {
    pub code: String,
    pub user_message: String,
    pub developer_message: String,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct UpdateScorePayload {
    #[schema(value_type = String)]
    pub merchant_id: id_type::ProfileId,
    pub gateway: String,
    pub status: TxnStatus,
    #[schema(value_type = String)]
    pub payment_id: id_type::PaymentId,
}

#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
pub struct UpdateScoreResponse {
    pub message: String,
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TxnStatus {
    Started,
    AuthenticationFailed,
    JuspayDeclined,
    PendingVbv,
    VBVSuccessful,
    Authorized,
    AuthorizationFailed,
    Charged,
    Authorizing,
    CODInitiated,
    Voided,
    VoidedPostCharge,
    VoidInitiated,
    Nop,
    CaptureInitiated,
    CaptureFailed,
    VoidFailed,
    AutoRefunded,
    PartialCharged,
    ToBeCharged,
    Pending,
    Failure,
    Declined,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct DecisionEngineConfigSetupRequest {
    pub merchant_id: String,
    pub config: DecisionEngineConfigVariant,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct GetDecisionEngineConfigRequest {
    pub merchant_id: String,
    pub algorithm: DecisionEngineDynamicAlgorithmType,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub enum DecisionEngineDynamicAlgorithmType {
    SuccessRate,
    Elimination,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "type", content = "data")]
#[serde(rename_all = "camelCase")]
pub enum DecisionEngineConfigVariant {
    SuccessRate(DecisionEngineSuccessRateData),
    Elimination(DecisionEngineEliminationData),
}

#[derive(Debug, Clone, Serialize, Deserialize, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct DecisionEngineSuccessRateData {
    pub default_latency_threshold: Option<f64>,
    pub default_bucket_size: Option<i32>,
    pub default_hedging_percent: Option<f64>,
    pub default_lower_reset_factor: Option<f64>,
    pub default_upper_reset_factor: Option<f64>,
    pub default_gateway_extra_score: Option<Vec<DecisionEngineGatewayWiseExtraScore>>,
    pub sub_level_input_config: Option<Vec<DecisionEngineSRSubLevelInputConfig>>,
}

impl DecisionEngineSuccessRateData {
    pub fn update(&mut self, new_config: Self) {
        if let Some(threshold) = new_config.default_latency_threshold {
            self.default_latency_threshold = Some(threshold);
        }
        if let Some(bucket_size) = new_config.default_bucket_size {
            self.default_bucket_size = Some(bucket_size);
        }
        if let Some(hedging_percent) = new_config.default_hedging_percent {
            self.default_hedging_percent = Some(hedging_percent);
        }
        if let Some(lower_reset_factor) = new_config.default_lower_reset_factor {
            self.default_lower_reset_factor = Some(lower_reset_factor);
        }
        if let Some(upper_reset_factor) = new_config.default_upper_reset_factor {
            self.default_upper_reset_factor = Some(upper_reset_factor);
        }
        if let Some(gateway_extra_score) = new_config.default_gateway_extra_score {
            self.default_gateway_extra_score
                .as_mut()
                .map(|score| score.extend(gateway_extra_score));
        }
        if let Some(sub_level_input_config) = new_config.sub_level_input_config {
            self.sub_level_input_config.as_mut().map(|config| {
                config.extend(sub_level_input_config);
            });
        }
    }
}
#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct DecisionEngineSRSubLevelInputConfig {
    pub payment_method_type: Option<String>,
    pub payment_method: Option<String>,
    pub latency_threshold: Option<f64>,
    pub bucket_size: Option<i32>,
    pub hedging_percent: Option<f64>,
    pub lower_reset_factor: Option<f64>,
    pub upper_reset_factor: Option<f64>,
    pub gateway_extra_score: Option<Vec<DecisionEngineGatewayWiseExtraScore>>,
}

impl DecisionEngineSRSubLevelInputConfig {
    pub fn update(&mut self, new_config: Self) {
        if let Some(payment_method_type) = new_config.payment_method_type {
            self.payment_method_type = Some(payment_method_type);
        }
        if let Some(payment_method) = new_config.payment_method {
            self.payment_method = Some(payment_method);
        }
        if let Some(latency_threshold) = new_config.latency_threshold {
            self.latency_threshold = Some(latency_threshold);
        }
        if let Some(bucket_size) = new_config.bucket_size {
            self.bucket_size = Some(bucket_size);
        }
        if let Some(hedging_percent) = new_config.hedging_percent {
            self.hedging_percent = Some(hedging_percent);
        }
        if let Some(lower_reset_factor) = new_config.lower_reset_factor {
            self.lower_reset_factor = Some(lower_reset_factor);
        }
        if let Some(upper_reset_factor) = new_config.upper_reset_factor {
            self.upper_reset_factor = Some(upper_reset_factor);
        }
        if let Some(gateway_extra_score) = new_config.gateway_extra_score {
            self.gateway_extra_score
                .as_mut()
                .map(|score| score.extend(gateway_extra_score));
        }
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct DecisionEngineGatewayWiseExtraScore {
    pub gateway_name: String,
    pub gateway_sigma_factor: f64,
}

impl DecisionEngineGatewayWiseExtraScore {
    pub fn update(&mut self, new_config: Self) {
        self.gateway_name = new_config.gateway_name;
        self.gateway_sigma_factor = new_config.gateway_sigma_factor;
    }
}

#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
#[serde(rename_all = "camelCase")]
pub struct DecisionEngineEliminationData {
    pub threshold: f64,
}

impl DecisionEngineEliminationData {
    pub fn update(&mut self, new_config: Self) {
        self.threshold = new_config.threshold;
    }
}

#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct MerchantAccount {
    pub merchant_id: String,
    pub gateway_success_rate_based_decider_input: Option<String>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct FetchRoutingConfig {
    pub merchant_id: String,
    pub algorithm: AlgorithmType,
}

#[derive(Debug, Serialize, Deserialize, Clone, Copy)]
#[serde(rename_all = "camelCase")]
pub enum AlgorithmType {
    SuccessRate,
    Elimination,
    DebitRouting,
}


        request
            .business_sub_label
            .clone()
            .map(|bsl| payment_attempt.business_sub_label.replace(bsl));
        request
            .payment_method_type
            .map(|pmt| payment_attempt.payment_method_type.replace(pmt));
        request
            .payment_experience
            .map(|experience| payment_attempt.payment_experience.replace(experience));
        payment_attempt.amount_to_capture = request
            .amount_to_capture
            .or(payment_attempt.amount_to_capture);
        request
            .capture_method
            .map(|i| payment_attempt.capture_method.replace(i));
    }
    fn populate_payment_intent_with_request(
        payment_intent: &mut storage::PaymentIntent,
        request: &api::PaymentsRequest,
    ) {
        request
            .return_url
            .clone()
            .map(|i| payment_intent.return_url.replace(i.to_string()));

        payment_intent.business_country = request.business_country;

        payment_intent
            .business_label
            .clone_from(&request.business_label);

        request
            .description
            .clone()
            .map(|i| payment_intent.description.replace(i));

        request
            .statement_descriptor_name
            .clone()
            .map(|i| payment_intent.statement_descriptor_name.replace(i));

        request
            .statement_descriptor_suffix
            .clone()
            .map(|i| payment_intent.statement_descriptor_suffix.replace(i));

        request
            .client_secret
            .clone()
            .map(|i| payment_intent.client_secret.replace(i));
    }
}


pub struct AciCaptureResultDetails {
    extended_description: String,
    #[serde(rename = "clearingInstituteName")]
    clearing_institute_name: String,
    connector_tx_id1: String,
    connector_tx_id3: String,
    connector_tx_id2: String,
    acquirer_response: String,
}


OpenAPI Block Path: paths."/account/{account_id}/connectors/{merchant_connector_id}"
{
  "get": {
    "tags": [
      "Merchant Connector Account"
    ],
    "summary": "Merchant Connector - Retrieve",
    "description": "Retrieves details of a Connector account",
    "operationId": "Retrieve a Merchant Connector",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "The unique identifier for the merchant account",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "merchant_connector_id",
        "in": "path",
        "description": "The unique identifier for the Merchant Connector",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Merchant Connector retrieved successfully",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MerchantConnectorResponse"
            }
          }
        }
      },
      "401": {
        "description": "Unauthorized request"
      },
      "404": {
        "description": "Merchant Connector does not exist in records"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  },
  "post": {
    "tags": [
      "Merchant Connector Account"
    ],
    "summary": "Merchant Connector - Update",
    "description": "To update an existing Merchant Connector account. Helpful in enabling/disabling different payment methods and other settings for the connector",
    "operationId": "Update a Merchant Connector",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "The unique identifier for the merchant account",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "merchant_connector_id",
        "in": "path",
        "description": "The unique identifier for the Merchant Connector",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "requestBody": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/MerchantConnectorUpdate"
          },
          "examples": {
            "Enable card payment method": {
              "value": {
                "connector_type": "payment_processor",
                "payment_methods_enabled": [
                  {
                    "payment_method": "card"
                  }
                ]
              }
            },
            "Update webhook secret": {
              "value": {
                "connector_webhook_details": {
                  "merchant_secret": "{{webhook_secret}}"
                }
              }
            }
          }
        }
      },
      "required": true
    },
    "responses": {
      "200": {
        "description": "Merchant Connector Updated",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MerchantConnectorResponse"
            }
          }
        }
      },
      "401": {
        "description": "Unauthorized request"
      },
      "404": {
        "description": "Merchant Connector does not exist in records"
      }
    },
    "security": [
      {
        "api_key": []
      }
    ]
  },
  "delete": {
    "tags": [
      "Merchant Connector Account"
    ],
    "summary": "Merchant Connector - Delete",
    "description": "Delete or Detach a Merchant Connector from Merchant Account",
    "operationId": "Delete a Merchant Connector",
    "parameters": [
      {
        "name": "account_id",
        "in": "path",
        "description": "The unique identifier for the merchant account",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      {
        "name": "merchant_connector_id",
        "in": "path",
        "description": "The unique identifier for the Merchant Connector",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    ],
    "responses": {
      "200": {
        "description": "Merchant Connector Deleted",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/MerchantConnectorDeleteResponse"
            }
          }
        }
      },
      "401": {
        "description": "Unauthorized request"
      },
      "404": {
        "description": "Merchant Connector does not exist in records"
      }
    },
    "security": [
      {
        "admin_api_key": []
      }
    ]
  }
}


pub fn set_offset_n_count(&mut self, offset: i64, count: i64) -> QueryResult<()> {
        self.offset = Some(offset);
        self.count = Some(count);
        Ok(())
    }


impl ConnectorCommon for Payeezy {
    fn id(&self) -> &'static str {
        "payeezy"
    }

    fn get_currency_unit(&self) -> api::CurrencyUnit {
        api::CurrencyUnit::Base
    }

    fn common_get_content_type(&self) -> &'static str {
        "application/json"
    }

    fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str {
        connectors.payeezy.base_url.as_ref()
    }

    fn build_error_response(
        &self,
        res: Response,
        event_builder: Option<&mut ConnectorEvent>,
    ) -> CustomResult<ErrorResponse, errors::ConnectorError> {
        let response: payeezy::PayeezyErrorResponse = res
            .response
            .parse_struct("payeezy ErrorResponse")
            .change_context(errors::ConnectorError::ResponseDeserializationFailed)?;

        event_builder.map(|i| i.set_error_response_body(&response));
        router_env::logger::info!(connector_response=?response);

        let error_messages: Vec<String> = response
            .error
            .messages
            .iter()
            .map(|m| m.description.clone())
            .collect();

        Ok(ErrorResponse {
            status_code: res.status_code,
            code: response.transaction_status,
            message: error_messages.join(", "),
            reason: None,
            attempt_status: None,
            connector_transaction_id: None,
            network_advice_code: None,
            network_decline_code: None,
            network_error_message: None,
            connector_metadata: None,
        })
    }
}


pub struct CoingatePaymentsResponse {
    status: CoingatePaymentStatus,
    id: i64,
    payment_url: Option<String>,
    order_id: Option<String>,
}


pub async fn trigger_payments_webhook<F, Op, D>(
    merchant_account: domain::MerchantAccount,
    business_profile: domain::Profile,
    key_store: &domain::MerchantKeyStore,
    payment_data: D,
    customer: Option<domain::Customer>,
    state: &SessionState,
    operation: Op,
) -> RouterResult<()>
where
    F: Send + Clone + Sync,
    Op: Debug,
    D: payments_core::OperationSessionGetters<F>,
{
    todo!()
}


pub struct ClientProcessorInformation {
    avs: Option<Avs>,
    card_verification: Option<CardVerification>,
    processor: Option<ProcessorResponse>,
    network_transaction_id: Option<Secret<String>>,
    approval_code: Option<String>,
    merchant_advice: Option<MerchantAdvice>,
    response_code: Option<String>,
    ach_verification: Option<AchVerification>,
    system_trace_audit_number: Option<String>,
    event_status: Option<String>,
    retrieval_reference_number: Option<String>,
    consumer_authentication_response: Option<ConsumerAuthenticationResponse>,
    response_details: Option<String>,
    transaction_id: Option<Secret<String>>,
}


pub struct Bambora3DsResponse {
    #[serde(rename = "3d_session_data")]
    three_d_session_data: Secret<String>,
    contents: String,
}


impl Mandate {
    /// Returns customer_user_agent_extended with customer_user_agent as fallback
    pub fn get_user_agent_extended(&self) -> Option<String> {
        self.customer_user_agent_extended
            .clone()
            .or_else(|| self.customer_user_agent.clone())
    }
}


Documentation: api-reference/intelligent-router-api-reference/success-rate/fetch-success-rate-for-an-entity.mdx
# Type: Doc File

---
openapi: post /success_rate.SuccessRateCalculator/FetchSuccessRate
---


pub fn is_merchant_connector_account_id_in_connector_mandate_details(
            &self,
            profile_id: Option<&id_type::ProfileId>,
            connector_mandate_details: &CommonMandateReference,
        ) -> bool {
            let mca_ids = self
                .iter()
                .filter(|mca| {
                    mca.disabled.is_some_and(|disabled| !disabled)
                        && profile_id.is_some_and(|profile_id| *profile_id == mca.profile_id)
                })
                .map(|mca| mca.get_id())
                .collect::<std::collections::HashSet<_>>();

            connector_mandate_details
            .payments
            .as_ref()
            .as_ref().is_some_and(|payments| {
                payments.0.keys().any(|mca_id| mca_ids.contains(mca_id))
            })
        }


File: crates/router/src/types/storage/file.rs

pub use diesel_models::file::{
    FileMetadata, FileMetadataNew, FileMetadataUpdate, FileMetadataUpdateInternal,
};


pub struct Entity {
    pub entity_id: String,
    pub entity_type: common_enums::EntityType,
}


pub struct JuspaythreedsserverRefundRequest {
    pub amount: StringMinorUnit,
}


impl webhooks::IncomingWebhook for Worldpayxml {
    fn get_webhook_object_reference_id(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::ObjectReferenceId, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_event_type(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<api_models::webhooks::IncomingWebhookEvent, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }

    fn get_webhook_resource_object(
        &self,
        _request: &webhooks::IncomingWebhookRequestDetails<'_>,
    ) -> CustomResult<Box<dyn masking::ErasedMaskSerialize>, errors::ConnectorError> {
        Err(report!(errors::ConnectorError::WebhooksNotImplemented))
    }
}

impl webhooks::IncomingWebhook for for Worldpayxml


File: crates/router/src/types/storage/ephemeral_key.rs

#[cfg(feature = "v2")]
pub use diesel_models::ephemeral_key::{ClientSecretType, ClientSecretTypeNew};
pub use diesel_models::ephemeral_key::{EphemeralKey, EphemeralKeyNew};

#[cfg(feature = "v2")]
use crate::db::errors;
#[cfg(feature = "v2")]
use crate::types::transformers::ForeignTryFrom;
#[cfg(feature = "v2")]
impl ForeignTryFrom<ClientSecretType> for api_models::ephemeral_key::ClientSecretResponse {
    type Error = errors::ApiErrorResponse;
    fn foreign_try_from(from: ClientSecretType) -> Result<Self, errors::ApiErrorResponse> {
        match from.resource_id {
            common_utils::types::authentication::ResourceId::Payment(global_payment_id) => {
                Err(errors::ApiErrorResponse::InternalServerError)
            }
            common_utils::types::authentication::ResourceId::PaymentMethodSession(
                global_payment_id,
            ) => Err(errors::ApiErrorResponse::InternalServerError),
            common_utils::types::authentication::ResourceId::Customer(global_customer_id) => {
                Ok(Self {
                    resource_id: api_models::ephemeral_key::ResourceId::Customer(
                        global_customer_id.clone(),
                    ),
                    created_at: from.created_at,
                    expires: from.expires,
                    secret: from.secret,
                    id: from.id,
                })
            }
        }
    }
}


pub async fn find_optional_by_address_id(
        conn: &PgPooledConn,
        address_id: &str,
    ) -> StorageResult<Option<Self>> {
        generics::generic_find_by_id_optional::<<Self as HasTable>::Table, _, _>(
            conn,
            address_id.to_owned(),
        )
        .await
    }


pub async fn connector_update(
    state: web::Data<AppState>,
    req: HttpRequest,
    path: web::Path<common_utils::id_type::MerchantConnectorAccountId>,
    json_payload: web::Json<api_models::admin::MerchantConnectorUpdate>,
) -> HttpResponse {
    let flow = Flow::MerchantConnectorsUpdate;
    let id = path.into_inner();
    let payload = json_payload.into_inner();
    let merchant_id = payload.merchant_id.clone();

    Box::pin(api::server_wrap(
        flow,
        state,
        &req,
        payload,
        |state, _, req, _| update_connector(state, &merchant_id, None, &id, req),
        auth::auth_type(
            &auth::V2AdminApiAuth,
            &auth::JWTAuthMerchantFromRoute {
                merchant_id: merchant_id.clone(),
                required_permission: Permission::MerchantConnectorWrite,
            },
            req.headers(),
        ),
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


impl Capturable for PaymentsApproveData {}

impl Capturable for for PaymentsApproveData


impl api::PaymentCapture for CtpMastercard {}

impl api::PaymentCapture for for CtpMastercard


impl ResourceId {
    /// Get string representation of enclosed ID type
    pub fn to_str(&self) -> &str {
        match self {
            Self::Payment(id) => id.get_string_repr(),
            Self::Customer(id) => id.get_string_repr(),
            Self::PaymentMethodSession(id) => id.get_string_repr(),
        }
    }
}


impl ConnectorValidation for HyperswitchVault {}

impl ConnectorValidation for for HyperswitchVault


pub struct SamsungPayTokenData {
    #[serde(rename = "type")]
    pub three_ds_type: Option<String>,
    pub version: String,
    pub data: Secret<String>,
}


pub struct NoonApplePay {
    payment_info: Secret<String>,
}


pub struct ConnectorParamsWithKeys {
    /// base url
    pub base_url: String,
    /// api key
    pub api_key: Secret<String>,
    /// merchant ID
    pub merchant_id: Secret<String>,
}


pub struct CustomerDeleteResponse {
    /// The identifier for the customer object
    #[schema(value_type = String, max_length = 255, example = "cus_y3oqhf46pyzuxjbcn2giaqnb44")]
    pub customer_id: id_type::CustomerId,
    /// Whether customer was deleted or not
    #[schema(example = false)]
    pub customer_deleted: bool,
    /// Whether address was deleted or not
    #[schema(example = false)]
    pub address_deleted: bool,
    /// Whether payment methods deleted or not
    #[schema(example = false)]
    pub payment_methods_deleted: bool,
}


impl PayoutsInterface for KafkaStore {
    type Error = errors::StorageError;
    async fn find_payout_by_merchant_id_payout_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payout_id: &id_type::PayoutId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        self.diesel_store
            .find_payout_by_merchant_id_payout_id(merchant_id, payout_id, storage_scheme)
            .await
    }

    async fn update_payout(
        &self,
        this: &storage::Payouts,
        payout_update: storage::PayoutsUpdate,
        payout_attempt: &storage::PayoutAttempt,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        let payout = self
            .diesel_store
            .update_payout(this, payout_update, payout_attempt, storage_scheme)
            .await?;
        if let Err(err) = self
            .kafka_producer
            .log_payout(
                &KafkaPayout::from_storage(&payout, payout_attempt),
                Some(KafkaPayout::from_storage(this, payout_attempt)),
                self.tenant_id.clone(),
            )
            .await
        {
            logger::error!(message="Failed to update analytics entry for Payouts {payout:?}\n{payout_attempt:?}", error_message=?err);
        };
        Ok(payout)
    }

    async fn insert_payout(
        &self,
        payout: storage::PayoutsNew,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<storage::Payouts, errors::StorageError> {
        self.diesel_store
            .insert_payout(payout, storage_scheme)
            .await
    }

    async fn find_optional_payout_by_merchant_id_payout_id(
        &self,
        merchant_id: &id_type::MerchantId,
        payout_id: &id_type::PayoutId,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Option<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .find_optional_payout_by_merchant_id_payout_id(merchant_id, payout_id, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        filters: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .filter_payouts_by_constraints(merchant_id, filters, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_and_attempts(
        &self,
        merchant_id: &id_type::MerchantId,
        filters: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<
        Vec<(
            storage::Payouts,
            storage::PayoutAttempt,
            Option<diesel_models::Customer>,
            Option<diesel_models::Address>,
        )>,
        errors::StorageError,
    > {
        self.diesel_store
            .filter_payouts_and_attempts(merchant_id, filters, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_payouts_by_time_range_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        time_range: &common_utils::types::TimeRange,
        storage_scheme: MerchantStorageScheme,
    ) -> CustomResult<Vec<storage::Payouts>, errors::StorageError> {
        self.diesel_store
            .filter_payouts_by_time_range_constraints(merchant_id, time_range, storage_scheme)
            .await
    }

    #[cfg(feature = "olap")]
    async fn get_total_count_of_filtered_payouts(
        &self,
        merchant_id: &id_type::MerchantId,
        active_payout_ids: &[id_type::PayoutId],
        connector: Option<Vec<api_models::enums::PayoutConnectors>>,
        currency: Option<Vec<enums::Currency>>,
        status: Option<Vec<enums::PayoutStatus>>,
        payout_method: Option<Vec<enums::PayoutType>>,
    ) -> CustomResult<i64, errors::StorageError> {
        self.diesel_store
            .get_total_count_of_filtered_payouts(
                merchant_id,
                active_payout_ids,
                connector,
                currency,
                status,
                payout_method,
            )
            .await
    }

    #[cfg(feature = "olap")]
    async fn filter_active_payout_ids_by_constraints(
        &self,
        merchant_id: &id_type::MerchantId,
        constraints: &hyperswitch_domain_models::payouts::PayoutFetchConstraints,
    ) -> CustomResult<Vec<id_type::PayoutId>, errors::StorageError> {
        self.diesel_store
            .filter_active_payout_ids_by_constraints(merchant_id, constraints)
            .await
    }
}

impl PayoutsInterface for for KafkaStore


pub fn get_inner_db_merchant_connector_account(&self) -> Option<&MerchantConnectorAccount> {
        match self {
            Self::MerchantConnectorAccount(merchant_connector_account) => {
                Some(merchant_connector_account)
            }
            Self::MerchantConnectorDetails(_) => None,
        }
    }


impl Refund for Signifyd {}


pub struct TokenDetails {
    pub exp_month: Secret<String>,
    pub exp_year: Secret<String>,
}


File: crates/router/tests/connectors/zen.rs

use std::str::FromStr;

use cards::CardNumber;
use common_utils::{pii::Email, types::MinorUnit};
use hyperswitch_domain_models::types::OrderDetailsWithAmount;
use masking::Secret;
use router::types::{self, domain, storage::enums};

use crate::{
    connector_auth,
    utils::{self, ConnectorActions},
};

#[derive(Clone, Copy)]
struct ZenTest;
impl ConnectorActions for ZenTest {}
impl utils::Connector for ZenTest {
    fn get_data(&self) -> types::api::ConnectorData {
        use router::connector::Zen;
        utils::construct_connector_data_old(
            Box::new(&Zen),
            types::Connector::Zen,
            types::api::GetToken::Connector,
            None,
        )
    }

    fn get_auth_token(&self) -> types::ConnectorAuthType {
        utils::to_connector_auth_type(
            connector_auth::ConnectorAuthentication::new()
                .zen
                .expect("Missing connector authentication configuration")
                .into(),
        )
    }

    fn get_name(&self) -> String {
        "zen".to_string()
    }
}

static CONNECTOR: ZenTest = ZenTest {};

// Cards Positive Tests
// Creates a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_only_authorize_payment() {
    let response = CONNECTOR
        .authorize_payment(None, None)
        .await
        .expect("Authorize payment response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized);
}

// Captures a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(None, None, None)
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Partially captures a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_partially_capture_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_capture_payment(
            None,
            Some(types::PaymentsCaptureData {
                amount_to_capture: 50,
                ..utils::PaymentCaptureType::default().0
            }),
            None,
        )
        .await
        .expect("Capture payment response");
    assert_eq!(response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_sync_authorized_payment() {
    let authorize_response = CONNECTOR
        .authorize_payment(None, None)
        .await
        .expect("Authorize payment response");
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Authorized,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                encoded_data: None,
                capture_method: None,
                sync_type: types::SyncRequestType::SinglePaymentSync,
                connector_meta: None,
                mandate_id: None,
                payment_method_type: None,
                currency: enums::Currency::USD,
                payment_experience: None,
                amount: MinorUnit::new(100),
                integrity_object: None,
                ..Default::default()
            }),
            None,
        )
        .await
        .expect("PSync response");
    assert_eq!(response.status, enums::AttemptStatus::Authorized,);
}

// Voids a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and void is not supported"]
#[actix_web::test]
async fn should_void_authorized_payment() {
    let response = CONNECTOR
        .authorize_and_void_payment(
            None,
            Some(types::PaymentsCancelData {
                connector_transaction_id: String::from(""),
                cancellation_reason: Some("requested_by_customer".to_string()),
                ..Default::default()
            }),
            None,
        )
        .await
        .expect("Void payment response");
    assert_eq!(response.status, enums::AttemptStatus::Voided);
}

// Refunds a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(None, None, None, None)
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_partially_refund_manually_captured_payment() {
    let response = CONNECTOR
        .capture_payment_and_refund(
            None,
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Synchronizes a refund using the manual capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_sync_manually_captured_refund() {
    let refund_response = CONNECTOR
        .capture_payment_and_refund(None, None, None, None)
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_make_payment() {
    let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
}

// Synchronizes a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_sync_auto_captured_payment() {
    let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let response = CONNECTOR
        .psync_retry_till_status_matches(
            enums::AttemptStatus::Charged,
            Some(types::PaymentsSyncData {
                connector_transaction_id: types::ResponseId::ConnectorTransactionId(
                    txn_id.unwrap(),
                ),
                encoded_data: None,
                capture_method: Some(enums::CaptureMethod::Automatic),
                sync_type: types::SyncRequestType::SinglePaymentSync,
                connector_meta: None,
                mandate_id: None,
                payment_method_type: None,
                currency: enums::Currency::USD,
                payment_experience: None,
                amount: MinorUnit::new(100),
                integrity_object: None,
                ..Default::default()
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(response.status, enums::AttemptStatus::Charged,);
}

// Refunds a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_refund_auto_captured_payment() {
    let response = CONNECTOR
        .make_payment_and_refund(None, None, None)
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Partially refunds a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_partially_refund_succeeded_payment() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        refund_response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Creates multiple refunds against a payment using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_refund_succeeded_payment_multiple_times() {
    CONNECTOR
        .make_payment_and_multiple_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 50,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .await;
}

// Synchronizes a refund using the automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_sync_refund() {
    let refund_response = CONNECTOR
        .make_payment_and_refund(None, None, None)
        .await
        .unwrap();
    let response = CONNECTOR
        .rsync_retry_till_status_matches(
            enums::RefundStatus::Success,
            refund_response.response.unwrap().connector_refund_id,
            None,
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap().refund_status,
        enums::RefundStatus::Success,
    );
}

// Cards Negative scenarios
// Creates a payment with incorrect card number.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_card_number() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_number: CardNumber::from_str("1234567891011").unwrap(),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// Creates a payment with incorrect CVC.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_cvc() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_cvc: Secret::new("12345".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// Creates a payment with incorrect expiry month.
#[actix_web::test]
async fn should_fail_payment_for_invalid_exp_month() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_month: Secret::new("20".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// Creates a payment with incorrect expiry year.
#[actix_web::test]
async fn should_fail_payment_for_incorrect_expiry_year() {
    let response = CONNECTOR
        .make_payment(
            Some(types::PaymentsAuthorizeData {
                payment_method_data: domain::PaymentMethodData::Card(domain::Card {
                    card_exp_year: Secret::new("2000".to_string()),
                    ..utils::CCardType::default().0
                }),
                order_details: Some(vec![OrderDetailsWithAmount {
                    product_name: "iphone 13".to_string(),
                    quantity: 1,
                    amount: MinorUnit::new(1000),
                    product_img_link: None,
                    requires_shipping: None,
                    product_id: None,
                    category: None,
                    sub_category: None,
                    brand: None,
                    product_type: None,
                    product_tax_code: None,
                    tax_rate: None,
                    total_tax_amount: None,
                    description: None,
                    sku: None,
                    upc: None,
                    commodity_code: None,
                    unit_of_measure: None,
                    total_amount: None,
                    unit_discount_amount: None,
                }]),
                email: Some(Email::from_str("test@gmail.com").unwrap()),
                webhook_url: Some("https://1635-116-74-253-164.ngrok-free.app".to_string()),
                ..utils::PaymentAuthorizeType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response
            .response
            .unwrap_err()
            .message
            .split_once(';')
            .unwrap()
            .0,
        "Request data doesn't pass validation".to_string(),
    );
}

// Voids a payment using automatic capture flow (Non 3DS).
#[ignore = "Connector triggers 3DS payment on test card and void is not supported"]
#[actix_web::test]
async fn should_fail_void_payment_for_auto_capture() {
    let authorize_response = CONNECTOR.make_payment(None, None).await.unwrap();
    assert_eq!(authorize_response.status, enums::AttemptStatus::Charged);
    let txn_id = utils::get_connector_transaction_id(authorize_response.response);
    assert_ne!(txn_id, None, "Empty connector transaction id");
    let void_response = CONNECTOR
        .void_payment(txn_id.unwrap(), None, None)
        .await
        .unwrap();
    assert_eq!(
        void_response.response.unwrap_err().message,
        "You cannot cancel this PaymentIntent because it has a status of succeeded."
    );
}

// Captures a payment using invalid connector payment id.
#[ignore = "Connector triggers 3DS payment on test card and capture is not supported"]
#[actix_web::test]
async fn should_fail_capture_for_invalid_payment() {
    let capture_response = CONNECTOR
        .capture_payment("123456789".to_string(), None, None)
        .await
        .unwrap();
    assert_eq!(
        capture_response.response.unwrap_err().message,
        String::from("No such payment_intent: '123456789'")
    );
}

// Refunds a payment with refund amount higher than payment amount.
#[ignore = "Connector triggers 3DS payment on test card"]
#[actix_web::test]
async fn should_fail_for_refund_amount_higher_than_payment_amount() {
    let response = CONNECTOR
        .make_payment_and_refund(
            None,
            Some(types::RefundsData {
                refund_amount: 150,
                ..utils::PaymentRefundType::default().0
            }),
            None,
        )
        .await
        .unwrap();
    assert_eq!(
        response.response.unwrap_err().message,
        "Refund amount (₹1.50) is greater than charge amount (₹1.00)",
    );
}

// Connector dependent test cases goes here

// [#478]: add unit tests for non 3DS, wallets & webhooks in connector tests


pub fn get_pm_link_config_as_value(
        &self,
    ) -> CustomResult<Option<serde_json::Value>, errors::ParsingError> {
        self.pm_collect_link_config
            .as_ref()
            .map(|pm_collect_link_config| pm_collect_link_config.encode_to_value())
            .transpose()
    }


impl super::api_event::events::ApiLogsFilterAnalytics for ClickhouseClient {}

impl super::api_event::events::ApiLogsFilterAnalytics for for ClickhouseClient


pub struct AddressNew {
    pub address_id: String,
    pub city: Option<String>,
    pub country: Option<enums::CountryAlpha2>,
    pub line1: Option<Encryption>,
    pub line2: Option<Encryption>,
    pub line3: Option<Encryption>,
    pub state: Option<Encryption>,
    pub zip: Option<Encryption>,
    pub first_name: Option<Encryption>,
    pub last_name: Option<Encryption>,
    pub phone_number: Option<Encryption>,
    pub country_code: Option<String>,
    pub customer_id: Option<common_utils::id_type::CustomerId>,
    pub merchant_id: common_utils::id_type::MerchantId,
    pub payment_id: Option<common_utils::id_type::PaymentId>,
    pub created_at: PrimitiveDateTime,
    pub modified_at: PrimitiveDateTime,
    pub updated_by: String,
    pub email: Option<Encryption>,
    pub origin_zip: Option<Encryption>,
}


pub async fn reset_tracking_id(
    state: web::Data<AppState>,
    http_req: HttpRequest,
    json_payload: web::Json<api_types::ResetTrackingIdRequest>,
) -> HttpResponse {
    let flow = Flow::ResetTrackingId;
    let req_payload = json_payload.into_inner();
    Box::pin(api::server_wrap(
        flow.clone(),
        state,
        &http_req,
        req_payload.clone(),
        core::reset_tracking_id,
        &auth::JWTAuth {
            permission: Permission::MerchantAccountWrite,
        },
        api_locking::LockAction::NotApplicable,
    ))
    .await
}


pub struct AmountOfMoney {
    amount: MinorUnit,
    currency_code: String,
}


File: crates/diesel_models/src/organization.rs
 Public functions: 6
 Public structs: 6

use common_utils::{id_type, pii};
use diesel::{AsChangeset, Identifiable, Insertable, Queryable, Selectable};

#[cfg(feature = "v1")]
use crate::schema::organization;
#[cfg(feature = "v2")]
use crate::schema_v2::organization;
pub trait OrganizationBridge {
    fn get_organization_id(&self) -> id_type::OrganizationId;
    fn get_organization_name(&self) -> Option<String>;
    fn set_organization_name(&mut self, organization_name: String);
}
#[cfg(feature = "v1")]
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
#[diesel(
    table_name = organization,
    primary_key(org_id),
    check_for_backend(diesel::pg::Pg)
)]
pub struct Organization {
    org_id: id_type::OrganizationId,
    org_name: Option<String>,
    pub organization_details: Option<pii::SecretSerdeValue>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    #[allow(dead_code)]
    id: Option<id_type::OrganizationId>,
    #[allow(dead_code)]
    organization_name: Option<String>,
    pub version: common_enums::ApiVersion,
    pub organization_type: Option<common_enums::OrganizationType>,
    pub platform_merchant_id: Option<id_type::MerchantId>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, Identifiable, Queryable, Selectable)]
#[diesel(
    table_name = organization,
    primary_key(id),
    check_for_backend(diesel::pg::Pg)
)]
pub struct Organization {
    pub organization_details: Option<pii::SecretSerdeValue>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    id: id_type::OrganizationId,
    organization_name: Option<String>,
    pub version: common_enums::ApiVersion,
    pub organization_type: Option<common_enums::OrganizationType>,
    pub platform_merchant_id: Option<id_type::MerchantId>,
}

#[cfg(feature = "v1")]
impl Organization {
    pub fn new(org_new: OrganizationNew) -> Self {
        let OrganizationNew {
            org_id,
            org_name,
            organization_details,
            metadata,
            created_at,
            modified_at,
            id: _,
            organization_name: _,
            version,
            organization_type,
            platform_merchant_id,
        } = org_new;
        Self {
            id: Some(org_id.clone()),
            organization_name: org_name.clone(),
            org_id,
            org_name,
            organization_details,
            metadata,
            created_at,
            modified_at,
            version,
            organization_type: Some(organization_type),
            platform_merchant_id,
        }
    }

    pub fn get_organization_type(&self) -> common_enums::OrganizationType {
        self.organization_type.unwrap_or_default()
    }
}

#[cfg(feature = "v2")]
impl Organization {
    pub fn new(org_new: OrganizationNew) -> Self {
        let OrganizationNew {
            id,
            organization_name,
            organization_details,
            metadata,
            created_at,
            modified_at,
            version,
            organization_type,
            platform_merchant_id,
        } = org_new;
        Self {
            id,
            organization_name,
            organization_details,
            metadata,
            created_at,
            modified_at,
            version,
            organization_type: Some(organization_type),
            platform_merchant_id,
        }
    }

    pub fn get_organization_type(&self) -> common_enums::OrganizationType {
        self.organization_type.unwrap_or_default()
    }
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, Insertable)]
#[diesel(table_name = organization, primary_key(org_id))]
pub struct OrganizationNew {
    org_id: id_type::OrganizationId,
    org_name: Option<String>,
    id: id_type::OrganizationId,
    organization_name: Option<String>,
    pub organization_details: Option<pii::SecretSerdeValue>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub version: common_enums::ApiVersion,
    pub organization_type: common_enums::OrganizationType,
    pub platform_merchant_id: Option<id_type::MerchantId>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, Insertable)]
#[diesel(table_name = organization, primary_key(id))]
pub struct OrganizationNew {
    id: id_type::OrganizationId,
    organization_name: Option<String>,
    pub organization_details: Option<pii::SecretSerdeValue>,
    pub metadata: Option<pii::SecretSerdeValue>,
    pub created_at: time::PrimitiveDateTime,
    pub modified_at: time::PrimitiveDateTime,
    pub version: common_enums::ApiVersion,
    pub organization_type: common_enums::OrganizationType,
    pub platform_merchant_id: Option<id_type::MerchantId>,
}

#[cfg(feature = "v1")]
impl OrganizationNew {
    pub fn new(
        id: id_type::OrganizationId,
        organization_type: common_enums::OrganizationType,
        organization_name: Option<String>,
    ) -> Self {
        Self {
            org_id: id.clone(),
            org_name: organization_name.clone(),
            id,
            organization_name,
            organization_details: None,
            metadata: None,
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            version: common_types::consts::API_VERSION,
            organization_type,
            platform_merchant_id: None,
        }
    }
}

#[cfg(feature = "v2")]
impl OrganizationNew {
    pub fn new(
        id: id_type::OrganizationId,
        organization_type: common_enums::OrganizationType,
        organization_name: Option<String>,
    ) -> Self {
        Self {
            id,
            organization_name,
            organization_details: None,
            metadata: None,
            created_at: common_utils::date_time::now(),
            modified_at: common_utils::date_time::now(),
            version: common_types::consts::API_VERSION,
            organization_type,
            platform_merchant_id: None,
        }
    }
}

#[cfg(feature = "v1")]
#[derive(Clone, Debug, AsChangeset)]
#[diesel(table_name = organization)]
pub struct OrganizationUpdateInternal {
    org_name: Option<String>,
    organization_name: Option<String>,
    organization_details: Option<pii::SecretSerdeValue>,
    metadata: Option<pii::SecretSerdeValue>,
    modified_at: time::PrimitiveDateTime,
    platform_merchant_id: Option<id_type::MerchantId>,
}

#[cfg(feature = "v2")]
#[derive(Clone, Debug, AsChangeset)]
#[diesel(table_name = organization)]
pub struct OrganizationUpdateInternal {
    organization_name: Option<String>,
    organization_details: Option<pii::SecretSerdeValue>,
    metadata: Option<pii::SecretSerdeValue>,
    modified_at: time::PrimitiveDateTime,
    platform_merchant_id: Option<id_type::MerchantId>,
}

pub enum OrganizationUpdate {
    Update {
        organization_name: Option<String>,
        organization_details: Option<pii::SecretSerdeValue>,
        metadata: Option<pii::SecretSerdeValue>,
        platform_merchant_id: Option<id_type::MerchantId>,
    },
}

#[cfg(feature = "v1")]
impl From<OrganizationUpdate> for OrganizationUpdateInternal {
    fn from(value: OrganizationUpdate) -> Self {
        match value {
            OrganizationUpdate::Update {
                organization_name,
                organization_details,
                metadata,
                platform_merchant_id,
            } => Self {
                org_name: organization_name.clone(),
                organization_name,
                organization_details,
                metadata,
                modified_at: common_utils::date_time::now(),
                platform_merchant_id,
            },
        }
    }
}

#[cfg(feature = "v2")]
impl From<OrganizationUpdate> for OrganizationUpdateInternal {
    fn from(value: OrganizationUpdate) -> Self {
        match value {
            OrganizationUpdate::Update {
                organization_name,
                organization_details,
                metadata,
                platform_merchant_id,
            } => Self {
                organization_name,
                organization_details,
                metadata,
                modified_at: common_utils::date_time::now(),
                platform_merchant_id,
            },
        }
    }
}

#[cfg(feature = "v1")]
impl OrganizationBridge for Organization {
    fn get_organization_id(&self) -> id_type::OrganizationId {
        self.org_id.clone()
    }
    fn get_organization_name(&self) -> Option<String> {
        self.org_name.clone()
    }
    fn set_organization_name(&mut self, organization_name: String) {
        self.org_name = Some(organization_name);
    }
}

#[cfg(feature = "v1")]
impl OrganizationBridge for OrganizationNew {
    fn get_organization_id(&self) -> id_type::OrganizationId {
        self.org_id.clone()
    }
    fn get_organization_name(&self) -> Option<String> {
        self.org_name.clone()
    }
    fn set_organization_name(&mut self, organization_name: String) {
        self.org_name = Some(organization_name);
    }
}

#[cfg(feature = "v2")]
impl OrganizationBridge for Organization {
    fn get_organization_id(&self) -> id_type::OrganizationId {
        self.id.clone()
    }
    fn get_organization_name(&self) -> Option<String> {
        self.organization_name.clone()
    }
    fn set_organization_name(&mut self, organization_name: String) {
        self.organization_name = Some(organization_name);
    }
}

#[cfg(feature = "v2")]
impl OrganizationBridge for OrganizationNew {
    fn get_organization_id(&self) -> id_type::OrganizationId {
        self.id.clone()
    }
    fn get_organization_name(&self) -> Option<String> {
        self.organization_name.clone()
    }
    fn set_organization_name(&mut self, organization_name: String) {
        self.organization_name = Some(organization_name);
    }
}


pub struct PaymentsResponse {
    id: String,
    amount: Option<MinorUnit>,
    currency: Option<String>,
    action_id: Option<String>,
    status: CheckoutPaymentStatus,
    #[serde(rename = "_links")]
    links: Links,
    balances: Option<Balances>,
    reference: Option<String>,
    response_code: Option<String>,
    response_summary: Option<String>,
    approved: Option<bool>,
    processed_on: Option<String>,
}