From f24797834553794f341bd4f3be3afe5fcba693ed Mon Sep 17 00:00:00 2001 From: Pa1NarK <69745008+pixincreate@users.noreply.github.com> Date: Tue, 22 Oct 2024 12:53:51 +0530 Subject: [PATCH 01/24] feat(cypress): execute cypress tests in parallel (#6225) --- .github/workflows/cypress-tests-runner.yml | 31 +--- cypress-tests/cypress.config.js | 29 +--- cypress-tests/readme.md | 43 ++++- scripts/execute_cypress.sh | 188 +++++++++++++++++++++ 4 files changed, 234 insertions(+), 57 deletions(-) create mode 100755 scripts/execute_cypress.sh diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index a878a9db8e4..be6518e5395 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -13,7 +13,8 @@ concurrency: env: CARGO_INCREMENTAL: 0 CARGO_NET_RETRY: 10 - CONNECTORS: stripe + PAYMENTS_CONNECTORS: "stripe" + PAYOUTS_CONNECTORS: "wise" RUST_BACKTRACE: short RUSTUP_MAX_RETRIES: 10 RUN_TESTS: ${{ ((github.event_name == 'pull_request') && (github.event.pull_request.head.repo.full_name == github.event.pull_request.base.repo.full_name)) || (github.event_name == 'merge_group')}} @@ -68,7 +69,7 @@ jobs: CONNECTOR_AUTH_PASSPHRASE: ${{ secrets.CONNECTOR_AUTH_PASSPHRASE }} CONNECTOR_CREDS_S3_BUCKET_URI: ${{ secrets.CONNECTOR_CREDS_S3_BUCKET_URI}} DESTINATION_FILE_NAME: "creds.json.gpg" - S3_SOURCE_FILE_NAME: "f64157fe-a8f7-43a8-a268-b17e9a8c305f.json.gpg" + S3_SOURCE_FILE_NAME: "5a3f7679-445e-4621-86c5-39bd8d26b7c5.json.gpg" shell: bash run: | mkdir -p ".github/secrets" ".github/test" @@ -186,29 +187,10 @@ jobs: if: ${{ env.RUN_TESTS == 'true' }} env: CYPRESS_BASEURL: "http://localhost:8080" + ROUTER__SERVER__WORKERS: 4 shell: bash -leuo pipefail {0} run: | - cd cypress-tests - - RED='\033[0;31m' - RESET='\033[0m' - - failed_connectors=() - - for connector in $(echo "${CONNECTORS}" | tr "," "\n"); do - echo "${connector}" - for service in "payments" "payouts"; do - if ! ROUTER__SERVER__WORKERS=4 CYPRESS_CONNECTOR="${connector}" npm run cypress:"${service}"; then - failed_connectors+=("${connector}-${service}") - fi - done - done - - if [ ${#failed_connectors[@]} -gt 0 ]; then - echo -e "${RED}One or more connectors failed to run:${RESET}" - printf '%s\n' "${failed_connectors[@]}" - exit 1 - fi + . scripts/execute_cypress.sh --parallel 3 kill "${{ env.PID }}" @@ -218,6 +200,5 @@ jobs: with: name: cypress-test-results path: | - cypress-tests/cypress/reports/*.json - cypress-tests/cypress/reports/*.html + cypress-tests/cypress/reports/ retention-days: 1 diff --git a/cypress-tests/cypress.config.js b/cypress-tests/cypress.config.js index 8e7eb77fe2a..ab71597f7fa 100644 --- a/cypress-tests/cypress.config.js +++ b/cypress-tests/cypress.config.js @@ -5,6 +5,7 @@ const path = require("path"); let globalState; // Fetch from environment variable const connectorId = process.env.CYPRESS_CONNECTOR || "service"; +const screenshotsFolderName = `screenshots/${connectorId}`; const reportName = process.env.REPORT_NAME || `${connectorId}_report`; module.exports = defineConfig({ @@ -25,36 +26,12 @@ module.exports = defineConfig({ return null; }, }); - on("after:screenshot", (details) => { - // Full path to the screenshot file - const screenshotPath = details.path; - - // Extract filename without extension - const name = path.basename( - screenshotPath, - path.extname(screenshotPath) - ); - - // Define a new name with a connectorId - const newName = `[${connectorId}] ${name}.png`; - const newPath = path.join(path.dirname(screenshotPath), newName); - - return fs - .rename(screenshotPath, newPath) - .then(() => { - console.log("Screenshot renamed successfully"); - return { path: newPath }; - }) - .catch((err) => { - console.error("Failed to rename screenshot:", err); - }); - }); }, experimentalRunAllSpecs: true, reporter: "cypress-mochawesome-reporter", reporterOptions: { - reportDir: "cypress/reports", + reportDir: `cypress/reports/${connectorId}`, reportFilename: reportName, reportPageTitle: `[${connectorId}] Cypress test report`, embeddedScreenshots: true, @@ -66,4 +43,6 @@ module.exports = defineConfig({ chromeWebSecurity: false, defaultCommandTimeout: 10000, pageLoadTimeout: 20000, + + screenshotsFolder: screenshotsFolderName, }); diff --git a/cypress-tests/readme.md b/cypress-tests/readme.md index dccb66ed0e5..fb8856ce58c 100644 --- a/cypress-tests/readme.md +++ b/cypress-tests/readme.md @@ -27,10 +27,16 @@ To run test cases, follow these steps: 2. Install Cypress and its dependencies to `cypress-tests` directory by running the following command: ```shell - npm install + npm ci ``` -3. Set environment variables for cypress +3. Insert data to `cards_info` table in `hyperswitch_db` + + ```shell + psql --host=localhost --port=5432 --username=db_user --dbname=hyperswitch_db --command "\copy cards_info FROM '.github/data/cards_info.csv' DELIMITER ',' CSV HEADER;" + ``` + +4. Set environment variables for cypress ```shell export CYPRESS_CONNECTOR="connector_id" @@ -40,7 +46,7 @@ To run test cases, follow these steps: export CYPRESS_CONNECTOR_AUTH_FILE_PATH="path/to/creds.json" ``` -4. Run Cypress test cases +5. Run Cypress test cases To run the tests in interactive mode run the following command @@ -72,6 +78,32 @@ To run test cases, follow these steps: npm run cypress:routing ``` +In order to run cypress tests against multiple connectors at a time: + +1. Set up `.env` file that exports necessary info: + + ```env + export DEBUG=cypress:cli + + export CYPRESS_ADMINAPIKEY='admin_api_key' + export CYPRESS_BASEURL='base_url' + export CYPRESS_CONNECTOR_AUTH_FILE_PATH="path/to/creds.json" + + export PAYMENTS_CONNECTORS="payment_connector_1 payment_connector_2 payment_connector_3 payment_connector_4" + export PAYOUTS_CONNECTORS="payout_connector_1 payout_connector_2 payout_connector_3" + export PAYMENT_METHOD_LIST="" + export ROUTING="" + ``` + +2. In terminal, execute: + + ```shell + source .env + scripts/execute_cypress.sh + ``` + + Optionally, `--parallel ` can be passed to run cypress tests in parallel. By default, when `parallel` command is passed, it will be run in batches of `5`. + > [!NOTE] > To learn about how creds file should be structured, refer to the [example.creds.json](#example-credsjson) section below. @@ -157,10 +189,7 @@ Cypress.Commands.add("listMandateCallTest", (globalState) => { if (xRequestId) { cy.task("cli_log", "x-request-id ->> " + xRequestId); } else { - cy.task( - "cli_log", - "x-request-id is not available in the response headers" - ); + cy.task("cli_log", "x-request-id is not available in the response headers"); } expect(response.headers["content-type"]).to.include("application/json"); console.log(response.body); diff --git a/scripts/execute_cypress.sh b/scripts/execute_cypress.sh new file mode 100755 index 00000000000..1f1219ee717 --- /dev/null +++ b/scripts/execute_cypress.sh @@ -0,0 +1,188 @@ +#! /usr/bin/env bash + +set -euo pipefail + +# Initialize tmp_file globally +tmp_file="" + +# Define arrays for services, etc. +# Read service arrays from environment variables +read -r -a payments <<< "${PAYMENTS_CONNECTORS[@]:-}" +read -r -a payouts <<< "${PAYOUTS_CONNECTORS[@]:-}" +read -r -a payment_method_list <<< "${PAYMENT_METHOD_LIST[@]:-}" +read -r -a routing <<< "${ROUTING[@]:-}" + +# Define arrays +connector_map=() +failed_connectors=() + +# Define an associative array to map environment variables to service names +declare -A services=( + ["PAYMENTS_CONNECTORS"]="payments" + ["PAYOUTS_CONNECTORS"]="payouts" + ["PAYMENT_METHOD_LIST"]="payment_method_list" + ["ROUTING"]="routing" +) + +# Function to print messages in color +function print_color() { + # Input params + local color="$1" + local message="$2" + + # Define colors + local reset='\033[0m' + local red='\033[0;31m' + local green='\033[0;32m' + local yellow='\033[0;33m' + + # Use indirect reference to get the color value + echo -e "${!color}${message}${reset}" +} +export -f print_color + +# Function to check if a command exists +function command_exists() { + command -v "$1" > /dev/null 2>&1 +} + +# Function to read service arrays from environment variables +function read_service_arrays() { + # Loop through the associative array and check if each service is exported + for var in "${!services[@]}"; do + if [[ -n "${!var+x}" ]]; then + connector_map+=("${services[$var]}") + else + print_color "yellow" "Environment variable ${var} is not set. Skipping..." + fi + done +} + +# Function to execute Cypress tests +function execute_test() { + if [[ $# -lt 3 ]]; then + print_color "red" "ERROR: Insufficient arguments provided to execute_test." + exit 1 + fi + + local connector="$1" + local service="$2" + local tmp_file="$3" + + print_color "yellow" "Executing tests for ${service} with connector ${connector}..." + + export REPORT_NAME="${service}_${connector}_report" + + if ! CYPRESS_CONNECTOR="$connector" npm run "cypress:$service"; then + echo "${service}-${connector}" >> "${tmp_file}" + fi +} +export -f execute_test + +# Function to run tests +function run_tests() { + local jobs="${1:-1}" + tmp_file=$(mktemp) + + # Ensure temporary file is removed on script exit + trap 'cleanup' EXIT + + for service in "${connector_map[@]}"; do + declare -n connectors="$service" + + if [[ ${#connectors[@]} -eq 0 ]]; then + # Service-level test (e.g., payment-method-list or routing) + [[ $service == "payment_method_list" ]] && service="payment-method-list" + + echo "Running ${service} tests without connectors..." + export REPORT_NAME="${service}_report" + + if ! npm run "cypress:${service}"; then + echo "${service}" >> "${tmp_file}" + fi + else + # Connector-specific tests (e.g., payments or payouts) + print_color "yellow" "Running tests for service: '${service}' with connectors: [${connectors[*]}] in batches of ${jobs}..." + + # Execute tests in parallel + printf '%s\n' "${connectors[@]}" | parallel --jobs "${jobs}" execute_test {} "${service}" "${tmp_file}" + fi + done + + # Collect failed connectors + if [[ -s "${tmp_file}" ]]; then + failed_connectors=($(< "${tmp_file}")) + print_color "red" "One or more connectors failed to run:" + printf '%s\n' "${failed_connectors[@]}" + exit 1 + else + print_color "green" "Cypress tests execution successful!" + fi +} + +# Function to check and install dependencies +function check_dependencies() { + # parallel and npm are mandatory dependencies. exit the script if not found. + local dependencies=("parallel" "npm") + + for cmd in "${dependencies[@]}"; do + if ! command_exists "$cmd"; then + print_color "red" "ERROR: ${cmd^} is not installed!" + exit 1 + else + print_color "green" "${cmd^} is installed already!" + + if [[ ${cmd} == "npm" ]]; then + npm ci || { + print_color "red" "Command \`npm ci\` failed!" + exit 1 + } + fi + fi + done +} + +# Cleanup function to handle exit +function cleanup() { + print_color "yellow" "Cleaning up..." + if [[ -d "cypress-tests" ]]; then + cd - + fi + + if [[ -n "${tmp_file}" && -f "${tmp_file}" ]]; then + rm -f "${tmp_file}" + fi +} + +# Main function +function main() { + local command="${1:-}" + local jobs="${2:-5}" + + # Ensure script runs from 'cypress-tests' directory + if [[ "$(basename "$PWD")" != "cypress-tests" ]]; then + print_color "yellow" "Changing directory to 'cypress-tests'..." + cd cypress-tests || { + print_color "red" "ERROR: Directory 'cypress-tests' not found!" + exit 1 + } + fi + + check_dependencies + read_service_arrays + + case "$command" in + --parallel | -p) + print_color "yellow" "WARNING: Running Cypress tests in parallel is more resource-intensive!" + # At present, parallel execution is restricted to not run out of memory + # But can be scaled up by passing the value as an argument + run_tests "$jobs" + ;; + *) + run_tests 1 + ;; + esac +} + +# Execute the main function with passed arguments +main "$@" From e5710fa084ed5b0a4969a63b14a7f8e3433a3c64 Mon Sep 17 00:00:00 2001 From: Mani Chandra <84711804+ThisIsMani@users.noreply.github.com> Date: Tue, 22 Oct 2024 15:20:43 +0530 Subject: [PATCH 02/24] refactor(permissions): Remove permissions field from permission info API response (#6376) --- crates/api_models/src/user_role.rs | 43 ------------------ .../router/src/services/authorization/info.rs | 21 +-------- .../src/services/authorization/permissions.rs | 45 ------------------- crates/router/src/utils/user_role.rs | 42 +---------------- 4 files changed, 3 insertions(+), 148 deletions(-) diff --git a/crates/api_models/src/user_role.rs b/crates/api_models/src/user_role.rs index ab32651e729..e64639646d1 100644 --- a/crates/api_models/src/user_role.rs +++ b/crates/api_models/src/user_role.rs @@ -4,42 +4,6 @@ use masking::Secret; pub mod role; -#[derive(Debug, serde::Serialize)] -pub enum Permission { - PaymentRead, - PaymentWrite, - RefundRead, - RefundWrite, - ApiKeyRead, - ApiKeyWrite, - MerchantAccountRead, - MerchantAccountWrite, - MerchantConnectorAccountRead, - MerchantConnectorAccountWrite, - RoutingRead, - RoutingWrite, - DisputeRead, - DisputeWrite, - MandateRead, - MandateWrite, - CustomerRead, - CustomerWrite, - Analytics, - ThreeDsDecisionManagerWrite, - ThreeDsDecisionManagerRead, - SurchargeDecisionManagerWrite, - SurchargeDecisionManagerRead, - UsersRead, - UsersWrite, - MerchantAccountCreate, - WebhookEventRead, - PayoutWrite, - PayoutRead, - WebhookEventWrite, - GenerateReport, - ReconAdmin, -} - #[derive(Clone, Debug, serde::Serialize, PartialEq, Eq, Hash)] pub enum ParentGroup { Operations, @@ -69,7 +33,6 @@ pub enum AuthorizationInfo { pub struct GroupInfo { pub group: PermissionGroup, pub description: &'static str, - pub permissions: Vec, } #[derive(Debug, serde::Serialize, Clone)] @@ -79,12 +42,6 @@ pub struct ParentInfo { pub groups: Vec, } -#[derive(Debug, serde::Serialize)] -pub struct PermissionInfo { - pub enum_name: Permission, - pub description: &'static str, -} - #[derive(Debug, serde::Deserialize, serde::Serialize)] pub struct UpdateUserRoleRequest { pub email: pii::Email, diff --git a/crates/router/src/services/authorization/info.rs b/crates/router/src/services/authorization/info.rs index 7cfde3efeea..031e0b56729 100644 --- a/crates/router/src/services/authorization/info.rs +++ b/crates/router/src/services/authorization/info.rs @@ -1,9 +1,7 @@ -use api_models::user_role::{GroupInfo, ParentGroup, PermissionInfo}; +use api_models::user_role::{GroupInfo, ParentGroup}; use common_enums::PermissionGroup; use strum::IntoEnumIterator; -use super::{permission_groups::get_permissions_vec, permissions::Permission}; - // TODO: To be deprecated pub fn get_group_authorization_info() -> Vec { PermissionGroup::iter() @@ -11,25 +9,10 @@ pub fn get_group_authorization_info() -> Vec { .collect() } -// TODO: To be deprecated -pub fn get_permission_info_from_permissions(permissions: &[Permission]) -> Vec { - permissions - .iter() - .map(|&per| PermissionInfo { - description: Permission::get_permission_description(&per), - enum_name: per.into(), - }) - .collect() -} - // TODO: To be deprecated fn get_group_info_from_permission_group(group: PermissionGroup) -> GroupInfo { let description = get_group_description(group); - GroupInfo { - group, - description, - permissions: get_permission_info_from_permissions(get_permissions_vec(&group)), - } + GroupInfo { group, description } } // TODO: To be deprecated diff --git a/crates/router/src/services/authorization/permissions.rs b/crates/router/src/services/authorization/permissions.rs index 2f0617557ca..2121ba0f944 100644 --- a/crates/router/src/services/authorization/permissions.rs +++ b/crates/router/src/services/authorization/permissions.rs @@ -37,48 +37,3 @@ pub enum Permission { GenerateReport, ReconAdmin, } - -impl Permission { - pub fn get_permission_description(&self) -> &'static str { - match self { - Self::PaymentRead => "View all payments", - Self::PaymentWrite => "Create payment, download payments data", - Self::RefundRead => "View all refunds", - Self::RefundWrite => "Create refund, download refunds data", - Self::ApiKeyRead => "View API keys", - Self::ApiKeyWrite => "Create and update API keys", - Self::MerchantAccountRead => "View merchant account details", - Self::MerchantAccountWrite => { - "Update merchant account details, configure webhooks, manage api keys" - } - Self::MerchantConnectorAccountRead => "View connectors configured", - Self::MerchantConnectorAccountWrite => { - "Create, update, verify and delete connector configurations" - } - Self::RoutingRead => "View routing configuration", - Self::RoutingWrite => "Create and activate routing configurations", - Self::DisputeRead => "View disputes", - Self::DisputeWrite => "Create and update disputes", - Self::MandateRead => "View mandates", - Self::MandateWrite => "Create and update mandates", - Self::CustomerRead => "View customers", - Self::CustomerWrite => "Create, update and delete customers", - Self::Analytics => "Access to analytics module", - Self::ThreeDsDecisionManagerWrite => "Create and update 3DS decision rules", - Self::ThreeDsDecisionManagerRead => { - "View all 3DS decision rules configured for a merchant" - } - Self::SurchargeDecisionManagerWrite => "Create and update the surcharge decision rules", - Self::SurchargeDecisionManagerRead => "View all the surcharge decision rules", - Self::UsersRead => "View all the users for a merchant", - Self::UsersWrite => "Invite users, assign and update roles", - Self::MerchantAccountCreate => "Create merchant account", - Self::WebhookEventRead => "View webhook events", - Self::WebhookEventWrite => "Trigger retries for webhook events", - Self::PayoutRead => "View all payouts", - Self::PayoutWrite => "Create payout, download payout data", - Self::GenerateReport => "Generate reports for payments, refunds and disputes", - Self::ReconAdmin => "View and manage reconciliation reports", - } - } -} diff --git a/crates/router/src/utils/user_role.rs b/crates/router/src/utils/user_role.rs index 0ea423989f5..6f0d94d2927 100644 --- a/crates/router/src/utils/user_role.rs +++ b/crates/router/src/utils/user_role.rs @@ -1,6 +1,5 @@ use std::{cmp, collections::HashSet}; -use api_models::user_role as user_role_api; use common_enums::{EntityType, PermissionGroup}; use common_utils::id_type; use diesel_models::{ @@ -16,49 +15,10 @@ use crate::{ core::errors::{UserErrors, UserResult}, db::user_role::{ListUserRolesByOrgIdPayload, ListUserRolesByUserIdPayload}, routes::SessionState, - services::authorization::{self as authz, permissions::Permission, roles}, + services::authorization::{self as authz, roles}, types::domain, }; -impl From for user_role_api::Permission { - fn from(value: Permission) -> Self { - match value { - Permission::PaymentRead => Self::PaymentRead, - Permission::PaymentWrite => Self::PaymentWrite, - Permission::RefundRead => Self::RefundRead, - Permission::RefundWrite => Self::RefundWrite, - Permission::ApiKeyRead => Self::ApiKeyRead, - Permission::ApiKeyWrite => Self::ApiKeyWrite, - Permission::MerchantAccountRead => Self::MerchantAccountRead, - Permission::MerchantAccountWrite => Self::MerchantAccountWrite, - Permission::MerchantConnectorAccountRead => Self::MerchantConnectorAccountRead, - Permission::MerchantConnectorAccountWrite => Self::MerchantConnectorAccountWrite, - Permission::RoutingRead => Self::RoutingRead, - Permission::RoutingWrite => Self::RoutingWrite, - Permission::DisputeRead => Self::DisputeRead, - Permission::DisputeWrite => Self::DisputeWrite, - Permission::MandateRead => Self::MandateRead, - Permission::MandateWrite => Self::MandateWrite, - Permission::CustomerRead => Self::CustomerRead, - Permission::CustomerWrite => Self::CustomerWrite, - Permission::Analytics => Self::Analytics, - Permission::ThreeDsDecisionManagerWrite => Self::ThreeDsDecisionManagerWrite, - Permission::ThreeDsDecisionManagerRead => Self::ThreeDsDecisionManagerRead, - Permission::SurchargeDecisionManagerWrite => Self::SurchargeDecisionManagerWrite, - Permission::SurchargeDecisionManagerRead => Self::SurchargeDecisionManagerRead, - Permission::UsersRead => Self::UsersRead, - Permission::UsersWrite => Self::UsersWrite, - Permission::MerchantAccountCreate => Self::MerchantAccountCreate, - Permission::WebhookEventRead => Self::WebhookEventRead, - Permission::WebhookEventWrite => Self::WebhookEventWrite, - Permission::PayoutRead => Self::PayoutRead, - Permission::PayoutWrite => Self::PayoutWrite, - Permission::GenerateReport => Self::GenerateReport, - Permission::ReconAdmin => Self::ReconAdmin, - } - } -} - pub fn validate_role_groups(groups: &[PermissionGroup]) -> UserResult<()> { if groups.is_empty() { return Err(report!(UserErrors::InvalidRoleOperation)) From 3d1a3cdc8f942a3dca2e6a200bf9200366bd62f1 Mon Sep 17 00:00:00 2001 From: Kashif Date: Tue, 22 Oct 2024 18:08:36 +0530 Subject: [PATCH 03/24] refactor(connector): [WorldPay] propagate refusal codes as error code and messages (#6392) --- crates/router/src/connector/worldpay.rs | 62 ++++++++++++++++++- .../router/src/connector/worldpay/response.rs | 4 +- .../src/connector/worldpay/transformers.rs | 55 +++++++++------- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/crates/router/src/connector/worldpay.rs b/crates/router/src/connector/worldpay.rs index 97da36f39b3..777594a4534 100644 --- a/crates/router/src/connector/worldpay.rs +++ b/crates/router/src/connector/worldpay.rs @@ -123,7 +123,7 @@ impl ConnectorCommon for Worldpay { code: response.error_name, message: response.message, reason: response.validation_errors.map(|e| e.to_string()), - attempt_status: None, + attempt_status: Some(enums::AttemptStatus::Failure), connector_transaction_id: None, }) } @@ -344,7 +344,25 @@ impl ConnectorIntegration, ) -> CustomResult { - self.build_error_response(res, event_builder) + let response = if !res.response.is_empty() { + res.response + .parse_struct("WorldpayErrorResponse") + .change_context(errors::ConnectorError::ResponseDeserializationFailed)? + } else { + WorldpayErrorResponse::default(res.status_code) + }; + + event_builder.map(|i| i.set_error_response_body(&response)); + router_env::logger::info!(connector_response=?response); + + Ok(ErrorResponse { + status_code: res.status_code, + code: response.error_name, + message: response.message, + reason: response.validation_errors.map(|e| e.to_string()), + attempt_status: None, + connector_transaction_id: None, + }) } fn handle_response( @@ -510,6 +528,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::PaymentSession for Worldpay {} @@ -622,6 +648,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::PaymentsCompleteAuthorize for Worldpay {} @@ -729,6 +763,14 @@ impl ) -> CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl api::Refund for Worldpay {} @@ -839,6 +881,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } impl ConnectorIntegration for Worldpay { @@ -909,6 +959,14 @@ impl ConnectorIntegration CustomResult { self.build_error_response(res, event_builder) } + + fn get_5xx_error_response( + &self, + res: Response, + event_builder: Option<&mut ConnectorEvent>, + ) -> CustomResult { + self.build_error_response(res, event_builder) + } } #[async_trait::async_trait] diff --git a/crates/router/src/connector/worldpay/response.rs b/crates/router/src/connector/worldpay/response.rs index edc3c26948f..c62310867f0 100644 --- a/crates/router/src/connector/worldpay/response.rs +++ b/crates/router/src/connector/worldpay/response.rs @@ -53,8 +53,8 @@ pub struct FraudHighRiskResponse { pub struct RefusedResponse { pub refusal_description: String, pub refusal_code: String, - pub risk_factors: Vec, - pub fraud: Fraud, + pub risk_factors: Option>, + pub fraud: Option, #[serde(rename = "threeDS")] pub three_ds: Option, } diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index a28d3bff7ed..be8b7737b16 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -419,13 +419,13 @@ impl ), ) -> Result { let (router_data, optional_correlation_id) = item; - let (description, redirection_data) = router_data + let (description, redirection_data, error) = router_data .response .other_fields .as_ref() .map(|other_fields| match other_fields { WorldpayPaymentResponseFields::AuthorizedResponse(res) => { - (res.description.clone(), None) + (res.description.clone(), None, None) } WorldpayPaymentResponseFields::DDCResponse(res) => ( None, @@ -444,6 +444,7 @@ impl ), ]), }), + None, ), WorldpayPaymentResponseFields::ThreeDsChallenged(res) => ( None, @@ -455,28 +456,30 @@ impl res.challenge.jwt.clone().expose(), )]), }), + None, + ), + WorldpayPaymentResponseFields::RefusedResponse(res) => ( + None, + None, + Some((res.refusal_code.clone(), res.refusal_description.clone())), ), - WorldpayPaymentResponseFields::FraudHighRisk(_) - | WorldpayPaymentResponseFields::RefusedResponse(_) => (None, None), + WorldpayPaymentResponseFields::FraudHighRisk(_) => (None, None, None), }) - .unwrap_or((None, None)); + .unwrap_or((None, None, None)); let worldpay_status = router_data.response.outcome.clone(); - let optional_reason = match worldpay_status { + let optional_error_message = match worldpay_status { PaymentOutcome::ThreeDsAuthenticationFailed => { Some("3DS authentication failed from issuer".to_string()) } PaymentOutcome::ThreeDsUnavailable => { Some("3DS authentication unavailable from issuer".to_string()) } - PaymentOutcome::FraudHighRisk => { - Some("Transaction marked as high risk by Worldpay".to_string()) - } - PaymentOutcome::Refused => Some("Transaction refused by issuer".to_string()), + PaymentOutcome::FraudHighRisk => Some("Transaction marked as high risk".to_string()), _ => None, }; let status = enums::AttemptStatus::from(worldpay_status.clone()); - let response = optional_reason.map_or( - Ok(PaymentsResponseData::TransactionResponse { + let response = match (optional_error_message, error) { + (None, None) => Ok(PaymentsResponseData::TransactionResponse { resource_id: types::ResponseId::foreign_try_from(( router_data.response, optional_correlation_id.clone(), @@ -489,17 +492,23 @@ impl incremental_authorization_allowed: None, charge_id: None, }), - |reason| { - Err(types::ErrorResponse { - code: worldpay_status.to_string(), - message: reason.clone(), - reason: Some(reason), - status_code: router_data.http_code, - attempt_status: Some(status), - connector_transaction_id: optional_correlation_id, - }) - }, - ); + (Some(reason), _) => Err(types::ErrorResponse { + code: worldpay_status.to_string(), + message: reason.clone(), + reason: Some(reason), + status_code: router_data.http_code, + attempt_status: Some(status), + connector_transaction_id: optional_correlation_id, + }), + (_, Some((code, message))) => Err(types::ErrorResponse { + code, + message: message.clone(), + reason: Some(message), + status_code: router_data.http_code, + attempt_status: Some(status), + connector_transaction_id: optional_correlation_id, + }), + }; Ok(Self { status, description, From 1ca7223b974fcebebf4f552c5fb0e0d8a562cb1f Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 23 Oct 2024 00:25:01 +0000 Subject: [PATCH 04/24] chore(version): 2024.10.23.0 --- CHANGELOG.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1b59fc7ec9..a8e4c71a87c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,21 @@ All notable changes to HyperSwitch will be documented here. - - - +## 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 From 4ef48c39b3ed7c1fcda9c850da766a0bdb701335 Mon Sep 17 00:00:00 2001 From: Sandeep Kumar <83278309+tsdk02@users.noreply.github.com> Date: Wed, 23 Oct 2024 11:54:48 +0530 Subject: [PATCH 05/24] feat(analytics): remove additional filters from PaymentIntentFilters (#6403) --- crates/analytics/src/payment_intents/core.rs | 9 -- .../analytics/src/payment_intents/filters.rs | 11 +-- .../analytics/src/payment_intents/metrics.rs | 9 -- .../metrics/payment_intent_count.rs | 9 -- .../metrics/payments_success_rate.rs | 9 -- .../payment_intent_count.rs | 9 -- .../payment_processed_amount.rs | 9 -- .../payments_distribution.rs | 9 -- .../payments_success_rate.rs | 9 -- .../smart_retried_amount.rs | 9 -- .../successful_smart_retries.rs | 9 -- .../total_smart_retries.rs | 9 -- .../metrics/smart_retried_amount.rs | 9 -- .../metrics/successful_smart_retries.rs | 9 -- .../metrics/total_smart_retries.rs | 9 -- crates/analytics/src/payment_intents/types.rs | 57 ----------- crates/analytics/src/sqlx.rs | 96 ------------------- crates/analytics/src/utils.rs | 6 -- .../src/analytics/payment_intents.rs | 67 +------------ 19 files changed, 2 insertions(+), 361 deletions(-) diff --git a/crates/analytics/src/payment_intents/core.rs b/crates/analytics/src/payment_intents/core.rs index e04c3b7bd9e..af46baed23e 100644 --- a/crates/analytics/src/payment_intents/core.rs +++ b/crates/analytics/src/payment_intents/core.rs @@ -371,15 +371,6 @@ pub async fn get_filters( PaymentIntentDimensions::PaymentIntentStatus => fil.status.map(|i| i.as_ref().to_string()), PaymentIntentDimensions::Currency => fil.currency.map(|i| i.as_ref().to_string()), PaymentIntentDimensions::ProfileId => fil.profile_id, - PaymentIntentDimensions::Connector => fil.connector, - PaymentIntentDimensions::AuthType => fil.authentication_type.map(|i| i.as_ref().to_string()), - PaymentIntentDimensions::PaymentMethod => fil.payment_method, - PaymentIntentDimensions::PaymentMethodType => fil.payment_method_type, - PaymentIntentDimensions::CardNetwork => fil.card_network, - PaymentIntentDimensions::MerchantId => fil.merchant_id, - PaymentIntentDimensions::CardLast4 => fil.card_last_4, - PaymentIntentDimensions::CardIssuer => fil.card_issuer, - PaymentIntentDimensions::ErrorReason => fil.error_reason, }) .collect::>(); res.query_data.push(PaymentIntentFilterValue { diff --git a/crates/analytics/src/payment_intents/filters.rs b/crates/analytics/src/payment_intents/filters.rs index 25d43e76f03..e81b050214c 100644 --- a/crates/analytics/src/payment_intents/filters.rs +++ b/crates/analytics/src/payment_intents/filters.rs @@ -1,6 +1,6 @@ use api_models::analytics::{payment_intents::PaymentIntentDimensions, Granularity, TimeRange}; use common_utils::errors::ReportSwitchExt; -use diesel_models::enums::{AuthenticationType, Currency, IntentStatus}; +use diesel_models::enums::{Currency, IntentStatus}; use error_stack::ResultExt; use time::PrimitiveDateTime; @@ -54,13 +54,4 @@ pub struct PaymentIntentFilterRow { pub status: Option>, pub currency: Option>, pub profile_id: Option, - pub connector: Option, - pub authentication_type: Option>, - pub payment_method: Option, - pub payment_method_type: Option, - pub card_network: Option, - pub merchant_id: Option, - pub card_last_4: Option, - pub card_issuer: Option, - pub error_reason: Option, } diff --git a/crates/analytics/src/payment_intents/metrics.rs b/crates/analytics/src/payment_intents/metrics.rs index 8ee9d24b5a0..e9d7f244306 100644 --- a/crates/analytics/src/payment_intents/metrics.rs +++ b/crates/analytics/src/payment_intents/metrics.rs @@ -34,15 +34,6 @@ pub struct PaymentIntentMetricRow { pub status: Option>, pub currency: Option>, pub profile_id: Option, - pub connector: Option, - pub authentication_type: Option>, - pub payment_method: Option, - pub payment_method_type: Option, - pub card_network: Option, - pub merchant_id: Option, - pub card_last_4: Option, - pub card_issuer: Option, - pub error_reason: Option, pub first_attempt: Option, pub total: Option, pub count: Option, diff --git a/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs b/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs index b301a9b9b23..4632cbe9f37 100644 --- a/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs +++ b/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs @@ -101,15 +101,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/payments_success_rate.rs b/crates/analytics/src/payment_intents/metrics/payments_success_rate.rs index 07b1bfcf69f..14e168b3523 100644 --- a/crates/analytics/src/payment_intents/metrics/payments_success_rate.rs +++ b/crates/analytics/src/payment_intents/metrics/payments_success_rate.rs @@ -114,15 +114,6 @@ where None, i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_intent_count.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_intent_count.rs index 7475a75bb53..644bf35a723 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_intent_count.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_intent_count.rs @@ -101,15 +101,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_processed_amount.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_processed_amount.rs index 506965375f5..e7772245063 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_processed_amount.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payment_processed_amount.rs @@ -128,15 +128,6 @@ where None, i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_distribution.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_distribution.rs index 0b55c101a7c..eed6bf85a2c 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_distribution.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_distribution.rs @@ -113,15 +113,6 @@ where None, i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_success_rate.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_success_rate.rs index 8c340d0b2d6..bd1f8bbbcd9 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_success_rate.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/payments_success_rate.rs @@ -114,15 +114,6 @@ where None, i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/smart_retried_amount.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/smart_retried_amount.rs index 8105a4c82a4..6d36aca5172 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/smart_retried_amount.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/smart_retried_amount.rs @@ -122,15 +122,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/successful_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/successful_smart_retries.rs index 0b28cb5366d..bf97e4c41ef 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/successful_smart_retries.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/successful_smart_retries.rs @@ -111,15 +111,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/total_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/total_smart_retries.rs index 20ef8be6277..cea5b2fa465 100644 --- a/crates/analytics/src/payment_intents/metrics/sessionized_metrics/total_smart_retries.rs +++ b/crates/analytics/src/payment_intents/metrics/sessionized_metrics/total_smart_retries.rs @@ -106,15 +106,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs b/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs index 8468911f7bb..b23fcafdee0 100644 --- a/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs +++ b/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs @@ -122,15 +122,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs index a19bdec518c..4fe5f3a26f5 100644 --- a/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs +++ b/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs @@ -111,15 +111,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs index f5539abd9f5..e98efa9f6ab 100644 --- a/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs +++ b/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs @@ -106,15 +106,6 @@ where i.status.as_ref().map(|i| i.0), i.currency.as_ref().map(|i| i.0), i.profile_id.clone(), - i.connector.clone(), - i.authentication_type.as_ref().map(|i| i.0), - i.payment_method.clone(), - i.payment_method_type.clone(), - i.card_network.clone(), - i.merchant_id.clone(), - i.card_last_4.clone(), - i.card_issuer.clone(), - i.error_reason.clone(), TimeRange { start_time: match (granularity, i.start_bucket) { (Some(g), Some(st)) => g.clip_to_start(st)?, diff --git a/crates/analytics/src/payment_intents/types.rs b/crates/analytics/src/payment_intents/types.rs index 1a9a2f2ed65..03f2a196c20 100644 --- a/crates/analytics/src/payment_intents/types.rs +++ b/crates/analytics/src/payment_intents/types.rs @@ -30,63 +30,6 @@ where .add_filter_in_range_clause(PaymentIntentDimensions::ProfileId, &self.profile_id) .attach_printable("Error adding profile id filter")?; } - if !self.connector.is_empty() { - builder - .add_filter_in_range_clause(PaymentIntentDimensions::Connector, &self.connector) - .attach_printable("Error adding connector filter")?; - } - if !self.auth_type.is_empty() { - builder - .add_filter_in_range_clause(PaymentIntentDimensions::AuthType, &self.auth_type) - .attach_printable("Error adding auth type filter")?; - } - if !self.payment_method.is_empty() { - builder - .add_filter_in_range_clause( - PaymentIntentDimensions::PaymentMethod, - &self.payment_method, - ) - .attach_printable("Error adding payment method filter")?; - } - if !self.payment_method_type.is_empty() { - builder - .add_filter_in_range_clause( - PaymentIntentDimensions::PaymentMethodType, - &self.payment_method_type, - ) - .attach_printable("Error adding payment method type filter")?; - } - if !self.card_network.is_empty() { - builder - .add_filter_in_range_clause( - PaymentIntentDimensions::CardNetwork, - &self.card_network, - ) - .attach_printable("Error adding card network filter")?; - } - if !self.merchant_id.is_empty() { - builder - .add_filter_in_range_clause(PaymentIntentDimensions::MerchantId, &self.merchant_id) - .attach_printable("Error adding merchant id filter")?; - } - if !self.card_last_4.is_empty() { - builder - .add_filter_in_range_clause(PaymentIntentDimensions::CardLast4, &self.card_last_4) - .attach_printable("Error adding card last 4 filter")?; - } - if !self.card_issuer.is_empty() { - builder - .add_filter_in_range_clause(PaymentIntentDimensions::CardIssuer, &self.card_issuer) - .attach_printable("Error adding card issuer filter")?; - } - if !self.error_reason.is_empty() { - builder - .add_filter_in_range_clause( - PaymentIntentDimensions::ErrorReason, - &self.error_reason, - ) - .attach_printable("Error adding error reason filter")?; - } Ok(()) } } diff --git a/crates/analytics/src/sqlx.rs b/crates/analytics/src/sqlx.rs index ae72bbeffea..89eb2ee0bde 100644 --- a/crates/analytics/src/sqlx.rs +++ b/crates/analytics/src/sqlx.rs @@ -604,45 +604,6 @@ impl<'a> FromRow<'a, PgRow> for super::payment_intents::metrics::PaymentIntentMe ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; - let connector: Option = row.try_get("connector").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let authentication_type: Option> = - row.try_get("authentication_type").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let payment_method: Option = - row.try_get("payment_method").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let payment_method_type: Option = - row.try_get("payment_method_type").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_network: Option = row.try_get("card_network").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let merchant_id: Option = row.try_get("merchant_id").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_last_4: Option = row.try_get("card_last_4").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_issuer: Option = row.try_get("card_issuer").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let error_reason: Option = row.try_get("error_reason").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; let total: Option = row.try_get("total").or_else(|e| match e { ColumnNotFound(_) => Ok(Default::default()), e => Err(e), @@ -666,15 +627,6 @@ impl<'a> FromRow<'a, PgRow> for super::payment_intents::metrics::PaymentIntentMe status, currency, profile_id, - connector, - authentication_type, - payment_method, - payment_method_type, - card_network, - merchant_id, - card_last_4, - card_issuer, - error_reason, first_attempt, total, count, @@ -700,58 +652,10 @@ impl<'a> FromRow<'a, PgRow> for super::payment_intents::filters::PaymentIntentFi ColumnNotFound(_) => Ok(Default::default()), e => Err(e), })?; - let connector: Option = row.try_get("connector").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let authentication_type: Option> = - row.try_get("authentication_type").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let payment_method: Option = - row.try_get("payment_method").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let payment_method_type: Option = - row.try_get("payment_method_type").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_network: Option = row.try_get("card_network").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let merchant_id: Option = row.try_get("merchant_id").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_last_4: Option = row.try_get("card_last_4").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let card_issuer: Option = row.try_get("card_issuer").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; - let error_reason: Option = row.try_get("error_reason").or_else(|e| match e { - ColumnNotFound(_) => Ok(Default::default()), - e => Err(e), - })?; Ok(Self { status, currency, profile_id, - connector, - authentication_type, - payment_method, - payment_method_type, - card_network, - merchant_id, - card_last_4, - card_issuer, - error_reason, }) } } diff --git a/crates/analytics/src/utils.rs b/crates/analytics/src/utils.rs index fc21bf09819..435e95451fe 100644 --- a/crates/analytics/src/utils.rs +++ b/crates/analytics/src/utils.rs @@ -35,12 +35,6 @@ pub fn get_payment_intent_dimensions() -> Vec { PaymentIntentDimensions::PaymentIntentStatus, PaymentIntentDimensions::Currency, PaymentIntentDimensions::ProfileId, - PaymentIntentDimensions::Connector, - PaymentIntentDimensions::AuthType, - PaymentIntentDimensions::PaymentMethod, - PaymentIntentDimensions::PaymentMethodType, - PaymentIntentDimensions::CardNetwork, - PaymentIntentDimensions::MerchantId, ] .into_iter() .map(Into::into) diff --git a/crates/api_models/src/analytics/payment_intents.rs b/crates/api_models/src/analytics/payment_intents.rs index 41f11c19ef8..d018437ae8c 100644 --- a/crates/api_models/src/analytics/payment_intents.rs +++ b/crates/api_models/src/analytics/payment_intents.rs @@ -6,9 +6,7 @@ use std::{ use common_utils::id_type; use super::{NameDescription, TimeRange}; -use crate::enums::{ - AuthenticationType, Connector, Currency, IntentStatus, PaymentMethod, PaymentMethodType, -}; +use crate::enums::{Currency, IntentStatus}; #[derive(Clone, Debug, Default, serde::Deserialize, serde::Serialize)] pub struct PaymentIntentFilters { @@ -18,24 +16,6 @@ pub struct PaymentIntentFilters { pub currency: Vec, #[serde(default)] pub profile_id: Vec, - #[serde(default)] - pub connector: Vec, - #[serde(default)] - pub auth_type: Vec, - #[serde(default)] - pub payment_method: Vec, - #[serde(default)] - pub payment_method_type: Vec, - #[serde(default)] - pub card_network: Vec, - #[serde(default)] - pub merchant_id: Vec, - #[serde(default)] - pub card_last_4: Vec, - #[serde(default)] - pub card_issuer: Vec, - #[serde(default)] - pub error_reason: Vec, } #[derive( @@ -60,15 +40,6 @@ pub enum PaymentIntentDimensions { PaymentIntentStatus, Currency, ProfileId, - Connector, - AuthType, - PaymentMethod, - PaymentMethodType, - CardNetwork, - MerchantId, - CardLast4, - CardIssuer, - ErrorReason, } #[derive( @@ -138,15 +109,6 @@ pub struct PaymentIntentMetricsBucketIdentifier { pub status: Option, pub currency: Option, pub profile_id: Option, - pub connector: Option, - pub auth_type: Option, - pub payment_method: Option, - pub payment_method_type: Option, - pub card_network: Option, - pub merchant_id: Option, - pub card_last_4: Option, - pub card_issuer: Option, - pub error_reason: Option, #[serde(rename = "time_range")] pub time_bucket: TimeRange, #[serde(rename = "time_bucket")] @@ -160,30 +122,12 @@ impl PaymentIntentMetricsBucketIdentifier { status: Option, currency: Option, profile_id: Option, - connector: Option, - auth_type: Option, - payment_method: Option, - payment_method_type: Option, - card_network: Option, - merchant_id: Option, - card_last_4: Option, - card_issuer: Option, - error_reason: Option, normalized_time_range: TimeRange, ) -> Self { Self { status, currency, profile_id, - connector, - auth_type, - payment_method, - payment_method_type, - card_network, - merchant_id, - card_last_4, - card_issuer, - error_reason, time_bucket: normalized_time_range, start_time: normalized_time_range.start_time, } @@ -195,15 +139,6 @@ impl Hash for PaymentIntentMetricsBucketIdentifier { self.status.map(|i| i.to_string()).hash(state); self.currency.hash(state); self.profile_id.hash(state); - self.connector.hash(state); - self.auth_type.map(|i| i.to_string()).hash(state); - self.payment_method.hash(state); - self.payment_method_type.hash(state); - self.card_network.hash(state); - self.merchant_id.hash(state); - self.card_last_4.hash(state); - self.card_issuer.hash(state); - self.error_reason.hash(state); self.time_bucket.hash(state); } } From 5a10e5867a0f3097a40c8a6868454ff06630ed2c Mon Sep 17 00:00:00 2001 From: Sai Harsha Vardhan <56996463+sai-harsha-vardhan@users.noreply.github.com> Date: Wed, 23 Oct 2024 16:53:46 +0530 Subject: [PATCH 06/24] feat(router): add api_models and openapi changes for refunds create api v2 (#6385) --- .../api-reference/refunds/refunds--create.mdx | 3 + api-reference-v2/mint.json | 6 + api-reference-v2/openapi_spec.json | 202 +++++++++++++++--- crates/api_models/src/events/refund.rs | 15 ++ crates/api_models/src/refunds.rs | 112 ++++++++++ crates/common_utils/src/events.rs | 6 + crates/common_utils/src/id_type.rs | 7 +- crates/common_utils/src/id_type/global_id.rs | 3 + .../src/id_type/global_id/refunds.rs | 71 ++++++ crates/common_utils/src/id_type/refunds.rs | 10 + crates/diesel_models/Cargo.toml | 4 +- crates/diesel_models/src/refund.rs | 1 + crates/openapi/src/openapi_v2.rs | 5 + crates/openapi/src/routes/refunds.rs | 53 +++++ .../src/events/outgoing_webhook_logs.rs | 9 +- 15 files changed, 469 insertions(+), 38 deletions(-) create mode 100644 api-reference-v2/api-reference/refunds/refunds--create.mdx create mode 100644 crates/common_utils/src/id_type/global_id/refunds.rs create mode 100644 crates/common_utils/src/id_type/refunds.rs diff --git a/api-reference-v2/api-reference/refunds/refunds--create.mdx b/api-reference-v2/api-reference/refunds/refunds--create.mdx new file mode 100644 index 00000000000..fa52f18c286 --- /dev/null +++ b/api-reference-v2/api-reference/refunds/refunds--create.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /v2/refunds +--- \ No newline at end of file diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json index 4d990aa5d40..5efdb1ed2ad 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -107,6 +107,12 @@ "api-reference/customers/customers--delete", "api-reference/customers/customers--list" ] + }, + { + "group": "Refunds", + "pages": [ + "api-reference/refunds/refunds--create" + ] } ], "footerSocials": { diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 41bda6be854..72afa1dc3da 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -1847,6 +1847,72 @@ } ] } + }, + "/v2/refunds": { + "post": { + "tags": [ + "Refunds" + ], + "summary": "Refunds - Create", + "description": "Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded", + "operationId": "Create a Refund", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefundsCreateRequest" + }, + "examples": { + "Create an instant refund to refund partial amount": { + "value": { + "amount": 654, + "merchant_reference_id": "ref_123", + "payment_id": "{{payment_id}}", + "refund_type": "instant" + } + }, + "Create an instant refund to refund the whole amount": { + "value": { + "merchant_reference_id": "ref_123", + "payment_id": "{{payment_id}}", + "refund_type": "instant" + } + }, + "Create an instant refund with reason": { + "value": { + "amount": 6540, + "merchant_reference_id": "ref_123", + "payment_id": "{{payment_id}}", + "reason": "Customer returned product", + "refund_type": "instant" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Refund created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RefundResponse" + } + } + } + }, + "400": { + "description": "Missing Mandatory fields" + } + }, + "security": [ + { + "api_key": [] + } + ] + } } }, "components": { @@ -18108,6 +18174,21 @@ } } }, + "RefundErrorDetails": { + "type": "object", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "string" + }, + "message": { + "type": "string" + } + } + }, "RefundListRequest": { "allOf": [ { @@ -18298,89 +18379,89 @@ "RefundResponse": { "type": "object", "required": [ - "refund_id", + "id", "payment_id", "amount", "currency", "status", - "connector" + "created_at", + "updated_at", + "connector", + "profile_id", + "merchant_connector_id" ], "properties": { - "refund_id": { + "id": { "type": "string", - "description": "Unique Identifier for the refund" + "description": "Global Refund Id for the refund" }, "payment_id": { "type": "string", "description": "The payment id against which refund is initiated" }, + "merchant_reference_id": { + "type": "string", + "description": "Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.", + "example": "ref_mbabizu24mvu3mela5njyhpit4", + "nullable": true, + "maxLength": 30, + "minLength": 30 + }, "amount": { "type": "integer", "format": "int64", - "description": "The refund amount, which should be less than or equal to the total payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc", + "description": "The refund amount", "example": 6540, "minimum": 100 }, "currency": { - "type": "string", - "description": "The three-letter ISO currency code" + "$ref": "#/components/schemas/Currency" }, "status": { "$ref": "#/components/schemas/RefundStatus" }, "reason": { "type": "string", - "description": "An arbitrary string attached to the object. Often useful for displaying to users and your customer support executive", + "description": "An arbitrary string attached to the object", "nullable": true }, "metadata": { "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object", - "nullable": true - }, - "error_message": { - "type": "string", - "description": "The error message", + "description": "Metadata is useful for storing additional, unstructured information on an object", "nullable": true }, - "error_code": { - "type": "string", - "description": "The code for the error", + "error_details": { + "allOf": [ + { + "$ref": "#/components/schemas/RefundErrorDetails" + } + ], "nullable": true }, "created_at": { "type": "string", "format": "date-time", - "description": "The timestamp at which refund is created", - "nullable": true + "description": "The timestamp at which refund is created" }, "updated_at": { "type": "string", "format": "date-time", - "description": "The timestamp at which refund is updated", - "nullable": true + "description": "The timestamp at which refund is updated" }, "connector": { - "type": "string", - "description": "The connector used for the refund and the corresponding payment", - "example": "stripe" + "$ref": "#/components/schemas/Connector" }, "profile_id": { "type": "string", - "description": "The id of business profile for this refund", - "nullable": true + "description": "The id of business profile for this refund" }, "merchant_connector_id": { "type": "string", - "description": "The merchant_connector_id of the processor through which this payment went through", - "nullable": true + "description": "The merchant_connector_id of the processor through which this payment went through" }, - "charges": { - "allOf": [ - { - "$ref": "#/components/schemas/ChargeRefunds" - } - ], + "connector_refund_reference_id": { + "type": "string", + "description": "The reference id of the connector for the refund", "nullable": true } } @@ -18421,6 +18502,59 @@ }, "additionalProperties": false }, + "RefundsCreateRequest": { + "type": "object", + "required": [ + "payment_id" + ], + "properties": { + "payment_id": { + "type": "string", + "description": "The payment id against which refund is initiated", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "maxLength": 30, + "minLength": 30 + }, + "merchant_reference_id": { + "type": "string", + "description": "Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment.", + "example": "ref_mbabizu24mvu3mela5njyhpit4", + "nullable": true, + "maxLength": 30, + "minLength": 30 + }, + "amount": { + "type": "integer", + "format": "int64", + "description": "Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the amount_captured of the payment", + "example": 6540, + "nullable": true, + "minimum": 100 + }, + "reason": { + "type": "string", + "description": "Reason for the refund. Often useful for displaying to users and your customer support executive.", + "example": "Customer returned the product", + "nullable": true, + "maxLength": 255 + }, + "refund_type": { + "allOf": [ + { + "$ref": "#/components/schemas/RefundType" + } + ], + "default": "Instant", + "nullable": true + }, + "metadata": { + "type": "object", + "description": "Metadata is useful for storing additional, unstructured information on an object.", + "nullable": true + } + }, + "additionalProperties": false + }, "RequestIncrementalAuthorization": { "type": "string", "enum": [ diff --git a/crates/api_models/src/events/refund.rs b/crates/api_models/src/events/refund.rs index d180753735f..e87ae154471 100644 --- a/crates/api_models/src/events/refund.rs +++ b/crates/api_models/src/events/refund.rs @@ -6,6 +6,7 @@ use crate::refunds::{ RefundUpdateRequest, RefundsRetrieveRequest, }; +#[cfg(feature = "v1")] impl ApiEventMetric for RefundRequest { fn get_api_event_type(&self) -> Option { let payment_id = self.payment_id.clone(); @@ -18,6 +19,7 @@ impl ApiEventMetric for RefundRequest { } } +#[cfg(feature = "v1")] impl ApiEventMetric for RefundResponse { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Refund { @@ -27,6 +29,17 @@ impl ApiEventMetric for RefundResponse { } } +#[cfg(feature = "v2")] +impl ApiEventMetric for RefundResponse { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Refund { + payment_id: self.payment_id.clone(), + refund_id: self.id.clone(), + }) + } +} + +#[cfg(feature = "v1")] impl ApiEventMetric for RefundsRetrieveRequest { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Refund { @@ -36,6 +49,7 @@ impl ApiEventMetric for RefundsRetrieveRequest { } } +#[cfg(feature = "v1")] impl ApiEventMetric for RefundUpdateRequest { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Refund { @@ -45,6 +59,7 @@ impl ApiEventMetric for RefundUpdateRequest { } } +#[cfg(feature = "v1")] impl ApiEventMetric for RefundManualUpdateRequest { fn get_api_event_type(&self) -> Option { Some(ApiEventsType::Refund { diff --git a/crates/api_models/src/refunds.rs b/crates/api_models/src/refunds.rs index 237a903d80c..f42eb8095b4 100644 --- a/crates/api_models/src/refunds.rs +++ b/crates/api_models/src/refunds.rs @@ -61,6 +61,45 @@ pub struct RefundRequest { pub charges: Option, } +#[cfg(feature = "v2")] +#[derive(Debug, ToSchema, Clone, Deserialize, Serialize)] +#[serde(deny_unknown_fields)] +pub struct RefundsCreateRequest { + /// The payment id against which refund is initiated + #[schema( + max_length = 30, + min_length = 30, + example = "pay_mbabizu24mvu3mela5njyhpit4", + value_type = String, + )] + pub payment_id: common_utils::id_type::GlobalPaymentId, + + /// Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment. + #[schema( + max_length = 30, + min_length = 30, + example = "ref_mbabizu24mvu3mela5njyhpit4", + value_type = Option, + )] + pub merchant_reference_id: Option, + + /// Total amount for which the refund is to be initiated. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, this will default to the amount_captured of the payment + #[schema(value_type = Option , minimum = 100, example = 6540)] + pub amount: Option, + + /// Reason for the refund. Often useful for displaying to users and your customer support executive. + #[schema(max_length = 255, example = "Customer returned the product")] + pub reason: Option, + + /// To indicate whether to refund needs to be instant or scheduled. Default value is instant + #[schema(default = "Instant", example = "Instant")] + pub refund_type: Option, + + /// Metadata is useful for storing additional, unstructured information on an object. + #[schema(value_type = Option, example = r#"{ "city": "NY", "unit": "245" }"#)] + pub metadata: Option, +} + #[derive(Default, Debug, Clone, Deserialize)] pub struct RefundsRetrieveBody { pub force_sync: Option, @@ -125,6 +164,7 @@ pub enum RefundType { Instant, } +#[cfg(feature = "v1")] #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] pub struct RefundResponse { /// Unique Identifier for the refund @@ -168,6 +208,78 @@ pub struct RefundResponse { pub charges: Option, } +#[cfg(feature = "v1")] +impl RefundResponse { + pub fn get_refund_id_as_string(&self) -> String { + self.refund_id.clone() + } +} + +#[cfg(feature = "v2")] +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] +pub struct RefundResponse { + /// Global Refund Id for the refund + #[schema(value_type = String)] + pub id: common_utils::id_type::GlobalRefundId, + /// The payment id against which refund is initiated + #[schema(value_type = String)] + pub payment_id: common_utils::id_type::GlobalPaymentId, + /// Unique Identifier for the Refund. This is to ensure idempotency for multiple partial refunds initiated against the same payment. + #[schema( + max_length = 30, + min_length = 30, + example = "ref_mbabizu24mvu3mela5njyhpit4", + value_type = Option, + )] + pub merchant_reference_id: Option, + /// The refund amount + #[schema(value_type = i64 , minimum = 100, example = 6540)] + pub amount: MinorUnit, + /// The three-letter ISO currency code + #[schema(value_type = Currency)] + pub currency: common_enums::Currency, + /// The status for refund + pub status: RefundStatus, + /// An arbitrary string attached to the object + pub reason: Option, + /// Metadata is useful for storing additional, unstructured information on an object + #[schema(value_type = Option)] + pub metadata: Option, + /// The error details for the refund + pub error_details: Option, + /// The timestamp at which refund is created + #[serde(with = "common_utils::custom_serde::iso8601")] + pub created_at: PrimitiveDateTime, + /// The timestamp at which refund is updated + #[serde(with = "common_utils::custom_serde::iso8601")] + pub updated_at: PrimitiveDateTime, + /// The connector used for the refund and the corresponding payment + #[schema(example = "stripe", value_type = Connector)] + pub connector: enums::Connector, + /// The id of business profile for this refund + #[schema(value_type = String)] + pub profile_id: common_utils::id_type::ProfileId, + /// The merchant_connector_id of the processor through which this payment went through + #[schema(value_type = String)] + pub merchant_connector_id: common_utils::id_type::MerchantConnectorAccountId, + /// The reference id of the connector for the refund + pub connector_refund_reference_id: Option, +} + +#[cfg(feature = "v2")] +impl RefundResponse { + pub fn get_refund_id_as_string(&self) -> String { + self.id.get_string_repr().to_owned() + } +} + +#[cfg(feature = "v2")] +#[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] +pub struct RefundErrorDetails { + pub code: String, + pub message: String, +} + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize, ToSchema)] pub struct RefundListRequest { /// The identifier for the payment diff --git a/crates/common_utils/src/events.rs b/crates/common_utils/src/events.rs index e30aa708979..656b2993700 100644 --- a/crates/common_utils/src/events.rs +++ b/crates/common_utils/src/events.rs @@ -23,10 +23,16 @@ pub enum ApiEventsType { Payment { payment_id: id_type::GlobalPaymentId, }, + #[cfg(feature = "v1")] Refund { payment_id: Option, refund_id: String, }, + #[cfg(feature = "v2")] + Refund { + payment_id: id_type::GlobalPaymentId, + refund_id: id_type::GlobalRefundId, + }, PaymentMethod { payment_method_id: String, payment_method: Option, diff --git a/crates/common_utils/src/id_type.rs b/crates/common_utils/src/id_type.rs index c256559fc1c..859732aed02 100644 --- a/crates/common_utils/src/id_type.rs +++ b/crates/common_utils/src/id_type.rs @@ -10,6 +10,7 @@ mod merchant_connector_account; mod organization; mod payment; mod profile; +mod refunds; mod routing; #[cfg(feature = "v2")] @@ -25,12 +26,16 @@ use diesel::{ sql_types, }; #[cfg(feature = "v2")] -pub use global_id::{payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, CellId}; +pub use global_id::{ + payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, refunds::GlobalRefundId, + CellId, +}; pub use merchant::MerchantId; pub use merchant_connector_account::MerchantConnectorAccountId; pub use organization::OrganizationId; pub use payment::{PaymentId, PaymentReferenceId}; pub use profile::ProfileId; +pub use refunds::RefundReferenceId; pub use routing::RoutingId; use serde::{Deserialize, Serialize}; use thiserror::Error; diff --git a/crates/common_utils/src/id_type/global_id.rs b/crates/common_utils/src/id_type/global_id.rs index 0709ce84d58..0032c531e47 100644 --- a/crates/common_utils/src/id_type/global_id.rs +++ b/crates/common_utils/src/id_type/global_id.rs @@ -1,6 +1,7 @@ #![allow(unused)] pub mod payment; pub mod payment_methods; +pub mod refunds; use diesel::{backend::Backend, deserialize::FromSql, serialize::ToSql, sql_types}; use error_stack::ResultExt; @@ -24,6 +25,7 @@ pub(crate) enum GlobalEntity { Customer, Payment, PaymentMethod, + Refund, } impl GlobalEntity { @@ -32,6 +34,7 @@ impl GlobalEntity { Self::Customer => "cus", Self::Payment => "pay", Self::PaymentMethod => "pm", + Self::Refund => "ref", } } } diff --git a/crates/common_utils/src/id_type/global_id/refunds.rs b/crates/common_utils/src/id_type/global_id/refunds.rs new file mode 100644 index 00000000000..64e47516114 --- /dev/null +++ b/crates/common_utils/src/id_type/global_id/refunds.rs @@ -0,0 +1,71 @@ +use error_stack::ResultExt; + +use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types}; + +/// A global id that can be used to identify a refund +#[derive( + Debug, + Clone, + Hash, + PartialEq, + Eq, + serde::Serialize, + serde::Deserialize, + diesel::expression::AsExpression, +)] +#[diesel(sql_type = diesel::sql_types::Text)] +pub struct GlobalRefundId(super::GlobalId); + +// Database related implementations so that this field can be used directly in the database tables +crate::impl_queryable_id_type!(GlobalRefundId); + +impl GlobalRefundId { + /// Get string representation of the id + pub fn get_string_repr(&self) -> &str { + self.0.get_string_repr() + } + + /// Generate a new GlobalRefundId from a cell id + pub fn generate(cell_id: crate::id_type::CellId) -> Self { + let global_id = super::GlobalId::generate(cell_id, super::GlobalEntity::Refund); + Self(global_id) + } +} + +// TODO: refactor the macro to include this id use case as well +impl TryFrom> for GlobalRefundId { + type Error = error_stack::Report; + fn try_from(value: std::borrow::Cow<'static, str>) -> Result { + use error_stack::ResultExt; + let merchant_ref_id = super::GlobalId::from_string(value).change_context( + errors::ValidationError::IncorrectValueProvided { + field_name: "refund_id", + }, + )?; + Ok(Self(merchant_ref_id)) + } +} + +// TODO: refactor the macro to include this id use case as well +impl diesel::serialize::ToSql for GlobalRefundId +where + DB: diesel::backend::Backend, + super::GlobalId: diesel::serialize::ToSql, +{ + fn to_sql<'b>( + &'b self, + out: &mut diesel::serialize::Output<'b, '_, DB>, + ) -> diesel::serialize::Result { + self.0.to_sql(out) + } +} + +impl diesel::deserialize::FromSql for GlobalRefundId +where + DB: diesel::backend::Backend, + super::GlobalId: diesel::deserialize::FromSql, +{ + fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result { + super::GlobalId::from_sql(value).map(Self) + } +} diff --git a/crates/common_utils/src/id_type/refunds.rs b/crates/common_utils/src/id_type/refunds.rs new file mode 100644 index 00000000000..478ff03380b --- /dev/null +++ b/crates/common_utils/src/id_type/refunds.rs @@ -0,0 +1,10 @@ +crate::id_type!(RefundReferenceId, "A type for refund_reference_id"); +crate::impl_id_type_methods!(RefundReferenceId, "refund_reference_id"); + +// This is to display the `RefundReferenceId` as RefundReferenceId(abcd) +crate::impl_debug_id_type!(RefundReferenceId); +crate::impl_try_from_cow_str_id_type!(RefundReferenceId, "refund_reference_id"); + +// Database related implementations so that this field can be used directly in the database tables +crate::impl_queryable_id_type!(RefundReferenceId); +crate::impl_to_sql_from_sql_id_type!(RefundReferenceId); diff --git a/crates/diesel_models/Cargo.toml b/crates/diesel_models/Cargo.toml index 02d917f3b17..120a606d58b 100644 --- a/crates/diesel_models/Cargo.toml +++ b/crates/diesel_models/Cargo.toml @@ -10,8 +10,8 @@ license.workspace = true [features] default = ["kv_store"] kv_store = [] -v1 = [] -v2 = [] +v1 = ["common_utils/v1"] +v2 = ["common_utils/v2"] customer_v2 = [] payment_methods_v2 = [] diff --git a/crates/diesel_models/src/refund.rs b/crates/diesel_models/src/refund.rs index 9e850bc9f1f..42a22b91396 100644 --- a/crates/diesel_models/src/refund.rs +++ b/crates/diesel_models/src/refund.rs @@ -317,6 +317,7 @@ pub struct RefundCoreWorkflow { pub connector_transaction_data: Option, } +#[cfg(feature = "v1")] impl common_utils::events::ApiEventMetric for Refund { fn get_api_event_type(&self) -> Option { Some(common_utils::events::ApiEventsType::Refund { diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index bf95fbe743a..7c961b2b2b2 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -123,6 +123,9 @@ Never share your secret api keys. Keep them guarded and secure. //Routes for payments routes::payments::payments_create_intent, + + //Routes for refunds + routes::refunds::refunds_create, ), components(schemas( common_utils::types::MinorUnit, @@ -140,6 +143,8 @@ Never share your secret api keys. Keep them guarded and secure. common_utils::payout_method_utils::PaypalAdditionalData, common_utils::payout_method_utils::VenmoAdditionalData, api_models::refunds::RefundRequest, + api_models::refunds::RefundsCreateRequest, + api_models::refunds::RefundErrorDetails, api_models::refunds::RefundType, api_models::refunds::RefundResponse, api_models::refunds::RefundStatus, diff --git a/crates/openapi/src/routes/refunds.rs b/crates/openapi/src/routes/refunds.rs index 5c72fe8b48f..4e096e243a8 100644 --- a/crates/openapi/src/routes/refunds.rs +++ b/crates/openapi/src/routes/refunds.rs @@ -44,6 +44,7 @@ operation_id = "Create a Refund", security(("api_key" = [])) )] +#[cfg(feature = "v1")] pub async fn refunds_create() {} /// Refunds - Retrieve @@ -159,3 +160,55 @@ pub fn refunds_list_profile() {} security(("api_key" = [])) )] pub async fn refunds_filter_list() {} + +/// Refunds - Create +/// +/// Creates a refund against an already processed payment. In case of some processors, you can even opt to refund only a partial amount multiple times until the original charge amount has been refunded +#[utoipa::path( + post, + path = "/v2/refunds", + request_body( + content = RefundsCreateRequest, + examples( + ( + "Create an instant refund to refund the whole amount" = ( + value = json!({ + "payment_id": "{{payment_id}}", + "merchant_reference_id": "ref_123", + "refund_type": "instant" + }) + ) + ), + ( + "Create an instant refund to refund partial amount" = ( + value = json!({ + "payment_id": "{{payment_id}}", + "merchant_reference_id": "ref_123", + "refund_type": "instant", + "amount": 654 + }) + ) + ), + ( + "Create an instant refund with reason" = ( + value = json!({ + "payment_id": "{{payment_id}}", + "merchant_reference_id": "ref_123", + "refund_type": "instant", + "amount": 6540, + "reason": "Customer returned product" + }) + ) + ), + ) + ), + responses( + (status = 200, description = "Refund created", body = RefundResponse), + (status = 400, description = "Missing Mandatory fields") + ), + tag = "Refunds", + operation_id = "Create a Refund", + security(("api_key" = [])) +)] +#[cfg(feature = "v2")] +pub async fn refunds_create() {} diff --git a/crates/router/src/events/outgoing_webhook_logs.rs b/crates/router/src/events/outgoing_webhook_logs.rs index b2a8202e0e6..db5a40fc6ea 100644 --- a/crates/router/src/events/outgoing_webhook_logs.rs +++ b/crates/router/src/events/outgoing_webhook_logs.rs @@ -34,11 +34,18 @@ pub enum OutgoingWebhookEventContent { payout_id: String, content: Value, }, + #[cfg(feature = "v1")] Refund { payment_id: common_utils::id_type::PaymentId, refund_id: String, content: Value, }, + #[cfg(feature = "v2")] + Refund { + payment_id: common_utils::id_type::GlobalPaymentId, + refund_id: String, + content: Value, + }, Dispute { payment_id: common_utils::id_type::PaymentId, attempt_id: String, @@ -64,7 +71,7 @@ impl OutgoingWebhookEventMetric for OutgoingWebhookContent { }), Self::RefundDetails(refund_payload) => Some(OutgoingWebhookEventContent::Refund { payment_id: refund_payload.payment_id.clone(), - refund_id: refund_payload.refund_id.clone(), + refund_id: refund_payload.get_refund_id_as_string(), content: masking::masked_serialize(&refund_payload) .unwrap_or(serde_json::json!({"error":"failed to serialize"})), }), From af0aeeea53014d8fe5c955cbad3fe8b371c44889 Mon Sep 17 00:00:00 2001 From: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:36:33 +0530 Subject: [PATCH 07/24] fix(connector_config): include the `payment_processing_details_at` `Hyperswitch` option only if apple pay token decryption flow is supported for the connector (#6386) --- .../connector_configs/toml/development.toml | 24 +++++++++---------- crates/connector_configs/toml/production.toml | 18 +++++++------- crates/connector_configs/toml/sandbox.toml | 24 +++++++++---------- 3 files changed, 33 insertions(+), 33 deletions(-) diff --git a/crates/connector_configs/toml/development.toml b/crates/connector_configs/toml/development.toml index 78f3c627fca..180aadffde3 100644 --- a/crates/connector_configs/toml/development.toml +++ b/crates/connector_configs/toml/development.toml @@ -281,7 +281,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[adyen.metadata.google_pay]] name="merchant_name" @@ -484,7 +484,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[authorizedotnet.metadata.google_pay]] name="merchant_name" @@ -813,7 +813,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[bluesnap.metadata.google_pay]] name="merchant_name" @@ -1115,7 +1115,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[checkout.metadata.google_pay]] name="merchant_name" @@ -1941,7 +1941,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [nexixpay] [[nexixpay.credit]] @@ -2062,7 +2062,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[nmi.metadata.google_pay]] name="merchant_name" @@ -2202,7 +2202,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[noon.metadata.google_pay]] name="merchant_name" @@ -2379,7 +2379,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[nuvei.metadata.google_pay]] name="merchant_name" @@ -2839,7 +2839,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [shift4] [[shift4.credit]] @@ -3244,7 +3244,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[trustpay.metadata.google_pay]] name="merchant_name" @@ -3473,7 +3473,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[worldpay.metadata.google_pay]] name="merchant_name" @@ -4196,7 +4196,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Hyperswitch"] [fiuu.connector_webhook_details] merchant_secret="Source verification key" \ No newline at end of file diff --git a/crates/connector_configs/toml/production.toml b/crates/connector_configs/toml/production.toml index 9ca992ecad4..c7849fcc227 100644 --- a/crates/connector_configs/toml/production.toml +++ b/crates/connector_configs/toml/production.toml @@ -188,7 +188,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[adyen.metadata.google_pay]] name="merchant_name" @@ -352,7 +352,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[authorizedotnet.metadata.google_pay]] name="merchant_name" @@ -477,7 +477,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[bluesnap.metadata.google_pay]] name="merchant_name" @@ -970,7 +970,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[checkout.metadata.google_pay]] name="merchant_name" @@ -1680,7 +1680,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [nexixpay] [[nexixpay.credit]] @@ -2054,7 +2054,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [shift4] [[shift4.credit]] @@ -2359,7 +2359,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[trustpay.metadata.google_pay]] name="merchant_name" @@ -2529,7 +2529,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[worldpay.metadata.google_pay]] name="merchant_name" @@ -3191,7 +3191,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Hyperswitch"] [fiuu.connector_webhook_details] merchant_secret="Source verification key" \ No newline at end of file diff --git a/crates/connector_configs/toml/sandbox.toml b/crates/connector_configs/toml/sandbox.toml index 39421babc87..2a753008e81 100644 --- a/crates/connector_configs/toml/sandbox.toml +++ b/crates/connector_configs/toml/sandbox.toml @@ -280,7 +280,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[adyen.metadata.google_pay]] name="merchant_name" @@ -488,7 +488,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[authorizedotnet.metadata.google_pay]] name="merchant_name" @@ -814,7 +814,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[bluesnap.metadata.google_pay]] name="merchant_name" @@ -1115,7 +1115,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[checkout.metadata.google_pay]] name="merchant_name" @@ -1939,7 +1939,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [nexixpay] [[nexixpay.credit]] @@ -2059,7 +2059,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[nmi.metadata.google_pay]] name="merchant_name" @@ -2198,7 +2198,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[noon.metadata.google_pay]] name="merchant_name" @@ -2374,7 +2374,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[nuvei.metadata.google_pay]] name="merchant_name" @@ -2832,7 +2832,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [shift4] [[shift4.credit]] @@ -3235,7 +3235,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[trustpay.metadata.google_pay]] name="merchant_name" @@ -3462,7 +3462,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Connector"] [[worldpay.metadata.google_pay]] name="merchant_name" @@ -4190,7 +4190,7 @@ label="Payment Processing Details At" placeholder="Enter Payment Processing Details At" required=true type="Radio" -options=["Connector","Hyperswitch"] +options=["Hyperswitch"] [fiuu.connector_webhook_details] merchant_secret="Source verification key" \ No newline at end of file From 829a20cc933267551e49565d06eb08e03e5f13bb Mon Sep 17 00:00:00 2001 From: spritianeja03 <146620839+spritianeja03@users.noreply.github.com> Date: Wed, 23 Oct 2024 17:56:24 +0530 Subject: [PATCH 08/24] refactor(connector): Move connectors Forte, Nexinets, Payeezy, Payu and Zen from Router to Hyperswitch Connector Trait (#6261) Co-authored-by: Spriti Aneja Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> --- Cargo.lock | 1 + crates/common_utils/src/consts.rs | 4 + crates/hyperswitch_connectors/Cargo.toml | 1 + .../hyperswitch_connectors/src/connectors.rs | 12 +- .../src/connectors}/forte.rs | 323 +++++++------ .../src/connectors}/forte/transformers.rs | 144 +++--- .../src/connectors}/nexinets.rs | 371 ++++++++------- .../src/connectors}/nexinets/transformers.rs | 302 ++++++------- .../src/connectors}/payeezy.rs | 308 ++++++------- .../src/connectors}/payeezy/transformers.rs | 300 ++++++------ .../src/connectors}/payu.rs | 425 ++++++++--------- .../src/connectors}/payu/transformers.rs | 128 +++--- .../src/connectors}/zen.rs | 356 +++++++-------- .../src/connectors}/zen/transformers.rs | 427 +++++++++--------- .../hyperswitch_connectors/src/constants.rs | 3 + .../src/default_implementations.rs | 210 +++++++-- .../src/default_implementations_v2.rs | 154 ++++++- crates/hyperswitch_connectors/src/utils.rs | 98 ++++ crates/router/src/connector.rs | 28 +- .../connector_integration_v2_impls.rs | 110 ----- crates/router/src/core/payments/flows.rs | 154 ------- 21 files changed, 1912 insertions(+), 1947 deletions(-) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/forte.rs (69%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/forte/transformers.rs (79%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/nexinets.rs (65%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/nexinets/transformers.rs (67%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/payeezy.rs (63%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/payeezy/transformers.rs (57%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/payu.rs (61%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/payu/transformers.rs (82%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/zen.rs (64%) rename crates/{router/src/connector => hyperswitch_connectors/src/connectors}/zen/transformers.rs (71%) diff --git a/Cargo.lock b/Cargo.lock index 347d4e58797..9ccedba3c39 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3997,6 +3997,7 @@ dependencies = [ "hyperswitch_interfaces", "image", "masking", + "mime", "once_cell", "qrcode", "rand", diff --git a/crates/common_utils/src/consts.rs b/crates/common_utils/src/consts.rs index 21e5866aea0..5fc2fea9c8b 100644 --- a/crates/common_utils/src/consts.rs +++ b/crates/common_utils/src/consts.rs @@ -118,6 +118,10 @@ pub const CELL_IDENTIFIER_LENGTH: u8 = 5; /// General purpose base64 engine pub const BASE64_ENGINE: base64::engine::GeneralPurpose = base64::engine::general_purpose::STANDARD; + +/// URL Safe base64 engine +pub const BASE64_ENGINE_URL_SAFE: base64::engine::GeneralPurpose = + base64::engine::general_purpose::URL_SAFE; /// Regex for matching a domain /// Eg - /// http://www.example.com diff --git a/crates/hyperswitch_connectors/Cargo.toml b/crates/hyperswitch_connectors/Cargo.toml index 2676f637223..86d6da446ee 100644 --- a/crates/hyperswitch_connectors/Cargo.toml +++ b/crates/hyperswitch_connectors/Cargo.toml @@ -20,6 +20,7 @@ error-stack = "0.4.1" hex = "0.4.3" http = "0.2.12" image = { version = "0.25.1", default-features = false, features = ["png"] } +mime = "0.3.17" once_cell = "1.19.0" qrcode = "0.14.0" rand = "0.8.5" diff --git a/crates/hyperswitch_connectors/src/connectors.rs b/crates/hyperswitch_connectors/src/connectors.rs index ddd9fa861a6..3e8857e8d31 100644 --- a/crates/hyperswitch_connectors/src/connectors.rs +++ b/crates/hyperswitch_connectors/src/connectors.rs @@ -10,11 +10,15 @@ pub mod dlocal; pub mod fiserv; pub mod fiservemea; pub mod fiuu; +pub mod forte; pub mod globepay; pub mod helcim; pub mod mollie; +pub mod nexinets; pub mod nexixpay; pub mod novalnet; +pub mod payeezy; +pub mod payu; pub mod powertranz; pub mod square; pub mod stax; @@ -23,12 +27,14 @@ pub mod thunes; pub mod tsys; pub mod volt; pub mod worldline; +pub mod zen; pub use self::{ bambora::Bambora, billwerk::Billwerk, bitpay::Bitpay, cashtocode::Cashtocode, coinbase::Coinbase, cryptopay::Cryptopay, deutschebank::Deutschebank, digitalvirgo::Digitalvirgo, dlocal::Dlocal, fiserv::Fiserv, fiservemea::Fiservemea, fiuu::Fiuu, - globepay::Globepay, helcim::Helcim, mollie::Mollie, nexixpay::Nexixpay, novalnet::Novalnet, - powertranz::Powertranz, square::Square, stax::Stax, taxjar::Taxjar, thunes::Thunes, tsys::Tsys, - volt::Volt, worldline::Worldline, + forte::Forte, globepay::Globepay, helcim::Helcim, mollie::Mollie, nexinets::Nexinets, + nexixpay::Nexixpay, novalnet::Novalnet, payeezy::Payeezy, payu::Payu, powertranz::Powertranz, + square::Square, stax::Stax, taxjar::Taxjar, thunes::Thunes, tsys::Tsys, volt::Volt, + worldline::Worldline, zen::Zen, }; diff --git a/crates/router/src/connector/forte.rs b/crates/hyperswitch_connectors/src/connectors/forte.rs similarity index 69% rename from crates/router/src/connector/forte.rs rename to crates/hyperswitch_connectors/src/connectors/forte.rs index 5ffa3a589c3..fd5c7792887 100644 --- a/crates/router/src/connector/forte.rs +++ b/crates/hyperswitch_connectors/src/connectors/forte.rs @@ -1,38 +1,55 @@ pub mod transformers; +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; use base64::Engine; +use common_enums::enums; use common_utils::{ - request::RequestContent, + consts::BASE64_ENGINE, + errors::CustomResult, + ext_traits::BytesExt, + request::{Method, Request, RequestBuilder, RequestContent}, types::{AmountConvertor, FloatMajorUnit, FloatMajorUnitForConnector}, }; -use diesel_models::enums; use error_stack::{report, ResultExt}; -use masking::PeekInterface; -use transformers as forte; - -use super::utils::convert_amount; -use crate::{ - configs::settings, - connector::{ - utils as connector_utils, - utils::{PaymentsSyncRequestData, RefundsRequestData}, +use hyperswitch_domain_models::{ + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, }, - consts, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, Response, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + consts::NO_ERROR_CODE, + errors, + events::connector_api_logs::ConnectorEvent, + types::{self, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface}; +use transformers as forte; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{ + construct_not_supported_error_report, convert_amount, PaymentsSyncRequestData, + RefundsRequestData, }, - utils::BytesExt, }; + #[derive(Clone)] pub struct Forte { amount_converter: &'static (dyn AmountConvertor + Sync), @@ -59,12 +76,8 @@ impl api::RefundExecute for Forte {} impl api::RefundSync for Forte {} impl api::PaymentToken for Forte {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Forte +impl ConnectorIntegration + for Forte { } pub const AUTH_ORG_ID_HEADER: &str = "X-Forte-Auth-Organization-Id"; @@ -75,9 +88,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let content_type = ConnectorCommon::common_get_content_type(self); let mut common_headers = self.get_auth_header(&req.connector_auth_type)?; common_headers.push(( @@ -97,14 +110,14 @@ impl ConnectorCommon for Forte { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.forte.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = forte::ForteAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; let raw_basic_token = format!( @@ -112,7 +125,7 @@ impl ConnectorCommon for Forte { auth.api_access_id.peek(), auth.api_secret_key.peek() ); - let basic_token = format!("Basic {}", consts::BASE64_ENGINE.encode(raw_basic_token)); + let basic_token = format!("Basic {}", BASE64_ENGINE.encode(raw_basic_token)); Ok(vec![ ( headers::AUTHORIZATION.to_string(), @@ -141,7 +154,7 @@ impl ConnectorCommon for Forte { let code = response .response .response_code - .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()); + .unwrap_or_else(|| NO_ERROR_CODE.to_string()); Ok(ErrorResponse { status_code: res.status_code, code, @@ -163,38 +176,22 @@ impl ConnectorValidation for Forte { match capture_method { enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_supported_error_report(capture_method, self.id()), + construct_not_supported_error_report(capture_method, self.id()), ), } } } -impl ConnectorIntegration - for Forte -{ -} +impl ConnectorIntegration for Forte {} -impl ConnectorIntegration - for Forte -{ -} +impl ConnectorIntegration for Forte {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Forte -{ +impl ConnectorIntegration for Forte { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Forte".to_string()) .into(), @@ -202,14 +199,12 @@ impl } } -impl ConnectorIntegration - for Forte -{ +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -219,8 +214,8 @@ impl ConnectorIntegration CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; Ok(format!( @@ -233,8 +228,8 @@ impl ConnectorIntegration CustomResult { let amount = convert_amount( self.amount_converter, @@ -249,12 +244,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .url(&types::PaymentsAuthorizeType::get_url( self, req, connectors, )?) @@ -271,10 +266,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: forte::FortePaymentsResponse = res .response .parse_struct("Forte AuthorizeResponse") @@ -283,7 +278,7 @@ impl ConnectorIntegration - for Forte -{ +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -316,8 +309,8 @@ impl ConnectorIntegration CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; let txn_id = PaymentsSyncRequestData::get_connector_transaction_id(&req.request) @@ -333,12 +326,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) @@ -347,10 +340,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: forte::FortePaymentsSyncResponse = res .response .parse_struct("forte PaymentsSyncResponse") @@ -359,7 +352,7 @@ impl ConnectorIntegration - for Forte -{ +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -392,8 +383,8 @@ impl ConnectorIntegration CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; Ok(format!( @@ -406,8 +397,8 @@ impl ConnectorIntegration CustomResult { let connector_req = forte::ForteCaptureRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -415,12 +406,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Put) + RequestBuilder::new() + .method(Method::Put) .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsCaptureType::get_headers( @@ -435,10 +426,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: forte::ForteCaptureResponse = res .response .parse_struct("Forte PaymentsCaptureResponse") @@ -447,7 +438,7 @@ impl ConnectorIntegration - for Forte -{ +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -479,8 +468,8 @@ impl ConnectorIntegration CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; Ok(format!( @@ -493,8 +482,8 @@ impl ConnectorIntegration CustomResult { let connector_req = forte::ForteCancelRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -502,12 +491,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Put) + RequestBuilder::new() + .method(Method::Put) .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) @@ -520,10 +509,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: forte::ForteCancelResponse = res .response .parse_struct("forte CancelResponse") @@ -532,7 +521,7 @@ impl ConnectorIntegration for Forte { +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -563,8 +552,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; Ok(format!( @@ -577,8 +566,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let refund_amount = convert_amount( self.amount_converter, @@ -593,11 +582,11 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) .url(&types::RefundExecuteType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundExecuteType::get_headers( @@ -612,10 +601,10 @@ impl ConnectorIntegration, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: forte::RefundResponse = res .response .parse_struct("forte RefundResponse") @@ -624,7 +613,7 @@ impl ConnectorIntegration for Forte { +impl ConnectorIntegration for Forte { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -655,8 +644,8 @@ impl ConnectorIntegration CustomResult { let auth: forte::ForteAuthType = forte::ForteAuthType::try_from(&req.connector_auth_type)?; Ok(format!( @@ -670,12 +659,12 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) + RequestBuilder::new() + .method(Method::Get) .url(&types::RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() .headers(types::RefundSyncType::get_headers(self, req, connectors)?) @@ -685,10 +674,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: forte::RefundSyncResponse = res .response .parse_struct("forte RefundSyncResponse") @@ -697,7 +686,7 @@ impl ConnectorIntegration, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { - Ok(api::IncomingWebhookEvent::EventNotSupported) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Ok(IncomingWebhookEvent::EventNotSupported) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } diff --git a/crates/router/src/connector/forte/transformers.rs b/crates/hyperswitch_connectors/src/connectors/forte/transformers.rs similarity index 79% rename from crates/router/src/connector/forte/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/forte/transformers.rs index 79b90d685ee..d04ea7bfee4 100644 --- a/crates/router/src/connector/forte/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/forte/transformers.rs @@ -1,14 +1,24 @@ use cards::CardNumber; +use common_enums::enums; use common_utils::types::FloatMajorUnit; +use hyperswitch_domain_models::{ + payment_method_data::PaymentMethodData, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::errors; use masking::{PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::{ - self, AddressDetailsData, CardData, PaymentsAuthorizeRequestData, RouterData, + types::{PaymentsCaptureResponseRouterData, RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, AddressDetailsData, CardData as _PaymentsAuthorizeRequestData, + PaymentsAuthorizeRequestData, RouterData as _, }, - core::errors, - types::{self, api, domain, storage::enums, transformers::ForeignFrom}, }; #[derive(Debug, Serialize)] @@ -90,7 +100,7 @@ impl TryFrom<&ForteRouterData<&types::PaymentsAuthorizeRouterData>> for FortePay ))? } match item.request.payment_method_data { - domain::PaymentMethodData::Card(ref ccard) => { + PaymentMethodData::Card(ref ccard) => { let action = match item.request.is_auto_capture()? { true => ForteAction::Sale, false => ForteAction::Authorize, @@ -120,23 +130,23 @@ impl TryFrom<&ForteRouterData<&types::PaymentsAuthorizeRouterData>> for FortePay card, }) } - domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment {} - | domain::PaymentMethodData::Reward {} - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment {} + | PaymentMethodData::Reward {} + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Forte"), ))? @@ -153,11 +163,11 @@ pub struct ForteAuthType { pub(super) api_secret_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for ForteAuthType { +impl TryFrom<&ConnectorAuthType> for ForteAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::MultiAuthKey { + ConnectorAuthType::MultiAuthKey { api_key, key1, api_secret, @@ -196,17 +206,15 @@ impl From for enums::AttemptStatus { } } -impl ForeignFrom<(ForteResponseCode, ForteAction)> for enums::AttemptStatus { - fn foreign_from((response_code, action): (ForteResponseCode, ForteAction)) -> Self { - match response_code { - ForteResponseCode::A01 => match action { - ForteAction::Authorize => Self::Authorized, - ForteAction::Sale => Self::Pending, - ForteAction::Verify => Self::Charged, - }, - ForteResponseCode::A05 | ForteResponseCode::A06 => Self::Authorizing, - _ => Self::Failure, - } +fn get_status(response_code: ForteResponseCode, action: ForteAction) -> enums::AttemptStatus { + match response_code { + ForteResponseCode::A01 => match action { + ForteAction::Authorize => enums::AttemptStatus::Authorized, + ForteAction::Sale => enums::AttemptStatus::Pending, + ForteAction::Verify => enums::AttemptStatus::Charged, + }, + ForteResponseCode::A05 | ForteResponseCode::A06 => enums::AttemptStatus::Authorizing, + _ => enums::AttemptStatus::Failure, } } @@ -277,21 +285,20 @@ pub struct ForteMeta { pub auth_id: String, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let response_code = item.response.response.response_code; let action = item.response.action; let transaction_id = &item.response.transaction_id; Ok(Self { - status: enums::AttemptStatus::foreign_from((response_code, action)), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(transaction_id.to_string()), + status: get_status(response_code, action), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), redirection_data: None, mandate_reference: None, connector_metadata: Some(serde_json::json!(ForteMeta { @@ -323,24 +330,18 @@ pub struct FortePaymentsSyncResponse { pub response: ResponseStatus, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - FortePaymentsSyncResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let transaction_id = &item.response.transaction_id; Ok(Self { status: enums::AttemptStatus::from(item.response.status), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(transaction_id.to_string()), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), redirection_data: None, mandate_reference: None, connector_metadata: Some(serde_json::json!(ForteMeta { @@ -398,18 +399,18 @@ pub struct ForteCaptureResponse { pub response: CaptureResponseStatus, } -impl TryFrom> +impl TryFrom> for types::PaymentsCaptureRouterData { type Error = error_stack::Report; fn try_from( - item: types::PaymentsCaptureResponseRouterData, + item: PaymentsCaptureResponseRouterData, ) -> Result { let transaction_id = &item.response.transaction_id; Ok(Self { status: enums::AttemptStatus::from(item.response.response.response_code), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(transaction_id.clone()), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.clone()), redirection_data: None, mandate_reference: None, connector_metadata: Some(serde_json::json!(ForteMeta { @@ -466,19 +467,18 @@ pub struct ForteCancelResponse { pub response: CancelResponseStatus, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let transaction_id = &item.response.transaction_id; Ok(Self { status: enums::AttemptStatus::from(item.response.response.response_code), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(transaction_id.to_string()), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(transaction_id.to_string()), redirection_data: None, mandate_reference: None, connector_metadata: Some(serde_json::json!(ForteMeta { @@ -561,15 +561,15 @@ pub struct RefundResponse { pub response: ResponseStatus, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id, refund_status: enums::RefundStatus::from(item.response.response.response_code), }), @@ -584,15 +584,15 @@ pub struct RefundSyncResponse { transaction_id: String, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id, refund_status: enums::RefundStatus::from(item.response.status), }), diff --git a/crates/router/src/connector/nexinets.rs b/crates/hyperswitch_connectors/src/connectors/nexinets.rs similarity index 65% rename from crates/router/src/connector/nexinets.rs rename to crates/hyperswitch_connectors/src/connectors/nexinets.rs index 113b2924fec..902afe34134 100644 --- a/crates/router/src/connector/nexinets.rs +++ b/crates/hyperswitch_connectors/src/connectors/nexinets.rs @@ -1,32 +1,53 @@ pub mod transformers; -use std::fmt::Debug; - -use common_utils::request::RequestContent; +use api_models::webhooks::{IncomingWebhookEvent, ObjectReferenceId}; +use common_enums::enums; +use common_utils::{ + errors::CustomResult, + ext_traits::ByteSliceExt, + request::{Method, Request, RequestBuilder, RequestContent}, +}; use error_stack::{report, ResultExt}; -use transformers as nexinets; - -use crate::{ - configs::settings, - connector::{ - utils as connector_utils, - utils::{to_connector_meta, PaymentMethodDataType, PaymentsSyncRequestData}, +use hyperswitch_domain_models::{ + payment_method_data::PaymentMethodData, + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, }, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, + }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types::{ + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, }, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - storage::enums, - ErrorResponse, Response, + PaymentsAuthorizeType, PaymentsCaptureType, PaymentsSyncType, PaymentsVoidType, + RefundExecuteType, RefundSyncType, Response, + }, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::Mask; +use transformers as nexinets; + +use crate::{ + constants::headers, + types::ResponseRouterData, + utils::{ + construct_not_implemented_error_report, is_mandate_supported, to_connector_meta, + PaymentMethodDataType, PaymentsSyncRequestData, }, - utils::BytesExt, }; #[derive(Debug, Clone)] @@ -60,9 +81,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut header = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -82,14 +103,14 @@ impl ConnectorCommon for Nexinets { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.nexinets.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = nexinets::NexinetsAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -152,7 +173,7 @@ impl ConnectorValidation for Nexinets { match capture_method { enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_implemented_error_report(capture_method, self.id()), + construct_not_implemented_error_report(capture_method, self.id()), ), } } @@ -160,7 +181,7 @@ impl ConnectorValidation for Nexinets { fn validate_mandate_payment( &self, pm_type: Option, - pm_data: types::domain::payments::PaymentMethodData, + pm_data: PaymentMethodData, ) -> CustomResult<(), errors::ConnectorError> { let mandate_supported_pmd = std::collections::HashSet::from([ PaymentMethodDataType::Card, @@ -170,36 +191,22 @@ impl ConnectorValidation for Nexinets { PaymentMethodDataType::Giropay, PaymentMethodDataType::Ideal, ]); - connector_utils::is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) + is_mandate_supported(pm_data, pm_type, mandate_supported_pmd, self.id()) } } -impl ConnectorIntegration - for Nexinets -{ -} +impl ConnectorIntegration for Nexinets {} -impl ConnectorIntegration - for Nexinets -{ -} +impl ConnectorIntegration for Nexinets {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Nexinets +impl ConnectorIntegration + for Nexinets { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Nexinets".to_string()) .into(), @@ -207,14 +214,12 @@ impl } } -impl ConnectorIntegration - for Nexinets -{ +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -224,8 +229,8 @@ impl ConnectorIntegration CustomResult { let url = if req.request.capture_method == Some(enums::CaptureMethod::Automatic) { format!("{}/orders/debit", self.base_url(connectors)) @@ -237,8 +242,8 @@ impl ConnectorIntegration CustomResult { let connector_req = nexinets::NexinetsPaymentsRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -246,20 +251,16 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsAuthorizeType::get_url( - self, req, connectors, - )?) + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsAuthorizeType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsAuthorizeType::get_request_body( + .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?) + .set_body(PaymentsAuthorizeType::get_request_body( self, req, connectors, )?) .build(), @@ -268,10 +269,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: nexinets::NexinetsPreAuthOrDebitResponse = res .response .parse_struct("Nexinets PaymentsAuthorizeResponse") @@ -280,7 +281,7 @@ impl ConnectorIntegration - for Nexinets -{ +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -313,8 +312,8 @@ impl ConnectorIntegration CustomResult { let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(req.request.connector_meta.clone())?; @@ -334,25 +333,25 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .headers(PaymentsSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::PaymentsSyncRouterData, + data: &PaymentsSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: nexinets::NexinetsPaymentResponse = res .response .parse_struct("nexinets NexinetsPaymentResponse") @@ -361,7 +360,7 @@ impl ConnectorIntegration - for Nexinets -{ +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -394,8 +391,8 @@ impl ConnectorIntegration CustomResult { let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(req.request.connector_meta.clone())?; @@ -409,8 +406,8 @@ impl ConnectorIntegration CustomResult { let connector_req = nexinets::NexinetsCaptureOrVoidRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -418,18 +415,16 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsCaptureType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsCaptureType::get_request_body( + .headers(PaymentsCaptureType::get_headers(self, req, connectors)?) + .set_body(PaymentsCaptureType::get_request_body( self, req, connectors, )?) .build(), @@ -438,10 +433,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: nexinets::NexinetsPaymentResponse = res .response .parse_struct("NexinetsPaymentResponse") @@ -450,7 +445,7 @@ impl ConnectorIntegration - for Nexinets -{ +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -483,8 +476,8 @@ impl ConnectorIntegration CustomResult { let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(req.request.connector_meta.clone())?; @@ -498,8 +491,8 @@ impl ConnectorIntegration CustomResult { let connector_req = nexinets::NexinetsCaptureOrVoidRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -507,16 +500,14 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) - .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) - .set_body(types::PaymentsVoidType::get_request_body( - self, req, connectors, - )?) + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsVoidType::get_url(self, req, connectors)?) + .headers(PaymentsVoidType::get_headers(self, req, connectors)?) + .set_body(PaymentsVoidType::get_request_body(self, req, connectors)?) .build(); Ok(Some(request)) @@ -524,10 +515,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: nexinets::NexinetsPaymentResponse = res .response .parse_struct("NexinetsPaymentResponse") @@ -536,7 +527,7 @@ impl ConnectorIntegration - for Nexinets -{ +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -569,8 +558,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(req.request.connector_metadata.clone())?; @@ -584,8 +573,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_req = nexinets::NexinetsRefundRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -593,29 +582,25 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::RefundExecuteType::get_url(self, req, connectors)?) + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&RefundExecuteType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundExecuteType::get_headers( - self, req, connectors, - )?) - .set_body(types::RefundExecuteType::get_request_body( - self, req, connectors, - )?) + .headers(RefundExecuteType::get_headers(self, req, connectors)?) + .set_body(RefundExecuteType::get_request_body(self, req, connectors)?) .build(); Ok(Some(request)) } fn handle_response( &self, - data: &types::RefundsRouterData, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: nexinets::NexinetsRefundResponse = res .response .parse_struct("nexinets RefundResponse") @@ -624,7 +609,7 @@ impl ConnectorIntegration for Nexinets { +impl ConnectorIntegration for Nexinets { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -655,8 +640,8 @@ impl ConnectorIntegration CustomResult { let transaction_id = req .request @@ -674,25 +659,25 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::RefundSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .headers(RefundSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::RefundSyncRouterData, + data: &RefundSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: nexinets::NexinetsRefundResponse = res .response .parse_struct("nexinets RefundSyncResponse") @@ -701,7 +686,7 @@ impl ConnectorIntegration, - ) -> CustomResult { + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { - Ok(api::IncomingWebhookEvent::EventNotSupported) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Ok(IncomingWebhookEvent::EventNotSupported) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } @@ -743,12 +728,8 @@ impl api::IncomingWebhook for Nexinets { impl api::PaymentToken for Nexinets {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Nexinets +impl ConnectorIntegration + for Nexinets { // Not Implemented (R) } diff --git a/crates/router/src/connector/nexinets/transformers.rs b/crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs similarity index 67% rename from crates/router/src/connector/nexinets/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs index 6cf35f5d87d..eeb24233bef 100644 --- a/crates/router/src/connector/nexinets/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/nexinets/transformers.rs @@ -1,20 +1,33 @@ use base64::Engine; use cards::CardNumber; -use common_utils::errors::CustomResult; -use domain::PaymentMethodData; +use common_enums::{enums, AttemptStatus}; +use common_utils::{consts, errors::CustomResult, request::Method}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{ + ApplePayWalletData, BankRedirectData, Card, PaymentMethodData, WalletData, + }, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{ + MandateReference, PaymentsResponseData, RedirectForm, RefundsResponseData, + }, + types::{ + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + RefundsRouterData, + }, +}; +use hyperswitch_interfaces::errors; use masking::{ExposeInterface, PeekInterface, Secret}; use serde::{Deserialize, Serialize}; use url::Url; use crate::{ - connector::utils::{ - self, CardData, PaymentsAuthorizeRequestData, PaymentsCancelRequestData, WalletData, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, CardData, PaymentsAuthorizeRequestData, PaymentsCancelRequestData, WalletData as _, }, - consts, - core::errors, - services, - types::{self, api, domain, storage::enums, transformers::ForeignFrom}, }; #[derive(Debug, Serialize)] @@ -163,9 +176,9 @@ pub struct ApplepayPaymentMethod { token_type: String, } -impl TryFrom<&types::PaymentsAuthorizeRouterData> for NexinetsPaymentsRequest { +impl TryFrom<&PaymentsAuthorizeRouterData> for NexinetsPaymentsRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { + fn try_from(item: &PaymentsAuthorizeRouterData) -> Result { let return_url = item.request.router_return_url.clone(); let nexinets_async = NexinetsAsyncDetails { success_url: return_url.clone(), @@ -195,11 +208,11 @@ pub struct NexinetsAuthType { pub(super) api_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for NexinetsAuthType { +impl TryFrom<&ConnectorAuthType> for NexinetsAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::BodyKey { api_key, key1 } => { + ConnectorAuthType::BodyKey { api_key, key1 } => { let auth_key = format!("{}:{}", key1.peek(), api_key.peek()); let auth_header = format!("Basic {}", consts::BASE64_ENGINE.encode(auth_key)); Ok(Self { @@ -224,48 +237,48 @@ pub enum NexinetsPaymentStatus { Aborted, } -impl ForeignFrom<(NexinetsPaymentStatus, NexinetsTransactionType)> for enums::AttemptStatus { - fn foreign_from((status, method): (NexinetsPaymentStatus, NexinetsTransactionType)) -> Self { - match status { - NexinetsPaymentStatus::Success => match method { - NexinetsTransactionType::Preauth => Self::Authorized, - NexinetsTransactionType::Debit | NexinetsTransactionType::Capture => Self::Charged, - NexinetsTransactionType::Cancel => Self::Voided, - }, - NexinetsPaymentStatus::Declined - | NexinetsPaymentStatus::Failure - | NexinetsPaymentStatus::Expired - | NexinetsPaymentStatus::Aborted => match method { - NexinetsTransactionType::Preauth => Self::AuthorizationFailed, - NexinetsTransactionType::Debit | NexinetsTransactionType::Capture => { - Self::CaptureFailed - } - NexinetsTransactionType::Cancel => Self::VoidFailed, - }, - NexinetsPaymentStatus::Ok => match method { - NexinetsTransactionType::Preauth => Self::Authorized, - _ => Self::Pending, - }, - NexinetsPaymentStatus::Pending => Self::AuthenticationPending, - NexinetsPaymentStatus::InProgress => Self::Pending, - } +fn get_status(status: NexinetsPaymentStatus, method: NexinetsTransactionType) -> AttemptStatus { + match status { + NexinetsPaymentStatus::Success => match method { + NexinetsTransactionType::Preauth => AttemptStatus::Authorized, + NexinetsTransactionType::Debit | NexinetsTransactionType::Capture => { + AttemptStatus::Charged + } + NexinetsTransactionType::Cancel => AttemptStatus::Voided, + }, + NexinetsPaymentStatus::Declined + | NexinetsPaymentStatus::Failure + | NexinetsPaymentStatus::Expired + | NexinetsPaymentStatus::Aborted => match method { + NexinetsTransactionType::Preauth => AttemptStatus::AuthorizationFailed, + NexinetsTransactionType::Debit | NexinetsTransactionType::Capture => { + AttemptStatus::CaptureFailed + } + NexinetsTransactionType::Cancel => AttemptStatus::VoidFailed, + }, + NexinetsPaymentStatus::Ok => match method { + NexinetsTransactionType::Preauth => AttemptStatus::Authorized, + _ => AttemptStatus::Pending, + }, + NexinetsPaymentStatus::Pending => AttemptStatus::AuthenticationPending, + NexinetsPaymentStatus::InProgress => AttemptStatus::Pending, } } -impl TryFrom<&common_enums::enums::BankNames> for NexinetsBIC { +impl TryFrom<&enums::BankNames> for NexinetsBIC { type Error = error_stack::Report; - fn try_from(bank: &common_enums::enums::BankNames) -> Result { + fn try_from(bank: &enums::BankNames) -> Result { match bank { - common_enums::enums::BankNames::AbnAmro => Ok(Self::AbnAmro), - common_enums::enums::BankNames::AsnBank => Ok(Self::AsnBank), - common_enums::enums::BankNames::Bunq => Ok(Self::Bunq), - common_enums::enums::BankNames::Ing => Ok(Self::Ing), - common_enums::enums::BankNames::Knab => Ok(Self::Knab), - common_enums::enums::BankNames::Rabobank => Ok(Self::Rabobank), - common_enums::enums::BankNames::Regiobank => Ok(Self::Regiobank), - common_enums::enums::BankNames::SnsBank => Ok(Self::SnsBank), - common_enums::enums::BankNames::TriodosBank => Ok(Self::TriodosBank), - common_enums::enums::BankNames::VanLanschot => Ok(Self::VanLanschot), + enums::BankNames::AbnAmro => Ok(Self::AbnAmro), + enums::BankNames::AsnBank => Ok(Self::AsnBank), + enums::BankNames::Bunq => Ok(Self::Bunq), + enums::BankNames::Ing => Ok(Self::Ing), + enums::BankNames::Knab => Ok(Self::Knab), + enums::BankNames::Rabobank => Ok(Self::Rabobank), + enums::BankNames::Regiobank => Ok(Self::Regiobank), + enums::BankNames::SnsBank => Ok(Self::SnsBank), + enums::BankNames::TriodosBank => Ok(Self::TriodosBank), + enums::BankNames::VanLanschot => Ok(Self::VanLanschot), _ => Err(errors::ConnectorError::FlowNotSupported { flow: bank.to_string(), connector: "Nexinets".to_string(), @@ -311,24 +324,12 @@ pub struct NexinetsPaymentsMetadata { pub psync_flow: NexinetsTransactionType, } -impl - TryFrom< - types::ResponseRouterData< - F, - NexinetsPreAuthOrDebitResponse, - T, - types::PaymentsResponseData, - >, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - NexinetsPreAuthOrDebitResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let transaction = match item.response.transactions.first() { Some(order) => order, @@ -343,11 +344,11 @@ impl let redirection_data = item .response .redirect_url - .map(|url| services::RedirectForm::from((url, services::Method::Get))); + .map(|url| RedirectForm::from((url, Method::Get))); let resource_id = match item.response.transaction_type.clone() { - NexinetsTransactionType::Preauth => types::ResponseId::NoResponseId, + NexinetsTransactionType::Preauth => ResponseId::NoResponseId, NexinetsTransactionType::Debit => { - types::ResponseId::ConnectorTransactionId(transaction.transaction_id.clone()) + ResponseId::ConnectorTransactionId(transaction.transaction_id.clone()) } _ => Err(errors::ConnectorError::ResponseHandlingFailed)?, }; @@ -355,17 +356,14 @@ impl .response .payment_instrument .payment_instrument_id - .map(|id| types::MandateReference { + .map(|id| MandateReference { connector_mandate_id: Some(id.expose()), payment_method_id: None, mandate_metadata: None, }); Ok(Self { - status: enums::AttemptStatus::foreign_from(( - transaction.status.clone(), - item.response.transaction_type, - )), - response: Ok(types::PaymentsResponseData::TransactionResponse { + status: get_status(transaction.status.clone(), item.response.transaction_type), + response: Ok(PaymentsResponseData::TransactionResponse { resource_id, redirection_data, mandate_reference, @@ -393,9 +391,9 @@ pub struct NexinetsOrder { pub order_id: String, } -impl TryFrom<&types::PaymentsCaptureRouterData> for NexinetsCaptureOrVoidRequest { +impl TryFrom<&PaymentsCaptureRouterData> for NexinetsCaptureOrVoidRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsCaptureRouterData) -> Result { + fn try_from(item: &PaymentsCaptureRouterData) -> Result { Ok(Self { initial_amount: item.request.amount_to_capture, currency: item.request.currency, @@ -403,9 +401,9 @@ impl TryFrom<&types::PaymentsCaptureRouterData> for NexinetsCaptureOrVoidRequest } } -impl TryFrom<&types::PaymentsCancelRouterData> for NexinetsCaptureOrVoidRequest { +impl TryFrom<&PaymentsCancelRouterData> for NexinetsCaptureOrVoidRequest { type Error = error_stack::Report; - fn try_from(item: &types::PaymentsCancelRouterData) -> Result { + fn try_from(item: &PaymentsCancelRouterData) -> Result { Ok(Self { initial_amount: item.request.get_amount()?, currency: item.request.get_currency()?, @@ -423,13 +421,12 @@ pub struct NexinetsPaymentResponse { pub transaction_type: NexinetsTransactionType, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let transaction_id = Some(item.response.transaction_id.clone()); let connector_metadata = serde_json::to_value(NexinetsPaymentsMetadata { @@ -440,16 +437,13 @@ impl .change_context(errors::ConnectorError::ResponseHandlingFailed)?; let resource_id = match item.response.transaction_type.clone() { NexinetsTransactionType::Debit | NexinetsTransactionType::Capture => { - types::ResponseId::ConnectorTransactionId(item.response.transaction_id) + ResponseId::ConnectorTransactionId(item.response.transaction_id) } - _ => types::ResponseId::NoResponseId, + _ => ResponseId::NoResponseId, }; Ok(Self { - status: enums::AttemptStatus::foreign_from(( - item.response.status, - item.response.transaction_type, - )), - response: Ok(types::PaymentsResponseData::TransactionResponse { + status: get_status(item.response.status, item.response.transaction_type), + response: Ok(PaymentsResponseData::TransactionResponse { resource_id, redirection_data: None, mandate_reference: None, @@ -473,9 +467,9 @@ pub struct NexinetsRefundRequest { pub currency: enums::Currency, } -impl TryFrom<&types::RefundsRouterData> for NexinetsRefundRequest { +impl TryFrom<&RefundsRouterData> for NexinetsRefundRequest { type Error = error_stack::Report; - fn try_from(item: &types::RefundsRouterData) -> Result { + fn try_from(item: &RefundsRouterData) -> Result { Ok(Self { initial_amount: item.request.refund_amount, currency: item.request.currency, @@ -521,15 +515,15 @@ impl From for enums::RefundStatus { } } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id, refund_status: enums::RefundStatus::from(item.response.status), }), @@ -538,15 +532,15 @@ impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id, refund_status: enums::RefundStatus::from(item.response.status), }), @@ -571,7 +565,7 @@ pub struct OrderErrorDetails { } fn get_payment_details_and_product( - item: &types::PaymentsAuthorizeRouterData, + item: &PaymentsAuthorizeRouterData, ) -> Result< (Option, NexinetsProduct), error_stack::Report, @@ -583,9 +577,9 @@ fn get_payment_details_and_product( )), PaymentMethodData::Wallet(wallet) => Ok(get_wallet_details(wallet)?), PaymentMethodData::BankRedirect(bank_redirect) => match bank_redirect { - domain::BankRedirectData::Eps { .. } => Ok((None, NexinetsProduct::Eps)), - domain::BankRedirectData::Giropay { .. } => Ok((None, NexinetsProduct::Giropay)), - domain::BankRedirectData::Ideal { bank_name, .. } => Ok(( + BankRedirectData::Eps { .. } => Ok((None, NexinetsProduct::Eps)), + BankRedirectData::Giropay { .. } => Ok((None, NexinetsProduct::Giropay)), + BankRedirectData::Ideal { bank_name, .. } => Ok(( Some(NexinetsPaymentDetails::BankRedirects(Box::new( NexinetsBankRedirects { bic: bank_name @@ -595,21 +589,21 @@ fn get_payment_details_and_product( ))), NexinetsProduct::Ideal, )), - domain::BankRedirectData::Sofort { .. } => Ok((None, NexinetsProduct::Sofort)), - domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Bizum { .. } - | domain::BankRedirectData::Interac { .. } - | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland { .. } - | domain::BankRedirectData::OnlineBankingPoland { .. } - | domain::BankRedirectData::OnlineBankingSlovakia { .. } - | domain::BankRedirectData::OpenBankingUk { .. } - | domain::BankRedirectData::Przelewy24 { .. } - | domain::BankRedirectData::Trustly { .. } - | domain::BankRedirectData::OnlineBankingFpx { .. } - | domain::BankRedirectData::OnlineBankingThailand { .. } - | domain::BankRedirectData::LocalBankRedirect {} => { + BankRedirectData::Sofort { .. } => Ok((None, NexinetsProduct::Sofort)), + BankRedirectData::BancontactCard { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Bizum { .. } + | BankRedirectData::Interac { .. } + | BankRedirectData::OnlineBankingCzechRepublic { .. } + | BankRedirectData::OnlineBankingFinland { .. } + | BankRedirectData::OnlineBankingPoland { .. } + | BankRedirectData::OnlineBankingSlovakia { .. } + | BankRedirectData::OpenBankingUk { .. } + | BankRedirectData::Przelewy24 { .. } + | BankRedirectData::Trustly { .. } + | BankRedirectData::OnlineBankingFpx { .. } + | BankRedirectData::OnlineBankingThailand { .. } + | BankRedirectData::LocalBankRedirect {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("nexinets"), ))? @@ -638,8 +632,8 @@ fn get_payment_details_and_product( } fn get_card_data( - item: &types::PaymentsAuthorizeRouterData, - card: &domain::payments::Card, + item: &PaymentsAuthorizeRouterData, + card: &Card, ) -> Result { let (card_data, cof_contract) = match item.request.is_mandate_payment() { true => { @@ -666,10 +660,10 @@ fn get_card_data( } fn get_applepay_details( - wallet_data: &domain::WalletData, - applepay_data: &domain::ApplePayWalletData, + wallet_data: &WalletData, + applepay_data: &ApplePayWalletData, ) -> CustomResult { - let payment_data = wallet_data.get_wallet_token_as_json("Apple Pay".to_string())?; + let payment_data = WalletData::get_wallet_token_as_json(wallet_data, "Apple Pay".to_string())?; Ok(ApplePayDetails { payment_data, payment_method: ApplepayPaymentMethod { @@ -681,9 +675,7 @@ fn get_applepay_details( }) } -fn get_card_details( - req_card: &domain::payments::Card, -) -> Result { +fn get_card_details(req_card: &Card) -> Result { Ok(CardDetails { card_number: req_card.card_number.clone(), expiry_month: req_card.card_exp_month.clone(), @@ -693,14 +685,14 @@ fn get_card_details( } fn get_wallet_details( - wallet: &domain::WalletData, + wallet: &WalletData, ) -> Result< (Option, NexinetsProduct), error_stack::Report, > { match wallet { - domain::WalletData::PaypalRedirect(_) => Ok((None, NexinetsProduct::Paypal)), - domain::WalletData::ApplePay(applepay_data) => Ok(( + WalletData::PaypalRedirect(_) => Ok((None, NexinetsProduct::Paypal)), + WalletData::ApplePay(applepay_data) => Ok(( Some(NexinetsPaymentDetails::Wallet(Box::new( NexinetsWalletDetails::ApplePayToken(Box::new(get_applepay_details( wallet, @@ -709,32 +701,32 @@ fn get_wallet_details( ))), NexinetsProduct::Applepay, )), - domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePayRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect { .. } - | domain::WalletData::GooglePay(_) - | domain::WalletData::GooglePayRedirect(_) - | domain::WalletData::GooglePayThirdPartySdk(_) - | domain::WalletData::MbWayRedirect(_) - | domain::WalletData::MobilePayRedirect(_) - | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) - | domain::WalletData::TwintRedirect { .. } - | domain::WalletData::VippsRedirect { .. } - | domain::WalletData::TouchNGoRedirect(_) - | domain::WalletData::WeChatPayRedirect(_) - | domain::WalletData::WeChatPayQr(_) - | domain::WalletData::CashappQr(_) - | domain::WalletData::SwishQr(_) - | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( + WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePayRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect { .. } + | WalletData::GooglePay(_) + | WalletData::GooglePayRedirect(_) + | WalletData::GooglePayThirdPartySdk(_) + | WalletData::MbWayRedirect(_) + | WalletData::MobilePayRedirect(_) + | WalletData::PaypalSdk(_) + | WalletData::Paze(_) + | WalletData::SamsungPay(_) + | WalletData::TwintRedirect { .. } + | WalletData::VippsRedirect { .. } + | WalletData::TouchNGoRedirect(_) + | WalletData::WeChatPayRedirect(_) + | WalletData::WeChatPayQr(_) + | WalletData::CashappQr(_) + | WalletData::SwishQr(_) + | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("nexinets"), ))?, } diff --git a/crates/router/src/connector/payeezy.rs b/crates/hyperswitch_connectors/src/connectors/payeezy.rs similarity index 63% rename from crates/router/src/connector/payeezy.rs rename to crates/hyperswitch_connectors/src/connectors/payeezy.rs index 5783cf1bc14..cb22d0cb7b0 100644 --- a/crates/router/src/connector/payeezy.rs +++ b/crates/hyperswitch_connectors/src/connectors/payeezy.rs @@ -1,34 +1,49 @@ -mod transformers; - -use std::fmt::Debug; +pub mod transformers; +use api_models::webhooks::IncomingWebhookEvent; use base64::Engine; -use common_utils::request::RequestContent; -use diesel_models::enums; +use common_enums::{CaptureMethod, PaymentMethodType}; +use common_utils::{ + errors::CustomResult, + ext_traits::ByteSliceExt, + request::{Method, Request, RequestBuilder, RequestContent}, +}; use error_stack::{report, ResultExt}; -use masking::ExposeInterface; +use hyperswitch_domain_models::{ + router_data::{AccessToken, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, + }, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, + }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types::{ + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{ + PaymentsAuthorizeType, PaymentsCaptureType, PaymentsVoidType, RefundExecuteType, Response, + }, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{ExposeInterface, Mask}; use rand::distributions::DistString; use ring::hmac; use transformers as payeezy; use crate::{ - configs::settings, - connector::utils as connector_utils, - consts, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, - }, - types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, Response, - }, - utils::BytesExt, + constants::headers, types::ResponseRouterData, utils::construct_not_implemented_error_report, }; #[derive(Debug, Clone)] @@ -40,9 +55,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let auth = payeezy::PayeezyAuthType::try_from(&req.connector_auth_type)?; let request_payload = self .get_request_body(req, connectors)? @@ -66,7 +81,7 @@ where let key = hmac::Key::new(hmac::HMAC_SHA256, auth.api_secret.expose().as_bytes()); let tag = hmac::sign(&key, signature_string.expose().as_bytes()); let hmac_sign = hex::encode(tag); - let signature_value = consts::BASE64_ENGINE_URL_SAFE.encode(hmac_sign); + let signature_value = common_utils::consts::BASE64_ENGINE_URL_SAFE.encode(hmac_sign); Ok(vec![ ( headers::CONTENT_TYPE.to_string(), @@ -100,7 +115,7 @@ impl ConnectorCommon for Payeezy { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.payeezy.base_url.as_ref() } @@ -138,14 +153,14 @@ impl ConnectorCommon for Payeezy { impl ConnectorValidation for Payeezy { fn validate_capture_method( &self, - capture_method: Option, - _pmt: Option, + capture_method: Option, + _pmt: Option, ) -> CustomResult<(), errors::ConnectorError> { let capture_method = capture_method.unwrap_or_default(); match capture_method { - enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), - enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_implemented_error_report(capture_method, self.id()), + CaptureMethod::Automatic | CaptureMethod::Manual => Ok(()), + CaptureMethod::ManualMultiple | CaptureMethod::Scheduled => Err( + construct_not_implemented_error_report(capture_method, self.id()), ), } } @@ -154,22 +169,12 @@ impl ConnectorValidation for Payeezy { impl api::Payment for Payeezy {} impl api::MandateSetup for Payeezy {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Payeezy -{ +impl ConnectorIntegration for Payeezy { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Payeezy".to_string()) .into(), @@ -179,26 +184,20 @@ impl impl api::PaymentToken for Payeezy {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Payeezy +impl ConnectorIntegration + for Payeezy { // Not Implemented (R) } impl api::PaymentVoid for Payeezy {} -impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -208,8 +207,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( @@ -221,8 +220,8 @@ impl ConnectorIntegration CustomResult { let connector_req = payeezy::PayeezyCaptureOrVoidRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -230,27 +229,25 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) - .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) - .set_body(types::PaymentsVoidType::get_request_body( - self, req, connectors, - )?) + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsVoidType::get_url(self, req, connectors)?) + .headers(PaymentsVoidType::get_headers(self, req, connectors)?) + .set_body(PaymentsVoidType::get_request_body(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::PaymentsCancelRouterData, + data: &PaymentsCancelRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: payeezy::PayeezyPaymentsResponse = res .response .parse_struct("Payeezy PaymentsResponse") @@ -259,7 +256,7 @@ impl ConnectorIntegration - for Payeezy -{ -} +impl ConnectorIntegration for Payeezy {} impl api::PaymentSync for Payeezy {} -impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { // default implementation of build_request method will be executed } impl api::PaymentCapture for Payeezy {} -impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -308,8 +298,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( @@ -321,8 +311,8 @@ impl ConnectorIntegration CustomResult { let router_obj = payeezy::PayeezyRouterData::try_from(( &self.get_currency_unit(), @@ -337,17 +327,15 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) - .headers(types::PaymentsCaptureType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsCaptureType::get_request_body( + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsCaptureType::get_url(self, req, connectors)?) + .headers(PaymentsCaptureType::get_headers(self, req, connectors)?) + .set_body(PaymentsCaptureType::get_request_body( self, req, connectors, )?) .build(), @@ -356,10 +344,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: payeezy::PayeezyPaymentsResponse = res .response .parse_struct("Payeezy PaymentsResponse") @@ -368,7 +356,7 @@ impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { //TODO: implement sessions flow } impl api::PaymentAuthorize for Payeezy {} -impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -412,16 +396,16 @@ impl ConnectorIntegration CustomResult { Ok(format!("{}v1/transactions", self.base_url(connectors))) } fn get_request_body( &self, - req: &types::PaymentsAuthorizeRouterData, - _connectors: &settings::Connectors, + req: &PaymentsAuthorizeRouterData, + _connectors: &Connectors, ) -> CustomResult { let router_obj = payeezy::PayeezyRouterData::try_from(( &self.get_currency_unit(), @@ -436,19 +420,15 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsAuthorizeType::get_url( - self, req, connectors, - )?) - .headers(types::PaymentsAuthorizeType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsAuthorizeType::get_request_body( + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?) + .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?) + .set_body(PaymentsAuthorizeType::get_request_body( self, req, connectors, )?) .build(), @@ -457,10 +437,10 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: payeezy::PayeezyPaymentsResponse = res .response .parse_struct("payeezy Response") @@ -469,7 +449,7 @@ impl ConnectorIntegration - for Payeezy -{ +impl ConnectorIntegration for Payeezy { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -507,8 +485,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { let connector_payment_id = req.request.connector_transaction_id.clone(); Ok(format!( @@ -520,8 +498,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let router_obj = payeezy::PayeezyRouterData::try_from(( &self.get_currency_unit(), @@ -535,28 +513,24 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::RefundExecuteType::get_url(self, req, connectors)?) - .headers(types::RefundExecuteType::get_headers( - self, req, connectors, - )?) - .set_body(types::RefundExecuteType::get_request_body( - self, req, connectors, - )?) + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&RefundExecuteType::get_url(self, req, connectors)?) + .headers(RefundExecuteType::get_headers(self, req, connectors)?) + .set_body(RefundExecuteType::get_request_body(self, req, connectors)?) .build(); Ok(Some(request)) } fn handle_response( &self, - data: &types::RefundsRouterData, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { // Parse the response into a payeezy::RefundResponse let response: payeezy::RefundResponse = res .response @@ -567,12 +541,12 @@ impl ConnectorIntegration for Payeezy { +impl ConnectorIntegration for Payeezy { // default implementation of build_request method will be executed } #[async_trait::async_trait] -impl api::IncomingWebhook for Payeezy { +impl IncomingWebhook for Payeezy { fn get_webhook_object_reference_id( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { - Ok(api::IncomingWebhookEvent::EventNotSupported) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Ok(IncomingWebhookEvent::EventNotSupported) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } diff --git a/crates/router/src/connector/payeezy/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs similarity index 57% rename from crates/router/src/connector/payeezy/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs index 685bf3c0fbb..47c5c40363e 100644 --- a/crates/router/src/connector/payeezy/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payeezy/transformers.rs @@ -1,32 +1,43 @@ use cards::CardNumber; -use common_utils::ext_traits::Encode; +use common_enums::{enums, AttemptStatus, CaptureMethod, Currency, PaymentMethod}; +use common_utils::{errors::ParsingError, ext_traits::Encode}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::PaymentMethodData, + router_data::{ConnectorAuthType, RouterData}, + router_flow_types::Execute, + router_request_types::ResponseId, + router_response_types::{MandateReference, PaymentsResponseData, RefundsResponseData}, + types::{ + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + RefundsRouterData, + }, +}; +use hyperswitch_interfaces::{api::CurrencyUnit, errors::ConnectorError}; use masking::{ExposeInterface, Secret}; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::{self, CardData, RouterData}, - core::errors, - types::{self, api, domain, storage::enums, transformers::ForeignFrom}, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + get_amount_as_string, get_unimplemented_payment_method_error_message, to_connector_meta, + CardData, CardIssuer, RouterData as _, + }, }; + #[derive(Debug, Serialize)] pub struct PayeezyRouterData { pub amount: String, pub router_data: T, } -impl TryFrom<(&api::CurrencyUnit, enums::Currency, i64, T)> for PayeezyRouterData { - type Error = error_stack::Report; +impl TryFrom<(&CurrencyUnit, Currency, i64, T)> for PayeezyRouterData { + type Error = error_stack::Report; fn try_from( - (currency_unit, currency, amount, router_data): ( - &api::CurrencyUnit, - enums::Currency, - i64, - T, - ), + (currency_unit, currency, amount, router_data): (&CurrencyUnit, Currency, i64, T), ) -> Result { - let amount = utils::get_amount_as_string(currency_unit, amount, currency)?; + let amount = get_amount_as_string(currency_unit, amount, currency)?; Ok(Self { amount, router_data, @@ -53,20 +64,20 @@ pub enum PayeezyCardType { Discover, } -impl TryFrom for PayeezyCardType { - type Error = error_stack::Report; - fn try_from(issuer: utils::CardIssuer) -> Result { +impl TryFrom for PayeezyCardType { + type Error = error_stack::Report; + fn try_from(issuer: CardIssuer) -> Result { match issuer { - utils::CardIssuer::AmericanExpress => Ok(Self::AmericanExpress), - utils::CardIssuer::Master => Ok(Self::Mastercard), - utils::CardIssuer::Discover => Ok(Self::Discover), - utils::CardIssuer::Visa => Ok(Self::Visa), - - utils::CardIssuer::Maestro - | utils::CardIssuer::DinersClub - | utils::CardIssuer::JCB - | utils::CardIssuer::CarteBlanche => Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Payeezy"), + CardIssuer::AmericanExpress => Ok(Self::AmericanExpress), + CardIssuer::Master => Ok(Self::Mastercard), + CardIssuer::Discover => Ok(Self::Discover), + CardIssuer::Visa => Ok(Self::Visa), + + CardIssuer::Maestro + | CardIssuer::DinersClub + | CardIssuer::JCB + | CardIssuer::CarteBlanche => Err(ConnectorError::NotImplemented( + get_unimplemented_payment_method_error_message("Payeezy"), ))?, } } @@ -118,36 +129,36 @@ pub enum Initiator { CardHolder, } -impl TryFrom<&PayeezyRouterData<&types::PaymentsAuthorizeRouterData>> for PayeezyPaymentsRequest { - type Error = error_stack::Report; +impl TryFrom<&PayeezyRouterData<&PaymentsAuthorizeRouterData>> for PayeezyPaymentsRequest { + type Error = error_stack::Report; fn try_from( - item: &PayeezyRouterData<&types::PaymentsAuthorizeRouterData>, + item: &PayeezyRouterData<&PaymentsAuthorizeRouterData>, ) -> Result { match item.router_data.payment_method { - diesel_models::enums::PaymentMethod::Card => get_card_specific_payment_data(item), - - diesel_models::enums::PaymentMethod::CardRedirect - | diesel_models::enums::PaymentMethod::PayLater - | diesel_models::enums::PaymentMethod::Wallet - | diesel_models::enums::PaymentMethod::BankRedirect - | diesel_models::enums::PaymentMethod::BankTransfer - | diesel_models::enums::PaymentMethod::Crypto - | diesel_models::enums::PaymentMethod::BankDebit - | diesel_models::enums::PaymentMethod::Reward - | diesel_models::enums::PaymentMethod::RealTimePayment - | diesel_models::enums::PaymentMethod::Upi - | diesel_models::enums::PaymentMethod::Voucher - | diesel_models::enums::PaymentMethod::OpenBanking - | diesel_models::enums::PaymentMethod::GiftCard => { - Err(errors::ConnectorError::NotImplemented("Payment methods".to_string()).into()) + PaymentMethod::Card => get_card_specific_payment_data(item), + + PaymentMethod::CardRedirect + | PaymentMethod::PayLater + | PaymentMethod::Wallet + | PaymentMethod::BankRedirect + | PaymentMethod::BankTransfer + | PaymentMethod::Crypto + | PaymentMethod::BankDebit + | PaymentMethod::Reward + | PaymentMethod::RealTimePayment + | PaymentMethod::Upi + | PaymentMethod::Voucher + | PaymentMethod::OpenBanking + | PaymentMethod::GiftCard => { + Err(ConnectorError::NotImplemented("Payment methods".to_string()).into()) } } } } fn get_card_specific_payment_data( - item: &PayeezyRouterData<&types::PaymentsAuthorizeRouterData>, -) -> Result> { + item: &PayeezyRouterData<&PaymentsAuthorizeRouterData>, +) -> Result> { let merchant_ref = item.router_data.attempt_id.to_string(); let method = PayeezyPaymentMethodType::CreditCard; let amount = item.amount.clone(); @@ -167,11 +178,9 @@ fn get_card_specific_payment_data( }) } fn get_transaction_type_and_stored_creds( - item: &types::PaymentsAuthorizeRouterData, -) -> Result< - (PayeezyTransactionType, Option), - error_stack::Report, -> { + item: &PaymentsAuthorizeRouterData, +) -> Result<(PayeezyTransactionType, Option), error_stack::Report> +{ let connector_mandate_id = item.request.mandate_id.as_ref().and_then(|mandate_ids| { match mandate_ids.mandate_reference_id.clone() { Some(api_models::payments::MandateReferenceId::ConnectorMandateId( @@ -203,36 +212,32 @@ fn get_transaction_type_and_stored_creds( ) } else { match item.request.capture_method { - Some(diesel_models::enums::CaptureMethod::Manual) => { - Ok((PayeezyTransactionType::Authorize, None)) - } - Some(diesel_models::enums::CaptureMethod::Automatic) => { - Ok((PayeezyTransactionType::Purchase, None)) + Some(CaptureMethod::Manual) => Ok((PayeezyTransactionType::Authorize, None)), + Some(CaptureMethod::Automatic) => Ok((PayeezyTransactionType::Purchase, None)), + + Some(CaptureMethod::ManualMultiple) | Some(CaptureMethod::Scheduled) | None => { + Err(ConnectorError::FlowNotSupported { + flow: item.request.capture_method.unwrap_or_default().to_string(), + connector: "Payeezy".to_string(), + }) } - - Some(diesel_models::enums::CaptureMethod::ManualMultiple) - | Some(diesel_models::enums::CaptureMethod::Scheduled) - | None => Err(errors::ConnectorError::FlowNotSupported { - flow: item.request.capture_method.unwrap_or_default().to_string(), - connector: "Payeezy".to_string(), - }), }? }; Ok((transaction_type, stored_credentials)) } fn is_mandate_payment( - item: &types::PaymentsAuthorizeRouterData, + item: &PaymentsAuthorizeRouterData, connector_mandate_id: Option<&String>, ) -> bool { item.request.setup_mandate_details.is_some() || connector_mandate_id.is_some() } fn get_payment_method_data( - item: &PayeezyRouterData<&types::PaymentsAuthorizeRouterData>, -) -> Result> { + item: &PayeezyRouterData<&PaymentsAuthorizeRouterData>, +) -> Result> { match item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(ref card) => { + PaymentMethodData::Card(ref card) => { let card_type = PayeezyCardType::try_from(card.get_card_issuer()?)?; let payeezy_card = PayeezyCard { card_type, @@ -247,25 +252,25 @@ fn get_payment_method_data( Ok(PayeezyPaymentMethod::PayeezyCard(payeezy_card)) } - domain::PaymentMethodData::CardRedirect(_) - | domain::PaymentMethodData::Wallet(_) - | domain::PaymentMethodData::PayLater(_) - | domain::PaymentMethodData::BankRedirect(_) - | domain::PaymentMethodData::BankDebit(_) - | domain::PaymentMethodData::BankTransfer(_) - | domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::Voucher(_) - | domain::PaymentMethodData::GiftCard(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { - Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Payeezy"), + PaymentMethodData::CardRedirect(_) + | PaymentMethodData::Wallet(_) + | PaymentMethodData::PayLater(_) + | PaymentMethodData::BankRedirect(_) + | PaymentMethodData::BankDebit(_) + | PaymentMethodData::BankTransfer(_) + | PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::Voucher(_) + | PaymentMethodData::GiftCard(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + Err(ConnectorError::NotImplemented( + get_unimplemented_payment_method_error_message("Payeezy"), ))? } } @@ -278,10 +283,10 @@ pub struct PayeezyAuthType { pub(super) merchant_token: Secret, } -impl TryFrom<&types::ConnectorAuthType> for PayeezyAuthType { - type Error = error_stack::Report; - fn try_from(item: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::SignatureKey { +impl TryFrom<&ConnectorAuthType> for PayeezyAuthType { + type Error = error_stack::Report; + fn try_from(item: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::SignatureKey { api_key, key1, api_secret, @@ -293,7 +298,7 @@ impl TryFrom<&types::ConnectorAuthType> for PayeezyAuthType { merchant_token: key1.to_owned(), }) } else { - Err(errors::ConnectorError::FailedToObtainAuthType.into()) + Err(ConnectorError::FailedToObtainAuthType.into()) } } } @@ -341,16 +346,12 @@ pub struct PayeezyCaptureOrVoidRequest { currency_code: String, } -impl TryFrom<&PayeezyRouterData<&types::PaymentsCaptureRouterData>> - for PayeezyCaptureOrVoidRequest -{ - type Error = error_stack::Report; - fn try_from( - item: &PayeezyRouterData<&types::PaymentsCaptureRouterData>, - ) -> Result { +impl TryFrom<&PayeezyRouterData<&PaymentsCaptureRouterData>> for PayeezyCaptureOrVoidRequest { + type Error = error_stack::Report; + fn try_from(item: &PayeezyRouterData<&PaymentsCaptureRouterData>) -> Result { let metadata: PayeezyPaymentsMetadata = - utils::to_connector_meta(item.router_data.request.connector_meta.clone()) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + to_connector_meta(item.router_data.request.connector_meta.clone()) + .change_context(ConnectorError::RequestEncodingFailed)?; Ok(Self { transaction_type: PayeezyTransactionType::Capture, amount: item.amount.clone(), @@ -360,18 +361,18 @@ impl TryFrom<&PayeezyRouterData<&types::PaymentsCaptureRouterData>> } } -impl TryFrom<&types::PaymentsCancelRouterData> for PayeezyCaptureOrVoidRequest { - type Error = error_stack::Report; - fn try_from(item: &types::PaymentsCancelRouterData) -> Result { +impl TryFrom<&PaymentsCancelRouterData> for PayeezyCaptureOrVoidRequest { + type Error = error_stack::Report; + fn try_from(item: &PaymentsCancelRouterData) -> Result { let metadata: PayeezyPaymentsMetadata = - utils::to_connector_meta(item.request.connector_meta.clone()) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + to_connector_meta(item.request.connector_meta.clone()) + .change_context(ConnectorError::RequestEncodingFailed)?; Ok(Self { transaction_type: PayeezyTransactionType::Void, amount: item .request .amount - .ok_or(errors::ConnectorError::RequestEncodingFailed)? + .ok_or(ConnectorError::RequestEncodingFailed)? .to_string(), currency_code: item.request.currency.unwrap_or_default().to_string(), transaction_tag: metadata.transaction_tag, @@ -397,39 +398,38 @@ pub struct PayeezyPaymentsMetadata { transaction_tag: String, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { - type Error = error_stack::Report; + type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { let metadata = item .response .transaction_tag .map(|txn_tag| construct_payeezy_payments_metadata(txn_tag).encode_to_value()) .transpose() - .change_context(errors::ConnectorError::ResponseHandlingFailed)?; + .change_context(ConnectorError::ResponseHandlingFailed)?; let mandate_reference = item .response .stored_credentials .map(|credentials| credentials.cardbrand_original_transaction_id) - .map(|id| types::MandateReference { + .map(|id| MandateReference { connector_mandate_id: Some(id.expose()), payment_method_id: None, mandate_metadata: None, }); - let status = enums::AttemptStatus::foreign_from(( + let status = get_status( item.response.transaction_status, item.response.transaction_type, - )); + ); Ok(Self { status, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId( item.response.transaction_id.clone(), ), redirection_data: None, @@ -449,26 +449,28 @@ impl } } -impl ForeignFrom<(PayeezyPaymentStatus, PayeezyTransactionType)> for enums::AttemptStatus { - fn foreign_from((status, method): (PayeezyPaymentStatus, PayeezyTransactionType)) -> Self { - match status { - PayeezyPaymentStatus::Approved => match method { - PayeezyTransactionType::Authorize => Self::Authorized, - PayeezyTransactionType::Capture - | PayeezyTransactionType::Purchase - | PayeezyTransactionType::Recurring => Self::Charged, - PayeezyTransactionType::Void => Self::Voided, - PayeezyTransactionType::Refund | PayeezyTransactionType::Pending => Self::Pending, - }, - PayeezyPaymentStatus::Declined | PayeezyPaymentStatus::NotProcessed => match method { - PayeezyTransactionType::Capture => Self::CaptureFailed, - PayeezyTransactionType::Authorize - | PayeezyTransactionType::Purchase - | PayeezyTransactionType::Recurring => Self::AuthorizationFailed, - PayeezyTransactionType::Void => Self::VoidFailed, - PayeezyTransactionType::Refund | PayeezyTransactionType::Pending => Self::Pending, - }, - } +fn get_status(status: PayeezyPaymentStatus, method: PayeezyTransactionType) -> AttemptStatus { + match status { + PayeezyPaymentStatus::Approved => match method { + PayeezyTransactionType::Authorize => AttemptStatus::Authorized, + PayeezyTransactionType::Capture + | PayeezyTransactionType::Purchase + | PayeezyTransactionType::Recurring => AttemptStatus::Charged, + PayeezyTransactionType::Void => AttemptStatus::Voided, + PayeezyTransactionType::Refund | PayeezyTransactionType::Pending => { + AttemptStatus::Pending + } + }, + PayeezyPaymentStatus::Declined | PayeezyPaymentStatus::NotProcessed => match method { + PayeezyTransactionType::Capture => AttemptStatus::CaptureFailed, + PayeezyTransactionType::Authorize + | PayeezyTransactionType::Purchase + | PayeezyTransactionType::Recurring => AttemptStatus::AuthorizationFailed, + PayeezyTransactionType::Void => AttemptStatus::VoidFailed, + PayeezyTransactionType::Refund | PayeezyTransactionType::Pending => { + AttemptStatus::Pending + } + }, } } @@ -482,14 +484,12 @@ pub struct PayeezyRefundRequest { currency_code: String, } -impl TryFrom<&PayeezyRouterData<&types::RefundsRouterData>> for PayeezyRefundRequest { - type Error = error_stack::Report; - fn try_from( - item: &PayeezyRouterData<&types::RefundsRouterData>, - ) -> Result { +impl TryFrom<&PayeezyRouterData<&RefundsRouterData>> for PayeezyRefundRequest { + type Error = error_stack::Report; + fn try_from(item: &PayeezyRouterData<&RefundsRouterData>) -> Result { let metadata: PayeezyPaymentsMetadata = - utils::to_connector_meta(item.router_data.request.connector_metadata.clone()) - .change_context(errors::ConnectorError::RequestEncodingFailed)?; + to_connector_meta(item.router_data.request.connector_metadata.clone()) + .change_context(ConnectorError::RequestEncodingFailed)?; Ok(Self { transaction_type: PayeezyTransactionType::Refund, amount: item.amount.clone(), @@ -538,15 +538,13 @@ pub struct RefundResponse { pub gateway_message: String, } -impl TryFrom> - for types::RefundsRouterData -{ - type Error = error_stack::Report; +impl TryFrom> for RefundsRouterData { + type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.transaction_id, refund_status: enums::RefundStatus::from(item.response.transaction_status), }), diff --git a/crates/router/src/connector/payu.rs b/crates/hyperswitch_connectors/src/connectors/payu.rs similarity index 61% rename from crates/router/src/connector/payu.rs rename to crates/hyperswitch_connectors/src/connectors/payu.rs index 4ff317d1f71..05f983b8fbb 100644 --- a/crates/router/src/connector/payu.rs +++ b/crates/hyperswitch_connectors/src/connectors/payu.rs @@ -1,30 +1,49 @@ pub mod transformers; -use std::fmt::Debug; - -use common_utils::request::RequestContent; -use diesel_models::enums; +use api_models::webhooks::IncomingWebhookEvent; +use common_enums::enums; +use common_utils::{ + errors::CustomResult, + ext_traits::ByteSliceExt, + request::{Method, Request, RequestBuilder, RequestContent}, +}; use error_stack::{report, ResultExt}; -use masking::PeekInterface; -use transformers as payu; - -use crate::{ - configs::settings, - connector::utils as connector_utils, - core::errors::{self, CustomResult}, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, +use hyperswitch_domain_models::{ + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, + }, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - ErrorResponse, + PaymentsAuthorizeRouterData, PaymentsCancelRouterData, PaymentsCaptureRouterData, + PaymentsSyncRouterData, RefundSyncRouterData, RefundsRouterData, }, - utils::BytesExt, +}; +use hyperswitch_interfaces::{ + api::{self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorValidation}, + configs::Connectors, + errors, + events::connector_api_logs::ConnectorEvent, + types::{ + PaymentsAuthorizeType, PaymentsCaptureType, PaymentsSyncType, PaymentsVoidType, + RefreshTokenType, RefundExecuteType, RefundSyncType, Response, + }, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface}; +use transformers as payu; + +use crate::{ + constants::headers, + types::{RefreshTokenRouterData, ResponseRouterData}, + utils::construct_not_supported_error_report, }; #[derive(Debug, Clone)] @@ -36,9 +55,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -67,14 +86,14 @@ impl ConnectorCommon for Payu { "application/json" } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.payu.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = payu::PayuAuthType::try_from(auth_type) .change_context(errors::ConnectorError::FailedToObtainAuthType)?; Ok(vec![( @@ -85,7 +104,7 @@ impl ConnectorCommon for Payu { fn build_error_response( &self, - res: types::Response, + res: Response, event_builder: Option<&mut ConnectorEvent>, ) -> CustomResult { let response: payu::PayuErrorResponse = res @@ -117,7 +136,7 @@ impl ConnectorValidation for Payu { match capture_method { enums::CaptureMethod::Automatic | enums::CaptureMethod::Manual => Ok(()), enums::CaptureMethod::ManualMultiple | enums::CaptureMethod::Scheduled => Err( - connector_utils::construct_not_supported_error_report(capture_method, self.id()), + construct_not_supported_error_report(capture_method, self.id()), ), } } @@ -126,22 +145,12 @@ impl ConnectorValidation for Payu { impl api::Payment for Payu {} impl api::MandateSetup for Payu {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Payu -{ +impl ConnectorIntegration for Payu { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err( errors::ConnectorError::NotImplemented("Setup Mandate flow for Payu".to_string()) .into(), @@ -151,26 +160,20 @@ impl impl api::PaymentToken for Payu {} -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Payu +impl ConnectorIntegration + for Payu { // Not Implemented (R) } impl api::PaymentVoid for Payu {} -impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::PaymentsCancelRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -180,8 +183,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = &req.request.connector_transaction_id; Ok(format!( @@ -193,23 +196,23 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Delete) - .url(&types::PaymentsVoidType::get_url(self, req, connectors)?) + req: &PaymentsCancelRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Delete) + .url(&PaymentsVoidType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsVoidType::get_headers(self, req, connectors)?) + .headers(PaymentsVoidType::get_headers(self, req, connectors)?) .build(); Ok(Some(request)) } fn handle_response( &self, - data: &types::PaymentsCancelRouterData, + data: &PaymentsCancelRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuPaymentsCancelResponse = res .response .parse_struct("PaymentCancelResponse") @@ -218,7 +221,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -236,13 +239,11 @@ impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { fn get_url( &self, - _req: &types::RefreshTokenRouterData, - connectors: &settings::Connectors, + _req: &RefreshTokenRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}", @@ -257,21 +258,19 @@ impl ConnectorIntegration CustomResult)>, errors::ConnectorError> { + _req: &RefreshTokenRouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { Ok(vec![( headers::CONTENT_TYPE.to_string(), - types::RefreshTokenType::get_content_type(self) - .to_string() - .into(), + RefreshTokenType::get_content_type(self).to_string().into(), )]) } fn get_request_body( &self, - req: &types::RefreshTokenRouterData, - _connectors: &settings::Connectors, + req: &RefreshTokenRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_req = payu::PayuAuthUpdateRequest::try_from(req)?; @@ -280,18 +279,16 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefreshTokenRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { let req = Some( - services::RequestBuilder::new() - .method(services::Method::Post) + RequestBuilder::new() + .method(Method::Post) .attach_default_headers() - .headers(types::RefreshTokenType::get_headers(self, req, connectors)?) - .url(&types::RefreshTokenType::get_url(self, req, connectors)?) - .set_body(types::RefreshTokenType::get_request_body( - self, req, connectors, - )?) + .headers(RefreshTokenType::get_headers(self, req, connectors)?) + .url(&RefreshTokenType::get_url(self, req, connectors)?) + .set_body(RefreshTokenType::get_request_body(self, req, connectors)?) .build(), ); @@ -299,10 +296,10 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuAuthUpdateResponse = res .response .parse_struct("payu PayuAuthUpdateResponse") @@ -311,7 +308,7 @@ impl ConnectorIntegration, ) -> CustomResult { let response: payu::PayuAccessTokenErrorResponse = res @@ -344,14 +341,12 @@ impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -361,8 +356,8 @@ impl ConnectorIntegration CustomResult { let connector_payment_id = req .request @@ -379,32 +374,32 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .headers(PaymentsSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::PaymentsSyncRouterData, + data: &PaymentsSyncRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuPaymentsSyncResponse = res .response .parse_struct("payu OrderResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -414,7 +409,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -422,14 +417,12 @@ impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::PaymentsCaptureRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -439,8 +432,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -453,8 +446,8 @@ impl ConnectorIntegration CustomResult { let connector_req = payu::PayuPaymentsCaptureRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -462,18 +455,16 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsCaptureRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Put) - .url(&types::PaymentsCaptureType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Put) + .url(&PaymentsCaptureType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsCaptureType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsCaptureType::get_request_body( + .headers(PaymentsCaptureType::get_headers(self, req, connectors)?) + .set_body(PaymentsCaptureType::get_request_body( self, req, connectors, )?) .build(), @@ -482,17 +473,17 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuPaymentsCaptureResponse = res .response .parse_struct("payu CaptureResponse") .change_context(errors::ConnectorError::RequestEncodingFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -502,7 +493,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -511,22 +502,18 @@ impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { //TODO: implement sessions flow } impl api::PaymentAuthorize for Payu {} -impl ConnectorIntegration - for Payu -{ +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -536,8 +523,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}", @@ -548,8 +535,8 @@ impl ConnectorIntegration CustomResult { let connector_req = payu::PayuPaymentsRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -557,24 +544,16 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &RouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsAuthorizeType::get_url( - self, req, connectors, - )?) + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsAuthorizeType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsAuthorizeType::get_request_body( + .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?) + .set_body(PaymentsAuthorizeType::get_request_body( self, req, connectors, )?) .build(), @@ -583,17 +562,17 @@ impl ConnectorIntegration, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::PayuPaymentsResponse = res .response .parse_struct("PayuPaymentsResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -603,7 +582,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -614,12 +593,12 @@ impl api::Refund for Payu {} impl api::RefundExecute for Payu {} impl api::RefundSync for Payu {} -impl ConnectorIntegration for Payu { +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -629,8 +608,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}{}{}{}", @@ -643,8 +622,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_req = payu::PayuRefundRequest::try_from(req)?; Ok(RequestContent::Json(Box::new(connector_req))) @@ -652,36 +631,32 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::RefundExecuteType::get_url(self, req, connectors)?) + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&RefundExecuteType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundExecuteType::get_headers( - self, req, connectors, - )?) - .set_body(types::RefundExecuteType::get_request_body( - self, req, connectors, - )?) + .headers(RefundExecuteType::get_headers(self, req, connectors)?) + .set_body(RefundExecuteType::get_request_body(self, req, connectors)?) .build(); Ok(Some(request)) } fn handle_response( &self, - data: &types::RefundsRouterData, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult, errors::ConnectorError> { + res: Response, + ) -> CustomResult, errors::ConnectorError> { let response: payu::RefundResponse = res .response .parse_struct("payu RefundResponse") .change_context(errors::ConnectorError::RequestEncodingFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -691,19 +666,19 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) } } -impl ConnectorIntegration for Payu { +impl ConnectorIntegration for Payu { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { self.build_headers(req, connectors) } @@ -713,8 +688,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}{}{}{}", @@ -727,32 +702,32 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::RefundSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .headers(RefundSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::RefundSyncRouterData, + data: &RefundSyncRouterData, event_builder: Option<&mut ConnectorEvent>, - res: types::Response, - ) -> CustomResult { + res: Response, + ) -> CustomResult { let response: payu::RefundSyncResponse = res.response .parse_struct("payu RefundResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -762,7 +737,7 @@ impl ConnectorIntegration, ) -> CustomResult { self.build_error_response(res, event_builder) @@ -770,24 +745,24 @@ impl ConnectorIntegration, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } fn get_webhook_event_type( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { - Ok(api::IncomingWebhookEvent::EventNotSupported) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { + Ok(IncomingWebhookEvent::EventNotSupported) } fn get_webhook_resource_object( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Err(report!(errors::ConnectorError::WebhooksNotImplemented)) } diff --git a/crates/router/src/connector/payu/transformers.rs b/crates/hyperswitch_connectors/src/connectors/payu/transformers.rs similarity index 82% rename from crates/router/src/connector/payu/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/payu/transformers.rs index 5365fc74ef2..7b3792c0e24 100644 --- a/crates/router/src/connector/payu/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/payu/transformers.rs @@ -1,14 +1,25 @@ use base64::Engine; -use common_utils::pii::{Email, IpAddress}; +use common_enums::enums; +use common_utils::{ + consts::BASE64_ENGINE, + pii::{Email, IpAddress}, +}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{PaymentMethodData, WalletData}, + router_data::{AccessToken, ConnectorAuthType, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::ResponseId, + router_response_types::{PaymentsResponseData, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::errors; +use masking::Secret; use serde::{Deserialize, Serialize}; use crate::{ - connector::utils::AccessTokenRequestInfo, - consts, - core::errors, - pii::Secret, - types::{self, api, domain, storage::enums}, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::AccessTokenRequestInfo as _, }; const WALLET_IDENTIFIER: &str = "PBL"; @@ -70,7 +81,7 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest { fn try_from(item: &types::PaymentsAuthorizeRouterData) -> Result { let auth_type = PayuAuthType::try_from(&item.connector_auth_type)?; let payment_method = match item.request.payment_method_data.clone() { - domain::PaymentMethodData::Card(ccard) => Ok(PayuPaymentMethod { + PaymentMethodData::Card(ccard) => Ok(PayuPaymentMethod { pay_method: PayuPaymentMethodData::Card(PayuCard::Card { number: ccard.card_number, expiration_month: ccard.card_exp_month, @@ -78,19 +89,19 @@ impl TryFrom<&types::PaymentsAuthorizeRouterData> for PayuPaymentsRequest { cvv: ccard.card_cvc, }), }), - domain::PaymentMethodData::Wallet(wallet_data) => match wallet_data { - domain::WalletData::GooglePay(data) => Ok(PayuPaymentMethod { + PaymentMethodData::Wallet(wallet_data) => match wallet_data { + WalletData::GooglePay(data) => Ok(PayuPaymentMethod { pay_method: PayuPaymentMethodData::Wallet({ PayuWallet { value: PayuWalletCode::Ap, wallet_type: WALLET_IDENTIFIER.to_string(), authorization_code: Secret::new( - consts::BASE64_ENGINE.encode(data.tokenization_data.token), + BASE64_ENGINE.encode(data.tokenization_data.token), ), } }), }), - domain::WalletData::ApplePay(data) => Ok(PayuPaymentMethod { + WalletData::ApplePay(data) => Ok(PayuPaymentMethod { pay_method: PayuPaymentMethodData::Wallet({ PayuWallet { value: PayuWalletCode::Jp, @@ -140,11 +151,11 @@ pub struct PayuAuthType { pub(super) merchant_pos_id: Secret, } -impl TryFrom<&types::ConnectorAuthType> for PayuAuthType { +impl TryFrom<&ConnectorAuthType> for PayuAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { + fn try_from(auth_type: &ConnectorAuthType) -> Result { match auth_type { - types::ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { + ConnectorAuthType::BodyKey { api_key, key1 } => Ok(Self { api_key: api_key.to_owned(), merchant_pos_id: key1.to_owned(), }), @@ -188,20 +199,17 @@ pub struct PayuPaymentsResponse { pub ext_order_id: Option, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { Ok(Self { status: enums::AttemptStatus::from(item.response.status.status_code), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.order_id.clone(), - ), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.order_id.clone()), redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -241,24 +249,17 @@ pub struct PayuPaymentsCaptureResponse { status: PayuPaymentStatusData, } -impl - TryFrom< - types::ResponseRouterData, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - PayuPaymentsCaptureResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { Ok(Self { status: enums::AttemptStatus::from(item.response.status.status_code.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::NoResponseId, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -298,15 +299,15 @@ pub struct PayuAuthUpdateResponse { pub grant_type: String, } -impl TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { Ok(Self { - response: Ok(types::AccessToken { + response: Ok(AccessToken { token: item.response.access_token, expires: item.response.expires_in, }), @@ -323,26 +324,17 @@ pub struct PayuPaymentsCancelResponse { pub status: PayuPaymentStatusData, } -impl - TryFrom< - types::ResponseRouterData, - > for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - PayuPaymentsCancelResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { Ok(Self { status: enums::AttemptStatus::from(item.response.status.status_code.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId( - item.response.order_id.clone(), - ), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(item.response.order_id.clone()), redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -457,18 +449,12 @@ pub struct PayuPaymentsSyncResponse { properties: Option>, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData< - F, - PayuPaymentsSyncResponse, - T, - types::PaymentsResponseData, - >, + item: ResponseRouterData, ) -> Result { let order = match item.response.orders.first() { Some(order) => order, @@ -476,8 +462,8 @@ impl }; Ok(Self { status: enums::AttemptStatus::from(order.status.clone()), - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(order.order_id.clone()), + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(order.order_id.clone()), redirection_data: None, mandate_reference: None, connector_metadata: None, @@ -569,16 +555,16 @@ pub struct RefundResponse { refund: PayuRefundResponseData, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let refund_status = enums::RefundStatus::from(item.response.refund.status); Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.refund.refund_id, refund_status, }), @@ -591,19 +577,19 @@ impl TryFrom> pub struct RefundSyncResponse { refunds: Vec, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let refund = match item.response.refunds.first() { Some(refund) => refund, _ => Err(errors::ConnectorError::ResponseHandlingFailed)?, }; Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: refund.refund_id.clone(), refund_status: enums::RefundStatus::from(refund.status.clone()), }), diff --git a/crates/router/src/connector/zen.rs b/crates/hyperswitch_connectors/src/connectors/zen.rs similarity index 64% rename from crates/router/src/connector/zen.rs rename to crates/hyperswitch_connectors/src/connectors/zen.rs index 2d522dbdf1b..a90b10fbd86 100644 --- a/crates/router/src/connector/zen.rs +++ b/crates/hyperswitch_connectors/src/connectors/zen.rs @@ -2,34 +2,52 @@ pub mod transformers; use std::fmt::Debug; -use common_utils::{crypto, ext_traits::ByteSliceExt, request::RequestContent}; +use api_models::webhooks::IncomingWebhookEvent; +use common_enums::{CallConnectorAction, PaymentAction}; +use common_utils::{ + crypto, + errors::CustomResult, + ext_traits::{ByteSliceExt, BytesExt}, + request::{Method, Request, RequestBuilder, RequestContent}, +}; use error_stack::ResultExt; -use masking::{PeekInterface, Secret}; -use transformers as zen; -use uuid::Uuid; - -use self::transformers::{ZenPaymentStatus, ZenWebhookTxnType}; -use crate::{ - configs::settings, - consts, - core::{ - errors::{self, CustomResult}, - payments, +use hyperswitch_domain_models::{ + api::ApplicationResponse, + payment_method_data::PaymentMethodData, + router_data::{AccessToken, ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::{ + access_token_auth::AccessTokenAuth, + payments::{Authorize, Capture, PSync, PaymentMethodToken, Session, SetupMandate, Void}, + refunds::{Execute, RSync}, }, - events::connector_api_logs::ConnectorEvent, - headers, - services::{ - self, - request::{self, Mask}, - ConnectorIntegration, ConnectorValidation, + router_request_types::{ + AccessTokenRequestData, PaymentMethodTokenizationData, PaymentsAuthorizeData, + PaymentsCancelData, PaymentsCaptureData, PaymentsSessionData, PaymentsSyncData, + RefundsData, SetupMandateRequestData, }, + router_response_types::{PaymentsResponseData, RefundsResponseData}, types::{ - self, - api::{self, ConnectorCommon, ConnectorCommonExt}, - domain, ErrorResponse, Response, + PaymentsAuthorizeRouterData, PaymentsSyncRouterData, RefundSyncRouterData, + RefundsRouterData, }, - utils::BytesExt, }; +use hyperswitch_interfaces::{ + api::{ + self, ConnectorCommon, ConnectorCommonExt, ConnectorIntegration, ConnectorRedirectResponse, + ConnectorValidation, + }, + configs::Connectors, + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + errors, + events::connector_api_logs::ConnectorEvent, + types::{PaymentsAuthorizeType, PaymentsSyncType, RefundExecuteType, RefundSyncType, Response}, + webhooks::{IncomingWebhook, IncomingWebhookRequestDetails}, +}; +use masking::{Mask, PeekInterface, Secret}; +use transformers::{self as zen, ZenPaymentStatus, ZenWebhookTxnType}; +use uuid::Uuid; + +use crate::{constants::headers, types::ResponseRouterData}; #[derive(Debug, Clone)] pub struct Zen; @@ -48,7 +66,7 @@ impl api::RefundExecute for Zen {} impl api::RefundSync for Zen {} impl Zen { - fn get_default_header() -> (String, request::Maskable) { + fn get_default_header() -> (String, masking::Maskable) { ("request-id".to_string(), Uuid::new_v4().to_string().into()) } } @@ -59,9 +77,9 @@ where { fn build_headers( &self, - req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = vec![( headers::CONTENT_TYPE.to_string(), self.get_content_type().to_string().into(), @@ -87,14 +105,14 @@ impl ConnectorCommon for Zen { mime::APPLICATION_JSON.essence_str() } - fn base_url<'a>(&self, connectors: &'a settings::Connectors) -> &'a str { + fn base_url<'a>(&self, connectors: &'a Connectors) -> &'a str { connectors.zen.base_url.as_ref() } fn get_auth_header( &self, - auth_type: &types::ConnectorAuthType, - ) -> CustomResult)>, errors::ConnectorError> { + auth_type: &ConnectorAuthType, + ) -> CustomResult)>, errors::ConnectorError> { let auth = zen::ZenAuthType::try_from(auth_type)?; Ok(vec![( headers::AUTHORIZATION.to_string(), @@ -120,13 +138,9 @@ impl ConnectorCommon for Zen { code: response .error .clone() - .map_or(consts::NO_ERROR_CODE.to_string(), |error| error.code), + .map_or(NO_ERROR_CODE.to_string(), |error| error.code), message: response.error.map_or_else( - || { - response - .message - .unwrap_or(consts::NO_ERROR_MESSAGE.to_string()) - }, + || response.message.unwrap_or(NO_ERROR_MESSAGE.to_string()), |error| error.message, ), reason: None, @@ -139,7 +153,7 @@ impl ConnectorCommon for Zen { impl ConnectorValidation for Zen { fn validate_psync_reference_id( &self, - _data: &hyperswitch_domain_models::router_request_types::PaymentsSyncData, + _data: &PaymentsSyncData, _is_three_ds: bool, _status: common_enums::enums::AttemptStatus, _connector_meta_data: Option, @@ -149,58 +163,37 @@ impl ConnectorValidation for Zen { } } -impl ConnectorIntegration - for Zen -{ +impl ConnectorIntegration for Zen { //TODO: implement sessions flow } -impl - ConnectorIntegration< - api::PaymentMethodToken, - types::PaymentMethodTokenizationData, - types::PaymentsResponseData, - > for Zen +impl ConnectorIntegration + for Zen { // Not Implemented (R) } -impl ConnectorIntegration - for Zen -{ -} +impl ConnectorIntegration for Zen {} -impl - ConnectorIntegration< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - > for Zen -{ +impl ConnectorIntegration for Zen { fn build_request( &self, - _req: &types::RouterData< - api::SetupMandate, - types::SetupMandateRequestData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::NotImplemented("Setup Mandate flow for Zen".to_string()).into()) } } -impl ConnectorIntegration - for Zen -{ +impl ConnectorIntegration for Zen { fn get_headers( &self, - req: &types::PaymentsAuthorizeRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = self.build_headers(req, connectors)?; let api_headers = match req.request.payment_method_data { - domain::payments::PaymentMethodData::Wallet(_) => None, + PaymentMethodData::Wallet(_) => None, _ => Some(Self::get_default_header()), }; if let Some(api_header) = api_headers { @@ -215,11 +208,11 @@ impl ConnectorIntegration CustomResult { let endpoint = match &req.request.payment_method_data { - domain::payments::PaymentMethodData::Wallet(_) => { + PaymentMethodData::Wallet(_) => { let base_url = connectors .zen .secondary_base_url @@ -234,8 +227,8 @@ impl ConnectorIntegration CustomResult { let connector_router_data = zen::ZenRouterData::try_from(( &self.get_currency_unit(), @@ -249,20 +242,16 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsAuthorizeRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::PaymentsAuthorizeType::get_url( - self, req, connectors, - )?) + RequestBuilder::new() + .method(Method::Post) + .url(&PaymentsAuthorizeType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsAuthorizeType::get_headers( - self, req, connectors, - )?) - .set_body(types::PaymentsAuthorizeType::get_request_body( + .headers(PaymentsAuthorizeType::get_headers(self, req, connectors)?) + .set_body(PaymentsAuthorizeType::get_request_body( self, req, connectors, )?) .build(), @@ -271,17 +260,17 @@ impl ConnectorIntegration, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: zen::ZenPaymentsResponse = res .response .parse_struct("Zen PaymentsAuthorizeResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -297,14 +286,12 @@ impl ConnectorIntegration - for Zen -{ +impl ConnectorIntegration for Zen { fn get_headers( &self, - req: &types::PaymentsSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = self.build_headers(req, connectors)?; headers.push(Self::get_default_header()); Ok(headers) @@ -316,8 +303,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}v1/transactions/merchant/{}", @@ -328,32 +315,32 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &PaymentsSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::PaymentsSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&PaymentsSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::PaymentsSyncType::get_headers(self, req, connectors)?) + .headers(PaymentsSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::PaymentsSyncRouterData, + data: &PaymentsSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: zen::ZenPaymentsResponse = res .response .parse_struct("zen PaymentsSyncResponse") .change_context(errors::ConnectorError::ResponseDeserializationFailed)?; event_builder.map(|i| i.set_response_body(&response)); router_env::logger::info!(connector_response=?response); - types::RouterData::try_from(types::ResponseRouterData { + RouterData::try_from(ResponseRouterData { response, data: data.clone(), http_code: res.status_code, @@ -369,18 +356,12 @@ impl ConnectorIntegration - for Zen -{ +impl ConnectorIntegration for Zen { fn build_request( &self, - _req: &types::RouterData< - api::Capture, - types::PaymentsCaptureData, - types::PaymentsResponseData, - >, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::FlowNotSupported { flow: "Capture".to_owned(), connector: "Zen".to_owned(), @@ -389,14 +370,12 @@ impl ConnectorIntegration - for Zen -{ +impl ConnectorIntegration for Zen { fn build_request( &self, - _req: &types::RouterData, - _connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { + _req: &RouterData, + _connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Err(errors::ConnectorError::FlowNotSupported { flow: "Void".to_owned(), connector: "Zen".to_owned(), @@ -405,12 +384,12 @@ impl ConnectorIntegration for Zen { +impl ConnectorIntegration for Zen { fn get_headers( &self, - req: &types::RefundsRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = self.build_headers(req, connectors)?; headers.push(Self::get_default_header()); Ok(headers) @@ -422,8 +401,8 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, + _req: &RefundsRouterData, + connectors: &Connectors, ) -> CustomResult { Ok(format!( "{}v1/transactions/refund", @@ -433,8 +412,8 @@ impl ConnectorIntegration, - _connectors: &settings::Connectors, + req: &RefundsRouterData, + _connectors: &Connectors, ) -> CustomResult { let connector_router_data = zen::ZenRouterData::try_from(( &self.get_currency_unit(), @@ -448,29 +427,25 @@ impl ConnectorIntegration, - connectors: &settings::Connectors, - ) -> CustomResult, errors::ConnectorError> { - let request = services::RequestBuilder::new() - .method(services::Method::Post) - .url(&types::RefundExecuteType::get_url(self, req, connectors)?) + req: &RefundsRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { + let request = RequestBuilder::new() + .method(Method::Post) + .url(&RefundExecuteType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundExecuteType::get_headers( - self, req, connectors, - )?) - .set_body(types::RefundExecuteType::get_request_body( - self, req, connectors, - )?) + .headers(RefundExecuteType::get_headers(self, req, connectors)?) + .set_body(RefundExecuteType::get_request_body(self, req, connectors)?) .build(); Ok(Some(request)) } fn handle_response( &self, - data: &types::RefundsRouterData, + data: &RefundsRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult, errors::ConnectorError> { + ) -> CustomResult, errors::ConnectorError> { let response: zen::RefundResponse = res .response .parse_struct("zen RefundResponse") @@ -478,7 +453,7 @@ impl ConnectorIntegration for Zen { +impl ConnectorIntegration for Zen { fn get_headers( &self, - req: &types::RefundSyncRouterData, - connectors: &settings::Connectors, - ) -> CustomResult)>, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult)>, errors::ConnectorError> { let mut headers = self.build_headers(req, connectors)?; headers.push(Self::get_default_header()); Ok(headers) @@ -511,8 +486,8 @@ impl ConnectorIntegration CustomResult { Ok(format!( "{}v1/transactions/merchant/{}", @@ -523,25 +498,25 @@ impl ConnectorIntegration CustomResult, errors::ConnectorError> { + req: &RefundSyncRouterData, + connectors: &Connectors, + ) -> CustomResult, errors::ConnectorError> { Ok(Some( - services::RequestBuilder::new() - .method(services::Method::Get) - .url(&types::RefundSyncType::get_url(self, req, connectors)?) + RequestBuilder::new() + .method(Method::Get) + .url(&RefundSyncType::get_url(self, req, connectors)?) .attach_default_headers() - .headers(types::RefundSyncType::get_headers(self, req, connectors)?) + .headers(RefundSyncType::get_headers(self, req, connectors)?) .build(), )) } fn handle_response( &self, - data: &types::RefundSyncRouterData, + data: &RefundSyncRouterData, event_builder: Option<&mut ConnectorEvent>, res: Response, - ) -> CustomResult { + ) -> CustomResult { let response: zen::RefundResponse = res .response .parse_struct("zen RefundSyncResponse") @@ -550,7 +525,7 @@ impl ConnectorIntegration, + _request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { Ok(Box::new(crypto::Sha256)) } fn get_webhook_source_verification_signature( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets, ) -> CustomResult, errors::ConnectorError> { let webhook_body: zen::ZenWebhookSignature = request @@ -590,7 +565,7 @@ impl api::IncomingWebhook for Zen { fn get_webhook_source_verification_message( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, _merchant_id: &common_utils::id_type::MerchantId, _connector_webhook_secrets: &api_models::webhooks::ConnectorWebhookSecrets, ) -> CustomResult, errors::ConnectorError> { @@ -610,7 +585,7 @@ impl api::IncomingWebhook for Zen { async fn verify_webhook_source( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, merchant_id: &common_utils::id_type::MerchantId, connector_webhook_details: Option, _connector_account_details: crypto::Encryptable>, @@ -641,7 +616,7 @@ impl api::IncomingWebhook for Zen { fn get_webhook_object_reference_id( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult { let webhook_body: zen::ZenWebhookObjectReference = request .body @@ -663,8 +638,8 @@ impl api::IncomingWebhook for Zen { fn get_webhook_event_type( &self, - request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult { + request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult { let details: zen::ZenWebhookEventType = request .body .parse_struct("ZenWebhookEventType") @@ -672,22 +647,22 @@ impl api::IncomingWebhook for Zen { Ok(match &details.transaction_type { ZenWebhookTxnType::TrtPurchase => match &details.status { - ZenPaymentStatus::Rejected => api::IncomingWebhookEvent::PaymentIntentFailure, - ZenPaymentStatus::Accepted => api::IncomingWebhookEvent::PaymentIntentSuccess, + ZenPaymentStatus::Rejected => IncomingWebhookEvent::PaymentIntentFailure, + ZenPaymentStatus::Accepted => IncomingWebhookEvent::PaymentIntentSuccess, _ => Err(errors::ConnectorError::WebhookEventTypeNotFound)?, }, ZenWebhookTxnType::TrtRefund => match &details.status { - ZenPaymentStatus::Rejected => api::IncomingWebhookEvent::RefundFailure, - ZenPaymentStatus::Accepted => api::IncomingWebhookEvent::RefundSuccess, + ZenPaymentStatus::Rejected => IncomingWebhookEvent::RefundFailure, + ZenPaymentStatus::Accepted => IncomingWebhookEvent::RefundSuccess, _ => Err(errors::ConnectorError::WebhookEventTypeNotFound)?, }, - ZenWebhookTxnType::Unknown => api::IncomingWebhookEvent::EventNotSupported, + ZenWebhookTxnType::Unknown => IncomingWebhookEvent::EventNotSupported, }) } fn get_webhook_resource_object( &self, - request: &api::IncomingWebhookRequestDetails<'_>, + request: &IncomingWebhookRequestDetails<'_>, ) -> CustomResult, errors::ConnectorError> { let reference_object: serde_json::Value = serde_json::from_slice(request.body) .change_context(errors::ConnectorError::WebhookResourceObjectNotFound)?; @@ -695,29 +670,26 @@ impl api::IncomingWebhook for Zen { } fn get_webhook_api_response( &self, - _request: &api::IncomingWebhookRequestDetails<'_>, - ) -> CustomResult, errors::ConnectorError> - { - Ok(services::api::ApplicationResponse::Json( - serde_json::json!({ - "status": "ok" - }), - )) + _request: &IncomingWebhookRequestDetails<'_>, + ) -> CustomResult, errors::ConnectorError> { + Ok(ApplicationResponse::Json(serde_json::json!({ + "status": "ok" + }))) } } -impl services::ConnectorRedirectResponse for Zen { +impl ConnectorRedirectResponse for Zen { fn get_flow_type( &self, _query_params: &str, _json_payload: Option, - action: services::PaymentAction, - ) -> CustomResult { + action: PaymentAction, + ) -> CustomResult { match action { - services::PaymentAction::PSync - | services::PaymentAction::CompleteAuthorize - | services::PaymentAction::PaymentAuthenticateCompleteAuthorize => { - Ok(payments::CallConnectorAction::Trigger) + PaymentAction::PSync + | PaymentAction::CompleteAuthorize + | PaymentAction::PaymentAuthenticateCompleteAuthorize => { + Ok(CallConnectorAction::Trigger) } } } diff --git a/crates/router/src/connector/zen/transformers.rs b/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs similarity index 71% rename from crates/router/src/connector/zen/transformers.rs rename to crates/hyperswitch_connectors/src/connectors/zen/transformers.rs index 799753fd52c..a564fb4ee60 100644 --- a/crates/router/src/connector/zen/transformers.rs +++ b/crates/hyperswitch_connectors/src/connectors/zen/transformers.rs @@ -1,20 +1,39 @@ use cards::CardNumber; -use common_utils::{ext_traits::ValueExt, pii}; +use common_enums::enums; +use common_utils::{ + errors::CustomResult, + ext_traits::{OptionExt, ValueExt}, + pii::{self}, + request::Method, +}; use error_stack::ResultExt; +use hyperswitch_domain_models::{ + payment_method_data::{ + BankDebitData, BankRedirectData, BankTransferData, Card, CardRedirectData, GiftCardData, + PayLaterData, PaymentMethodData, VoucherData, WalletData, + }, + router_data::{ConnectorAuthType, ErrorResponse, RouterData}, + router_flow_types::refunds::{Execute, RSync}, + router_request_types::{BrowserInformation, ResponseId}, + router_response_types::{PaymentsResponseData, RedirectForm, RefundsResponseData}, + types, +}; +use hyperswitch_interfaces::{ + api, + consts::{NO_ERROR_CODE, NO_ERROR_MESSAGE}, + errors, +}; use masking::{ExposeInterface, PeekInterface, Secret}; use ring::digest; use serde::{Deserialize, Serialize}; use strum::Display; use crate::{ - connector::utils::{ - self, BrowserInformationData, CardData, PaymentsAuthorizeRequestData, RouterData, + types::{RefundsResponseRouterData, ResponseRouterData}, + utils::{ + self, BrowserInformationData, CardData, ForeignTryFrom, PaymentsAuthorizeRequestData, + RouterData as _, }, - consts, - core::errors::{self, CustomResult}, - services::{self, Method}, - types::{self, api, domain, storage::enums, transformers::ForeignTryFrom}, - utils::OptionExt, }; #[derive(Debug, Serialize)] @@ -41,10 +60,10 @@ pub struct ZenAuthType { pub(super) api_key: Secret, } -impl TryFrom<&types::ConnectorAuthType> for ZenAuthType { +impl TryFrom<&ConnectorAuthType> for ZenAuthType { type Error = error_stack::Report; - fn try_from(auth_type: &types::ConnectorAuthType) -> Result { - if let types::ConnectorAuthType::HeaderKey { api_key } = auth_type { + fn try_from(auth_type: &ConnectorAuthType) -> Result { + if let ConnectorAuthType::HeaderKey { api_key } = auth_type { Ok(Self { api_key: api_key.to_owned(), }) @@ -191,18 +210,10 @@ pub struct WalletSessionData { pub pay_wall_secret: Option>, } -impl - TryFrom<( - &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::Card, - )> for ZenPaymentsRequest -{ +impl TryFrom<(&ZenRouterData<&types::PaymentsAuthorizeRouterData>, &Card)> for ZenPaymentsRequest { type Error = error_stack::Report; fn try_from( - value: ( - &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::Card, - ), + value: (&ZenRouterData<&types::PaymentsAuthorizeRouterData>, &Card), ) -> Result { let (item, ccard) = value; let browser_info = item.router_data.request.get_browser_info()?; @@ -245,14 +256,14 @@ impl impl TryFrom<( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::VoucherData, + &VoucherData, )> for ZenPaymentsRequest { type Error = error_stack::Report; fn try_from( value: ( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::VoucherData, + &VoucherData, ), ) -> Result { let (item, voucher_data) = value; @@ -266,20 +277,20 @@ impl return_url: item.router_data.request.get_router_return_url()?, }); let payment_channel = match voucher_data { - domain::VoucherData::Boleto { .. } => ZenPaymentChannels::PclBoacompraBoleto, - domain::VoucherData::Efecty => ZenPaymentChannels::PclBoacompraEfecty, - domain::VoucherData::PagoEfectivo => ZenPaymentChannels::PclBoacompraPagoefectivo, - domain::VoucherData::RedCompra => ZenPaymentChannels::PclBoacompraRedcompra, - domain::VoucherData::RedPagos => ZenPaymentChannels::PclBoacompraRedpagos, - domain::VoucherData::Oxxo { .. } - | domain::VoucherData::Alfamart { .. } - | domain::VoucherData::Indomaret { .. } - | domain::VoucherData::SevenEleven { .. } - | domain::VoucherData::Lawson { .. } - | domain::VoucherData::MiniStop { .. } - | domain::VoucherData::FamilyMart { .. } - | domain::VoucherData::Seicomart { .. } - | domain::VoucherData::PayEasy { .. } => Err(errors::ConnectorError::NotImplemented( + VoucherData::Boleto { .. } => ZenPaymentChannels::PclBoacompraBoleto, + VoucherData::Efecty => ZenPaymentChannels::PclBoacompraEfecty, + VoucherData::PagoEfectivo => ZenPaymentChannels::PclBoacompraPagoefectivo, + VoucherData::RedCompra => ZenPaymentChannels::PclBoacompraRedcompra, + VoucherData::RedPagos => ZenPaymentChannels::PclBoacompraRedpagos, + VoucherData::Oxxo { .. } + | VoucherData::Alfamart { .. } + | VoucherData::Indomaret { .. } + | VoucherData::SevenEleven { .. } + | VoucherData::Lawson { .. } + | VoucherData::MiniStop { .. } + | VoucherData::FamilyMart { .. } + | VoucherData::Seicomart { .. } + | VoucherData::PayEasy { .. } => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ))?, }; @@ -299,14 +310,14 @@ impl impl TryFrom<( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &Box, + &Box, )> for ZenPaymentsRequest { type Error = error_stack::Report; fn try_from( value: ( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &Box, + &Box, ), ) -> Result { let (item, bank_transfer_data) = value; @@ -320,22 +331,22 @@ impl return_url: item.router_data.request.get_router_return_url()?, }); let payment_channel = match **bank_transfer_data { - domain::BankTransferData::MultibancoBankTransfer { .. } => { + BankTransferData::MultibancoBankTransfer { .. } => { ZenPaymentChannels::PclBoacompraMultibanco } - domain::BankTransferData::Pix { .. } => ZenPaymentChannels::PclBoacompraPix, - domain::BankTransferData::Pse { .. } => ZenPaymentChannels::PclBoacompraPse, - domain::BankTransferData::SepaBankTransfer { .. } - | domain::BankTransferData::AchBankTransfer { .. } - | domain::BankTransferData::BacsBankTransfer { .. } - | domain::BankTransferData::PermataBankTransfer { .. } - | domain::BankTransferData::BcaBankTransfer { .. } - | domain::BankTransferData::BniVaBankTransfer { .. } - | domain::BankTransferData::BriVaBankTransfer { .. } - | domain::BankTransferData::CimbVaBankTransfer { .. } - | domain::BankTransferData::DanamonVaBankTransfer { .. } - | domain::BankTransferData::LocalBankTransfer { .. } - | domain::BankTransferData::MandiriVaBankTransfer { .. } => { + BankTransferData::Pix { .. } => ZenPaymentChannels::PclBoacompraPix, + BankTransferData::Pse { .. } => ZenPaymentChannels::PclBoacompraPse, + BankTransferData::SepaBankTransfer { .. } + | BankTransferData::AchBankTransfer { .. } + | BankTransferData::BacsBankTransfer { .. } + | BankTransferData::PermataBankTransfer { .. } + | BankTransferData::BcaBankTransfer { .. } + | BankTransferData::BniVaBankTransfer { .. } + | BankTransferData::BriVaBankTransfer { .. } + | BankTransferData::CimbVaBankTransfer { .. } + | BankTransferData::DanamonVaBankTransfer { .. } + | BankTransferData::LocalBankTransfer { .. } + | BankTransferData::MandiriVaBankTransfer { .. } => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ))? @@ -437,14 +448,14 @@ impl impl TryFrom<( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::WalletData, + &WalletData, )> for ZenPaymentsRequest { type Error = error_stack::Report; fn try_from( (item, wallet_data): ( &ZenRouterData<&types::PaymentsAuthorizeRouterData>, - &domain::WalletData, + &WalletData, ), ) -> Result { let amount = item.amount.to_owned(); @@ -453,7 +464,7 @@ impl .parse_value("SessionObject") .change_context(errors::ConnectorError::RequestEncodingFailed)?; let (specified_payment_channel, session_data) = match wallet_data { - domain::WalletData::ApplePayRedirect(_) => ( + WalletData::ApplePayRedirect(_) => ( ZenPaymentChannels::PclApplepay, session .apple_pay @@ -461,7 +472,7 @@ impl wallet_name: "Apple Pay".to_string(), })?, ), - domain::WalletData::GooglePayRedirect(_) => ( + WalletData::GooglePayRedirect(_) => ( ZenPaymentChannels::PclGooglepay, session .google_pay @@ -469,32 +480,32 @@ impl wallet_name: "Google Pay".to_string(), })?, ), - domain::WalletData::WeChatPayRedirect(_) - | domain::WalletData::PaypalRedirect(_) - | domain::WalletData::ApplePay(_) - | domain::WalletData::GooglePay(_) - | domain::WalletData::AliPayQr(_) - | domain::WalletData::AliPayRedirect(_) - | domain::WalletData::AliPayHkRedirect(_) - | domain::WalletData::MomoRedirect(_) - | domain::WalletData::KakaoPayRedirect(_) - | domain::WalletData::GoPayRedirect(_) - | domain::WalletData::GcashRedirect(_) - | domain::WalletData::ApplePayThirdPartySdk(_) - | domain::WalletData::DanaRedirect {} - | domain::WalletData::GooglePayThirdPartySdk(_) - | domain::WalletData::MbWayRedirect(_) - | domain::WalletData::MobilePayRedirect(_) - | domain::WalletData::PaypalSdk(_) - | domain::WalletData::Paze(_) - | domain::WalletData::SamsungPay(_) - | domain::WalletData::TwintRedirect {} - | domain::WalletData::VippsRedirect {} - | domain::WalletData::TouchNGoRedirect(_) - | domain::WalletData::CashappQr(_) - | domain::WalletData::SwishQr(_) - | domain::WalletData::WeChatPayQr(_) - | domain::WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( + WalletData::WeChatPayRedirect(_) + | WalletData::PaypalRedirect(_) + | WalletData::ApplePay(_) + | WalletData::GooglePay(_) + | WalletData::AliPayQr(_) + | WalletData::AliPayRedirect(_) + | WalletData::AliPayHkRedirect(_) + | WalletData::MomoRedirect(_) + | WalletData::KakaoPayRedirect(_) + | WalletData::GoPayRedirect(_) + | WalletData::GcashRedirect(_) + | WalletData::ApplePayThirdPartySdk(_) + | WalletData::DanaRedirect {} + | WalletData::GooglePayThirdPartySdk(_) + | WalletData::MbWayRedirect(_) + | WalletData::MobilePayRedirect(_) + | WalletData::PaypalSdk(_) + | WalletData::Paze(_) + | WalletData::SamsungPay(_) + | WalletData::TwintRedirect {} + | WalletData::VippsRedirect {} + | WalletData::TouchNGoRedirect(_) + | WalletData::CashappQr(_) + | WalletData::SwishQr(_) + | WalletData::WeChatPayQr(_) + | WalletData::Mifinity(_) => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ))?, }; @@ -625,7 +636,7 @@ fn get_item_object( } fn get_browser_details( - browser_info: &types::BrowserInformation, + browser_info: &BrowserInformation, ) -> CustomResult { let screen_height = browser_info .screen_height @@ -669,36 +680,28 @@ impl TryFrom<&ZenRouterData<&types::PaymentsAuthorizeRouterData>> for ZenPayment item: &ZenRouterData<&types::PaymentsAuthorizeRouterData>, ) -> Result { match &item.router_data.request.payment_method_data { - domain::PaymentMethodData::Card(card) => Self::try_from((item, card)), - domain::PaymentMethodData::Wallet(wallet_data) => Self::try_from((item, wallet_data)), - domain::PaymentMethodData::Voucher(voucher_data) => { - Self::try_from((item, voucher_data)) - } - domain::PaymentMethodData::BankTransfer(bank_transfer_data) => { + PaymentMethodData::Card(card) => Self::try_from((item, card)), + PaymentMethodData::Wallet(wallet_data) => Self::try_from((item, wallet_data)), + PaymentMethodData::Voucher(voucher_data) => Self::try_from((item, voucher_data)), + PaymentMethodData::BankTransfer(bank_transfer_data) => { Self::try_from((item, bank_transfer_data)) } - domain::PaymentMethodData::BankRedirect(bank_redirect_data) => { + PaymentMethodData::BankRedirect(bank_redirect_data) => { Self::try_from(bank_redirect_data) } - domain::PaymentMethodData::PayLater(paylater_data) => Self::try_from(paylater_data), - domain::PaymentMethodData::BankDebit(bank_debit_data) => { - Self::try_from(bank_debit_data) - } - domain::PaymentMethodData::CardRedirect(car_redirect_data) => { - Self::try_from(car_redirect_data) - } - domain::PaymentMethodData::GiftCard(gift_card_data) => { - Self::try_from(gift_card_data.as_ref()) - } - domain::PaymentMethodData::Crypto(_) - | domain::PaymentMethodData::MandatePayment - | domain::PaymentMethodData::Reward - | domain::PaymentMethodData::RealTimePayment(_) - | domain::PaymentMethodData::Upi(_) - | domain::PaymentMethodData::OpenBanking(_) - | domain::PaymentMethodData::CardToken(_) - | domain::PaymentMethodData::NetworkToken(_) - | domain::PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { + PaymentMethodData::PayLater(paylater_data) => Self::try_from(paylater_data), + PaymentMethodData::BankDebit(bank_debit_data) => Self::try_from(bank_debit_data), + PaymentMethodData::CardRedirect(car_redirect_data) => Self::try_from(car_redirect_data), + PaymentMethodData::GiftCard(gift_card_data) => Self::try_from(gift_card_data.as_ref()), + PaymentMethodData::Crypto(_) + | PaymentMethodData::MandatePayment + | PaymentMethodData::Reward + | PaymentMethodData::RealTimePayment(_) + | PaymentMethodData::Upi(_) + | PaymentMethodData::OpenBanking(_) + | PaymentMethodData::CardToken(_) + | PaymentMethodData::NetworkToken(_) + | PaymentMethodData::CardDetailsForNetworkTransactionId(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ))? @@ -707,28 +710,28 @@ impl TryFrom<&ZenRouterData<&types::PaymentsAuthorizeRouterData>> for ZenPayment } } -impl TryFrom<&domain::BankRedirectData> for ZenPaymentsRequest { +impl TryFrom<&BankRedirectData> for ZenPaymentsRequest { type Error = error_stack::Report; - fn try_from(value: &domain::BankRedirectData) -> Result { + fn try_from(value: &BankRedirectData) -> Result { match value { - domain::BankRedirectData::Ideal { .. } - | domain::BankRedirectData::Sofort { .. } - | domain::BankRedirectData::BancontactCard { .. } - | domain::BankRedirectData::Blik { .. } - | domain::BankRedirectData::Trustly { .. } - | domain::BankRedirectData::Eps { .. } - | domain::BankRedirectData::Giropay { .. } - | domain::BankRedirectData::Przelewy24 { .. } - | domain::BankRedirectData::Bizum {} - | domain::BankRedirectData::Interac { .. } - | domain::BankRedirectData::OnlineBankingCzechRepublic { .. } - | domain::BankRedirectData::OnlineBankingFinland { .. } - | domain::BankRedirectData::OnlineBankingPoland { .. } - | domain::BankRedirectData::OnlineBankingSlovakia { .. } - | domain::BankRedirectData::OpenBankingUk { .. } - | domain::BankRedirectData::OnlineBankingFpx { .. } - | domain::BankRedirectData::OnlineBankingThailand { .. } - | domain::BankRedirectData::LocalBankRedirect {} => { + BankRedirectData::Ideal { .. } + | BankRedirectData::Sofort { .. } + | BankRedirectData::BancontactCard { .. } + | BankRedirectData::Blik { .. } + | BankRedirectData::Trustly { .. } + | BankRedirectData::Eps { .. } + | BankRedirectData::Giropay { .. } + | BankRedirectData::Przelewy24 { .. } + | BankRedirectData::Bizum {} + | BankRedirectData::Interac { .. } + | BankRedirectData::OnlineBankingCzechRepublic { .. } + | BankRedirectData::OnlineBankingFinland { .. } + | BankRedirectData::OnlineBankingPoland { .. } + | BankRedirectData::OnlineBankingSlovakia { .. } + | BankRedirectData::OpenBankingUk { .. } + | BankRedirectData::OnlineBankingFpx { .. } + | BankRedirectData::OnlineBankingThailand { .. } + | BankRedirectData::LocalBankRedirect {} => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ) @@ -738,66 +741,60 @@ impl TryFrom<&domain::BankRedirectData> for ZenPaymentsRequest { } } -impl TryFrom<&domain::payments::PayLaterData> for ZenPaymentsRequest { +impl TryFrom<&PayLaterData> for ZenPaymentsRequest { type Error = error_stack::Report; - fn try_from(value: &domain::payments::PayLaterData) -> Result { + fn try_from(value: &PayLaterData) -> Result { match value { - domain::payments::PayLaterData::KlarnaRedirect { .. } - | domain::payments::PayLaterData::KlarnaSdk { .. } - | domain::payments::PayLaterData::AffirmRedirect {} - | domain::payments::PayLaterData::AfterpayClearpayRedirect { .. } - | domain::payments::PayLaterData::PayBrightRedirect {} - | domain::payments::PayLaterData::WalleyRedirect {} - | domain::payments::PayLaterData::AlmaRedirect {} - | domain::payments::PayLaterData::AtomeRedirect {} => { - Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Zen"), - ) - .into()) - } + PayLaterData::KlarnaRedirect { .. } + | PayLaterData::KlarnaSdk { .. } + | PayLaterData::AffirmRedirect {} + | PayLaterData::AfterpayClearpayRedirect { .. } + | PayLaterData::PayBrightRedirect {} + | PayLaterData::WalleyRedirect {} + | PayLaterData::AlmaRedirect {} + | PayLaterData::AtomeRedirect {} => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("Zen"), + ) + .into()), } } } -impl TryFrom<&domain::BankDebitData> for ZenPaymentsRequest { +impl TryFrom<&BankDebitData> for ZenPaymentsRequest { type Error = error_stack::Report; - fn try_from(value: &domain::BankDebitData) -> Result { + fn try_from(value: &BankDebitData) -> Result { match value { - domain::BankDebitData::AchBankDebit { .. } - | domain::BankDebitData::SepaBankDebit { .. } - | domain::BankDebitData::BecsBankDebit { .. } - | domain::BankDebitData::BacsBankDebit { .. } => { - Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Zen"), - ) - .into()) - } + BankDebitData::AchBankDebit { .. } + | BankDebitData::SepaBankDebit { .. } + | BankDebitData::BecsBankDebit { .. } + | BankDebitData::BacsBankDebit { .. } => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("Zen"), + ) + .into()), } } } -impl TryFrom<&domain::payments::CardRedirectData> for ZenPaymentsRequest { +impl TryFrom<&CardRedirectData> for ZenPaymentsRequest { type Error = error_stack::Report; - fn try_from(value: &domain::payments::CardRedirectData) -> Result { + fn try_from(value: &CardRedirectData) -> Result { match value { - domain::payments::CardRedirectData::Knet {} - | domain::payments::CardRedirectData::Benefit {} - | domain::payments::CardRedirectData::MomoAtm {} - | domain::payments::CardRedirectData::CardRedirect {} => { - Err(errors::ConnectorError::NotImplemented( - utils::get_unimplemented_payment_method_error_message("Zen"), - ) - .into()) - } + CardRedirectData::Knet {} + | CardRedirectData::Benefit {} + | CardRedirectData::MomoAtm {} + | CardRedirectData::CardRedirect {} => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("Zen"), + ) + .into()), } } } -impl TryFrom<&domain::GiftCardData> for ZenPaymentsRequest { +impl TryFrom<&GiftCardData> for ZenPaymentsRequest { type Error = error_stack::Report; - fn try_from(value: &domain::GiftCardData) -> Result { + fn try_from(value: &GiftCardData) -> Result { match value { - domain::GiftCardData::PaySafeCard {} | domain::GiftCardData::Givex(_) => { + GiftCardData::PaySafeCard {} | GiftCardData::Givex(_) => { Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("Zen"), ) @@ -879,29 +876,24 @@ pub struct ZenMerchantActionData { redirect_url: url::Url, } -impl - TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - item: types::ResponseRouterData, + item: ResponseRouterData, ) -> Result { match item.response { - ZenPaymentsResponse::ApiResponse(response) => { - Self::try_from(types::ResponseRouterData { - response, - data: item.data, - http_code: item.http_code, - }) - } - ZenPaymentsResponse::CheckoutResponse(response) => { - Self::try_from(types::ResponseRouterData { - response, - data: item.data, - http_code: item.http_code, - }) - } + ZenPaymentsResponse::ApiResponse(response) => Self::try_from(ResponseRouterData { + response, + data: item.data, + http_code: item.http_code, + }), + ZenPaymentsResponse::CheckoutResponse(response) => Self::try_from(ResponseRouterData { + response, + data: item.data, + http_code: item.http_code, + }), } } } @@ -912,14 +904,14 @@ fn get_zen_response( ) -> CustomResult< ( enums::AttemptStatus, - Option, - types::PaymentsResponseData, + Option, + PaymentsResponseData, ), errors::ConnectorError, > { let redirection_data_action = response.merchant_action.map(|merchant_action| { ( - services::RedirectForm::from((merchant_action.data.redirect_url, Method::Get)), + RedirectForm::from((merchant_action.data.redirect_url, Method::Get)), merchant_action.action, ) }); @@ -929,14 +921,14 @@ fn get_zen_response( }; let status = enums::AttemptStatus::foreign_try_from((response.status, action))?; let error = if utils::is_payment_failure(status) { - Some(types::ErrorResponse { + Some(ErrorResponse { code: response .reject_code - .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), + .unwrap_or_else(|| NO_ERROR_CODE.to_string()), message: response .reject_reason .clone() - .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()), reason: response.reject_reason, status_code, attempt_status: Some(status), @@ -945,8 +937,8 @@ fn get_zen_response( } else { None }; - let payment_response_data = types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::ConnectorTransactionId(response.id.clone()), + let payment_response_data = PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::ConnectorTransactionId(response.id.clone()), redirection_data, mandate_reference: None, connector_metadata: None, @@ -958,12 +950,12 @@ fn get_zen_response( Ok((status, error, payment_response_data)) } -impl TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - value: types::ResponseRouterData, + value: ResponseRouterData, ) -> Result { let (status, error, payment_response_data) = get_zen_response(value.response.clone(), value.http_code)?; @@ -976,21 +968,21 @@ impl TryFrom TryFrom> - for types::RouterData +impl TryFrom> + for RouterData { type Error = error_stack::Report; fn try_from( - value: types::ResponseRouterData, + value: ResponseRouterData, ) -> Result { - let redirection_data = Some(services::RedirectForm::from(( + let redirection_data = Some(RedirectForm::from(( value.response.redirect_url, Method::Get, ))); Ok(Self { status: enums::AttemptStatus::AuthenticationPending, - response: Ok(types::PaymentsResponseData::TransactionResponse { - resource_id: types::ResponseId::NoResponseId, + response: Ok(PaymentsResponseData::TransactionResponse { + resource_id: ResponseId::NoResponseId, redirection_data, mandate_reference: None, connector_metadata: None, @@ -1054,12 +1046,12 @@ pub struct RefundResponse { reject_reason: Option, } -impl TryFrom> - for types::RefundsRouterData +impl TryFrom> + for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let (error, refund_response_data) = get_zen_refund_response(item.response, item.http_code)?; Ok(Self { @@ -1072,18 +1064,17 @@ impl TryFrom> fn get_zen_refund_response( response: RefundResponse, status_code: u16, -) -> CustomResult<(Option, types::RefundsResponseData), errors::ConnectorError> -{ +) -> CustomResult<(Option, RefundsResponseData), errors::ConnectorError> { let refund_status = enums::RefundStatus::from(response.status); let error = if utils::is_refund_failure(refund_status) { - Some(types::ErrorResponse { + Some(ErrorResponse { code: response .reject_code - .unwrap_or_else(|| consts::NO_ERROR_CODE.to_string()), + .unwrap_or_else(|| NO_ERROR_CODE.to_string()), message: response .reject_reason .clone() - .unwrap_or_else(|| consts::NO_ERROR_MESSAGE.to_string()), + .unwrap_or_else(|| NO_ERROR_MESSAGE.to_string()), reason: response.reject_reason, status_code, attempt_status: None, @@ -1092,23 +1083,21 @@ fn get_zen_refund_response( } else { None }; - let refund_response_data = types::RefundsResponseData { + let refund_response_data = RefundsResponseData { connector_refund_id: response.id, refund_status, }; Ok((error, refund_response_data)) } -impl TryFrom> - for types::RefundsRouterData -{ +impl TryFrom> for types::RefundsRouterData { type Error = error_stack::Report; fn try_from( - item: types::RefundsResponseRouterData, + item: RefundsResponseRouterData, ) -> Result { let refund_status = enums::RefundStatus::from(item.response.status); Ok(Self { - response: Ok(types::RefundsResponseData { + response: Ok(RefundsResponseData { connector_refund_id: item.response.id, refund_status, }), diff --git a/crates/hyperswitch_connectors/src/constants.rs b/crates/hyperswitch_connectors/src/constants.rs index 6c579977005..7ee75ddc4d1 100644 --- a/crates/hyperswitch_connectors/src/constants.rs +++ b/crates/hyperswitch_connectors/src/constants.rs @@ -1,6 +1,7 @@ /// Header Constants pub(crate) mod headers { pub(crate) const API_KEY: &str = "API-KEY"; + pub(crate) const APIKEY: &str = "apikey"; pub(crate) const API_TOKEN: &str = "Api-Token"; pub(crate) const AUTHORIZATION: &str = "Authorization"; pub(crate) const CONTENT_TYPE: &str = "Content-Type"; @@ -8,7 +9,9 @@ pub(crate) mod headers { pub(crate) const IDEMPOTENCY_KEY: &str = "Idempotency-Key"; pub(crate) const MESSAGE_SIGNATURE: &str = "Message-Signature"; pub(crate) const MERCHANT_ID: &str = "Merchant-ID"; + pub(crate) const NONCE: &str = "nonce"; pub(crate) const TIMESTAMP: &str = "Timestamp"; + pub(crate) const TOKEN: &str = "token"; pub(crate) const X_ACCEPT_VERSION: &str = "X-Accept-Version"; pub(crate) const X_CC_API_KEY: &str = "X-CC-Api-Key"; pub(crate) const X_CC_VERSION: &str = "X-CC-Version"; diff --git a/crates/hyperswitch_connectors/src/default_implementations.rs b/crates/hyperswitch_connectors/src/default_implementations.rs index 1e411ded76f..abdaf1e92c4 100644 --- a/crates/hyperswitch_connectors/src/default_implementations.rs +++ b/crates/hyperswitch_connectors/src/default_implementations.rs @@ -101,10 +101,14 @@ default_imp_for_authorize_session_token!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -112,7 +116,8 @@ default_imp_for_authorize_session_token!( connectors::Volt, connectors::Thunes, connectors::Tsys, - connectors::Worldline + connectors::Worldline, + connectors::Zen ); macro_rules! default_imp_for_calculate_tax { @@ -140,15 +145,20 @@ default_imp_for_calculate_tax!( connectors::Dlocal, connectors::Fiserv, connectors::Fiservemea, + connectors::Forte, connectors::Helcim, connectors::Stax, connectors::Square, connectors::Novalnet, connectors::Mollie, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Fiuu, connectors::Globepay, connectors::Worldline, + connectors::Zen, connectors::Powertranz, connectors::Thunes, connectors::Tsys, @@ -181,16 +191,21 @@ default_imp_for_session_update!( connectors::Dlocal, connectors::Fiserv, connectors::Fiservemea, + connectors::Forte, connectors::Helcim, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Mollie, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Fiuu, connectors::Globepay, connectors::Worldline, + connectors::Zen, connectors::Powertranz, connectors::Thunes, connectors::Tsys, @@ -224,12 +239,16 @@ default_imp_for_post_session_tokens!( connectors::Square, connectors::Fiserv, connectors::Fiservemea, + connectors::Forte, connectors::Helcim, connectors::Stax, connectors::Taxjar, connectors::Mollie, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Fiuu, connectors::Globepay, connectors::Worldline, @@ -237,7 +256,8 @@ default_imp_for_post_session_tokens!( connectors::Thunes, connectors::Tsys, connectors::Deutschebank, - connectors::Volt + connectors::Volt, + connectors::Zen ); use crate::connectors; @@ -267,16 +287,21 @@ default_imp_for_complete_authorize!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, + connectors::Payeezy, + connectors::Payu, connectors::Stax, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_incremental_authorization { @@ -307,10 +332,14 @@ default_imp_for_incremental_authorization!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -319,7 +348,8 @@ default_imp_for_incremental_authorization!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_create_customer { @@ -350,18 +380,23 @@ default_imp_for_create_customer!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Mollie, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Square, connectors::Taxjar, connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_connector_redirect_response { @@ -393,9 +428,13 @@ default_imp_for_connector_redirect_response!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Stax, connectors::Square, @@ -434,9 +473,13 @@ default_imp_for_pre_processing_steps!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -445,7 +488,8 @@ default_imp_for_pre_processing_steps!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_post_processing_steps{ @@ -476,10 +520,14 @@ default_imp_for_post_processing_steps!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -488,7 +536,8 @@ default_imp_for_post_processing_steps!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_approve { @@ -519,10 +568,14 @@ default_imp_for_approve!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -531,7 +584,8 @@ default_imp_for_approve!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_reject { @@ -562,10 +616,14 @@ default_imp_for_reject!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -574,7 +632,8 @@ default_imp_for_reject!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_webhook_source_verification { @@ -605,10 +664,14 @@ default_imp_for_webhook_source_verification!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -617,7 +680,8 @@ default_imp_for_webhook_source_verification!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_accept_dispute { @@ -649,10 +713,14 @@ default_imp_for_accept_dispute!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -661,7 +729,8 @@ default_imp_for_accept_dispute!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_submit_evidence { @@ -692,10 +761,14 @@ default_imp_for_submit_evidence!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -704,7 +777,8 @@ default_imp_for_submit_evidence!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_defend_dispute { @@ -735,10 +809,14 @@ default_imp_for_defend_dispute!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -747,7 +825,8 @@ default_imp_for_defend_dispute!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_file_upload { @@ -787,10 +866,14 @@ default_imp_for_file_upload!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -799,7 +882,8 @@ default_imp_for_file_upload!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -832,10 +916,14 @@ default_imp_for_payouts_create!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -844,7 +932,8 @@ default_imp_for_payouts_create!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -877,10 +966,14 @@ default_imp_for_payouts_retrieve!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -889,7 +982,8 @@ default_imp_for_payouts_retrieve!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -922,10 +1016,14 @@ default_imp_for_payouts_eligibility!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -934,7 +1032,8 @@ default_imp_for_payouts_eligibility!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -967,10 +1066,14 @@ default_imp_for_payouts_fulfill!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -979,7 +1082,8 @@ default_imp_for_payouts_fulfill!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -1012,10 +1116,14 @@ default_imp_for_payouts_cancel!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1024,7 +1132,8 @@ default_imp_for_payouts_cancel!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -1057,10 +1166,14 @@ default_imp_for_payouts_quote!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1069,7 +1182,8 @@ default_imp_for_payouts_quote!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -1102,10 +1216,14 @@ default_imp_for_payouts_recipient!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1114,7 +1232,8 @@ default_imp_for_payouts_recipient!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -1147,10 +1266,14 @@ default_imp_for_payouts_recipient_account!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1159,7 +1282,8 @@ default_imp_for_payouts_recipient_account!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1192,10 +1316,14 @@ default_imp_for_frm_sale!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1204,7 +1332,8 @@ default_imp_for_frm_sale!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1237,10 +1366,14 @@ default_imp_for_frm_checkout!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1249,7 +1382,8 @@ default_imp_for_frm_checkout!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1282,10 +1416,14 @@ default_imp_for_frm_transaction!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1294,7 +1432,8 @@ default_imp_for_frm_transaction!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1327,10 +1466,14 @@ default_imp_for_frm_fulfillment!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1339,7 +1482,8 @@ default_imp_for_frm_fulfillment!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1372,10 +1516,14 @@ default_imp_for_frm_record_return!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1384,7 +1532,8 @@ default_imp_for_frm_record_return!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_revoking_mandates { @@ -1414,10 +1563,14 @@ default_imp_for_revoking_mandates!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1426,5 +1579,6 @@ default_imp_for_revoking_mandates!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); diff --git a/crates/hyperswitch_connectors/src/default_implementations_v2.rs b/crates/hyperswitch_connectors/src/default_implementations_v2.rs index 54c0b6a8289..5b0edb55ef1 100644 --- a/crates/hyperswitch_connectors/src/default_implementations_v2.rs +++ b/crates/hyperswitch_connectors/src/default_implementations_v2.rs @@ -217,10 +217,14 @@ default_imp_for_new_connector_integration_payment!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -229,7 +233,8 @@ default_imp_for_new_connector_integration_payment!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_refund { @@ -261,10 +266,14 @@ default_imp_for_new_connector_integration_refund!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -273,7 +282,8 @@ default_imp_for_new_connector_integration_refund!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_connector_access_token { @@ -300,10 +310,14 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -312,7 +326,8 @@ default_imp_for_new_connector_integration_connector_access_token!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_accept_dispute { @@ -345,10 +360,14 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -357,7 +376,8 @@ default_imp_for_new_connector_integration_accept_dispute!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_submit_evidence { @@ -389,10 +409,14 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -401,7 +425,8 @@ default_imp_for_new_connector_integration_submit_evidence!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_defend_dispute { @@ -433,10 +458,14 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -445,7 +474,8 @@ default_imp_for_new_connector_integration_defend_dispute!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_file_upload { @@ -487,10 +517,14 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -499,7 +533,8 @@ default_imp_for_new_connector_integration_file_upload!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -533,10 +568,14 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -545,7 +584,8 @@ default_imp_for_new_connector_integration_payouts_create!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -579,10 +619,14 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -591,7 +635,8 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -625,10 +670,14 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -637,7 +686,8 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -671,10 +721,14 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -683,7 +737,8 @@ default_imp_for_new_connector_integration_payouts_cancel!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -717,10 +772,14 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -729,7 +788,8 @@ default_imp_for_new_connector_integration_payouts_quote!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -763,10 +823,14 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -775,7 +839,8 @@ default_imp_for_new_connector_integration_payouts_recipient!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -809,10 +874,14 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -821,7 +890,8 @@ default_imp_for_new_connector_integration_payouts_sync!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "payouts")] @@ -855,10 +925,14 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -867,7 +941,8 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_webhook_source_verification { @@ -899,10 +974,14 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -911,7 +990,8 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -945,10 +1025,14 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -957,7 +1041,8 @@ default_imp_for_new_connector_integration_frm_sale!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -991,10 +1076,14 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1003,7 +1092,8 @@ default_imp_for_new_connector_integration_frm_checkout!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1037,10 +1127,14 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1049,7 +1143,8 @@ default_imp_for_new_connector_integration_frm_transaction!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1083,10 +1178,14 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1095,7 +1194,8 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); #[cfg(feature = "frm")] @@ -1129,10 +1229,14 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1141,7 +1245,8 @@ default_imp_for_new_connector_integration_frm_record_return!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); macro_rules! default_imp_for_new_connector_integration_revoking_mandates { @@ -1172,10 +1277,14 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Fiserv, connectors::Fiservemea, connectors::Fiuu, + connectors::Forte, connectors::Globepay, connectors::Helcim, connectors::Novalnet, + connectors::Nexinets, connectors::Nexixpay, + connectors::Payeezy, + connectors::Payu, connectors::Powertranz, connectors::Mollie, connectors::Stax, @@ -1184,5 +1293,6 @@ default_imp_for_new_connector_integration_revoking_mandates!( connectors::Thunes, connectors::Tsys, connectors::Worldline, - connectors::Volt + connectors::Volt, + connectors::Zen ); diff --git a/crates/hyperswitch_connectors/src/utils.rs b/crates/hyperswitch_connectors/src/utils.rs index 0134253f2f9..652ec82c5ed 100644 --- a/crates/hyperswitch_connectors/src/utils.rs +++ b/crates/hyperswitch_connectors/src/utils.rs @@ -32,6 +32,8 @@ use once_cell::sync::Lazy; use regex::Regex; use serde::Serializer; +use crate::types::RefreshTokenRouterData; + type Error = error_stack::Report; pub(crate) fn construct_not_supported_error_report( @@ -45,6 +47,15 @@ pub(crate) fn construct_not_supported_error_report( .into() } +pub(crate) fn to_currency_base_unit_with_zero_decimal_check( + amount: i64, + currency: enums::Currency, +) -> Result> { + currency + .to_currency_base_unit_with_zero_decimal_check(amount) + .change_context(errors::ConnectorError::RequestEncodingFailed) +} + pub(crate) fn get_amount_as_string( currency_unit: &api::CurrencyUnit, amount: i64, @@ -193,6 +204,16 @@ pub(crate) fn is_payment_failure(status: AttemptStatus) -> bool { } } +pub fn is_refund_failure(status: enums::RefundStatus) -> bool { + match status { + common_enums::RefundStatus::Failure | common_enums::RefundStatus::TransactionFailure => { + true + } + common_enums::RefundStatus::ManualReview + | common_enums::RefundStatus::Pending + | common_enums::RefundStatus::Success => false, + } +} // TODO: Make all traits as `pub(crate) trait` once all connectors are moved. pub trait RouterData { fn get_billing(&self) -> Result<&Address, Error>; @@ -892,6 +913,19 @@ static CARD_REGEX: Lazy>> = Lazy map }); +pub trait AccessTokenRequestInfo { + fn get_request_id(&self) -> Result, Error>; +} + +impl AccessTokenRequestInfo for RefreshTokenRouterData { + fn get_request_id(&self) -> Result, Error> { + self.request + .id + .clone() + .ok_or_else(missing_field_err("request.id")) + } +} + pub trait AddressDetailsData { fn get_first_name(&self) -> Result<&Secret, Error>; fn get_last_name(&self) -> Result<&Secret, Error>; @@ -2051,3 +2085,67 @@ impl From for PaymentMethodDataType { } } } +pub trait ApplePay { + fn get_applepay_decoded_payment_data(&self) -> Result, Error>; +} + +impl ApplePay for hyperswitch_domain_models::payment_method_data::ApplePayWalletData { + fn get_applepay_decoded_payment_data(&self) -> Result, Error> { + let token = Secret::new( + String::from_utf8(BASE64_ENGINE.decode(&self.payment_data).change_context( + errors::ConnectorError::InvalidWalletToken { + wallet_name: "Apple Pay".to_string(), + }, + )?) + .change_context(errors::ConnectorError::InvalidWalletToken { + wallet_name: "Apple Pay".to_string(), + })?, + ); + Ok(token) + } +} + +pub trait WalletData { + fn get_wallet_token(&self) -> Result, Error>; + fn get_wallet_token_as_json(&self, wallet_name: String) -> Result + where + T: serde::de::DeserializeOwned; + fn get_encoded_wallet_token(&self) -> Result; +} + +impl WalletData for hyperswitch_domain_models::payment_method_data::WalletData { + fn get_wallet_token(&self) -> Result, Error> { + match self { + Self::GooglePay(data) => Ok(Secret::new(data.tokenization_data.token.clone())), + Self::ApplePay(data) => Ok(data.get_applepay_decoded_payment_data()?), + Self::PaypalSdk(data) => Ok(Secret::new(data.token.clone())), + _ => Err(errors::ConnectorError::InvalidWallet.into()), + } + } + fn get_wallet_token_as_json(&self, wallet_name: String) -> Result + where + T: serde::de::DeserializeOwned, + { + serde_json::from_str::(self.get_wallet_token()?.peek()) + .change_context(errors::ConnectorError::InvalidWalletToken { wallet_name }) + } + + fn get_encoded_wallet_token(&self) -> Result { + match self { + Self::GooglePay(_) => { + let json_token: serde_json::Value = + self.get_wallet_token_as_json("Google Pay".to_owned())?; + let token_as_vec = serde_json::to_vec(&json_token).change_context( + errors::ConnectorError::InvalidWalletToken { + wallet_name: "Google Pay".to_string(), + }, + )?; + let encoded_token = BASE64_ENGINE.encode(token_as_vec); + Ok(encoded_token) + } + _ => Err( + errors::ConnectorError::NotImplemented("SELECTED PAYMENT METHOD".to_owned()).into(), + ), + } + } +} diff --git a/crates/router/src/connector.rs b/crates/router/src/connector.rs index c0c64d76415..d8d834e759a 100644 --- a/crates/router/src/connector.rs +++ b/crates/router/src/connector.rs @@ -14,7 +14,6 @@ pub mod datatrans; #[cfg(feature = "dummy_connector")] pub mod dummyconnector; pub mod ebanx; -pub mod forte; pub mod globalpay; pub mod gocardless; pub mod gpayments; @@ -24,18 +23,15 @@ pub mod klarna; pub mod mifinity; pub mod multisafepay; pub mod netcetera; -pub mod nexinets; pub mod nmi; pub mod noon; pub mod nuvei; pub mod opayo; pub mod opennode; pub mod paybox; -pub mod payeezy; pub mod payme; pub mod payone; pub mod paypal; -pub mod payu; pub mod placetopay; pub mod plaid; pub mod prophetpay; @@ -52,7 +48,6 @@ pub mod wellsfargo; pub mod wellsfargopayout; pub mod wise; pub mod worldpay; -pub mod zen; pub mod zsl; pub use hyperswitch_connectors::connectors::{ @@ -60,10 +55,12 @@ pub use hyperswitch_connectors::connectors::{ cashtocode::Cashtocode, coinbase, coinbase::Coinbase, cryptopay, cryptopay::Cryptopay, deutschebank, deutschebank::Deutschebank, digitalvirgo, digitalvirgo::Digitalvirgo, dlocal, dlocal::Dlocal, fiserv, fiserv::Fiserv, fiservemea, fiservemea::Fiservemea, fiuu, fiuu::Fiuu, - globepay, globepay::Globepay, helcim, helcim::Helcim, mollie, mollie::Mollie, nexixpay, - nexixpay::Nexixpay, novalnet, novalnet::Novalnet, powertranz, powertranz::Powertranz, square, - square::Square, stax, stax::Stax, taxjar, taxjar::Taxjar, thunes, thunes::Thunes, tsys, - tsys::Tsys, volt, volt::Volt, worldline, worldline::Worldline, + forte, forte::Forte, globepay, globepay::Globepay, helcim, helcim::Helcim, mollie, + mollie::Mollie, nexinets, nexinets::Nexinets, nexixpay, nexixpay::Nexixpay, novalnet, + novalnet::Novalnet, payeezy, payeezy::Payeezy, payu, payu::Payu, powertranz, + powertranz::Powertranz, square, square::Square, stax, stax::Stax, taxjar, taxjar::Taxjar, + thunes, thunes::Thunes, tsys, tsys::Tsys, volt, volt::Volt, worldline, worldline::Worldline, + zen, zen::Zen, }; #[cfg(feature = "dummy_connector")] @@ -72,13 +69,12 @@ pub use self::{ aci::Aci, adyen::Adyen, adyenplatform::Adyenplatform, airwallex::Airwallex, authorizedotnet::Authorizedotnet, bamboraapac::Bamboraapac, bankofamerica::Bankofamerica, bluesnap::Bluesnap, boku::Boku, braintree::Braintree, checkout::Checkout, - cybersource::Cybersource, datatrans::Datatrans, ebanx::Ebanx, forte::Forte, - globalpay::Globalpay, gocardless::Gocardless, gpayments::Gpayments, iatapay::Iatapay, - itaubank::Itaubank, klarna::Klarna, mifinity::Mifinity, multisafepay::Multisafepay, - netcetera::Netcetera, nexinets::Nexinets, nmi::Nmi, noon::Noon, nuvei::Nuvei, opayo::Opayo, - opennode::Opennode, paybox::Paybox, payeezy::Payeezy, payme::Payme, payone::Payone, - paypal::Paypal, payu::Payu, placetopay::Placetopay, plaid::Plaid, prophetpay::Prophetpay, + cybersource::Cybersource, datatrans::Datatrans, ebanx::Ebanx, globalpay::Globalpay, + gocardless::Gocardless, gpayments::Gpayments, iatapay::Iatapay, itaubank::Itaubank, + klarna::Klarna, mifinity::Mifinity, multisafepay::Multisafepay, netcetera::Netcetera, nmi::Nmi, + noon::Noon, nuvei::Nuvei, opayo::Opayo, opennode::Opennode, paybox::Paybox, payme::Payme, + payone::Payone, paypal::Paypal, placetopay::Placetopay, plaid::Plaid, prophetpay::Prophetpay, rapyd::Rapyd, razorpay::Razorpay, riskified::Riskified, shift4::Shift4, signifyd::Signifyd, stripe::Stripe, threedsecureio::Threedsecureio, trustpay::Trustpay, wellsfargo::Wellsfargo, - wellsfargopayout::Wellsfargopayout, wise::Wise, worldpay::Worldpay, zen::Zen, zsl::Zsl, + wellsfargopayout::Wellsfargopayout, wise::Wise, worldpay::Worldpay, zsl::Zsl, }; diff --git a/crates/router/src/core/payments/connector_integration_v2_impls.rs b/crates/router/src/core/payments/connector_integration_v2_impls.rs index 4e900321f95..80a06bbc482 100644 --- a/crates/router/src/core/payments/connector_integration_v2_impls.rs +++ b/crates/router/src/core/payments/connector_integration_v2_impls.rs @@ -704,7 +704,6 @@ default_imp_for_new_connector_integration_payment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -714,18 +713,15 @@ default_imp_for_new_connector_integration_payment!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -740,7 +736,6 @@ default_imp_for_new_connector_integration_payment!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -776,7 +771,6 @@ default_imp_for_new_connector_integration_refund!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -786,18 +780,15 @@ default_imp_for_new_connector_integration_refund!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -811,7 +802,6 @@ default_imp_for_new_connector_integration_refund!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -842,7 +832,6 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -852,18 +841,15 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -877,7 +863,6 @@ default_imp_for_new_connector_integration_connector_access_token!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -930,7 +915,6 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -940,18 +924,15 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -965,7 +946,6 @@ default_imp_for_new_connector_integration_accept_dispute!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1000,7 +980,6 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1010,18 +989,15 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1035,7 +1011,6 @@ default_imp_for_new_connector_integration_defend_dispute!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1054,7 +1029,6 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1064,18 +1038,15 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1089,7 +1060,6 @@ default_imp_for_new_connector_integration_submit_evidence!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1135,7 +1105,6 @@ default_imp_for_new_connector_integration_file_upload!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1145,18 +1114,15 @@ default_imp_for_new_connector_integration_file_upload!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1170,7 +1136,6 @@ default_imp_for_new_connector_integration_file_upload!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1296,7 +1261,6 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1306,18 +1270,15 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1331,7 +1292,6 @@ default_imp_for_new_connector_integration_payouts_create!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1369,7 +1329,6 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1379,18 +1338,15 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1404,7 +1360,6 @@ default_imp_for_new_connector_integration_payouts_eligibility!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1442,7 +1397,6 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1452,18 +1406,15 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1477,7 +1428,6 @@ default_imp_for_new_connector_integration_payouts_fulfill!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1515,7 +1465,6 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1525,18 +1474,15 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1550,7 +1496,6 @@ default_imp_for_new_connector_integration_payouts_cancel!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1588,7 +1533,6 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1598,18 +1542,15 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1623,7 +1564,6 @@ default_imp_for_new_connector_integration_payouts_quote!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1661,7 +1601,6 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1671,18 +1610,15 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1696,7 +1632,6 @@ default_imp_for_new_connector_integration_payouts_recipient!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1734,7 +1669,6 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1744,18 +1678,15 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1769,7 +1700,6 @@ default_imp_for_new_connector_integration_payouts_sync!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1807,7 +1737,6 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1817,18 +1746,15 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1842,7 +1768,6 @@ default_imp_for_new_connector_integration_payouts_recipient_account!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -1878,7 +1803,6 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1888,18 +1812,15 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1913,7 +1834,6 @@ default_imp_for_new_connector_integration_webhook_source_verification!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2039,7 +1959,6 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2049,18 +1968,15 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2074,7 +1990,6 @@ default_imp_for_new_connector_integration_frm_sale!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2112,7 +2027,6 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2122,18 +2036,15 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2147,7 +2058,6 @@ default_imp_for_new_connector_integration_frm_checkout!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2185,7 +2095,6 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2195,18 +2104,15 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2220,7 +2126,6 @@ default_imp_for_new_connector_integration_frm_transaction!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2258,7 +2163,6 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2268,18 +2172,15 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2293,7 +2194,6 @@ default_imp_for_new_connector_integration_frm_fulfillment!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2331,7 +2231,6 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2341,18 +2240,15 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2366,7 +2262,6 @@ default_imp_for_new_connector_integration_frm_record_return!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); @@ -2401,7 +2296,6 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2411,18 +2305,15 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -2436,7 +2327,6 @@ default_imp_for_new_connector_integration_revoking_mandates!( connector::Wellsfargo, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Plaid ); diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 700fff16cf5..3078cf72256 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -212,7 +212,6 @@ default_imp_for_complete_authorize!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, @@ -221,13 +220,10 @@ default_imp_for_complete_authorize!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Noon, connector::Opayo, connector::Opennode, - connector::Payeezy, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Rapyd, @@ -240,7 +236,6 @@ default_imp_for_complete_authorize!( connector::Wise, connector::Wellsfargo, connector::Wellsfargopayout, - connector::Zen, connector::Zsl ); macro_rules! default_imp_for_webhook_source_verification { @@ -284,7 +279,6 @@ default_imp_for_webhook_source_verification!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -294,17 +288,14 @@ default_imp_for_webhook_source_verification!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -320,7 +311,6 @@ default_imp_for_webhook_source_verification!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -366,7 +356,6 @@ default_imp_for_create_customer!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gpayments, connector::Iatapay, @@ -375,18 +364,15 @@ default_imp_for_create_customer!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -401,7 +387,6 @@ default_imp_for_create_customer!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -444,7 +429,6 @@ default_imp_for_connector_redirect_response!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, @@ -453,12 +437,9 @@ default_imp_for_connector_redirect_response!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Opayo, connector::Opennode, - connector::Payeezy, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -606,7 +587,6 @@ default_imp_for_accept_dispute!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -616,18 +596,15 @@ default_imp_for_accept_dispute!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -643,7 +620,6 @@ default_imp_for_accept_dispute!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -709,7 +685,6 @@ default_imp_for_file_upload!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -719,17 +694,14 @@ default_imp_for_file_upload!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -745,7 +717,6 @@ default_imp_for_file_upload!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -789,7 +760,6 @@ default_imp_for_submit_evidence!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -799,17 +769,14 @@ default_imp_for_submit_evidence!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -825,7 +792,6 @@ default_imp_for_submit_evidence!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -870,7 +836,6 @@ default_imp_for_defend_dispute!( connector::Datatrans, connector::Ebanx, connector::Globalpay, - connector::Forte, connector::Gocardless, connector::Gpayments, connector::Iatapay, @@ -879,17 +844,14 @@ default_imp_for_defend_dispute!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -906,7 +868,6 @@ default_imp_for_defend_dispute!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -966,21 +927,17 @@ default_imp_for_pre_processing_steps!( connector::Ebanx, connector::Iatapay, connector::Itaubank, - connector::Forte, connector::Globalpay, connector::Gpayments, connector::Klarna, connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -993,7 +950,6 @@ default_imp_for_pre_processing_steps!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1034,21 +990,17 @@ default_imp_for_post_processing_steps!( connector::Ebanx, connector::Iatapay, connector::Itaubank, - connector::Forte, connector::Globalpay, connector::Gpayments, connector::Klarna, connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payone, - connector::Payu, connector::Placetopay, connector::Prophetpay, connector::Rapyd, @@ -1059,7 +1011,6 @@ default_imp_for_post_processing_steps!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl, connector::Razorpay ); @@ -1188,7 +1139,6 @@ default_imp_for_payouts_create!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1198,17 +1148,14 @@ default_imp_for_payouts_create!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1222,7 +1169,6 @@ default_imp_for_payouts_create!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1269,7 +1215,6 @@ default_imp_for_payouts_retrieve!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1279,17 +1224,14 @@ default_imp_for_payouts_retrieve!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1305,7 +1247,6 @@ default_imp_for_payouts_retrieve!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1353,7 +1294,6 @@ default_imp_for_payouts_eligibility!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1363,18 +1303,15 @@ default_imp_for_payouts_eligibility!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1389,7 +1326,6 @@ default_imp_for_payouts_eligibility!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1432,7 +1368,6 @@ default_imp_for_payouts_fulfill!( connector::Braintree, connector::Checkout, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1442,16 +1377,13 @@ default_imp_for_payouts_fulfill!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1465,7 +1397,6 @@ default_imp_for_payouts_fulfill!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1510,7 +1441,6 @@ default_imp_for_payouts_cancel!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1520,18 +1450,15 @@ default_imp_for_payouts_cancel!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1545,7 +1472,6 @@ default_imp_for_payouts_cancel!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1591,7 +1517,6 @@ default_imp_for_payouts_quote!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1601,18 +1526,15 @@ default_imp_for_payouts_quote!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1627,7 +1549,6 @@ default_imp_for_payouts_quote!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1673,7 +1594,6 @@ default_imp_for_payouts_recipient!( connector::Checkout, connector::Cybersource, connector::Datatrans, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1683,18 +1603,15 @@ default_imp_for_payouts_recipient!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1708,7 +1625,6 @@ default_imp_for_payouts_recipient!( connector::Wellsfargo, connector::Wellsfargopayout, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1758,7 +1674,6 @@ default_imp_for_payouts_recipient_account!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1768,18 +1683,15 @@ default_imp_for_payouts_recipient_account!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1794,7 +1706,6 @@ default_imp_for_payouts_recipient_account!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1840,7 +1751,6 @@ default_imp_for_approve!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1850,18 +1760,15 @@ default_imp_for_approve!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1877,7 +1784,6 @@ default_imp_for_approve!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -1923,7 +1829,6 @@ default_imp_for_reject!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -1933,18 +1838,15 @@ default_imp_for_reject!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -1960,7 +1862,6 @@ default_imp_for_reject!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2097,7 +1998,6 @@ default_imp_for_frm_sale!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2107,18 +2007,15 @@ default_imp_for_frm_sale!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2132,7 +2029,6 @@ default_imp_for_frm_sale!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2180,7 +2076,6 @@ default_imp_for_frm_checkout!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2190,18 +2085,15 @@ default_imp_for_frm_checkout!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2215,7 +2107,6 @@ default_imp_for_frm_checkout!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2263,7 +2154,6 @@ default_imp_for_frm_transaction!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2273,18 +2163,15 @@ default_imp_for_frm_transaction!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2298,7 +2185,6 @@ default_imp_for_frm_transaction!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2346,7 +2232,6 @@ default_imp_for_frm_fulfillment!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2356,18 +2241,15 @@ default_imp_for_frm_fulfillment!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2381,7 +2263,6 @@ default_imp_for_frm_fulfillment!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2429,7 +2310,6 @@ default_imp_for_frm_record_return!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2439,18 +2319,15 @@ default_imp_for_frm_record_return!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2464,7 +2341,6 @@ default_imp_for_frm_record_return!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2509,7 +2385,6 @@ default_imp_for_incremental_authorization!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2519,18 +2394,15 @@ default_imp_for_incremental_authorization!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2545,7 +2417,6 @@ default_imp_for_incremental_authorization!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2588,7 +2459,6 @@ default_imp_for_revoking_mandates!( connector::Checkout, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2598,17 +2468,14 @@ default_imp_for_revoking_mandates!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Nuvei, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2622,7 +2489,6 @@ default_imp_for_revoking_mandates!( connector::Trustpay, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2828,7 +2694,6 @@ default_imp_for_authorize_session_token!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2838,17 +2703,14 @@ default_imp_for_authorize_session_token!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nmi, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2864,7 +2726,6 @@ default_imp_for_authorize_session_token!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2908,7 +2769,6 @@ default_imp_for_calculate_tax!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2918,18 +2778,15 @@ default_imp_for_calculate_tax!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nuvei, connector::Nmi, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, connector::Paypal, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -2945,7 +2802,6 @@ default_imp_for_calculate_tax!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -2989,7 +2845,6 @@ default_imp_for_session_update!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -2999,17 +2854,14 @@ default_imp_for_session_update!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nuvei, connector::Nmi, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -3025,7 +2877,6 @@ default_imp_for_session_update!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); @@ -3069,7 +2920,6 @@ default_imp_for_post_session_tokens!( connector::Cybersource, connector::Datatrans, connector::Ebanx, - connector::Forte, connector::Globalpay, connector::Gocardless, connector::Gpayments, @@ -3079,17 +2929,14 @@ default_imp_for_post_session_tokens!( connector::Mifinity, connector::Multisafepay, connector::Netcetera, - connector::Nexinets, connector::Nuvei, connector::Nmi, connector::Noon, connector::Opayo, connector::Opennode, connector::Paybox, - connector::Payeezy, connector::Payme, connector::Payone, - connector::Payu, connector::Placetopay, connector::Plaid, connector::Prophetpay, @@ -3105,6 +2952,5 @@ default_imp_for_post_session_tokens!( connector::Wellsfargopayout, connector::Wise, connector::Worldpay, - connector::Zen, connector::Zsl ); From aee11c560e427195a0d321dff19c0d33ec60ba64 Mon Sep 17 00:00:00 2001 From: Kashif Date: Wed, 23 Oct 2024 19:21:03 +0530 Subject: [PATCH 09/24] fix(deployment-config): remove invalid currencies from worldpay filters (#6400) --- config/deployments/sandbox.toml | 8 ++--- .../src/connector/worldpay/transformers.rs | 35 ++++++++++--------- 2 files changed, 22 insertions(+), 21 deletions(-) diff --git a/config/deployments/sandbox.toml b/config/deployments/sandbox.toml index 6cc1193ab55..3346c4a2725 100644 --- a/config/deployments/sandbox.toml +++ b/config/deployments/sandbox.toml @@ -340,10 +340,10 @@ upi_collect = {country = "IN", currency = "INR"} open_banking_pis = {currency = "EUR,GBP"} [pm_filters.worldpay] -debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SAR,RSD,SCR,SLL,SG,ST,SBD,SOS,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,TMT,AED,UG,UA,US,UZ,VU,VE,VN,YER,CNY,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } -credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SAR,RSD,SCR,SLL,SG,ST,SBD,SOS,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,TMT,AED,UG,UA,US,UZ,VU,VE,VN,YER,CNY,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } -apple_pay.country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" -google_pay.country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" +debit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +credit = { country = "AF,DZ,AW,AU,AZ,BS,BH,BD,BB,BZ,BM,BT,BO,BA,BW,BR,BN,BG,BI,KH,CA,CV,KY,CL,CO,KM,CD,CR,CZ,DK,DJ,ST,DO,EC,EG,SV,ER,ET,FK,FJ,GM,GE,GH,GI,GT,GN,GY,HT,HN,HK,HU,IS,IN,ID,IR,IQ,IE,IL,IT,JM,JP,JO,KZ,KE,KW,LA,LB,LS,LR,LY,LT,MO,MK,MG,MW,MY,MV,MR,MU,MX,MD,MN,MA,MZ,MM,NA,NZ,NI,NG,KP,NO,AR,PK,PG,PY,PE,UY,PH,PL,GB,QA,OM,RO,RU,RW,WS,SG,ST,ZA,KR,LK,SH,SD,SR,SZ,SE,CH,SY,TW,TJ,TZ,TH,TT,TN,TR,UG,UA,US,UZ,VU,VE,VN,ZM,ZW", currency = "AFN,DZD,ANG,AWG,AUD,AZN,BSD,BHD,BDT,BBD,BZD,BMD,BTN,BOB,BAM,BWP,BRL,BND,BGN,BIF,KHR,CAD,CVE,KYD,XOF,XAF,XPF,CLP,COP,KMF,CDF,CRC,EUR,CZK,DKK,DJF,DOP,XCD,EGP,SVC,ERN,ETB,EUR,FKP,FJD,GMD,GEL,GHS,GIP,GTQ,GNF,GYD,HTG,HNL,HKD,HUF,ISK,INR,IDR,IRR,IQD,ILS,JMD,JPY,JOD,KZT,KES,KWD,LAK,LBP,LSL,LRD,LYD,MOP,MKD,MGA,MWK,MYR,MVR,MRU,MUR,MXN,MDL,MNT,MAD,MZN,MMK,NAD,NPR,NZD,NIO,NGN,KPW,NOK,ARS,PKR,PAB,PGK,PYG,PEN,UYU,PHP,PLN,GBP,QAR,OMR,RON,RUB,RWF,WST,SAR,RSD,SCR,SLL,SGD,STN,SBD,SOS,ZAR,KRW,LKR,SHP,SDG,SRD,SZL,SEK,CHF,SYP,TWD,TJS,TZS,THB,TOP,TTD,TND,TRY,TMT,AED,UGX,UAH,USD,UZS,VUV,VND,YER,CNY,ZMW,ZWL" } +google_pay = { country = "AL,DZ,AS,AO,AG,AR,AU,AT,AZ,BH,BY,BE,BR,BG,CA,CL,CO,HR,CZ,DK,DO,EG,EE,FI,FR,DE,GR,HK,HU,IN,ID,IE,IL,IT,JP,JO,KZ,KE,KW,LV,LB,LT,LU,MY,MX,NL,NZ,NO,OM,PK,PA,PE,PH,PL,PT,QA,RO,RU,SA,SG,SK,ZA,ES,LK,SE,CH,TW,TH,TR,UA,AE,GB,US,UY,VN" } +apple_pay = { country = "AU,CN,HK,JP,MO,MY,NZ,SG,TW,AM,AT,AZ,BY,BE,BG,HR,CY,CZ,DK,EE,FO,FI,FR,GE,DE,GR,GL,GG,HU,IS,IE,IM,IT,KZ,JE,LV,LI,LT,LU,MT,MD,MC,ME,NL,NO,PL,PT,RO,SM,RS,SK,SI,ES,SE,CH,UA,GB,AR,CO,CR,BR,MX,PE,BH,IL,JO,KW,PS,QA,SA,AE,CA,UM,US" } [pm_filters.zen] boleto = { country = "BR", currency = "BRL" } diff --git a/crates/router/src/connector/worldpay/transformers.rs b/crates/router/src/connector/worldpay/transformers.rs index be8b7737b16..fee004a6e4c 100644 --- a/crates/router/src/connector/worldpay/transformers.rs +++ b/crates/router/src/connector/worldpay/transformers.rs @@ -169,18 +169,25 @@ fn fetch_payment_instrument( } } -impl TryFrom<(enums::PaymentMethod, enums::PaymentMethodType)> for PaymentMethod { +impl TryFrom<(enums::PaymentMethod, Option)> for PaymentMethod { type Error = error_stack::Report; fn try_from( - src: (enums::PaymentMethod, enums::PaymentMethodType), + src: (enums::PaymentMethod, Option), ) -> Result { match (src.0, src.1) { (enums::PaymentMethod::Card, _) => Ok(Self::Card), - (enums::PaymentMethod::Wallet, enums::PaymentMethodType::ApplePay) => { - Ok(Self::ApplePay) - } - (enums::PaymentMethod::Wallet, enums::PaymentMethodType::GooglePay) => { - Ok(Self::GooglePay) + (enums::PaymentMethod::Wallet, pmt) => { + let pm = pmt.ok_or(errors::ConnectorError::MissingRequiredField { + field_name: "payment_method_type", + })?; + match pm { + enums::PaymentMethodType::ApplePay => Ok(Self::ApplePay), + enums::PaymentMethodType::GooglePay => Ok(Self::GooglePay), + _ => Err(errors::ConnectorError::NotImplemented( + utils::get_unimplemented_payment_method_error_message("worldpay"), + ) + .into()), + } } _ => Err(errors::ConnectorError::NotImplemented( utils::get_unimplemented_payment_method_error_message("worldpay"), @@ -280,16 +287,10 @@ impl .map(|capture_method| AutoSettlement { auto: capture_method == enums::CaptureMethod::Automatic, }), - method: item - .router_data - .request - .payment_method_type - .map(|pmt| PaymentMethod::try_from((item.router_data.payment_method, pmt))) - .transpose()? - .get_required_value("payment_method") - .change_context(errors::ConnectorError::MissingRequiredField { - field_name: "payment_method", - })?, + method: PaymentMethod::try_from(( + item.router_data.payment_method, + item.router_data.request.payment_method_type, + ))?, payment_instrument: fetch_payment_instrument( item.router_data.request.payment_method_data.clone(), item.router_data.get_optional_billing(), From aaa59b7bdd1aa160083b9709f7900918557d873e Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 24 Oct 2024 00:25:12 +0000 Subject: [PATCH 10/24] chore(version): 2024.10.24.0 --- CHANGELOG.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8e4c71a87c..de928c93d09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ All notable changes to HyperSwitch will be documented here. - - - +## 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 From 26e0c32f4da5689a1c01fbb456ac008a0b831710 Mon Sep 17 00:00:00 2001 From: Pa1NarK <69745008+pixincreate@users.noreply.github.com> Date: Thu, 24 Oct 2024 14:00:55 +0530 Subject: [PATCH 11/24] docs(cypress): refactor cypress documentation for more clarity (#6415) --- .github/workflows/cypress-tests-runner.yml | 2 +- cypress-tests/{readme.md => README.md} | 171 +++++++++++++-------- 2 files changed, 109 insertions(+), 64 deletions(-) rename cypress-tests/{readme.md => README.md} (59%) diff --git a/.github/workflows/cypress-tests-runner.yml b/.github/workflows/cypress-tests-runner.yml index be6518e5395..0c9ac7caa5e 100644 --- a/.github/workflows/cypress-tests-runner.yml +++ b/.github/workflows/cypress-tests-runner.yml @@ -190,7 +190,7 @@ jobs: ROUTER__SERVER__WORKERS: 4 shell: bash -leuo pipefail {0} run: | - . scripts/execute_cypress.sh --parallel 3 + scripts/execute_cypress.sh --parallel 3 kill "${{ env.PID }}" diff --git a/cypress-tests/readme.md b/cypress-tests/README.md similarity index 59% rename from cypress-tests/readme.md rename to cypress-tests/README.md index fb8856ce58c..0a071aa34a0 100644 --- a/cypress-tests/readme.md +++ b/cypress-tests/README.md @@ -8,10 +8,14 @@ This Tool is a solution designed to automate testing for the [Hyperswitch](https ### Prerequisites -Before installing Cypress, ensure you have the following prerequisites installed: +Before installing Cypress, ensure that `Node` and `npm` is installed on your machine. To check if it is installed, run the following command: -- npm (Node Package Manager) -- Node.js (18.x and above) +```shell +node -v +npm -v +``` + +If not, download and install `Node` from the official [Node.js website](https://nodejs.org/en/download/package-manager/current). This will also install `npm`. ### Run Test Cases on your local @@ -78,7 +82,7 @@ To run test cases, follow these steps: npm run cypress:routing ``` -In order to run cypress tests against multiple connectors at a time: +In order to run cypress tests against multiple connectors at a time or in parallel: 1. Set up `.env` file that exports necessary info: @@ -143,61 +147,79 @@ The folder structure of this directory is as follows: To add a new connector for testing with Hyperswitch, follow these steps: -1.Include the connector details in the `creds.json` file: +1. Include the connector details in the `creds.json` file: -example: + example: -```json -{ - "stripe": { - "auth_type": "HeaderKey", - "api_key": "SK_134" - } -} -``` + ```json + { + "stripe": { + "connector_account_details": { + "auth_type": "HeaderKey", + "api_key": "SK_134" + } + } + } + ``` -2.Add the new connector details to the ConnectorUtils folder (including CardNo and connector-specific information). +2. Add the new connector details to the ConnectorUtils folder (including CardNo and connector-specific information). -Refer to Stripe.js file for guidance: + Refer to Stripe.js file for guidance: -```javascript -/cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js -``` + ```javascript + /cypress-tests/cypress/e2e/ConnectorUtils/Stripe.js + ``` -Similarly, create a new file named newconnectorname.js and include all the relevant information for that connector. + **File Naming:** Create a new file named .js for your specific connector. -3.In util.js, import the new connector details. + **Include Relevant Information:** Populate the file with all the necessary details specific to that connector. + + **Handling Unsupported Features:** + + - If a connector does not support a specific payment method or feature: + - You can omit the relevant configurations in the .js file. + - The handling of unsupported features will be managed by the commons.js file, which will throw an unsupported or not implemented error as appropriate. + +3. In `Utils.js`, import the new connector details. ### Adding Functions -Similarly, add any helper functions or utilities in the `command.js` in support folder and import them into your tests as needed. +Similarly, add any helper functions or utilities in the `commands.js` in support folder and import them into your tests as needed. Example: Adding List Mandate function to support `ListMandate` scenario ```javascript Cypress.Commands.add("listMandateCallTest", (globalState) => { + // declare all the variables and constants const customerId = globalState.get("customerId"); + // construct the URL for the API call + const url: `${globalState.get("baseUrl")}/customers/${customerId}/mandates` + const api_key = globalState.get("apiKey"); + cy.request({ method: "GET", - url: `${globalState.get("baseUrl")}/customers/${customerId}/mandates`, + url: url, headers: { "Content-Type": "application/json", - "api-key": globalState.get("apiKey"), + "api-key": api_key, }, + // set failOnStatusCode to false to prevent Cypress from failing the test + failOnStatusCode: false, }).then((response) => { - const xRequestId = response.headers["x-request-id"]; - if (xRequestId) { - cy.task("cli_log", "x-request-id ->> " + xRequestId); - } else { - cy.task("cli_log", "x-request-id is not available in the response headers"); - } + // mandatorliy log the `x-request-id` to the console + logRequestId(response.headers["x-request-id"]); + expect(response.headers["content-type"]).to.include("application/json"); - console.log(response.body); - let i = 0; - for (i in response.body) { - if (response.body[i].mandate_id === globalState.get("mandateId")) { - expect(response.body[i].status).to.equal("active"); + + if (response.status === 200) { + // do the necessary validations like below + for (const key in response.body) { + expect(response.body[key]).to.have.property("mandate_id"); + expect(response.body[key]).to.have.property("status"); } + } else { + // handle the error response + expect(response.status).to.equal(400); } }); }); @@ -232,7 +254,14 @@ describe("Payment Scenarios", () => { }); ``` -You can create similar scenarios by calling other functions defined in `command.js`. These functions interact with utility files like `connector.js` and include necessary assertions to support various connector scenarios. +You can create similar scenarios by calling other functions defined in `commands.js`. These functions interact with utility files like `.js` and include necessary assertions to support various connector scenarios. + +### Debugging + +It is recommended to run `npm run cypress` while developing new test cases to debug and verify as it opens the Cypress UI allowing the developer to run individual tests. This also opens up the possibility to to view the test execution in real-time and debug any issues that may arise by viewing the request and response payloads directly. + +If, for any reason, the `globalState` object does not contain latest data, it must be due to the hooks not being executed in the correct order. In such cases, it is recommended to add `cy.log(globalState)` to the test case to verify the data in the `globalState` object. +Please refer to the Cypress's official documentation for more information on hooks and their execution order [here](https://docs.cypress.io/app/core-concepts/writing-and-organizing-tests#Hooks). ## Additional Resources @@ -243,47 +272,63 @@ For more information on using Cypress and writing effective tests, refer to the ```json { "adyen": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } }, "bankofamerica": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } }, "bluesnap": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } }, "cybersource": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } }, "nmi": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } }, "paypal": { - "auth_type": "BodyKey", - "api_key": "api_key", - "key1": "key1" + "connector_account_details": { + "auth_type": "BodyKey", + "api_key": "api_key", + "key1": "key1" + } }, "stripe": { - "auth_type": "HeaderKey", - "api_key": "api_key" + "connector_account_details": { + "auth_type": "HeaderKey", + "api_key": "api_key" + } }, "trustpay": { - "auth_type": "SignatureKey", - "api_key": "api_key", - "key1": "key1", - "api_secret": "api_secret" + "connector_account_details": { + "auth_type": "SignatureKey", + "api_key": "api_key", + "key1": "key1", + "api_secret": "api_secret" + } } } ``` From c7c1e1adabceeb0a03659bf8feb9aa06d85960ea Mon Sep 17 00:00:00 2001 From: Narayan Bhat <48803246+Narayanbhat166@users.noreply.github.com> Date: Thu, 24 Oct 2024 16:10:01 +0530 Subject: [PATCH 12/24] feat(payments_v2): add payment_confirm_intent api endpoint (#6263) Co-authored-by: hrithikesh026 Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com> Co-authored-by: sai-harsha-vardhan Co-authored-by: Shankar Singh C <83439957+ShankarSinghC@users.noreply.github.com> Co-authored-by: spritianeja03 <146620839+spritianeja03@users.noreply.github.com> Co-authored-by: Spriti Aneja --- .github/workflows/CI-pr.yml | 2 +- .../payments/payments--confirm-intent.mdx | 3 + api-reference-v2/mint.json | 3 +- api-reference-v2/openapi_spec.json | 3534 ++++++----------- crates/analytics/Cargo.toml | 4 +- crates/api_models/src/events/payment.rs | 23 +- crates/api_models/src/payments.rs | 342 +- crates/common_enums/src/enums.rs | 14 + crates/common_utils/src/events.rs | 9 + crates/common_utils/src/id_type.rs | 4 +- crates/common_utils/src/id_type/global_id.rs | 3 +- .../src/id_type/global_id/payment.rs | 56 +- crates/common_utils/src/macros.rs | 55 + crates/common_utils/src/types.rs | 89 + crates/connector_configs/Cargo.toml | 4 +- crates/diesel_models/src/payment_attempt.rs | 130 +- crates/diesel_models/src/payment_intent.rs | 771 +--- .../src/query/payment_attempt.rs | 6 +- .../src/query/user/sample_data.rs | 10 +- crates/diesel_models/src/schema_v2.rs | 12 +- crates/diesel_models/src/user/sample_data.rs | 228 +- crates/drainer/Cargo.toml | 2 +- crates/external_services/Cargo.toml | 8 +- crates/hyperswitch_connectors/Cargo.toml | 2 +- .../src/connectors/helcim.rs | 4 +- .../src/connectors/nexinets.rs | 4 +- crates/hyperswitch_domain_models/Cargo.toml | 4 +- crates/hyperswitch_domain_models/src/lib.rs | 12 +- .../hyperswitch_domain_models/src/payments.rs | 124 +- .../src/payments/payment_attempt.rs | 505 ++- .../src/payments/payment_intent.rs | 400 +- .../src/router_data.rs | 4 +- .../src/router_request_types.rs | 2 +- crates/hyperswitch_interfaces/Cargo.toml | 2 +- crates/kgraph_utils/Cargo.toml | 4 +- crates/openapi/Cargo.toml | 4 +- crates/openapi/src/main.rs | 3 + crates/openapi/src/openapi_v2.rs | 13 +- crates/openapi/src/routes/payments.rs | 42 +- crates/pm_auth/Cargo.toml | 2 +- crates/router/Cargo.toml | 2 +- .../compatibility/stripe/payment_intents.rs | 14 +- .../src/compatibility/stripe/setup_intents.rs | 8 +- crates/router/src/connector/utils.rs | 22 +- .../core/fraud_check/flows/checkout_flow.rs | 7 +- .../core/fraud_check/flows/record_return.rs | 4 +- .../src/core/fraud_check/flows/sale_flow.rs | 4 +- .../fraud_check/flows/transaction_flow.rs | 4 +- .../fraud_check/operation/fraud_check_post.rs | 3 +- .../router/src/core/payment_methods/cards.rs | 2 + .../surcharge_decision_configs.rs | 4 +- crates/router/src/core/payments.rs | 510 ++- crates/router/src/core/payments/flows.rs | 6 +- .../src/core/payments/flows/approve_flow.rs | 4 +- .../src/core/payments/flows/authorize_flow.rs | 78 +- .../src/core/payments/flows/cancel_flow.rs | 4 +- .../src/core/payments/flows/capture_flow.rs | 4 +- .../payments/flows/complete_authorize_flow.rs | 4 +- .../flows/incremental_authorization_flow.rs | 4 +- .../flows/post_session_tokens_flow.rs | 4 +- .../src/core/payments/flows/psync_flow.rs | 4 +- .../src/core/payments/flows/reject_flow.rs | 4 +- .../src/core/payments/flows/session_flow.rs | 16 +- .../payments/flows/session_update_flow.rs | 4 +- .../core/payments/flows/setup_mandate_flow.rs | 4 +- crates/router/src/core/payments/helpers.rs | 82 +- crates/router/src/core/payments/operations.rs | 34 +- .../payments/operations/payment_approve.rs | 4 +- .../payments/operations/payment_cancel.rs | 4 +- .../payments/operations/payment_capture.rs | 4 +- .../operations/payment_complete_authorize.rs | 4 +- .../payments/operations/payment_confirm.rs | 6 +- .../operations/payment_confirm_intent.rs | 370 ++ .../payments/operations/payment_create.rs | 4 +- .../operations/payment_create_intent.rs | 19 +- .../operations/payment_post_session_tokens.rs | 4 +- .../payments/operations/payment_reject.rs | 4 +- .../payments/operations/payment_response.rs | 231 +- .../payments/operations/payment_session.rs | 4 +- .../core/payments/operations/payment_start.rs | 4 +- .../payments/operations/payment_status.rs | 6 +- .../payments/operations/payment_update.rs | 6 +- .../payments_incremental_authorization.rs | 4 +- .../payments/operations/tax_calculation.rs | 4 +- crates/router/src/core/payments/retry.rs | 11 +- crates/router/src/core/payments/routing.rs | 11 + .../router/src/core/payments/transformers.rs | 513 ++- crates/router/src/core/pm_auth.rs | 4 +- crates/router/src/core/user/sample_data.rs | 4 +- crates/router/src/core/utils.rs | 2 +- crates/router/src/core/webhooks/incoming.rs | 6 +- crates/router/src/db/kafka_store.rs | 4 +- crates/router/src/db/user/sample_data.rs | 3 +- crates/router/src/lib.rs | 1 + crates/router/src/routes/app.rs | 110 +- crates/router/src/routes/lock_utils.rs | 1 + crates/router/src/routes/payments.rs | 127 +- crates/router/src/routes/payments/helpers.rs | 1 + crates/router/src/routes/pm_auth.rs | 13 +- crates/router/src/routes/poll.rs | 1 + crates/router/src/services/api.rs | 5 +- crates/router/src/services/authentication.rs | 115 +- crates/router/src/types.rs | 16 + crates/router/src/types/api.rs | 3 - crates/router/src/types/api/payments.rs | 19 +- crates/router/src/types/storage.rs | 4 +- .../src/types/storage/payment_attempt.rs | 4 +- crates/router/src/types/transformers.rs | 100 +- crates/router/src/utils/user/sample_data.rs | 4 +- .../src/workflows/outgoing_webhook_retry.rs | 4 +- crates/router/src/workflows/payment_sync.rs | 2 +- crates/router/tests/payments.rs | 4 +- crates/router/tests/payments2.rs | 4 +- crates/router_env/src/logger/types.rs | 2 + crates/scheduler/Cargo.toml | 2 +- crates/storage_impl/Cargo.toml | 4 +- .../src/mock_db/payment_attempt.rs | 2 +- .../src/payments/payment_attempt.rs | 12 +- justfile | 5 +- .../2024-08-28-081721_add_v2_columns/down.sql | 1 + .../2024-08-28-081721_add_v2_columns/up.sql | 1 + .../down.sql | 3 + .../up.sql | 20 + .../down.sql | 4 +- .../2024-10-08-081847_drop_v1_columns/up.sql | 4 +- 125 files changed, 4785 insertions(+), 4336 deletions(-) create mode 100644 api-reference-v2/api-reference/payments/payments--confirm-intent.mdx create mode 100644 crates/router/src/core/payments/operations/payment_confirm_intent.rs diff --git a/.github/workflows/CI-pr.yml b/.github/workflows/CI-pr.yml index 220c4f2577c..369da734da5 100644 --- a/.github/workflows/CI-pr.yml +++ b/.github/workflows/CI-pr.yml @@ -325,7 +325,7 @@ jobs: - name: Run cargo clippy with v2 features enabled shell: bash - run: just clippy_v2 -- -D warnings -Aunused -Aclippy::todo -Aclippy::diverging_sub_expression + run: just clippy_v2 - name: Run cargo check enabling only the release and v2 features shell: bash diff --git a/api-reference-v2/api-reference/payments/payments--confirm-intent.mdx b/api-reference-v2/api-reference/payments/payments--confirm-intent.mdx new file mode 100644 index 00000000000..58624c2771b --- /dev/null +++ b/api-reference-v2/api-reference/payments/payments--confirm-intent.mdx @@ -0,0 +1,3 @@ +--- +openapi: post /v2/payments/{id}/confirm-intent +--- \ No newline at end of file diff --git a/api-reference-v2/mint.json b/api-reference-v2/mint.json index 5efdb1ed2ad..974e530f311 100644 --- a/api-reference-v2/mint.json +++ b/api-reference-v2/mint.json @@ -38,7 +38,8 @@ "group": "Payments", "pages": [ "api-reference/payments/payments--create-intent", - "api-reference/payments/payments--session-token" + "api-reference/payments/payments--session-token", + "api-reference/payments/payments--confirm-intent" ] }, { diff --git a/api-reference-v2/openapi_spec.json b/api-reference-v2/openapi_spec.json index 72afa1dc3da..bd9de3a2962 100644 --- a/api-reference-v2/openapi_spec.json +++ b/api-reference-v2/openapi_spec.json @@ -663,7 +663,7 @@ ] } }, - "/v2/payments/{payment_id}/create_external_sdk_tokens": { + "/v2/payments/{payment_id}/create-external-sdk-tokens": { "post": { "tags": [ "Payments" @@ -1848,6 +1848,62 @@ ] } }, + "/v2/payments/{id}/confirm-intent": { + "post": { + "tags": [ + "Payments" + ], + "summary": "Payments - Confirm Intent", + "description": "**Confirms a payment intent object with the payment method data**\n\n.", + "operationId": "Confirm Payment Intent", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentsConfirmIntentRequest" + }, + "examples": { + "Confirm the payment intent with card details": { + "value": { + "payment_method_data": { + "card": { + "card_cvc": "123", + "card_exp_month": "10", + "card_exp_year": "25", + "card_holder_name": "joseph Doe", + "card_number": "4242424242424242" + } + }, + "payment_method_type": "card" + } + } + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Payment created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PaymentsConfirmIntentResponse" + } + } + } + }, + "400": { + "description": "Missing Mandatory fields" + } + }, + "security": [ + { + "publisable_key": [] + } + ] + } + }, "/v2/refunds": { "post": { "tags": [ @@ -2472,6 +2528,65 @@ } } }, + "AmountDetailsResponse": { + "type": "object", + "required": [ + "order_amount", + "currency", + "skip_external_tax_calculation", + "skip_surcharge_calculation" + ], + "properties": { + "order_amount": { + "type": "integer", + "format": "int64", + "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", + "example": 6540, + "minimum": 0 + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "shipping_cost": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "order_tax_amount": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "skip_external_tax_calculation": { + "$ref": "#/components/schemas/TaxCalculationOverride" + }, + "skip_surcharge_calculation": { + "$ref": "#/components/schemas/SurchargeCalculationOverride" + }, + "surcharge_amount": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "tax_on_surcharge": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + } + } + }, "AmountFilter": { "type": "object", "properties": { @@ -5485,6 +5600,88 @@ "greater_than_equal" ] }, + "ConfirmIntentAmountDetailsResponse": { + "type": "object", + "required": [ + "currency", + "skip_external_tax_calculation", + "skip_surcharge_calculation", + "net_amount", + "amount_capturable" + ], + "properties": { + "order_amount": { + "type": "integer", + "format": "int64", + "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", + "example": 6540, + "minimum": 0 + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "shipping_cost": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "order_tax_amount": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "skip_external_tax_calculation": { + "$ref": "#/components/schemas/TaxCalculationOverride" + }, + "skip_surcharge_calculation": { + "$ref": "#/components/schemas/SurchargeCalculationOverride" + }, + "surcharge_amount": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "tax_on_surcharge": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "net_amount": { + "$ref": "#/components/schemas/MinorUnit" + }, + "amount_to_capture": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + }, + "amount_capturable": { + "$ref": "#/components/schemas/MinorUnit" + }, + "amount_captured": { + "allOf": [ + { + "$ref": "#/components/schemas/MinorUnit" + } + ], + "nullable": true + } + } + }, "Connector": { "type": "string", "description": "A connector is an integration to fulfill payments", @@ -7101,6 +7298,34 @@ } } }, + "ErrorDetails": { + "type": "object", + "description": "Error details for the payment", + "required": [ + "code", + "message" + ], + "properties": { + "code": { + "type": "string", + "description": "The error code" + }, + "message": { + "type": "string", + "description": "The error message" + }, + "unified_code": { + "type": "string", + "description": "The unified error code across all connectors.\nThis can be relied upon for taking decisions based on the error.", + "nullable": true + }, + "unified_message": { + "type": "string", + "description": "The unified error message across all connectors.\nIf there is a translation available, this will have the translated message", + "nullable": true + } + } + }, "EventClass": { "type": "string", "enum": [ @@ -13009,255 +13234,262 @@ } } }, - "PaymentsConfirmRequest": { + "PaymentsConfirmIntentRequest": { "type": "object", + "description": "Request for Payment Intent Confirm", + "required": [ + "payment_method_data", + "payment_method_type", + "payment_method_subtype" + ], "properties": { - "amount": { - "type": "integer", - "format": "int64", - "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", - "example": 6540, - "nullable": true, - "minimum": 0 - }, - "currency": { - "allOf": [ - { - "$ref": "#/components/schemas/Currency" - } - ], + "return_url": { + "type": "string", + "description": "The URL to which you want the user to be redirected after the completion of the payment operation\nIf this url is not passed, the url configured in the business profile will be used", + "example": "https://hyperswitch.io", "nullable": true }, - "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. Also, it must be less than or equal to the original payment account.", - "example": 6540, - "nullable": true + "payment_method_data": { + "$ref": "#/components/schemas/PaymentMethodDataRequest" }, - "shipping_cost": { - "type": "integer", - "format": "int64", - "description": "The shipping cost for the payment. This is required for tax calculation in some regions.", - "example": 6540, - "nullable": true + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethod" }, - "payment_id": { - "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant. The value for this field can be specified in the request, it will be auto generated otherwise and returned in the API response.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "nullable": true, - "maxLength": 30, - "minLength": 30 + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" }, - "routing": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/StraightThroughAlgorithm" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "connector": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Connector" - }, - "description": "This allows to manually select a connector with which the payment can go through.", - "example": [ - "stripe", - "adyen" - ], - "nullable": true - }, - "capture_method": { + "customer_acceptance": { "allOf": [ { - "$ref": "#/components/schemas/CaptureMethod" + "$ref": "#/components/schemas/CustomerAcceptance" } ], "nullable": true }, - "authentication_type": { + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" - } - ], - "default": "three_ds", - "nullable": true - }, - "billing": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/BrowserInformation" } ], "nullable": true + } + } + }, + "PaymentsConfirmIntentResponse": { + "type": "object", + "description": "Response for Payment Intent Confirm", + "required": [ + "id", + "status", + "amount", + "connector", + "client_secret", + "created", + "payment_method_type", + "payment_method_subtype", + "merchant_connector_id" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "12345_pay_01926c58bc6e77c09e809964e72af8c8", + "maxLength": 64, + "minLength": 32 }, - "confirm": { - "type": "boolean", - "description": "Whether to confirm the payment (if applicable). It can be used to completely process a payment by attaching a payment method, setting `confirm=true` and `capture_method = automatic` in the *Payments/Create API* request itself.", - "default": false, - "example": true, - "nullable": true + "status": { + "$ref": "#/components/schemas/IntentStatus" }, - "customer": { + "amount": { + "$ref": "#/components/schemas/ConfirmIntentAmountDetailsResponse" + }, + "connector": { + "type": "string", + "description": "The connector used for the payment", + "example": "stripe" + }, + "client_secret": { + "type": "string", + "description": "It's a token used for client side verification." + }, + "created": { + "type": "string", + "format": "date-time", + "description": "Time when the payment was created", + "example": "2022-09-10T10:11:12Z" + }, + "payment_method_data": { "allOf": [ { - "$ref": "#/components/schemas/CustomerDetails" + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" } ], "nullable": true }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethod" }, - "off_session": { - "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. When making a recurring payment by passing a mandate_id, this parameter is mandatory", - "example": true, - "nullable": true + "payment_method_subtype": { + "$ref": "#/components/schemas/PaymentMethodType" }, - "description": { + "connector_transaction_id": { "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", + "description": "A unique identifier for a payment provided by the connector", + "example": "993672945374576J", "nullable": true }, - "return_url": { + "connector_reference_id": { "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", - "example": "https://hyperswitch.io", + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", "nullable": true }, - "setup_future_usage": { - "allOf": [ - { - "$ref": "#/components/schemas/FutureUsage" - } - ], - "nullable": true + "merchant_connector_id": { + "type": "string", + "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment" }, - "payment_method_data": { + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodDataRequest" + "$ref": "#/components/schemas/BrowserInformation" } ], "nullable": true }, - "payment_method": { + "error": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethod" + "$ref": "#/components/schemas/ErrorDetails" } ], "nullable": true + } + } + }, + "PaymentsCreateIntentRequest": { + "type": "object", + "required": [ + "amount_details" + ], + "properties": { + "amount_details": { + "$ref": "#/components/schemas/AmountDetails" }, - "payment_token": { + "merchant_reference_id": { "type": "string", - "description": "As Hyperswitch tokenises the sensitive details about the payments method, it provides the payment_token as a reference to a stored payment method, ensuring that the sensitive details are not exposed in any manner.", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "nullable": true, + "maxLength": 30, + "minLength": 30 + }, + "routing_algorithm_id": { + "type": "string", + "description": "The routing algorithm id to be used for the payment", "nullable": true }, - "shipping": { + "capture_method": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/CaptureMethod" } ], "nullable": true }, - "statement_descriptor_name": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 255 - }, - "statement_descriptor_suffix": { - "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", - "nullable": true, - "maxLength": 255 - }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", - "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", - "nullable": true - }, - "client_secret": { - "type": "string", - "description": "It's a token used for client side verification.", - "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", + "authentication_type": { + "allOf": [ + { + "$ref": "#/components/schemas/AuthenticationType" + } + ], + "default": "no_three_ds", "nullable": true }, - "mandate_data": { + "billing": { "allOf": [ { - "$ref": "#/components/schemas/MandateData" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "customer_acceptance": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/CustomerAcceptance" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "mandate_id": { + "customer_id": { "type": "string", - "description": "A unique identifier to link the payment to a mandate. To do Recurring payments after a mandate has been created, pass the mandate_id instead of payment_method_data", - "example": "mandate_iwer89rnjef349dni3", + "description": "The identifier for the customer", + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", "nullable": true, - "maxLength": 255 + "maxLength": 64, + "minLength": 1 }, - "browser_info": { + "customer_present": { "allOf": [ { - "$ref": "#/components/schemas/BrowserInformation" + "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" } ], "nullable": true }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], + "description": { + "type": "string", + "description": "A description for the payment", + "example": "It's my first payment request", "nullable": true }, - "payment_method_type": { + "return_url": { + "type": "string", + "description": "The URL to which you want the user to be redirected after the completion of the payment operation", + "example": "https://hyperswitch.io", + "nullable": true + }, + "setup_future_usage": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodType" + "$ref": "#/components/schemas/FutureUsage" } ], "nullable": true }, - "merchant_connector_details": { + "apply_mit_exemption": { "allOf": [ { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" + "$ref": "#/components/schemas/MitExemptionRequest" } ], "nullable": true }, + "statement_descriptor": { + "type": "string", + "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", + "example": "Hyperswitch Router", + "nullable": true, + "maxLength": 22 + }, + "order_details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDetailsWithAmount" + }, + "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", + "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", + "nullable": true + }, "allowed_payment_method_types": { "type": "array", "items": { @@ -13266,17 +13498,9 @@ "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", "nullable": true }, - "retry_action": { - "allOf": [ - { - "$ref": "#/components/schemas/RetryAction" - } - ], - "nullable": true - }, "metadata": { "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", + "description": "Metadata is useful for storing additional, unstructured information on an object.", "nullable": true }, "connector_metadata": { @@ -13287,43 +13511,42 @@ ], "nullable": true }, - "payment_link": { - "type": "boolean", - "description": "Whether to generate the payment link for this payment or not (if applicable)", - "default": false, - "example": true, - "nullable": true - }, - "payment_link_config": { + "feature_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" + "$ref": "#/components/schemas/FeatureMetadata" } ], "nullable": true }, - "payment_link_config_id": { - "type": "string", - "description": "Custom payment link config id set at business profile, send only if business_specific_configs is configured", + "payment_link_enabled": { + "allOf": [ + { + "$ref": "#/components/schemas/EnablePaymentLinkRequest" + } + ], "nullable": true }, - "payment_type": { + "payment_link_config": { "allOf": [ { - "$ref": "#/components/schemas/PaymentType" + "$ref": "#/components/schemas/PaymentLinkConfigRequest" } ], "nullable": true }, "request_incremental_authorization": { - "type": "boolean", - "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.", + "allOf": [ + { + "$ref": "#/components/schemas/RequestIncrementalAuthorization" + } + ], "nullable": true }, "session_expiry": { "type": "integer", "format": "int32", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins", + "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config\n(900) for 15 mins", "example": 900, "nullable": true, "minimum": 0 @@ -13334,226 +13557,9 @@ "nullable": true }, "request_external_three_ds_authentication": { - "type": "boolean", - "description": "Whether to perform external authentication (if applicable)", - "example": true, - "nullable": true - }, - "recurring_details": { "allOf": [ { - "$ref": "#/components/schemas/RecurringDetails" - } - ], - "nullable": true - }, - "charges": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentChargeRequest" - } - ], - "nullable": true - }, - "merchant_order_reference_id": { - "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 - }, - "skip_external_tax_calculation": { - "type": "boolean", - "description": "Whether to calculate tax for this payment intent", - "nullable": true - } - } - }, - "PaymentsCreateIntentRequest": { - "type": "object", - "required": [ - "amount_details" - ], - "properties": { - "amount_details": { - "$ref": "#/components/schemas/AmountDetails" - }, - "merchant_reference_id": { - "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "nullable": true, - "maxLength": 30, - "minLength": 30 - }, - "routing_algorithm_id": { - "type": "string", - "description": "The routing algorithm id to be used for the payment", - "nullable": true - }, - "capture_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], - "nullable": true - }, - "authentication_type": { - "allOf": [ - { - "$ref": "#/components/schemas/AuthenticationType" - } - ], - "default": "no_three_ds", - "nullable": true - }, - "billing": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "shipping": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "customer_present": { - "allOf": [ - { - "$ref": "#/components/schemas/PresenceOfCustomerDuringPayment" - } - ], - "nullable": true - }, - "description": { - "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", - "nullable": true - }, - "return_url": { - "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", - "example": "https://hyperswitch.io", - "nullable": true - }, - "setup_future_usage": { - "allOf": [ - { - "$ref": "#/components/schemas/FutureUsage" - } - ], - "nullable": true - }, - "apply_mit_exemption": { - "allOf": [ - { - "$ref": "#/components/schemas/MitExemptionRequest" - } - ], - "nullable": true - }, - "statement_descriptor": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 22 - }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", - "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", - "nullable": true - }, - "allowed_payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", - "nullable": true - }, - "metadata": { - "type": "object", - "description": "Metadata is useful for storing additional, unstructured information on an object.", - "nullable": true - }, - "connector_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/ConnectorMetadata" - } - ], - "nullable": true - }, - "feature_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/FeatureMetadata" - } - ], - "nullable": true - }, - "payment_link_enabled": { - "allOf": [ - { - "$ref": "#/components/schemas/EnablePaymentLinkRequest" - } - ], - "nullable": true - }, - "payment_link_config": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentLinkConfigRequest" - } - ], - "nullable": true - }, - "request_incremental_authorization": { - "allOf": [ - { - "$ref": "#/components/schemas/RequestIncrementalAuthorization" - } - ], - "nullable": true - }, - "session_expiry": { - "type": "integer", - "format": "int32", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds, if not sent it will be taken from profile config\n(900) for 15 mins", - "example": 900, - "nullable": true, - "minimum": 0 - }, - "frm_metadata": { - "type": "object", - "description": "Additional data related to some frm(Fraud Risk Management) connectors", - "nullable": true - }, - "request_external_three_ds_authentication": { - "allOf": [ - { - "$ref": "#/components/schemas/External3dsAuthenticationRequest" + "$ref": "#/components/schemas/External3dsAuthenticationRequest" } ], "nullable": true @@ -13583,7 +13589,7 @@ "description": "Global Payment Id for the payment" }, "amount_details": { - "$ref": "#/components/schemas/AmountDetails" + "$ref": "#/components/schemas/AmountDetailsResponse" }, "client_secret": { "type": "string", @@ -13734,166 +13740,259 @@ }, "additionalProperties": false }, - "PaymentsCreateRequest": { + "PaymentsCreateResponseOpenApi": { "type": "object", "required": [ + "payment_id", + "merchant_id", + "status", "amount", - "currency" + "net_amount", + "amount_capturable", + "currency", + "payment_method", + "attempt_count" ], "properties": { + "payment_id": { + "type": "string", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "maxLength": 30, + "minLength": 30 + }, + "merchant_id": { + "type": "string", + "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request", + "example": "merchant_1668273825", + "maxLength": 255 + }, + "status": { + "allOf": [ + { + "$ref": "#/components/schemas/IntentStatus" + } + ], + "default": "requires_confirmation" + }, "amount": { "type": "integer", "format": "int64", - "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", - "minimum": 0 + "description": "The payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", + "example": 6540 }, - "currency": { - "$ref": "#/components/schemas/Currency" + "net_amount": { + "type": "integer", + "format": "int64", + "description": "The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount + shipping_cost + order_tax_amount,\nIf no surcharge_details, shipping_cost, order_tax_amount, net_amount = amount", + "example": 6540 }, - "amount_to_capture": { + "shipping_cost": { "type": "integer", "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. Also, it must be less than or equal to the original payment account.", + "description": "The shipping cost for the payment.", "example": 6540, "nullable": true }, - "shipping_cost": { + "amount_capturable": { "type": "integer", "format": "int64", - "description": "The shipping cost for the payment. This is required for tax calculation in some regions.", + "description": "The maximum amount that could be captured from the payment", "example": 6540, - "nullable": true + "minimum": 100 }, - "payment_id": { + "amount_received": { + "type": "integer", + "format": "int64", + "description": "The amount which is already captured from the payment, this helps in the cases where merchants can't capture all capturable amount at once.", + "example": 6540, + "nullable": true + }, + "connector": { "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant. The value for this field can be specified in the request, it will be auto generated otherwise and returned in the API response.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", + "description": "The connector used for the payment", + "example": "stripe", + "nullable": true + }, + "client_secret": { + "type": "string", + "description": "It's a token used for client side verification.", + "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", + "nullable": true + }, + "created": { + "type": "string", + "format": "date-time", + "description": "Time when the payment was created", + "example": "2022-09-10T10:11:12Z", + "nullable": true + }, + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "customer_id": { + "type": "string", + "description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.\nThis field will be deprecated soon. Please refer to `customer.id`", + "deprecated": true, + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", "nullable": true, - "maxLength": 30, - "minLength": 30 + "maxLength": 64, + "minLength": 1 }, - "routing": { - "allOf": [ - { - "$ref": "#/components/schemas/StraightThroughAlgorithm" - } - ], + "description": { + "type": "string", + "description": "A description of the payment", + "example": "It's my first payment request", "nullable": true }, - "connector": { + "refunds": { "type": "array", "items": { - "$ref": "#/components/schemas/Connector" + "$ref": "#/components/schemas/RefundResponse" }, - "description": "This allows to manually select a connector with which the payment can go through.", - "example": [ - "stripe", - "adyen" - ], + "description": "List of refunds that happened on this intent, as same payment intent can have multiple refund requests depending on the nature of order", "nullable": true }, - "capture_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], + "disputes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" + }, + "description": "List of disputes that happened on this intent", "nullable": true }, - "authentication_type": { + "attempts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentAttemptResponse" + }, + "description": "List of attempts that happened on this intent", + "nullable": true + }, + "captures": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CaptureResponse" + }, + "description": "List of captures done on latest attempt", + "nullable": true + }, + "mandate_id": { + "type": "string", + "description": "A unique identifier to link the payment to a mandate, can be used instead of payment_method_data, in case of setting up recurring payments", + "example": "mandate_iwer89rnjef349dni3", + "nullable": true, + "maxLength": 255 + }, + "mandate_data": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/MandateData" } ], - "default": "three_ds", "nullable": true }, - "billing": { + "setup_future_usage": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/FutureUsage" } ], "nullable": true }, - "confirm": { + "off_session": { "type": "boolean", - "description": "Whether to confirm the payment (if applicable). It can be used to completely process a payment by attaching a payment method, setting `confirm=true` and `capture_method = automatic` in the *Payments/Create API* request itself.", - "default": false, + "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with confirm=true.", "example": true, "nullable": true }, - "customer": { + "capture_method": { "allOf": [ { - "$ref": "#/components/schemas/CustomerDetails" + "$ref": "#/components/schemas/CaptureMethod" } ], "nullable": true }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "off_session": { - "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. When making a recurring payment by passing a mandate_id, this parameter is mandatory", - "example": true, - "nullable": true + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" }, - "description": { - "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", + "payment_method_data": { + "allOf": [ + { + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" + } + ], "nullable": true }, - "return_url": { + "payment_token": { "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", - "example": "https://hyperswitch.io", + "description": "Provide a reference to a stored payment method", + "example": "187282ab-40ef-47a9-9206-5099ba31e432", "nullable": true }, - "setup_future_usage": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "payment_method_data": { + "billing": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodDataRequest" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "payment_method": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethod" - } - ], + "order_details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDetailsWithAmount" + }, + "description": "Information about the product , quantity and amount for connectors. (e.g. Klarna)", + "example": "[{\n \"product_name\": \"gillete creme\",\n \"quantity\": 15,\n \"amount\" : 900\n }]", "nullable": true }, - "payment_token": { + "email": { "type": "string", - "description": "As Hyperswitch tokenises the sensitive details about the payments method, it provides the payment_token as a reference to a stored payment method, ensuring that the sensitive details are not exposed in any manner.", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", + "description": "description: The customer's email address\nThis field will be deprecated soon. Please refer to `customer.email` object", + "deprecated": true, + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 + }, + "name": { + "type": "string", + "description": "description: The customer's name\nThis field will be deprecated soon. Please refer to `customer.name` object", + "deprecated": true, + "example": "John Test", + "nullable": true, + "maxLength": 255 + }, + "phone": { + "type": "string", + "description": "The customer's phone number\nThis field will be deprecated soon. Please refer to `customer.phone` object", + "deprecated": true, + "example": "9123456789", + "nullable": true, + "maxLength": 255 + }, + "return_url": { + "type": "string", + "description": "The URL to redirect after the completion of the operation", + "example": "https://hyperswitch.io", "nullable": true }, - "shipping": { + "authentication_type": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/AuthenticationType" } ], + "default": "three_ds", "nullable": true }, "statement_descriptor_name": { @@ -13905,49 +14004,34 @@ }, "statement_descriptor_suffix": { "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor.", + "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 255 characters for the concatenated descriptor.", "example": "Payment for shoes purchase", "nullable": true, "maxLength": 255 }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", - "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", - "nullable": true - }, - "mandate_data": { + "next_action": { "allOf": [ { - "$ref": "#/components/schemas/MandateData" + "$ref": "#/components/schemas/NextActionData" } ], "nullable": true }, - "customer_acceptance": { - "allOf": [ - { - "$ref": "#/components/schemas/CustomerAcceptance" - } - ], + "cancellation_reason": { + "type": "string", + "description": "If the payment was cancelled the reason will be provided here", "nullable": true }, - "mandate_id": { + "error_code": { "type": "string", - "description": "A unique identifier to link the payment to a mandate. To do Recurring payments after a mandate has been created, pass the mandate_id instead of payment_method_data", - "example": "mandate_iwer89rnjef349dni3", - "nullable": true, - "maxLength": 255 + "description": "If there was an error while calling the connectors the code is received here", + "example": "E0001", + "nullable": true }, - "browser_info": { - "allOf": [ - { - "$ref": "#/components/schemas/BrowserInformation" - } - ], + "error_message": { + "type": "string", + "description": "If there was an error while calling the connector the error message is received here", + "example": "Failed while verifying the card", "nullable": true }, "payment_experience": { @@ -13966,6 +14050,12 @@ ], "nullable": true }, + "connector_label": { + "type": "string", + "description": "The connector used for this payment along with the country and business details", + "example": "stripe_US_food", + "nullable": true + }, "business_country": { "allOf": [ { @@ -13976,16 +14066,12 @@ }, "business_label": { "type": "string", - "description": "Business label of the merchant for this payment.\nTo be deprecated soon. Pass the profile_id instead", - "example": "food", + "description": "The business label of merchant for this payment", "nullable": true }, - "merchant_connector_details": { - "allOf": [ - { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" - } - ], + "business_sub_label": { + "type": "string", + "description": "The business_sub_label for this payment", "nullable": true }, "allowed_payment_method_types": { @@ -13993,2265 +14079,1007 @@ "items": { "$ref": "#/components/schemas/PaymentMethodType" }, - "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", - "nullable": true - }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", + "description": "Allowed Payment Method Types for a given PaymentIntent", "nullable": true }, - "connector_metadata": { + "ephemeral_key": { "allOf": [ { - "$ref": "#/components/schemas/ConnectorMetadata" + "$ref": "#/components/schemas/EphemeralKeyCreateResponse" } ], "nullable": true }, - "payment_link": { + "manual_retry_allowed": { "type": "boolean", - "description": "Whether to generate the payment link for this payment or not (if applicable)", - "default": false, - "example": true, + "description": "If true the payment can be retried with same or different payment method which means the confirm call can be made again.", "nullable": true }, - "payment_link_config": { + "connector_transaction_id": { + "type": "string", + "description": "A unique identifier for a payment provided by the connector", + "example": "993672945374576J", + "nullable": true + }, + "frm_message": { "allOf": [ { - "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" + "$ref": "#/components/schemas/FrmMessage" } ], "nullable": true }, - "payment_link_config_id": { - "type": "string", - "description": "Custom payment link config id set at business profile, send only if business_specific_configs is configured", - "nullable": true - }, - "profile_id": { - "type": "string", - "description": "The business profile to be used for this payment, if not passed the default business profile associated with the merchant account will be used. It is mandatory in case multiple business profiles have been set up.", + "metadata": { + "type": "object", + "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", "nullable": true }, - "surcharge_details": { + "connector_metadata": { "allOf": [ { - "$ref": "#/components/schemas/RequestSurchargeDetails" + "$ref": "#/components/schemas/ConnectorMetadata" } ], "nullable": true }, - "payment_type": { + "feature_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentType" + "$ref": "#/components/schemas/FeatureMetadata" } ], "nullable": true }, - "request_incremental_authorization": { - "type": "boolean", - "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.", - "nullable": true - }, - "session_expiry": { - "type": "integer", - "format": "int32", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins", - "example": 900, - "nullable": true, - "minimum": 0 - }, - "frm_metadata": { - "type": "object", - "description": "Additional data related to some frm(Fraud Risk Management) connectors", - "nullable": true - }, - "request_external_three_ds_authentication": { - "type": "boolean", - "description": "Whether to perform external authentication (if applicable)", - "example": true, - "nullable": true - }, - "recurring_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RecurringDetails" - } - ], + "reference_id": { + "type": "string", + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", "nullable": true }, - "charges": { + "payment_link": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeRequest" + "$ref": "#/components/schemas/PaymentLinkResponse" } ], "nullable": true }, - "merchant_order_reference_id": { + "profile_id": { "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 - }, - "skip_external_tax_calculation": { - "type": "boolean", - "description": "Whether to calculate tax for this payment intent", + "description": "The business profile that is associated with this payment", "nullable": true - } - } - }, - "PaymentsCreateResponseOpenApi": { - "type": "object", - "required": [ - "payment_id", - "merchant_id", - "status", - "amount", - "net_amount", - "amount_capturable", - "currency", - "payment_method", - "attempt_count" - ], - "properties": { - "payment_id": { - "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "maxLength": 30, - "minLength": 30 - }, - "merchant_id": { - "type": "string", - "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request", - "example": "merchant_1668273825", - "maxLength": 255 }, - "status": { + "surcharge_details": { "allOf": [ { - "$ref": "#/components/schemas/IntentStatus" + "$ref": "#/components/schemas/RequestSurchargeDetails" } ], - "default": "requires_confirmation" - }, - "amount": { - "type": "integer", - "format": "int64", - "description": "The payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", - "example": 6540 - }, - "net_amount": { - "type": "integer", - "format": "int64", - "description": "The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount + shipping_cost + order_tax_amount,\nIf no surcharge_details, shipping_cost, order_tax_amount, net_amount = amount", - "example": 6540 - }, - "shipping_cost": { - "type": "integer", - "format": "int64", - "description": "The shipping cost for the payment.", - "example": 6540, "nullable": true }, - "amount_capturable": { - "type": "integer", - "format": "int64", - "description": "The maximum amount that could be captured from the payment", - "example": 6540, - "minimum": 100 - }, - "amount_received": { + "attempt_count": { "type": "integer", - "format": "int64", - "description": "The amount which is already captured from the payment, this helps in the cases where merchants can't capture all capturable amount at once.", - "example": 6540, - "nullable": true + "format": "int32", + "description": "Total number of attempts associated with this payment" }, - "connector": { + "merchant_decision": { "type": "string", - "description": "The connector used for the payment", - "example": "stripe", + "description": "Denotes the action(approve or reject) taken by merchant in case of manual review. Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment", "nullable": true }, - "client_secret": { + "merchant_connector_id": { "type": "string", - "description": "It's a token used for client side verification.", - "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", + "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", "nullable": true }, - "created": { - "type": "string", - "format": "date-time", - "description": "Time when the payment was created", - "example": "2022-09-10T10:11:12Z", + "incremental_authorization_allowed": { + "type": "boolean", + "description": "If true, incremental authorization can be performed on this payment, in case the funds authorized initially fall short.", "nullable": true }, - "currency": { - "$ref": "#/components/schemas/Currency" - }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.\nThis field will be deprecated soon. Please refer to `customer.id`", - "deprecated": true, - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "description": { - "type": "string", - "description": "A description of the payment", - "example": "It's my first payment request", + "authorization_count": { + "type": "integer", + "format": "int32", + "description": "Total number of authorizations happened in an incremental_authorization payment", "nullable": true }, - "refunds": { + "incremental_authorizations": { "type": "array", "items": { - "$ref": "#/components/schemas/RefundResponse" + "$ref": "#/components/schemas/IncrementalAuthorizationResponse" }, - "description": "List of refunds that happened on this intent, as same payment intent can have multiple refund requests depending on the nature of order", + "description": "List of incremental authorizations happened to the payment", "nullable": true }, - "disputes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" - }, - "description": "List of disputes that happened on this intent", + "external_authentication_details": { + "allOf": [ + { + "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" + } + ], "nullable": true }, - "attempts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentAttemptResponse" - }, - "description": "List of attempts that happened on this intent", + "external_3ds_authentication_attempted": { + "type": "boolean", + "description": "Flag indicating if external 3ds authentication is made or not", "nullable": true }, - "captures": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CaptureResponse" - }, - "description": "List of captures done on latest attempt", + "expires_on": { + "type": "string", + "format": "date-time", + "description": "Date Time for expiry of the payment", + "example": "2022-09-10T10:11:12Z", "nullable": true }, - "mandate_id": { + "fingerprint": { "type": "string", - "description": "A unique identifier to link the payment to a mandate, can be used instead of payment_method_data, in case of setting up recurring payments", - "example": "mandate_iwer89rnjef349dni3", - "nullable": true, - "maxLength": 255 + "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", + "nullable": true }, - "mandate_data": { + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/MandateData" + "$ref": "#/components/schemas/BrowserInformation" } ], "nullable": true }, - "setup_future_usage": { + "payment_method_id": { + "type": "string", + "description": "Identifier for Payment Method used for the payment", + "nullable": true + }, + "payment_method_status": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/PaymentMethodStatus" } ], "nullable": true }, - "off_session": { - "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with confirm=true.", - "example": true, + "updated": { + "type": "string", + "format": "date-time", + "description": "Date time at which payment was updated", + "example": "2022-09-10T10:11:12Z", "nullable": true }, - "capture_method": { + "charges": { "allOf": [ { - "$ref": "#/components/schemas/CaptureMethod" + "$ref": "#/components/schemas/PaymentChargeResponse" } ], "nullable": true }, - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" - }, - "payment_method_data": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" - } - ], - "nullable": true - }, - "payment_token": { - "type": "string", - "description": "Provide a reference to a stored payment method", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", - "nullable": true - }, - "shipping": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "billing": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Information about the product , quantity and amount for connectors. (e.g. Klarna)", - "example": "[{\n \"product_name\": \"gillete creme\",\n \"quantity\": 15,\n \"amount\" : 900\n }]", - "nullable": true - }, - "email": { - "type": "string", - "description": "description: The customer's email address\nThis field will be deprecated soon. Please refer to `customer.email` object", - "deprecated": true, - "example": "johntest@test.com", - "nullable": true, - "maxLength": 255 - }, - "name": { - "type": "string", - "description": "description: The customer's name\nThis field will be deprecated soon. Please refer to `customer.name` object", - "deprecated": true, - "example": "John Test", - "nullable": true, - "maxLength": 255 - }, - "phone": { - "type": "string", - "description": "The customer's phone number\nThis field will be deprecated soon. Please refer to `customer.phone` object", - "deprecated": true, - "example": "9123456789", - "nullable": true, - "maxLength": 255 - }, - "return_url": { - "type": "string", - "description": "The URL to redirect after the completion of the operation", - "example": "https://hyperswitch.io", - "nullable": true - }, - "authentication_type": { - "allOf": [ - { - "$ref": "#/components/schemas/AuthenticationType" - } - ], - "default": "three_ds", - "nullable": true - }, - "statement_descriptor_name": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 255 - }, - "statement_descriptor_suffix": { - "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 255 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", - "nullable": true, - "maxLength": 255 - }, - "next_action": { - "allOf": [ - { - "$ref": "#/components/schemas/NextActionData" - } - ], - "nullable": true - }, - "cancellation_reason": { - "type": "string", - "description": "If the payment was cancelled the reason will be provided here", - "nullable": true - }, - "error_code": { - "type": "string", - "description": "If there was an error while calling the connectors the code is received here", - "example": "E0001", - "nullable": true - }, - "error_message": { - "type": "string", - "description": "If there was an error while calling the connector the error message is received here", - "example": "Failed while verifying the card", - "nullable": true - }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], - "nullable": true - }, - "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], - "nullable": true - }, - "connector_label": { - "type": "string", - "description": "The connector used for this payment along with the country and business details", - "example": "stripe_US_food", - "nullable": true - }, - "business_country": { - "allOf": [ - { - "$ref": "#/components/schemas/CountryAlpha2" - } - ], - "nullable": true - }, - "business_label": { - "type": "string", - "description": "The business label of merchant for this payment", - "nullable": true - }, - "business_sub_label": { - "type": "string", - "description": "The business_sub_label for this payment", - "nullable": true - }, - "allowed_payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "Allowed Payment Method Types for a given PaymentIntent", - "nullable": true - }, - "ephemeral_key": { - "allOf": [ - { - "$ref": "#/components/schemas/EphemeralKeyCreateResponse" - } - ], - "nullable": true - }, - "manual_retry_allowed": { - "type": "boolean", - "description": "If true the payment can be retried with same or different payment method which means the confirm call can be made again.", - "nullable": true - }, - "connector_transaction_id": { - "type": "string", - "description": "A unique identifier for a payment provided by the connector", - "example": "993672945374576J", - "nullable": true - }, - "frm_message": { - "allOf": [ - { - "$ref": "#/components/schemas/FrmMessage" - } - ], - "nullable": true - }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", - "nullable": true - }, - "connector_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/ConnectorMetadata" - } - ], - "nullable": true - }, - "feature_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/FeatureMetadata" - } - ], - "nullable": true - }, - "reference_id": { - "type": "string", - "description": "reference(Identifier) to the payment at connector side", - "example": "993672945374576J", - "nullable": true - }, - "payment_link": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentLinkResponse" - } - ], - "nullable": true - }, - "profile_id": { - "type": "string", - "description": "The business profile that is associated with this payment", - "nullable": true - }, - "surcharge_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RequestSurchargeDetails" - } - ], - "nullable": true - }, - "attempt_count": { - "type": "integer", - "format": "int32", - "description": "Total number of attempts associated with this payment" - }, - "merchant_decision": { - "type": "string", - "description": "Denotes the action(approve or reject) taken by merchant in case of manual review. Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment", - "nullable": true - }, - "merchant_connector_id": { - "type": "string", - "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", - "nullable": true - }, - "incremental_authorization_allowed": { - "type": "boolean", - "description": "If true, incremental authorization can be performed on this payment, in case the funds authorized initially fall short.", - "nullable": true - }, - "authorization_count": { - "type": "integer", - "format": "int32", - "description": "Total number of authorizations happened in an incremental_authorization payment", - "nullable": true - }, - "incremental_authorizations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/IncrementalAuthorizationResponse" - }, - "description": "List of incremental authorizations happened to the payment", - "nullable": true - }, - "external_authentication_details": { - "allOf": [ - { - "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" - } - ], - "nullable": true - }, - "external_3ds_authentication_attempted": { - "type": "boolean", - "description": "Flag indicating if external 3ds authentication is made or not", - "nullable": true - }, - "expires_on": { - "type": "string", - "format": "date-time", - "description": "Date Time for expiry of the payment", - "example": "2022-09-10T10:11:12Z", - "nullable": true - }, - "fingerprint": { - "type": "string", - "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", - "nullable": true - }, - "browser_info": { - "allOf": [ - { - "$ref": "#/components/schemas/BrowserInformation" - } - ], - "nullable": true - }, - "payment_method_id": { - "type": "string", - "description": "Identifier for Payment Method used for the payment", - "nullable": true - }, - "payment_method_status": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodStatus" - } - ], - "nullable": true - }, - "updated": { - "type": "string", - "format": "date-time", - "description": "Date time at which payment was updated", - "example": "2022-09-10T10:11:12Z", - "nullable": true - }, - "charges": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentChargeResponse" - } - ], - "nullable": true - }, - "frm_metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.", - "nullable": true - }, - "merchant_order_reference_id": { - "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 - }, - "order_tax_amount": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true - }, - "connector_mandate_id": { - "type": "string", - "description": "Connector Identifier for the payment method", - "nullable": true - } - } - }, - "PaymentsDynamicTaxCalculationRequest": { - "type": "object", - "required": [ - "shipping", - "client_secret", - "payment_method_type" - ], - "properties": { - "shipping": { - "$ref": "#/components/schemas/Address" - }, - "client_secret": { - "type": "string", - "description": "Client Secret" - }, - "payment_method_type": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "session_id": { - "type": "string", - "description": "Session Id", - "nullable": true - } - } - }, - "PaymentsDynamicTaxCalculationResponse": { - "type": "object", - "required": [ - "payment_id", - "net_amount", - "display_amount" - ], - "properties": { - "payment_id": { - "type": "string", - "description": "The identifier for the payment" - }, - "net_amount": { - "$ref": "#/components/schemas/MinorUnit" - }, - "order_tax_amount": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true - }, - "shipping_cost": { - "allOf": [ - { - "$ref": "#/components/schemas/MinorUnit" - } - ], - "nullable": true - }, - "display_amount": { - "$ref": "#/components/schemas/DisplayAmountOnSdk" - } - } - }, - "PaymentsExternalAuthenticationRequest": { - "type": "object", - "required": [ - "client_secret", - "device_channel", - "threeds_method_comp_ind" - ], - "properties": { - "client_secret": { - "type": "string", - "description": "Client Secret" - }, - "sdk_information": { - "allOf": [ - { - "$ref": "#/components/schemas/SdkInformation" - } - ], - "nullable": true - }, - "device_channel": { - "$ref": "#/components/schemas/DeviceChannel" - }, - "threeds_method_comp_ind": { - "$ref": "#/components/schemas/ThreeDsCompletionIndicator" - } - } - }, - "PaymentsExternalAuthenticationResponse": { - "type": "object", - "required": [ - "trans_status", - "three_ds_requestor_url" - ], - "properties": { - "trans_status": { - "$ref": "#/components/schemas/TransactionStatus" - }, - "acs_url": { - "type": "string", - "description": "Access Server URL to be used for challenge submission", - "nullable": true - }, - "challenge_request": { - "type": "string", - "description": "Challenge request which should be sent to acs_url", - "nullable": true - }, - "acs_reference_number": { - "type": "string", - "description": "Unique identifier assigned by the EMVCo(Europay, Mastercard and Visa)", - "nullable": true - }, - "acs_trans_id": { - "type": "string", - "description": "Unique identifier assigned by the ACS to identify a single transaction", - "nullable": true - }, - "three_dsserver_trans_id": { - "type": "string", - "description": "Unique identifier assigned by the 3DS Server to identify a single transaction", - "nullable": true - }, - "acs_signed_content": { - "type": "string", - "description": "Contains the JWS object created by the ACS for the ARes(Authentication Response) message", - "nullable": true - }, - "three_ds_requestor_url": { - "type": "string", - "description": "Three DS Requestor URL" - } - } - }, - "PaymentsIncrementalAuthorizationRequest": { - "type": "object", - "required": [ - "amount" - ], - "properties": { - "amount": { - "type": "integer", - "format": "int64", - "description": "The total amount including previously authorized amount and additional amount", - "example": 6540 - }, - "reason": { - "type": "string", - "description": "Reason for incremental authorization", - "nullable": true - } - } - }, - "PaymentsRequest": { - "type": "object", - "properties": { - "amount": { - "type": "integer", - "format": "int64", - "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", - "example": 6540, - "nullable": true, - "minimum": 0 - }, - "currency": { - "allOf": [ - { - "$ref": "#/components/schemas/Currency" - } - ], - "nullable": true - }, - "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. Also, it must be less than or equal to the original payment account.", - "example": 6540, - "nullable": true - }, - "shipping_cost": { - "type": "integer", - "format": "int64", - "description": "The shipping cost for the payment. This is required for tax calculation in some regions.", - "example": 6540, - "nullable": true - }, - "payment_id": { - "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant. The value for this field can be specified in the request, it will be auto generated otherwise and returned in the API response.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "nullable": true, - "maxLength": 30, - "minLength": 30 - }, - "merchant_id": { - "type": "string", - "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request", - "example": "merchant_1668273825", - "nullable": true, - "maxLength": 255 - }, - "routing": { - "allOf": [ - { - "$ref": "#/components/schemas/StraightThroughAlgorithm" - } - ], - "nullable": true - }, - "connector": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Connector" - }, - "description": "This allows to manually select a connector with which the payment can go through.", - "example": [ - "stripe", - "adyen" - ], - "nullable": true - }, - "capture_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], - "nullable": true - }, - "authentication_type": { - "allOf": [ - { - "$ref": "#/components/schemas/AuthenticationType" - } - ], - "default": "three_ds", - "nullable": true - }, - "billing": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "capture_on": { - "type": "string", - "format": "date-time", - "description": "A timestamp (ISO 8601 code) that determines when the payment should be captured.\nProviding this field will automatically set `capture` to true", - "example": "2022-09-10T10:11:12Z", - "nullable": true - }, - "confirm": { - "type": "boolean", - "description": "Whether to confirm the payment (if applicable). It can be used to completely process a payment by attaching a payment method, setting `confirm=true` and `capture_method = automatic` in the *Payments/Create API* request itself.", - "default": false, - "example": true, - "nullable": true - }, - "customer": { - "allOf": [ - { - "$ref": "#/components/schemas/CustomerDetails" - } - ], - "nullable": true - }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "email": { - "type": "string", - "description": "The customer's email address.\nThis field will be deprecated soon, use the customer object instead", - "deprecated": true, - "example": "johntest@test.com", - "nullable": true, - "maxLength": 255 - }, - "name": { - "type": "string", - "description": "The customer's name.\nThis field will be deprecated soon, use the customer object instead.", - "deprecated": true, - "example": "John Test", - "nullable": true, - "maxLength": 255 - }, - "phone": { - "type": "string", - "description": "The customer's phone number\nThis field will be deprecated soon, use the customer object instead", - "deprecated": true, - "example": "9123456789", - "nullable": true, - "maxLength": 255 - }, - "phone_country_code": { - "type": "string", - "description": "The country code for the customer phone number\nThis field will be deprecated soon, use the customer object instead", - "deprecated": true, - "example": "+1", - "nullable": true, - "maxLength": 255 - }, - "off_session": { - "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. When making a recurring payment by passing a mandate_id, this parameter is mandatory", - "example": true, - "nullable": true - }, - "description": { - "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", - "nullable": true - }, - "return_url": { - "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", - "example": "https://hyperswitch.io", - "nullable": true - }, - "setup_future_usage": { - "allOf": [ - { - "$ref": "#/components/schemas/FutureUsage" - } - ], - "nullable": true - }, - "payment_method_data": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodDataRequest" - } - ], - "nullable": true - }, - "payment_method": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethod" - } - ], - "nullable": true - }, - "payment_token": { - "type": "string", - "description": "As Hyperswitch tokenises the sensitive details about the payments method, it provides the payment_token as a reference to a stored payment method, ensuring that the sensitive details are not exposed in any manner.", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", - "nullable": true - }, - "card_cvc": { - "type": "string", - "description": "This is used along with the payment_token field while collecting during saved card payments. This field will be deprecated soon, use the payment_method_data.card_token object instead", - "deprecated": true, - "nullable": true - }, - "shipping": { - "allOf": [ - { - "$ref": "#/components/schemas/Address" - } - ], - "nullable": true - }, - "statement_descriptor_name": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 255 - }, - "statement_descriptor_suffix": { - "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", - "nullable": true, - "maxLength": 255 - }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", - "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", - "nullable": true - }, - "client_secret": { - "type": "string", - "description": "It's a token used for client side verification.", - "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", - "nullable": true - }, - "mandate_data": { - "allOf": [ - { - "$ref": "#/components/schemas/MandateData" - } - ], - "nullable": true - }, - "customer_acceptance": { - "allOf": [ - { - "$ref": "#/components/schemas/CustomerAcceptance" - } - ], - "nullable": true - }, - "mandate_id": { - "type": "string", - "description": "A unique identifier to link the payment to a mandate. To do Recurring payments after a mandate has been created, pass the mandate_id instead of payment_method_data", - "example": "mandate_iwer89rnjef349dni3", - "nullable": true, - "maxLength": 255 - }, - "browser_info": { - "allOf": [ - { - "$ref": "#/components/schemas/BrowserInformation" - } - ], - "nullable": true - }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], - "nullable": true - }, - "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], - "nullable": true - }, - "business_country": { - "allOf": [ - { - "$ref": "#/components/schemas/CountryAlpha2" - } - ], - "nullable": true - }, - "business_label": { - "type": "string", - "description": "Business label of the merchant for this payment.\nTo be deprecated soon. Pass the profile_id instead", - "example": "food", - "nullable": true - }, - "merchant_connector_details": { - "allOf": [ - { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" - } - ], - "nullable": true - }, - "allowed_payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", - "nullable": true - }, - "business_sub_label": { - "type": "string", - "description": "Business sub label for the payment", - "nullable": true - }, - "retry_action": { - "allOf": [ - { - "$ref": "#/components/schemas/RetryAction" - } - ], - "nullable": true - }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", - "nullable": true - }, - "connector_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/ConnectorMetadata" - } - ], - "nullable": true - }, - "feature_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/FeatureMetadata" - } - ], - "nullable": true - }, - "payment_link": { - "type": "boolean", - "description": "Whether to generate the payment link for this payment or not (if applicable)", - "default": false, - "example": true, - "nullable": true - }, - "payment_link_config": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" - } - ], - "nullable": true - }, - "payment_link_config_id": { - "type": "string", - "description": "Custom payment link config id set at business profile, send only if business_specific_configs is configured", - "nullable": true - }, - "profile_id": { - "type": "string", - "description": "The business profile to be used for this payment, if not passed the default business profile associated with the merchant account will be used. It is mandatory in case multiple business profiles have been set up.", - "nullable": true - }, - "surcharge_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RequestSurchargeDetails" - } - ], - "nullable": true - }, - "payment_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentType" - } - ], - "nullable": true - }, - "request_incremental_authorization": { - "type": "boolean", - "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.", - "nullable": true - }, - "session_expiry": { - "type": "integer", - "format": "int32", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins", - "example": 900, - "nullable": true, - "minimum": 0 - }, - "frm_metadata": { - "type": "object", - "description": "Additional data related to some frm(Fraud Risk Management) connectors", - "nullable": true - }, - "request_external_three_ds_authentication": { - "type": "boolean", - "description": "Whether to perform external authentication (if applicable)", - "example": true, - "nullable": true - }, - "recurring_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RecurringDetails" - } - ], - "nullable": true - }, - "charges": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentChargeRequest" - } - ], - "nullable": true - }, - "merchant_order_reference_id": { - "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 - }, - "skip_external_tax_calculation": { - "type": "boolean", - "description": "Whether to calculate tax for this payment intent", - "nullable": true - } - }, - "additionalProperties": false - }, - "PaymentsResponse": { - "type": "object", - "required": [ - "payment_id", - "merchant_id", - "status", - "amount", - "net_amount", - "amount_capturable", - "currency", - "payment_method", - "attempt_count" - ], - "properties": { - "payment_id": { - "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "maxLength": 30, - "minLength": 30 - }, - "merchant_id": { - "type": "string", - "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request", - "example": "merchant_1668273825", - "maxLength": 255 - }, - "status": { - "allOf": [ - { - "$ref": "#/components/schemas/IntentStatus" - } - ], - "default": "requires_confirmation" - }, - "amount": { - "type": "integer", - "format": "int64", - "description": "The payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", - "example": 6540 - }, - "net_amount": { - "type": "integer", - "format": "int64", - "description": "The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount + shipping_cost + order_tax_amount,\nIf no surcharge_details, shipping_cost, order_tax_amount, net_amount = amount", - "example": 6540 - }, - "shipping_cost": { - "type": "integer", - "format": "int64", - "description": "The shipping cost for the payment.", - "example": 6540, - "nullable": true - }, - "amount_capturable": { - "type": "integer", - "format": "int64", - "description": "The maximum amount that could be captured from the payment", - "example": 6540, - "minimum": 100 - }, - "amount_received": { - "type": "integer", - "format": "int64", - "description": "The amount which is already captured from the payment, this helps in the cases where merchants can't capture all capturable amount at once.", - "example": 6540, - "nullable": true - }, - "connector": { - "type": "string", - "description": "The connector used for the payment", - "example": "stripe", - "nullable": true - }, - "client_secret": { - "type": "string", - "description": "It's a token used for client side verification.", - "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", - "nullable": true - }, - "created": { - "type": "string", - "format": "date-time", - "description": "Time when the payment was created", - "example": "2022-09-10T10:11:12Z", - "nullable": true - }, - "currency": { - "$ref": "#/components/schemas/Currency" - }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.\nThis field will be deprecated soon. Please refer to `customer.id`", - "deprecated": true, - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "customer": { - "allOf": [ - { - "$ref": "#/components/schemas/CustomerDetailsResponse" - } - ], - "nullable": true - }, - "description": { - "type": "string", - "description": "A description of the payment", - "example": "It's my first payment request", - "nullable": true - }, - "refunds": { - "type": "array", - "items": { - "$ref": "#/components/schemas/RefundResponse" - }, - "description": "List of refunds that happened on this intent, as same payment intent can have multiple refund requests depending on the nature of order", - "nullable": true - }, - "disputes": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" - }, - "description": "List of disputes that happened on this intent", - "nullable": true - }, - "attempts": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentAttemptResponse" - }, - "description": "List of attempts that happened on this intent", - "nullable": true - }, - "captures": { - "type": "array", - "items": { - "$ref": "#/components/schemas/CaptureResponse" - }, - "description": "List of captures done on latest attempt", + "frm_metadata": { + "type": "object", + "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.", "nullable": true }, - "mandate_id": { + "merchant_order_reference_id": { "type": "string", - "description": "A unique identifier to link the payment to a mandate, can be used instead of payment_method_data, in case of setting up recurring payments", - "example": "mandate_iwer89rnjef349dni3", + "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", + "example": "Custom_Order_id_123", "nullable": true, "maxLength": 255 }, - "mandate_data": { - "allOf": [ - { - "$ref": "#/components/schemas/MandateData" - } - ], - "nullable": true - }, - "setup_future_usage": { + "order_tax_amount": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "off_session": { - "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with confirm=true.", - "example": true, - "nullable": true - }, - "capture_on": { + "connector_mandate_id": { "type": "string", - "format": "date-time", - "description": "A timestamp (ISO 8601 code) that determines when the payment should be captured.\nProviding this field will automatically set `capture` to true", - "example": "2022-09-10T10:11:12Z", - "nullable": true - }, - "capture_method": { - "allOf": [ - { - "$ref": "#/components/schemas/CaptureMethod" - } - ], + "description": "Connector Identifier for the payment method", "nullable": true + } + } + }, + "PaymentsDynamicTaxCalculationRequest": { + "type": "object", + "required": [ + "shipping", + "client_secret", + "payment_method_type" + ], + "properties": { + "shipping": { + "$ref": "#/components/schemas/Address" }, - "payment_method": { - "$ref": "#/components/schemas/PaymentMethod" + "client_secret": { + "type": "string", + "description": "Client Secret" }, - "payment_method_data": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" - } - ], - "nullable": true + "payment_method_type": { + "$ref": "#/components/schemas/PaymentMethodType" }, - "payment_token": { + "session_id": { "type": "string", - "description": "Provide a reference to a stored payment method", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", + "description": "Session Id", "nullable": true + } + } + }, + "PaymentsDynamicTaxCalculationResponse": { + "type": "object", + "required": [ + "payment_id", + "net_amount", + "display_amount" + ], + "properties": { + "payment_id": { + "type": "string", + "description": "The identifier for the payment" }, - "shipping": { + "net_amount": { + "$ref": "#/components/schemas/MinorUnit" + }, + "order_tax_amount": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "billing": { + "shipping_cost": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Information about the product , quantity and amount for connectors. (e.g. Klarna)", - "example": "[{\n \"product_name\": \"gillete creme\",\n \"quantity\": 15,\n \"amount\" : 900\n }]", - "nullable": true - }, - "email": { - "type": "string", - "description": "description: The customer's email address\nThis field will be deprecated soon. Please refer to `customer.email` object", - "deprecated": true, - "example": "johntest@test.com", - "nullable": true, - "maxLength": 255 - }, - "name": { - "type": "string", - "description": "description: The customer's name\nThis field will be deprecated soon. Please refer to `customer.name` object", - "deprecated": true, - "example": "John Test", - "nullable": true, - "maxLength": 255 - }, - "phone": { - "type": "string", - "description": "The customer's phone number\nThis field will be deprecated soon. Please refer to `customer.phone` object", - "deprecated": true, - "example": "9123456789", - "nullable": true, - "maxLength": 255 - }, - "return_url": { + "display_amount": { + "$ref": "#/components/schemas/DisplayAmountOnSdk" + } + } + }, + "PaymentsExternalAuthenticationRequest": { + "type": "object", + "required": [ + "client_secret", + "device_channel", + "threeds_method_comp_ind" + ], + "properties": { + "client_secret": { "type": "string", - "description": "The URL to redirect after the completion of the operation", - "example": "https://hyperswitch.io", - "nullable": true + "description": "Client Secret" }, - "authentication_type": { + "sdk_information": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/SdkInformation" } ], - "default": "three_ds", "nullable": true }, - "statement_descriptor_name": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 255 - }, - "statement_descriptor_suffix": { - "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 255 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", - "nullable": true, - "maxLength": 255 + "device_channel": { + "$ref": "#/components/schemas/DeviceChannel" }, - "next_action": { - "allOf": [ - { - "$ref": "#/components/schemas/NextActionData" - } - ], - "nullable": true + "threeds_method_comp_ind": { + "$ref": "#/components/schemas/ThreeDsCompletionIndicator" + } + } + }, + "PaymentsExternalAuthenticationResponse": { + "type": "object", + "required": [ + "trans_status", + "three_ds_requestor_url" + ], + "properties": { + "trans_status": { + "$ref": "#/components/schemas/TransactionStatus" }, - "cancellation_reason": { + "acs_url": { "type": "string", - "description": "If the payment was cancelled the reason will be provided here", + "description": "Access Server URL to be used for challenge submission", "nullable": true }, - "error_code": { + "challenge_request": { "type": "string", - "description": "If there was an error while calling the connectors the code is received here", - "example": "E0001", + "description": "Challenge request which should be sent to acs_url", "nullable": true }, - "error_message": { + "acs_reference_number": { "type": "string", - "description": "If there was an error while calling the connector the error message is received here", - "example": "Failed while verifying the card", + "description": "Unique identifier assigned by the EMVCo(Europay, Mastercard and Visa)", "nullable": true }, - "unified_code": { + "acs_trans_id": { "type": "string", - "description": "error code unified across the connectors is received here if there was an error while calling connector", + "description": "Unique identifier assigned by the ACS to identify a single transaction", "nullable": true }, - "unified_message": { + "three_dsserver_trans_id": { "type": "string", - "description": "error message unified across the connectors is received here if there was an error while calling connector", - "nullable": true - }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], - "nullable": true - }, - "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], + "description": "Unique identifier assigned by the 3DS Server to identify a single transaction", "nullable": true }, - "connector_label": { + "acs_signed_content": { "type": "string", - "description": "The connector used for this payment along with the country and business details", - "example": "stripe_US_food", - "nullable": true - }, - "business_country": { - "allOf": [ - { - "$ref": "#/components/schemas/CountryAlpha2" - } - ], + "description": "Contains the JWS object created by the ACS for the ARes(Authentication Response) message", "nullable": true }, - "business_label": { + "three_ds_requestor_url": { "type": "string", - "description": "The business label of merchant for this payment", - "nullable": true + "description": "Three DS Requestor URL" + } + } + }, + "PaymentsIncrementalAuthorizationRequest": { + "type": "object", + "required": [ + "amount" + ], + "properties": { + "amount": { + "type": "integer", + "format": "int64", + "description": "The total amount including previously authorized amount and additional amount", + "example": 6540 }, - "business_sub_label": { + "reason": { "type": "string", - "description": "The business_sub_label for this payment", + "description": "Reason for incremental authorization", "nullable": true + } + } + }, + "PaymentsResponse": { + "type": "object", + "required": [ + "payment_id", + "merchant_id", + "status", + "amount", + "net_amount", + "amount_capturable", + "currency", + "payment_method", + "attempt_count" + ], + "properties": { + "payment_id": { + "type": "string", + "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant.", + "example": "pay_mbabizu24mvu3mela5njyhpit4", + "maxLength": 30, + "minLength": 30 }, - "allowed_payment_method_types": { - "type": "array", - "items": { - "$ref": "#/components/schemas/PaymentMethodType" - }, - "description": "Allowed Payment Method Types for a given PaymentIntent", - "nullable": true + "merchant_id": { + "type": "string", + "description": "This is an identifier for the merchant account. This is inferred from the API key\nprovided during the request", + "example": "merchant_1668273825", + "maxLength": 255 }, - "ephemeral_key": { + "status": { "allOf": [ { - "$ref": "#/components/schemas/EphemeralKeyCreateResponse" + "$ref": "#/components/schemas/IntentStatus" } ], - "nullable": true + "default": "requires_confirmation" }, - "manual_retry_allowed": { - "type": "boolean", - "description": "If true the payment can be retried with same or different payment method which means the confirm call can be made again.", - "nullable": true + "amount": { + "type": "integer", + "format": "int64", + "description": "The payment amount. Amount for the payment in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc.,", + "example": 6540 }, - "connector_transaction_id": { - "type": "string", - "description": "A unique identifier for a payment provided by the connector", - "example": "993672945374576J", - "nullable": true + "net_amount": { + "type": "integer", + "format": "int64", + "description": "The payment net amount. net_amount = amount + surcharge_details.surcharge_amount + surcharge_details.tax_amount + shipping_cost + order_tax_amount,\nIf no surcharge_details, shipping_cost, order_tax_amount, net_amount = amount", + "example": 6540 }, - "frm_message": { - "allOf": [ - { - "$ref": "#/components/schemas/FrmMessage" - } - ], + "shipping_cost": { + "type": "integer", + "format": "int64", + "description": "The shipping cost for the payment.", + "example": 6540, "nullable": true }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", - "nullable": true + "amount_capturable": { + "type": "integer", + "format": "int64", + "description": "The maximum amount that could be captured from the payment", + "example": 6540, + "minimum": 100 }, - "connector_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/ConnectorMetadata" - } - ], + "amount_received": { + "type": "integer", + "format": "int64", + "description": "The amount which is already captured from the payment, this helps in the cases where merchants can't capture all capturable amount at once.", + "example": 6540, "nullable": true }, - "feature_metadata": { - "allOf": [ - { - "$ref": "#/components/schemas/FeatureMetadata" - } - ], + "connector": { + "type": "string", + "description": "The connector used for the payment", + "example": "stripe", "nullable": true }, - "reference_id": { + "client_secret": { "type": "string", - "description": "reference(Identifier) to the payment at connector side", - "example": "993672945374576J", + "description": "It's a token used for client side verification.", + "example": "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo", "nullable": true }, - "payment_link": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentLinkResponse" - } - ], + "created": { + "type": "string", + "format": "date-time", + "description": "Time when the payment was created", + "example": "2022-09-10T10:11:12Z", "nullable": true }, - "profile_id": { + "currency": { + "$ref": "#/components/schemas/Currency" + }, + "customer_id": { "type": "string", - "description": "The business profile that is associated with this payment", - "nullable": true + "description": "The identifier for the customer object. If not provided the customer ID will be autogenerated.\nThis field will be deprecated soon. Please refer to `customer.id`", + "deprecated": true, + "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", + "nullable": true, + "maxLength": 64, + "minLength": 1 }, - "surcharge_details": { + "customer": { "allOf": [ { - "$ref": "#/components/schemas/RequestSurchargeDetails" + "$ref": "#/components/schemas/CustomerDetailsResponse" } ], "nullable": true }, - "attempt_count": { - "type": "integer", - "format": "int32", - "description": "Total number of attempts associated with this payment" - }, - "merchant_decision": { + "description": { "type": "string", - "description": "Denotes the action(approve or reject) taken by merchant in case of manual review. Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment", + "description": "A description of the payment", + "example": "It's my first payment request", "nullable": true }, - "merchant_connector_id": { - "type": "string", - "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", + "refunds": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RefundResponse" + }, + "description": "List of refunds that happened on this intent, as same payment intent can have multiple refund requests depending on the nature of order", "nullable": true }, - "incremental_authorization_allowed": { - "type": "boolean", - "description": "If true, incremental authorization can be performed on this payment, in case the funds authorized initially fall short.", + "disputes": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DisputeResponsePaymentsRetrieve" + }, + "description": "List of disputes that happened on this intent", "nullable": true }, - "authorization_count": { - "type": "integer", - "format": "int32", - "description": "Total number of authorizations happened in an incremental_authorization payment", + "attempts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentAttemptResponse" + }, + "description": "List of attempts that happened on this intent", "nullable": true }, - "incremental_authorizations": { + "captures": { "type": "array", "items": { - "$ref": "#/components/schemas/IncrementalAuthorizationResponse" + "$ref": "#/components/schemas/CaptureResponse" }, - "description": "List of incremental authorizations happened to the payment", + "description": "List of captures done on latest attempt", "nullable": true }, - "external_authentication_details": { + "mandate_id": { + "type": "string", + "description": "A unique identifier to link the payment to a mandate, can be used instead of payment_method_data, in case of setting up recurring payments", + "example": "mandate_iwer89rnjef349dni3", + "nullable": true, + "maxLength": 255 + }, + "mandate_data": { "allOf": [ { - "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" + "$ref": "#/components/schemas/MandateData" } ], "nullable": true }, - "external_3ds_authentication_attempted": { + "setup_future_usage": { + "allOf": [ + { + "$ref": "#/components/schemas/FutureUsage" + } + ], + "nullable": true + }, + "off_session": { "type": "boolean", - "description": "Flag indicating if external 3ds authentication is made or not", + "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. This parameter can only be used with confirm=true.", + "example": true, "nullable": true }, - "expires_on": { + "capture_on": { "type": "string", "format": "date-time", - "description": "Date Time for expiry of the payment", + "description": "A timestamp (ISO 8601 code) that determines when the payment should be captured.\nProviding this field will automatically set `capture` to true", "example": "2022-09-10T10:11:12Z", "nullable": true }, - "fingerprint": { - "type": "string", - "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", - "nullable": true - }, - "browser_info": { + "capture_method": { "allOf": [ { - "$ref": "#/components/schemas/BrowserInformation" + "$ref": "#/components/schemas/CaptureMethod" } ], "nullable": true }, - "payment_method_id": { - "type": "string", - "description": "Identifier for Payment Method used for the payment", - "nullable": true + "payment_method": { + "$ref": "#/components/schemas/PaymentMethod" }, - "payment_method_status": { + "payment_method_data": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodStatus" + "$ref": "#/components/schemas/PaymentMethodDataResponseWithBilling" } ], "nullable": true }, - "updated": { - "type": "string", - "format": "date-time", - "description": "Date time at which payment was updated", - "example": "2022-09-10T10:11:12Z", + "payment_token": { + "type": "string", + "description": "Provide a reference to a stored payment method", + "example": "187282ab-40ef-47a9-9206-5099ba31e432", "nullable": true }, - "charges": { + "shipping": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeResponse" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "frm_metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.", - "nullable": true - }, - "merchant_order_reference_id": { - "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 - }, - "order_tax_amount": { + "billing": { "allOf": [ { - "$ref": "#/components/schemas/MinorUnit" + "$ref": "#/components/schemas/Address" } ], "nullable": true }, - "connector_mandate_id": { - "type": "string", - "description": "Connector Identifier for the payment method", + "order_details": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OrderDetailsWithAmount" + }, + "description": "Information about the product , quantity and amount for connectors. (e.g. Klarna)", + "example": "[{\n \"product_name\": \"gillete creme\",\n \"quantity\": 15,\n \"amount\" : 900\n }]", "nullable": true - } - } - }, - "PaymentsRetrieveRequest": { - "type": "object", - "required": [ - "resource_id", - "force_sync" - ], - "properties": { - "resource_id": { - "type": "string", - "description": "The type of ID (ex: payment intent id, payment attempt id or connector txn id)" }, - "merchant_id": { + "email": { "type": "string", - "description": "The identifier for the Merchant Account.", - "nullable": true + "description": "description: The customer's email address\nThis field will be deprecated soon. Please refer to `customer.email` object", + "deprecated": true, + "example": "johntest@test.com", + "nullable": true, + "maxLength": 255 }, - "force_sync": { - "type": "boolean", - "description": "Decider to enable or disable the connector call for retrieve request" + "name": { + "type": "string", + "description": "description: The customer's name\nThis field will be deprecated soon. Please refer to `customer.name` object", + "deprecated": true, + "example": "John Test", + "nullable": true, + "maxLength": 255 }, - "param": { + "phone": { "type": "string", - "description": "The parameters passed to a retrieve request", - "nullable": true + "description": "The customer's phone number\nThis field will be deprecated soon. Please refer to `customer.phone` object", + "deprecated": true, + "example": "9123456789", + "nullable": true, + "maxLength": 255 }, - "connector": { + "return_url": { "type": "string", - "description": "The name of the connector", + "description": "The URL to redirect after the completion of the operation", + "example": "https://hyperswitch.io", "nullable": true }, - "merchant_connector_details": { + "authentication_type": { "allOf": [ { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" + "$ref": "#/components/schemas/AuthenticationType" } ], + "default": "three_ds", "nullable": true }, - "client_secret": { - "type": "string", - "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK", - "nullable": true - }, - "expand_captures": { - "type": "boolean", - "description": "If enabled provides list of captures linked to latest attempt", - "nullable": true - }, - "expand_attempts": { - "type": "boolean", - "description": "If enabled provides list of attempts linked to payment intent", - "nullable": true - } - } - }, - "PaymentsSessionRequest": { - "type": "object" - }, - "PaymentsSessionResponse": { - "type": "object", - "required": [ - "payment_id", - "client_secret", - "session_token" - ], - "properties": { - "payment_id": { + "statement_descriptor_name": { "type": "string", - "description": "The identifier for the payment" + "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", + "example": "Hyperswitch Router", + "nullable": true, + "maxLength": 255 }, - "client_secret": { + "statement_descriptor_suffix": { "type": "string", - "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK" - }, - "session_token": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SessionToken" - }, - "description": "The list of session token object" - } - } - }, - "PaymentsUpdateRequest": { - "type": "object", - "properties": { - "amount": { - "type": "integer", - "format": "int64", - "description": "The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies)", - "example": 6540, + "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 255 characters for the concatenated descriptor.", + "example": "Payment for shoes purchase", "nullable": true, - "minimum": 0 + "maxLength": 255 }, - "currency": { + "next_action": { "allOf": [ { - "$ref": "#/components/schemas/Currency" + "$ref": "#/components/schemas/NextActionData" } ], "nullable": true }, - "amount_to_capture": { - "type": "integer", - "format": "int64", - "description": "The Amount to be captured / debited from the users payment method. It shall be in lowest denomination of the currency. (i.e) in cents for USD denomination, in paisa for INR denomination etc., If not provided, the default amount_to_capture will be the payment amount. Also, it must be less than or equal to the original payment account.", - "example": 6540, + "cancellation_reason": { + "type": "string", + "description": "If the payment was cancelled the reason will be provided here", "nullable": true }, - "shipping_cost": { - "type": "integer", - "format": "int64", - "description": "The shipping cost for the payment. This is required for tax calculation in some regions.", - "example": 6540, + "error_code": { + "type": "string", + "description": "If there was an error while calling the connectors the code is received here", + "example": "E0001", "nullable": true }, - "payment_id": { + "error_message": { "type": "string", - "description": "Unique identifier for the payment. This ensures idempotency for multiple payments\nthat have been done by a single merchant. The value for this field can be specified in the request, it will be auto generated otherwise and returned in the API response.", - "example": "pay_mbabizu24mvu3mela5njyhpit4", - "nullable": true, - "maxLength": 30, - "minLength": 30 + "description": "If there was an error while calling the connector the error message is received here", + "example": "Failed while verifying the card", + "nullable": true }, - "routing": { - "allOf": [ - { - "$ref": "#/components/schemas/StraightThroughAlgorithm" - } - ], + "unified_code": { + "type": "string", + "description": "error code unified across the connectors is received here if there was an error while calling connector", "nullable": true }, - "connector": { - "type": "array", - "items": { - "$ref": "#/components/schemas/Connector" - }, - "description": "This allows to manually select a connector with which the payment can go through.", - "example": [ - "stripe", - "adyen" - ], + "unified_message": { + "type": "string", + "description": "error message unified across the connectors is received here if there was an error while calling connector", "nullable": true }, - "capture_method": { + "payment_experience": { "allOf": [ { - "$ref": "#/components/schemas/CaptureMethod" + "$ref": "#/components/schemas/PaymentExperience" } ], "nullable": true }, - "authentication_type": { + "payment_method_type": { "allOf": [ { - "$ref": "#/components/schemas/AuthenticationType" + "$ref": "#/components/schemas/PaymentMethodType" } ], - "default": "three_ds", "nullable": true }, - "billing": { + "connector_label": { + "type": "string", + "description": "The connector used for this payment along with the country and business details", + "example": "stripe_US_food", + "nullable": true + }, + "business_country": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/CountryAlpha2" } ], "nullable": true }, - "confirm": { - "type": "boolean", - "description": "Whether to confirm the payment (if applicable). It can be used to completely process a payment by attaching a payment method, setting `confirm=true` and `capture_method = automatic` in the *Payments/Create API* request itself.", - "default": false, - "example": true, + "business_label": { + "type": "string", + "description": "The business label of merchant for this payment", "nullable": true }, - "customer": { + "business_sub_label": { + "type": "string", + "description": "The business_sub_label for this payment", + "nullable": true + }, + "allowed_payment_method_types": { + "type": "array", + "items": { + "$ref": "#/components/schemas/PaymentMethodType" + }, + "description": "Allowed Payment Method Types for a given PaymentIntent", + "nullable": true + }, + "ephemeral_key": { "allOf": [ { - "$ref": "#/components/schemas/CustomerDetails" + "$ref": "#/components/schemas/EphemeralKeyCreateResponse" } ], "nullable": true }, - "customer_id": { - "type": "string", - "description": "The identifier for the customer", - "example": "cus_y3oqhf46pyzuxjbcn2giaqnb44", - "nullable": true, - "maxLength": 64, - "minLength": 1 - }, - "off_session": { + "manual_retry_allowed": { "type": "boolean", - "description": "Set to true to indicate that the customer is not in your checkout flow during this payment, and therefore is unable to authenticate. This parameter is intended for scenarios where you collect card details and charge them later. When making a recurring payment by passing a mandate_id, this parameter is mandatory", - "example": true, - "nullable": true - }, - "description": { - "type": "string", - "description": "A description for the payment", - "example": "It's my first payment request", + "description": "If true the payment can be retried with same or different payment method which means the confirm call can be made again.", "nullable": true }, - "return_url": { + "connector_transaction_id": { "type": "string", - "description": "The URL to which you want the user to be redirected after the completion of the payment operation", - "example": "https://hyperswitch.io", + "description": "A unique identifier for a payment provided by the connector", + "example": "993672945374576J", "nullable": true }, - "setup_future_usage": { + "frm_message": { "allOf": [ { - "$ref": "#/components/schemas/FutureUsage" + "$ref": "#/components/schemas/FrmMessage" } ], "nullable": true }, - "payment_method_data": { + "metadata": { + "type": "object", + "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", + "nullable": true + }, + "connector_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethodDataRequest" + "$ref": "#/components/schemas/ConnectorMetadata" } ], "nullable": true }, - "payment_method": { + "feature_metadata": { "allOf": [ { - "$ref": "#/components/schemas/PaymentMethod" + "$ref": "#/components/schemas/FeatureMetadata" } ], "nullable": true }, - "payment_token": { + "reference_id": { "type": "string", - "description": "As Hyperswitch tokenises the sensitive details about the payments method, it provides the payment_token as a reference to a stored payment method, ensuring that the sensitive details are not exposed in any manner.", - "example": "187282ab-40ef-47a9-9206-5099ba31e432", + "description": "reference(Identifier) to the payment at connector side", + "example": "993672945374576J", "nullable": true }, - "shipping": { + "payment_link": { "allOf": [ { - "$ref": "#/components/schemas/Address" + "$ref": "#/components/schemas/PaymentLinkResponse" } ], "nullable": true }, - "statement_descriptor_name": { - "type": "string", - "description": "For non-card charges, you can use this value as the complete description that appears on your customers’ statements. Must contain at least one letter, maximum 22 characters.", - "example": "Hyperswitch Router", - "nullable": true, - "maxLength": 255 - }, - "statement_descriptor_suffix": { + "profile_id": { "type": "string", - "description": "Provides information about a card payment that customers see on their statements. Concatenated with the prefix (shortened descriptor) or statement descriptor that’s set on the account to form the complete statement descriptor. Maximum 22 characters for the concatenated descriptor.", - "example": "Payment for shoes purchase", - "nullable": true, - "maxLength": 255 - }, - "order_details": { - "type": "array", - "items": { - "$ref": "#/components/schemas/OrderDetailsWithAmount" - }, - "description": "Use this object to capture the details about the different products for which the payment is being made. The sum of amount across different products here should be equal to the overall payment amount", - "example": "[{\n \"product_name\": \"Apple iPhone 16\",\n \"quantity\": 1,\n \"amount\" : 69000\n \"product_img_link\" : \"https://dummy-img-link.com\"\n }]", + "description": "The business profile that is associated with this payment", "nullable": true }, - "mandate_data": { + "surcharge_details": { "allOf": [ { - "$ref": "#/components/schemas/MandateData" + "$ref": "#/components/schemas/RequestSurchargeDetails" } ], "nullable": true }, - "customer_acceptance": { - "allOf": [ - { - "$ref": "#/components/schemas/CustomerAcceptance" - } - ], - "nullable": true + "attempt_count": { + "type": "integer", + "format": "int32", + "description": "Total number of attempts associated with this payment" }, - "browser_info": { - "allOf": [ - { - "$ref": "#/components/schemas/BrowserInformation" - } - ], + "merchant_decision": { + "type": "string", + "description": "Denotes the action(approve or reject) taken by merchant in case of manual review. Manual review can occur when the transaction is marked as risky by the frm_processor, payment processor or when there is underpayment/over payment incase of crypto payment", "nullable": true }, - "payment_experience": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentExperience" - } - ], + "merchant_connector_id": { + "type": "string", + "description": "Identifier of the connector ( merchant connector account ) which was chosen to make the payment", "nullable": true }, - "payment_method_type": { - "allOf": [ - { - "$ref": "#/components/schemas/PaymentMethodType" - } - ], + "incremental_authorization_allowed": { + "type": "boolean", + "description": "If true, incremental authorization can be performed on this payment, in case the funds authorized initially fall short.", "nullable": true }, - "merchant_connector_details": { - "allOf": [ - { - "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" - } - ], + "authorization_count": { + "type": "integer", + "format": "int32", + "description": "Total number of authorizations happened in an incremental_authorization payment", "nullable": true }, - "allowed_payment_method_types": { + "incremental_authorizations": { "type": "array", "items": { - "$ref": "#/components/schemas/PaymentMethodType" + "$ref": "#/components/schemas/IncrementalAuthorizationResponse" }, - "description": "Use this parameter to restrict the Payment Method Types to show for a given PaymentIntent", + "description": "List of incremental authorizations happened to the payment", "nullable": true }, - "retry_action": { + "external_authentication_details": { "allOf": [ { - "$ref": "#/components/schemas/RetryAction" + "$ref": "#/components/schemas/ExternalAuthenticationDetailsResponse" } ], "nullable": true }, - "metadata": { - "type": "object", - "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. Metadata is useful for storing additional, structured information on an object.", + "external_3ds_authentication_attempted": { + "type": "boolean", + "description": "Flag indicating if external 3ds authentication is made or not", "nullable": true }, - "connector_metadata": { + "expires_on": { + "type": "string", + "format": "date-time", + "description": "Date Time for expiry of the payment", + "example": "2022-09-10T10:11:12Z", + "nullable": true + }, + "fingerprint": { + "type": "string", + "description": "Payment Fingerprint, to identify a particular card.\nIt is a 20 character long alphanumeric code.", + "nullable": true + }, + "browser_info": { "allOf": [ { - "$ref": "#/components/schemas/ConnectorMetadata" + "$ref": "#/components/schemas/BrowserInformation" } ], "nullable": true }, - "payment_link": { - "type": "boolean", - "description": "Whether to generate the payment link for this payment or not (if applicable)", - "default": false, - "example": true, + "payment_method_id": { + "type": "string", + "description": "Identifier for Payment Method used for the payment", "nullable": true }, - "payment_link_config": { + "payment_method_status": { "allOf": [ { - "$ref": "#/components/schemas/PaymentCreatePaymentLinkConfig" + "$ref": "#/components/schemas/PaymentMethodStatus" } ], "nullable": true }, - "payment_link_config_id": { + "updated": { "type": "string", - "description": "Custom payment link config id set at business profile, send only if business_specific_configs is configured", + "format": "date-time", + "description": "Date time at which payment was updated", + "example": "2022-09-10T10:11:12Z", "nullable": true }, - "surcharge_details": { + "charges": { "allOf": [ { - "$ref": "#/components/schemas/RequestSurchargeDetails" + "$ref": "#/components/schemas/PaymentChargeResponse" } ], "nullable": true }, - "payment_type": { + "frm_metadata": { + "type": "object", + "description": "You can specify up to 50 keys, with key names up to 40 characters long and values up to 500 characters long. FRM Metadata is useful for storing additional, structured information on an object related to FRM.", + "nullable": true + }, + "merchant_order_reference_id": { + "type": "string", + "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", + "example": "Custom_Order_id_123", + "nullable": true, + "maxLength": 255 + }, + "order_tax_amount": { "allOf": [ { - "$ref": "#/components/schemas/PaymentType" + "$ref": "#/components/schemas/MinorUnit" } ], "nullable": true }, - "request_incremental_authorization": { - "type": "boolean", - "description": "Request an incremental authorization, i.e., increase the authorized amount on a confirmed payment before you capture it.", + "connector_mandate_id": { + "type": "string", + "description": "Connector Identifier for the payment method", "nullable": true + } + } + }, + "PaymentsRetrieveRequest": { + "type": "object", + "required": [ + "resource_id", + "force_sync" + ], + "properties": { + "resource_id": { + "type": "string", + "description": "The type of ID (ex: payment intent id, payment attempt id or connector txn id)" }, - "session_expiry": { - "type": "integer", - "format": "int32", - "description": "Will be used to expire client secret after certain amount of time to be supplied in seconds\n(900) for 15 mins", - "example": 900, - "nullable": true, - "minimum": 0 - }, - "frm_metadata": { - "type": "object", - "description": "Additional data related to some frm(Fraud Risk Management) connectors", + "merchant_id": { + "type": "string", + "description": "The identifier for the Merchant Account.", "nullable": true }, - "request_external_three_ds_authentication": { + "force_sync": { "type": "boolean", - "description": "Whether to perform external authentication (if applicable)", - "example": true, + "description": "Decider to enable or disable the connector call for retrieve request" + }, + "param": { + "type": "string", + "description": "The parameters passed to a retrieve request", "nullable": true }, - "recurring_details": { - "allOf": [ - { - "$ref": "#/components/schemas/RecurringDetails" - } - ], + "connector": { + "type": "string", + "description": "The name of the connector", "nullable": true }, - "charges": { + "merchant_connector_details": { "allOf": [ { - "$ref": "#/components/schemas/PaymentChargeRequest" + "$ref": "#/components/schemas/MerchantConnectorDetailsWrap" } ], "nullable": true }, - "merchant_order_reference_id": { + "client_secret": { "type": "string", - "description": "Merchant's identifier for the payment/invoice. This will be sent to the connector\nif the connector provides support to accept multiple reference ids.\nIn case the connector supports only one reference id, Hyperswitch's Payment ID will be sent as reference.", - "example": "Custom_Order_id_123", - "nullable": true, - "maxLength": 255 + "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK", + "nullable": true }, - "skip_external_tax_calculation": { + "expand_captures": { + "type": "boolean", + "description": "If enabled provides list of captures linked to latest attempt", + "nullable": true + }, + "expand_attempts": { "type": "boolean", - "description": "Whether to calculate tax for this payment intent", + "description": "If enabled provides list of attempts linked to payment intent", "nullable": true } } }, + "PaymentsSessionRequest": { + "type": "object" + }, + "PaymentsSessionResponse": { + "type": "object", + "required": [ + "payment_id", + "client_secret", + "session_token" + ], + "properties": { + "payment_id": { + "type": "string", + "description": "The identifier for the payment" + }, + "client_secret": { + "type": "string", + "description": "This is a token which expires after 15 minutes, used from the client to authenticate and create sessions from the SDK" + }, + "session_token": { + "type": "array", + "items": { + "$ref": "#/components/schemas/SessionToken" + }, + "description": "The list of session token object" + } + } + }, "PayoutActionRequest": { "type": "object" }, diff --git a/crates/analytics/Cargo.toml b/crates/analytics/Cargo.toml index 687d5a2e208..6cf886896c3 100644 --- a/crates/analytics/Cargo.toml +++ b/crates/analytics/Cargo.toml @@ -7,8 +7,8 @@ rust-version.workspace = true license.workspace = true [features] -v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1"] -v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2"] +v1 = ["api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "common_utils/v1"] +v2 = ["api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "common_utils/v2"] [dependencies] # First party crates diff --git a/crates/api_models/src/events/payment.rs b/crates/api_models/src/events/payment.rs index 7bbff94d453..000343864b2 100644 --- a/crates/api_models/src/events/payment.rs +++ b/crates/api_models/src/events/payment.rs @@ -1,9 +1,9 @@ use common_utils::events::{ApiEventMetric, ApiEventsType}; #[cfg(feature = "v2")] -use super::PaymentsCreateIntentRequest; -#[cfg(feature = "v2")] -use super::PaymentsCreateIntentResponse; +use super::{ + PaymentsConfirmIntentResponse, PaymentsCreateIntentRequest, PaymentsCreateIntentResponse, +}; #[cfg(all( any(feature = "v2", feature = "v1"), not(feature = "payment_methods_v2") @@ -20,7 +20,7 @@ use crate::{ PaymentMethodResponse, PaymentMethodUpdate, }, payments::{ - ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints, + self, ExtendedCardInfoResponse, PaymentIdType, PaymentListConstraints, PaymentListFilterConstraints, PaymentListFilters, PaymentListFiltersV2, PaymentListResponse, PaymentListResponseV2, PaymentsAggregateResponse, PaymentsApproveRequest, PaymentsCancelRequest, PaymentsCaptureRequest, @@ -29,8 +29,8 @@ use crate::{ PaymentsExternalAuthenticationResponse, PaymentsIncrementalAuthorizationRequest, PaymentsManualUpdateRequest, PaymentsManualUpdateResponse, PaymentsPostSessionTokensRequest, PaymentsPostSessionTokensResponse, PaymentsRejectRequest, - PaymentsRequest, PaymentsResponse, PaymentsRetrieveRequest, PaymentsSessionResponse, - PaymentsStartRequest, RedirectionResponse, + PaymentsResponse, PaymentsRetrieveRequest, PaymentsSessionResponse, PaymentsStartRequest, + RedirectionResponse, }, }; @@ -131,7 +131,7 @@ impl ApiEventMetric for PaymentsRejectRequest { } #[cfg(feature = "v1")] -impl ApiEventMetric for PaymentsRequest { +impl ApiEventMetric for payments::PaymentsRequest { fn get_api_event_type(&self) -> Option { match self.payment_id { Some(PaymentIdType::PaymentIntentId(ref id)) => Some(ApiEventsType::Payment { @@ -158,6 +158,15 @@ impl ApiEventMetric for PaymentsCreateIntentResponse { } } +#[cfg(feature = "v2")] +impl ApiEventMetric for PaymentsConfirmIntentResponse { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Payment { + payment_id: self.id.clone(), + }) + } +} + #[cfg(feature = "v1")] impl ApiEventMetric for PaymentsResponse { fn get_api_event_type(&self) -> Option { diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index fd1286a555e..fd8419e7f97 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -5,8 +5,6 @@ use std::{ }; pub mod additional_info; use cards::CardNumber; -#[cfg(feature = "v2")] -use common_utils::id_type::GlobalPaymentId; use common_utils::{ consts::default_payments_list_limit, crypto, @@ -117,7 +115,8 @@ pub struct CustomerDetailsResponse { pub phone_country_code: Option, } -#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +// Serialize is required because the api event requires Serialize to be implemented +#[derive(Debug, serde::Serialize, serde::Deserialize, Clone, ToSchema)] #[serde(deny_unknown_fields)] #[cfg(feature = "v2")] pub struct PaymentsCreateIntentRequest { @@ -288,16 +287,16 @@ impl PaymentsCreateIntentRequest { } } -#[derive(Debug, serde::Deserialize, serde::Serialize, Clone, ToSchema)] +#[derive(Debug, serde::Serialize, Clone, ToSchema)] #[serde(deny_unknown_fields)] #[cfg(feature = "v2")] pub struct PaymentsCreateIntentResponse { /// Global Payment Id for the payment #[schema(value_type = String)] - pub id: GlobalPaymentId, + pub id: id_type::GlobalPaymentId, /// The amount details for the payment - pub amount_details: AmountDetails, + pub amount_details: AmountDetailsResponse, /// It's a token used for client side verification. #[schema(value_type = String, example = "pay_U42c409qyHwOkWo3vK60_secret_el9ksDkiB8hi6j9N78yo")] @@ -448,6 +447,66 @@ pub struct AmountDetailsSetter { pub tax_on_surcharge: Option, } +#[cfg(feature = "v2")] +#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)] +pub struct AmountDetailsResponse { + /// The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies) + #[schema(value_type = u64, example = 6540)] + pub order_amount: MinorUnit, + /// The currency of the order + #[schema(example = "USD", value_type = Currency)] + pub currency: common_enums::Currency, + /// The shipping cost of the order. This has to be collected from the merchant + pub shipping_cost: Option, + /// Tax amount related to the order. This will be calculated by the external tax provider + pub order_tax_amount: Option, + /// The action to whether calculate tax by calling external tax provider or not + #[schema(value_type = TaxCalculationOverride)] + pub skip_external_tax_calculation: common_enums::TaxCalculationOverride, + /// The action to whether calculate surcharge or not + #[schema(value_type = SurchargeCalculationOverride)] + pub skip_surcharge_calculation: common_enums::SurchargeCalculationOverride, + /// The surcharge amount to be added to the order, collected from the merchant + pub surcharge_amount: Option, + /// tax on surcharge amount + pub tax_on_surcharge: Option, +} + +#[cfg(feature = "v2")] +#[derive(Clone, Debug, PartialEq, serde::Serialize, ToSchema)] +pub struct ConfirmIntentAmountDetailsResponse { + /// The payment amount. Amount for the payment in the lowest denomination of the currency, (i.e) in cents for USD denomination, in yen for JPY denomination etc. E.g., Pass 100 to charge $1.00 and 1 for 1¥ since ¥ is a zero-decimal currency. Read more about [the Decimal and Non-Decimal Currencies](https://github.com/juspay/hyperswitch/wiki/Decimal-and-Non%E2%80%90Decimal-Currencies) + #[schema(value_type = u64, example = 6540)] + #[serde(default, deserialize_with = "amount::deserialize")] + pub order_amount: MinorUnit, + /// The currency of the order + #[schema(example = "USD", value_type = Currency)] + pub currency: common_enums::Currency, + /// The shipping cost of the order. This has to be collected from the merchant + pub shipping_cost: Option, + /// Tax amount related to the order. This will be calculated by the external tax provider + pub order_tax_amount: Option, + /// The action to whether calculate tax by calling external tax provider or not + #[schema(value_type = TaxCalculationOverride)] + pub skip_external_tax_calculation: common_enums::TaxCalculationOverride, + /// The action to whether calculate surcharge or not + #[schema(value_type = SurchargeCalculationOverride)] + pub skip_surcharge_calculation: common_enums::SurchargeCalculationOverride, + /// The surcharge amount to be added to the order, collected from the merchant + pub surcharge_amount: Option, + /// tax on surcharge amount + pub tax_on_surcharge: Option, + /// The total amount of the order including tax, surcharge and shipping cost + pub net_amount: MinorUnit, + /// The amount that was requested to be captured for this payment + pub amount_to_capture: Option, + /// The amount that can be captured on the payment. Either in one go or through multiple captures. + /// This is applicable in case the capture method was either `manual` or `manual_multiple` + pub amount_capturable: MinorUnit, + /// The amount that was captured for this payment. This is the sum of all the captures done on this payment + pub amount_captured: Option, +} + #[cfg(feature = "v2")] impl AmountDetails { pub fn new(amount_details_setter: AmountDetailsSetter) -> Self { @@ -488,6 +547,7 @@ impl AmountDetails { } } +#[cfg(feature = "v1")] #[derive( Default, Debug, @@ -787,6 +847,7 @@ pub struct PaymentsRequest { pub skip_external_tax_calculation: Option, } +#[cfg(feature = "v1")] /// Checks if the inner values of two options are equal /// Returns true if values are not equal, returns false in other cases fn are_optional_values_invalid( @@ -799,6 +860,7 @@ fn are_optional_values_invalid( } } +#[cfg(feature = "v1")] impl PaymentsRequest { /// Get the customer id /// @@ -850,8 +912,61 @@ impl PaymentsRequest { None } } + + pub fn get_feature_metadata_as_value( + &self, + ) -> common_utils::errors::CustomResult< + Option, + common_utils::errors::ParsingError, + > { + self.feature_metadata + .as_ref() + .map(Encode::encode_to_value) + .transpose() + } + + pub fn get_connector_metadata_as_value( + &self, + ) -> common_utils::errors::CustomResult< + Option, + common_utils::errors::ParsingError, + > { + self.connector_metadata + .as_ref() + .map(Encode::encode_to_value) + .transpose() + } + + pub fn get_allowed_payment_method_types_as_value( + &self, + ) -> common_utils::errors::CustomResult< + Option, + common_utils::errors::ParsingError, + > { + self.allowed_payment_method_types + .as_ref() + .map(Encode::encode_to_value) + .transpose() + } + + pub fn get_order_details_as_value( + &self, + ) -> common_utils::errors::CustomResult< + Option>, + common_utils::errors::ParsingError, + > { + self.order_details + .as_ref() + .map(|od| { + od.iter() + .map(|order| order.encode_to_value().map(Secret::new)) + .collect::, _>>() + }) + .transpose() + } } +#[cfg(feature = "v1")] #[cfg(test)] mod payments_request_test { use common_utils::generate_customer_id_of_default_length; @@ -936,17 +1051,6 @@ pub struct PaymentChargeRequest { pub transfer_account_id: String, } -impl PaymentsRequest { - pub fn get_total_capturable_amount(&self) -> Option { - let surcharge_amount = self - .surcharge_details - .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) - .unwrap_or_default(); - self.amount - .map(|amount| MinorUnit::from(amount) + surcharge_amount) - } -} - /// Details of surcharge applied on this payment, if applicable #[derive( Default, Debug, Clone, serde::Serialize, serde::Deserialize, Copy, ToSchema, PartialEq, @@ -957,8 +1061,10 @@ pub struct RequestSurchargeDetails { pub tax_amount: Option, } +// for v2 use the type from common_utils::types +#[cfg(feature = "v1")] /// Browser information to be used for 3DS 2.0 -#[derive(ToSchema)] +#[derive(ToSchema, Debug, serde::Deserialize, serde::Serialize)] pub struct BrowserInformation { /// Color depth supported by the browser pub color_depth: Option, @@ -1013,29 +1119,6 @@ impl RequestSurchargeDetails { } } -#[derive(Default, Debug, Clone)] -pub struct HeaderPayload { - pub payment_confirm_source: Option, - pub client_source: Option, - pub client_version: Option, - pub x_hs_latency: Option, - pub browser_name: Option, - pub x_client_platform: Option, - pub x_merchant_domain: Option, - pub locale: Option, - pub x_app_id: Option, - pub x_redirect_uri: Option, -} - -impl HeaderPayload { - pub fn with_source(payment_confirm_source: api_enums::PaymentSource) -> Self { - Self { - payment_confirm_source: Some(payment_confirm_source), - ..Default::default() - } - } -} - #[derive(Debug, serde::Serialize, Clone, PartialEq, ToSchema, router_derive::PolymorphicSchema)] pub struct PaymentAttemptResponse { /// Unique identifier for the attempt @@ -1134,60 +1217,6 @@ pub struct CaptureResponse { pub reference_id: Option, } -impl PaymentsRequest { - pub fn get_feature_metadata_as_value( - &self, - ) -> common_utils::errors::CustomResult< - Option, - common_utils::errors::ParsingError, - > { - self.feature_metadata - .as_ref() - .map(Encode::encode_to_value) - .transpose() - } - - pub fn get_connector_metadata_as_value( - &self, - ) -> common_utils::errors::CustomResult< - Option, - common_utils::errors::ParsingError, - > { - self.connector_metadata - .as_ref() - .map(Encode::encode_to_value) - .transpose() - } - - pub fn get_allowed_payment_method_types_as_value( - &self, - ) -> common_utils::errors::CustomResult< - Option, - common_utils::errors::ParsingError, - > { - self.allowed_payment_method_types - .as_ref() - .map(Encode::encode_to_value) - .transpose() - } - - pub fn get_order_details_as_value( - &self, - ) -> common_utils::errors::CustomResult< - Option>, - common_utils::errors::ParsingError, - > { - self.order_details - .as_ref() - .map(|od| { - od.iter() - .map(|order| order.encode_to_value().map(Secret::new)) - .collect::, _>>() - }) - .transpose() - } -} - #[derive(Default, Debug, serde::Deserialize, serde::Serialize, Clone, Copy, PartialEq, Eq)] pub enum Amount { Value(NonZeroI64), @@ -1781,6 +1810,7 @@ impl GetAddressFromPaymentMethodData for BankDebitData { } } +#[cfg(feature = "v1")] /// Custom serializer and deserializer for PaymentMethodData mod payment_method_data_serde { @@ -1925,6 +1955,9 @@ mod payment_method_data_serde { /// The payment method information provided for making a payment #[derive(Debug, Clone, serde::Deserialize, serde::Serialize, ToSchema, Eq, PartialEq)] pub struct PaymentMethodDataRequest { + /// This field is optional because, in case of saved cards we pass the payment_token + /// There might be cases where we don't need to pass the payment_method_data and pass only payment method billing details + /// We have flattened it because to maintain backwards compatibility with the old API contract #[serde(flatten)] pub payment_method_data: Option, /// billing details for the payment method. @@ -4400,6 +4433,122 @@ pub struct PaymentsResponse { pub connector_mandate_id: Option, } +// Serialize is implemented because, this will be serialized in the api events. +// Usually request types should not have serialize implemented. +// +/// Request for Payment Intent Confirm +#[cfg(feature = "v2")] +#[derive(Debug, serde::Deserialize, serde::Serialize, ToSchema)] +pub struct PaymentsConfirmIntentRequest { + /// The URL to which you want the user to be redirected after the completion of the payment operation + /// If this url is not passed, the url configured in the business profile will be used + #[schema(value_type = Option, example = "https://hyperswitch.io")] + pub return_url: Option, + + /// The payment instrument data to be used for the payment + pub payment_method_data: PaymentMethodDataRequest, + + /// The payment method type to be used for the payment. This should match with the `payment_method_data` provided + #[schema(value_type = PaymentMethod, example = "card")] + pub payment_method_type: api_enums::PaymentMethod, + + /// The payment method subtype to be used for the payment. This should match with the `payment_method_data` provided + #[schema(value_type = PaymentMethodType, example = "apple_pay")] + pub payment_method_subtype: api_enums::PaymentMethodType, + + /// The shipping address for the payment. This will override the shipping address provided in the create-intent request + pub shipping: Option
, + + /// This "CustomerAcceptance" object is passed during Payments-Confirm request, it enlists the type, time, and mode of acceptance properties related to an acceptance done by the customer. The customer_acceptance sub object is usually passed by the SDK or client. + #[schema(value_type = Option)] + pub customer_acceptance: Option, + + /// Additional details required by 3DS 2.0 + #[schema(value_type = Option)] + pub browser_info: Option, +} + +/// Error details for the payment +#[cfg(feature = "v2")] +#[derive(Debug, serde::Serialize, ToSchema)] +pub struct ErrorDetails { + /// The error code + pub code: String, + /// The error message + pub message: String, + /// The unified error code across all connectors. + /// This can be relied upon for taking decisions based on the error. + pub unified_code: Option, + /// The unified error message across all connectors. + /// If there is a translation available, this will have the translated message + pub unified_message: Option, +} + +/// Response for Payment Intent Confirm +#[cfg(feature = "v2")] +#[derive(Debug, serde::Serialize, ToSchema)] +pub struct PaymentsConfirmIntentResponse { + /// Unique identifier for the payment. This ensures idempotency for multiple payments + /// that have been done by a single merchant. + #[schema( + min_length = 32, + max_length = 64, + example = "12345_pay_01926c58bc6e77c09e809964e72af8c8", + value_type = String, + )] + pub id: id_type::GlobalPaymentId, + + #[schema(value_type = IntentStatus, example = "success")] + pub status: api_enums::IntentStatus, + + /// Amount related information for this payment and attempt + pub amount: ConfirmIntentAmountDetailsResponse, + + /// The connector used for the payment + #[schema(example = "stripe")] + pub connector: String, + + /// It's a token used for client side verification. + #[schema(value_type = String)] + pub client_secret: common_utils::types::ClientSecret, + + /// Time when the payment was created + #[schema(example = "2022-09-10T10:11:12Z")] + #[serde(with = "common_utils::custom_serde::iso8601")] + pub created: PrimitiveDateTime, + + /// The payment method information provided for making a payment + #[schema(value_type = Option)] + #[serde(serialize_with = "serialize_payment_method_data_response")] + pub payment_method_data: Option, + + /// The payment method type for this payment attempt + #[schema(value_type = PaymentMethod, example = "wallet")] + pub payment_method_type: api_enums::PaymentMethod, + + #[schema(value_type = PaymentMethodType, example = "apple_pay")] + pub payment_method_subtype: api_enums::PaymentMethodType, + + /// A unique identifier for a payment provided by the connector + #[schema(value_type = Option, example = "993672945374576J")] + pub connector_transaction_id: Option, + + /// reference(Identifier) to the payment at connector side + #[schema(value_type = Option, example = "993672945374576J")] + pub connector_reference_id: Option, + + /// Identifier of the connector ( merchant connector account ) which was chosen to make the payment + #[schema(value_type = String)] + pub merchant_connector_id: id_type::MerchantConnectorAccountId, + + /// The browser information used for this payment + #[schema(value_type = Option)] + pub browser_info: Option, + + /// Error details for the payment if any + pub error: Option, +} + /// Fee information to be charged on the payment being collected #[derive(Setter, Clone, Default, Debug, PartialEq, serde::Serialize, ToSchema)] pub struct PaymentChargeResponse { @@ -4696,6 +4845,7 @@ pub struct MandateValidationFields { pub off_session: Option, } +#[cfg(feature = "v1")] impl From<&PaymentsRequest> for MandateValidationFields { fn from(req: &PaymentsRequest) -> Self { let recurring_details = req @@ -4757,6 +4907,7 @@ impl From for PaymentsSessionResponse { } } +#[cfg(feature = "v1")] impl From for PaymentsRequest { fn from(item: PaymentsStartRequest) -> Self { Self { @@ -6346,6 +6497,7 @@ pub struct ExtendedCardInfoResponse { pub payload: String, } +#[cfg(feature = "v1")] #[cfg(test)] mod payments_request_api_contract { #![allow(clippy::unwrap_used)] diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs index e36a6d74994..3ce9d079c63 100644 --- a/crates/common_enums/src/enums.rs +++ b/crates/common_enums/src/enums.rs @@ -1391,17 +1391,31 @@ pub enum MerchantStorageScheme { #[serde(rename_all = "snake_case")] #[strum(serialize_all = "snake_case")] pub enum IntentStatus { + /// The payment has succeeded. Refunds and disputes can be initiated. + /// Manual retries are not allowed to be performed. Succeeded, + /// The payment has failed. Refunds and disputes cannot be initiated. + /// This payment can be retried manually with a new payment attempt. Failed, + /// This payment has been cancelled. Cancelled, + /// This payment is still being processed by the payment processor. + /// The status update might happen through webhooks or polling with the connector. Processing, + /// The payment is waiting on some action from the customer. RequiresCustomerAction, + /// The payment is waiting on some action from the merchant + /// This would be in case of manual fraud approval RequiresMerchantAction, + /// The payment is waiting to be confirmed with the payment method by the customer. RequiresPaymentMethod, #[default] RequiresConfirmation, + /// The payment has been authorized, and it waiting to be captured. RequiresCapture, + /// The payment has been captured partially. The remaining amount is cannot be captured. PartiallyCaptured, + /// The payment has been captured partially and the remaining amount is capturable PartiallyCapturedAndCapturable, } diff --git a/crates/common_utils/src/events.rs b/crates/common_utils/src/events.rs index 656b2993700..a83c1d481cc 100644 --- a/crates/common_utils/src/events.rs +++ b/crates/common_utils/src/events.rs @@ -105,6 +105,15 @@ impl ApiEventMetric for id_type::PaymentId { } } +#[cfg(feature = "v2")] +impl ApiEventMetric for id_type::GlobalPaymentId { + fn get_api_event_type(&self) -> Option { + Some(ApiEventsType::Payment { + payment_id: self.clone(), + }) + } +} + impl ApiEventMetric for Result { fn get_api_event_type(&self) -> Option { match self { diff --git a/crates/common_utils/src/id_type.rs b/crates/common_utils/src/id_type.rs index 859732aed02..3d57a72376e 100644 --- a/crates/common_utils/src/id_type.rs +++ b/crates/common_utils/src/id_type.rs @@ -27,7 +27,9 @@ use diesel::{ }; #[cfg(feature = "v2")] pub use global_id::{ - payment::GlobalPaymentId, payment_methods::GlobalPaymentMethodId, refunds::GlobalRefundId, + payment::{GlobalAttemptId, GlobalPaymentId}, + payment_methods::GlobalPaymentMethodId, + refunds::GlobalRefundId, CellId, }; pub use merchant::MerchantId; diff --git a/crates/common_utils/src/id_type/global_id.rs b/crates/common_utils/src/id_type/global_id.rs index 0032c531e47..5490dcda7bd 100644 --- a/crates/common_utils/src/id_type/global_id.rs +++ b/crates/common_utils/src/id_type/global_id.rs @@ -1,4 +1,3 @@ -#![allow(unused)] pub mod payment; pub mod payment_methods; pub mod refunds; @@ -24,6 +23,7 @@ pub(crate) struct GlobalId(LengthId) pub(crate) enum GlobalEntity { Customer, Payment, + Attempt, PaymentMethod, Refund, } @@ -34,6 +34,7 @@ impl GlobalEntity { Self::Customer => "cus", Self::Payment => "pay", Self::PaymentMethod => "pm", + Self::Attempt => "att", Self::Refund => "ref", } } diff --git a/crates/common_utils/src/id_type/global_id/payment.rs b/crates/common_utils/src/id_type/global_id/payment.rs index a404c7bc9c4..6e5848e5a38 100644 --- a/crates/common_utils/src/id_type/global_id/payment.rs +++ b/crates/common_utils/src/id_type/global_id/payment.rs @@ -2,22 +2,16 @@ use error_stack::ResultExt; use crate::{errors, generate_id_with_default_len, generate_time_ordered_id_without_prefix, types}; -/// A global id that can be used to identify a payment -#[derive( - Debug, - Clone, - Hash, - PartialEq, - Eq, - serde::Serialize, - serde::Deserialize, - diesel::expression::AsExpression, -)] -#[diesel(sql_type = diesel::sql_types::Text)] -pub struct GlobalPaymentId(super::GlobalId); +crate::global_id_type!( + GlobalPaymentId, + "A global id that can be used to identify a payment + The format will be `__` + example - cell1_pay_uu1a2b3c4d5e6f7g8h9i0j1k2l3m4n5o6p" +); // Database related implementations so that this field can be used directly in the database tables crate::impl_queryable_id_type!(GlobalPaymentId); +crate::impl_to_sql_from_sql_global_id_type!(GlobalPaymentId); impl GlobalPaymentId { /// Get string representation of the id @@ -51,26 +45,24 @@ impl TryFrom> for GlobalPaymentId { } } -// TODO: refactor the macro to include this id use case as well -impl diesel::serialize::ToSql for GlobalPaymentId -where - DB: diesel::backend::Backend, - super::GlobalId: diesel::serialize::ToSql, -{ - fn to_sql<'b>( - &'b self, - out: &mut diesel::serialize::Output<'b, '_, DB>, - ) -> diesel::serialize::Result { - self.0.to_sql(out) +crate::global_id_type!( + GlobalAttemptId, + "A global id that can be used to identify a payment attempt" +); + +// Database related implementations so that this field can be used directly in the database tables +crate::impl_queryable_id_type!(GlobalAttemptId); +crate::impl_to_sql_from_sql_global_id_type!(GlobalAttemptId); + +impl GlobalAttemptId { + /// Generate a new GlobalAttemptId from a cell id + pub fn generate(cell_id: &super::CellId) -> Self { + let global_id = super::GlobalId::generate(cell_id.clone(), super::GlobalEntity::Attempt); + Self(global_id) } -} -impl diesel::deserialize::FromSql for GlobalPaymentId -where - DB: diesel::backend::Backend, - super::GlobalId: diesel::deserialize::FromSql, -{ - fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result { - super::GlobalId::from_sql(value).map(Self) + /// Get string representation of the id + pub fn get_string_repr(&self) -> &str { + self.0.get_string_repr() } } diff --git a/crates/common_utils/src/macros.rs b/crates/common_utils/src/macros.rs index 94d8074c301..21cec6f60fc 100644 --- a/crates/common_utils/src/macros.rs +++ b/crates/common_utils/src/macros.rs @@ -172,6 +172,27 @@ mod id_type { }; } + /// Defines a Global Id type + #[cfg(feature = "v2")] + #[macro_export] + macro_rules! global_id_type { + ($type:ident, $doc:literal) => { + #[doc = $doc] + #[derive( + Debug, + Clone, + Hash, + PartialEq, + Eq, + serde::Serialize, + serde::Deserialize, + diesel::expression::AsExpression, + )] + #[diesel(sql_type = diesel::sql_types::Text)] + pub struct $type($crate::id_type::global_id::GlobalId); + }; + } + /// Implements common methods on the specified ID type. #[macro_export] macro_rules! impl_id_type_methods { @@ -292,6 +313,40 @@ mod id_type { }; } + #[cfg(feature = "v2")] + /// Implements the `ToSql` and `FromSql` traits on the specified Global ID type. + #[macro_export] + macro_rules! impl_to_sql_from_sql_global_id_type { + ($type:ty, $diesel_type:ty) => { + impl diesel::serialize::ToSql<$diesel_type, DB> for $type + where + DB: diesel::backend::Backend, + $crate::id_type::global_id::GlobalId: diesel::serialize::ToSql<$diesel_type, DB>, + { + fn to_sql<'b>( + &'b self, + out: &mut diesel::serialize::Output<'b, '_, DB>, + ) -> diesel::serialize::Result { + self.0.to_sql(out) + } + } + + impl diesel::deserialize::FromSql<$diesel_type, DB> for $type + where + DB: diesel::backend::Backend, + $crate::id_type::global_id::GlobalId: + diesel::deserialize::FromSql<$diesel_type, DB>, + { + fn from_sql(value: DB::RawValue<'_>) -> diesel::deserialize::Result { + $crate::id_type::global_id::GlobalId::from_sql(value).map(Self) + } + } + }; + ($type:ty) => { + $crate::impl_to_sql_from_sql_global_id_type!($type, diesel::sql_types::Text); + }; + } + /// Implements the `Queryable` trait on the specified ID type. #[macro_export] macro_rules! impl_queryable_id_type { diff --git a/crates/common_utils/src/types.rs b/crates/common_utils/src/types.rs index a1c9b4c00c2..2e7977613d6 100644 --- a/crates/common_utils/src/types.rs +++ b/crates/common_utils/src/types.rs @@ -603,6 +603,13 @@ impl StringMajorUnit { /// This domain type can be used for any url pub struct Url(url::Url); +impl Url { + /// Get string representation of the url + pub fn get_string_repr(&self) -> &str { + self.0.as_str() + } +} + impl ToSql for Url where DB: Backend, @@ -667,6 +674,30 @@ mod client_secret_type { } } + impl FromStr for ClientSecret { + type Err = ParsingError; + + fn from_str(str_value: &str) -> Result { + let (payment_id, secret) = + str_value + .rsplit_once("_secret_") + .ok_or(ParsingError::EncodeError( + "Expected a string in the format '{payment_id}_secret_{secret}'", + ))?; + + let payment_id = id_type::GlobalPaymentId::try_from(Cow::Owned(payment_id.to_owned())) + .map_err(|err| { + logger::error!(global_payment_id_error=?err); + ParsingError::EncodeError("Error while constructing GlobalPaymentId") + })?; + + Ok(Self { + payment_id, + secret: masking::Secret::new(secret.to_owned()), + }) + } + } + impl<'de> Deserialize<'de> for ClientSecret { fn deserialize(deserializer: D) -> Result where @@ -1096,6 +1127,12 @@ impl Description { pub fn from_str_unchecked(input_str: &'static str) -> Self { Self(LengthString::new_unchecked(input_str.to_owned())) } + + // TODO: Remove this function in future once description in router data is updated to domain type + /// Get the string representation of the description + pub fn get_string_repr(&self) -> &str { + &self.0 .0 + } } /// Domain type for Statement Descriptor @@ -1273,6 +1310,58 @@ where } } +#[cfg(feature = "v2")] +/// Browser information to be used for 3DS 2.0 +// If any of the field is PII, then we can make them as secret +#[derive( + ToSchema, + Debug, + Clone, + serde::Deserialize, + serde::Serialize, + Eq, + PartialEq, + diesel::AsExpression, +)] +#[diesel(sql_type = Jsonb)] +pub struct BrowserInformation { + /// Color depth supported by the browser + pub color_depth: Option, + + /// Whether java is enabled in the browser + pub java_enabled: Option, + + /// Whether javascript is enabled in the browser + pub java_script_enabled: Option, + + /// Language supported + pub language: Option, + + /// The screen height in pixels + pub screen_height: Option, + + /// The screen width in pixels + pub screen_width: Option, + + /// Time zone of the client + pub time_zone: Option, + + /// Ip address of the client + #[schema(value_type = Option)] + pub ip_address: Option, + + /// List of headers that are accepted + #[schema( + example = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8" + )] + pub accept_header: Option, + + /// User-agent of the browser + pub user_agent: Option, +} + +#[cfg(feature = "v2")] +crate::impl_to_sql_from_sql_json!(BrowserInformation); /// Domain type for connector_transaction_id /// Maximum length for connector's transaction_id can be 128 characters in HS DB. /// In case connector's use an identifier whose length exceeds 128 characters, diff --git a/crates/connector_configs/Cargo.toml b/crates/connector_configs/Cargo.toml index 0c460a9f2b3..f8728968098 100644 --- a/crates/connector_configs/Cargo.toml +++ b/crates/connector_configs/Cargo.toml @@ -13,11 +13,11 @@ development = [] sandbox = [] dummy_connector = ["api_models/dummy_connector", "development"] payouts = ["api_models/payouts"] -v1 = ["api_models/v1"] +v1 = ["api_models/v1", "common_utils/v1"] [dependencies] # First party crates -api_models = { version = "0.1.0", path = "../api_models", package = "api_models"} +api_models = { version = "0.1.0", path = "../api_models", package = "api_models" } common_utils = { version = "0.1.0", path = "../common_utils" } # Third party crates diff --git a/crates/diesel_models/src/payment_attempt.rs b/crates/diesel_models/src/payment_attempt.rs index ae98b8a0481..ae4722a6f37 100644 --- a/crates/diesel_models/src/payment_attempt.rs +++ b/crates/diesel_models/src/payment_attempt.rs @@ -34,9 +34,8 @@ pub struct PaymentAttempt { pub connector: Option, pub error_message: Option, pub surcharge_amount: Option, - pub payment_method_id: Option, - pub confirm: bool, - pub authentication_type: Option, + pub payment_method_id: Option, + pub authentication_type: storage_enums::AuthenticationType, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601")] @@ -45,12 +44,12 @@ pub struct PaymentAttempt { pub last_synced: Option, pub cancellation_reason: Option, pub amount_to_capture: Option, - pub browser_info: Option, + pub browser_info: Option, pub error_code: Option, pub payment_token: Option, - pub connector_metadata: Option, + pub connector_metadata: Option, pub payment_experience: Option, - pub payment_method_data: Option, + pub payment_method_data: Option, pub preprocessing_step_id: Option, pub error_reason: Option, pub multiple_capture_count: Option, @@ -58,16 +57,15 @@ pub struct PaymentAttempt { pub amount_capturable: MinorUnit, pub updated_by: String, pub merchant_connector_id: Option, - pub authentication_data: Option, - pub encoded_data: Option, + pub authentication_data: Option, + pub encoded_data: Option>, pub unified_code: Option, pub unified_message: Option, - pub net_amount: Option, + pub net_amount: MinorUnit, pub external_three_ds_authentication_attempted: Option, pub authentication_connector: Option, pub authentication_id: Option, pub fingerprint_id: Option, - pub payment_method_billing_address_id: Option, pub charge_id: Option, pub client_source: Option, pub client_version: Option, @@ -75,15 +73,16 @@ pub struct PaymentAttempt { pub profile_id: id_type::ProfileId, pub organization_id: id_type::OrganizationId, pub card_network: Option, - pub payment_method_type_v2: Option, + pub payment_method_type_v2: storage_enums::PaymentMethod, pub connector_payment_id: Option, - pub payment_method_subtype: Option, + pub payment_method_subtype: storage_enums::PaymentMethodType, pub routing_result: Option, pub authentication_applied: Option, pub external_reference_id: Option, pub tax_on_surcharge: Option, + pub payment_method_billing_address: Option, pub connector_payment_data: Option, - pub id: String, + pub id: id_type::GlobalAttemptId, pub shipping_cost: Option, pub order_tax_amount: Option, pub connector_mandate_detail: Option, @@ -225,9 +224,8 @@ pub struct PaymentAttemptNew { pub error_message: Option, pub surcharge_amount: Option, pub tax_on_surcharge: Option, - pub payment_method_id: Option, - pub confirm: bool, - pub authentication_type: Option, + pub payment_method_id: Option, + pub authentication_type: storage_enums::AuthenticationType, #[serde(with = "common_utils::custom_serde::iso8601")] pub created_at: PrimitiveDateTime, #[serde(with = "common_utils::custom_serde::iso8601")] @@ -236,12 +234,12 @@ pub struct PaymentAttemptNew { pub last_synced: Option, pub cancellation_reason: Option, pub amount_to_capture: Option, - pub browser_info: Option, + pub browser_info: Option, pub payment_token: Option, pub error_code: Option, - pub connector_metadata: Option, + pub connector_metadata: Option, pub payment_experience: Option, - pub payment_method_data: Option, + pub payment_method_data: Option, pub preprocessing_step_id: Option, pub error_reason: Option, pub connector_response_reference_id: Option, @@ -249,16 +247,16 @@ pub struct PaymentAttemptNew { pub amount_capturable: MinorUnit, pub updated_by: String, pub merchant_connector_id: Option, - pub authentication_data: Option, - pub encoded_data: Option, + pub authentication_data: Option, + pub encoded_data: Option>, pub unified_code: Option, pub unified_message: Option, - pub net_amount: Option, + pub net_amount: MinorUnit, pub external_three_ds_authentication_attempted: Option, pub authentication_connector: Option, pub authentication_id: Option, pub fingerprint_id: Option, - pub payment_method_billing_address_id: Option, + pub payment_method_billing_address: Option, pub charge_id: Option, pub client_source: Option, pub client_version: Option, @@ -268,6 +266,9 @@ pub struct PaymentAttemptNew { pub card_network: Option, pub shipping_cost: Option, pub order_tax_amount: Option, + pub payment_method_type_v2: storage_enums::PaymentMethod, + pub payment_method_subtype: storage_enums::PaymentMethodType, + pub id: id_type::GlobalAttemptId, pub connector_mandate_detail: Option, } @@ -731,48 +732,48 @@ pub enum PaymentAttemptUpdate { // }, } +// TODO: uncomment fields as and when required #[cfg(feature = "v2")] #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = payment_attempt)] pub struct PaymentAttemptUpdateInternal { - net_amount: Option, - status: Option, - authentication_type: Option, - error_message: Option>, - payment_method_id: Option, - cancellation_reason: Option, - modified_at: PrimitiveDateTime, - browser_info: Option, - payment_token: Option, - error_code: Option>, - connector_metadata: Option, - payment_method_data: Option, - payment_experience: Option, - preprocessing_step_id: Option, - error_reason: Option>, - connector_response_reference_id: Option, - multiple_capture_count: Option, - surcharge_amount: Option, - tax_on_surcharge: Option, - amount_capturable: Option, - updated_by: String, - merchant_connector_id: Option>, - authentication_data: Option, - encoded_data: Option, - unified_code: Option>, - unified_message: Option>, - external_three_ds_authentication_attempted: Option, - authentication_connector: Option, - authentication_id: Option, - fingerprint_id: Option, - payment_method_billing_address_id: Option, - charge_id: Option, - client_source: Option, - client_version: Option, - customer_acceptance: Option, - card_network: Option, - connector_payment_data: Option, - connector_mandate_detail: Option, + // net_amount: Option, + pub status: Option, + // authentication_type: Option, + pub error_message: Option, + pub connector_payment_id: Option, + // payment_method_id: Option, + // cancellation_reason: Option, + pub modified_at: PrimitiveDateTime, + pub browser_info: Option, + // payment_token: Option, + pub error_code: Option, + // connector_metadata: Option, + // payment_method_data: Option, + // payment_experience: Option, + // preprocessing_step_id: Option, + pub error_reason: Option, + // connector_response_reference_id: Option, + // multiple_capture_count: Option, + // pub surcharge_amount: Option, + // tax_on_surcharge: Option, + // amount_capturable: Option, + pub updated_by: String, + pub merchant_connector_id: Option, + pub connector: Option, + // authentication_data: Option, + // encoded_data: Option, + pub unified_code: Option>, + pub unified_message: Option>, + // external_three_ds_authentication_attempted: Option, + // authentication_connector: Option, + // authentication_id: Option, + // fingerprint_id: Option, + // charge_id: Option, + // client_source: Option, + // client_version: Option, + // customer_acceptance: Option, + // card_network: Option, } #[cfg(feature = "v1")] @@ -832,13 +833,6 @@ pub struct PaymentAttemptUpdateInternal { pub connector_mandate_detail: Option, } -#[cfg(feature = "v2")] -impl PaymentAttemptUpdateInternal { - pub fn populate_derived_fields(self, source: &PaymentAttempt) -> Self { - todo!(); - } -} - #[cfg(feature = "v1")] impl PaymentAttemptUpdateInternal { pub fn populate_derived_fields(self, source: &PaymentAttempt) -> Self { diff --git a/crates/diesel_models/src/payment_intent.rs b/crates/diesel_models/src/payment_intent.rs index f53594075af..210b12b7aad 100644 --- a/crates/diesel_models/src/payment_intent.rs +++ b/crates/diesel_models/src/payment_intent.rs @@ -192,6 +192,26 @@ pub struct TaxDetails { pub payment_method_type: Option, } +impl TaxDetails { + /// Get the tax amount + /// If default tax is present, return the default tax amount + /// If default tax is not present, return the tax amount based on the payment method if it matches the provided payment method type + pub fn get_tax_amount(&self, payment_method: PaymentMethodType) -> Option { + self.payment_method_type + .as_ref() + .filter(|payment_method_type_tax| payment_method_type_tax.pmt == payment_method) + .map(|payment_method_type_tax| payment_method_type_tax.order_tax_amount) + .or_else(|| self.get_default_tax_amount()) + } + + /// Get the default tax amount + fn get_default_tax_amount(&self) -> Option { + self.default + .as_ref() + .map(|default_tax_details| default_tax_details.order_tax_amount) + } +} + common_utils::impl_to_sql_from_sql_json!(TaxDetails); #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] @@ -333,79 +353,15 @@ pub struct PaymentIntentNew { #[cfg(feature = "v2")] #[derive(Debug, Clone, Serialize, Deserialize)] pub enum PaymentIntentUpdate { - ResponseUpdate { - status: storage_enums::IntentStatus, - amount_captured: Option, - // Moved to attempt - // fingerprint_id: Option, - return_url: Option, - updated_by: String, - // Moved to attempt - // incremental_authorization_allowed: Option, - }, - MetadataUpdate { - metadata: pii::SecretSerdeValue, - updated_by: String, - }, - Update(Box), - PaymentCreateUpdate { - return_url: Option, - status: Option, - customer_id: Option, - shipping_address: Option, - billing_address: Option, - customer_details: Option, - updated_by: String, - }, - MerchantStatusUpdate { + /// Update the payment intent details on payment intent confirmation, before calling the connector + ConfirmIntent { status: storage_enums::IntentStatus, - shipping_address: Option, - billing_address: Option, updated_by: String, }, - PGStatusUpdate { + /// Update the payment intent details on payment intent confirmation, after calling the connector + ConfirmIntentPostUpdate { status: storage_enums::IntentStatus, updated_by: String, - // Moved to attempt - // incremental_authorization_allowed: Option, - }, - PaymentAttemptAndAttemptCountUpdate { - active_attempt_id: String, - attempt_count: i16, - updated_by: String, - }, - StatusAndAttemptUpdate { - status: storage_enums::IntentStatus, - active_attempt_id: String, - attempt_count: i16, - updated_by: String, - }, - ApproveUpdate { - status: storage_enums::IntentStatus, - frm_merchant_decision: Option, - updated_by: String, - }, - RejectUpdate { - status: storage_enums::IntentStatus, - frm_merchant_decision: Option, - updated_by: String, - }, - SurchargeApplicableUpdate { - surcharge_applicable: Option, - updated_by: String, - }, - IncrementalAuthorizationAmountUpdate { - amount: MinorUnit, - }, - AuthorizationCountUpdate { - authorization_count: i32, - }, - CompleteAuthorizeUpdate { - shipping_address: Option, - }, - ManualUpdate { - status: Option, - updated_by: String, }, } @@ -548,35 +504,36 @@ pub struct PaymentIntentUpdateFields { pub tax_details: Option, } +// TODO: uncomment fields as necessary #[cfg(feature = "v2")] #[derive(Clone, Debug, AsChangeset, router_derive::DebugAsDisplay)] #[diesel(table_name = payment_intent)] pub struct PaymentIntentUpdateInternal { - pub amount: Option, - pub currency: Option, + // pub amount: Option, + // pub currency: Option, pub status: Option, - pub amount_captured: Option, - pub customer_id: Option, - pub return_url: Option, - pub setup_future_usage: Option, - pub metadata: Option, + // pub amount_captured: Option, + // pub customer_id: Option, + // pub return_url: Option<>, + // pub setup_future_usage: Option, + // pub metadata: Option, pub modified_at: PrimitiveDateTime, - pub active_attempt_id: Option, - pub description: Option, - pub statement_descriptor: Option, - #[diesel(deserialize_as = super::OptionalDieselArray)] - pub order_details: Option>, - pub attempt_count: Option, + // pub active_attempt_id: Option, + // pub description: Option, + // pub statement_descriptor: Option, + // #[diesel(deserialize_as = super::OptionalDieselArray)] + // pub order_details: Option>, + // pub attempt_count: Option, pub updated_by: String, - pub surcharge_applicable: Option, - pub authorization_count: Option, - pub session_expiry: Option, - pub request_external_three_ds_authentication: Option, - pub frm_metadata: Option, - pub customer_details: Option, - pub billing_address: Option, - pub shipping_address: Option, - pub frm_merchant_decision: Option, + // pub surcharge_applicable: Option, + // pub authorization_count: Option, + // pub session_expiry: Option, + // pub request_external_three_ds_authentication: Option, + // pub frm_metadata: Option, + // pub customer_details: Option, + // pub billing_address: Option, + // pub shipping_address: Option, + // pub frm_merchant_decision: Option, } #[cfg(feature = "v1")] @@ -625,71 +582,60 @@ pub struct PaymentIntentUpdateInternal { #[cfg(feature = "v2")] impl PaymentIntentUpdate { pub fn apply_changeset(self, source: PaymentIntent) -> PaymentIntent { - todo!() - // let PaymentIntentUpdateInternal { - // amount, - // currency, - // status, - // amount_captured, - // customer_id, - // return_url, - // setup_future_usage, - // off_session, - // metadata, - // modified_at: _, - // active_attempt_id, - // description, - // statement_descriptor, - // order_details, - // attempt_count, - // frm_merchant_decision, - // payment_confirm_source, - // updated_by, - // surcharge_applicable, - // authorization_count, - // session_expiry, - // request_external_three_ds_authentication, - // frm_metadata, - // customer_details, - // billing_address, - // merchant_order_reference_id, - // shipping_address, - // is_payment_processor_token_flow, - // } = self.into(); - // PaymentIntent { - // amount: amount.unwrap_or(source.amount), - // currency: currency.unwrap_or(source.currency), - // status: status.unwrap_or(source.status), - // amount_captured: amount_captured.or(source.amount_captured), - // customer_id: customer_id.or(source.customer_id), - // return_url: return_url.or(source.return_url), - // setup_future_usage: setup_future_usage.or(source.setup_future_usage), - // off_session: off_session.or(source.off_session), - // metadata: metadata.or(source.metadata), - // modified_at: common_utils::date_time::now(), - // active_attempt_id: active_attempt_id.unwrap_or(source.active_attempt_id), - // description: description.or(source.description), - // statement_descriptor: statement_descriptor.or(source.statement_descriptor), - // order_details: order_details.or(source.order_details), - // attempt_count: attempt_count.unwrap_or(source.attempt_count), - // frm_merchant_decision: frm_merchant_decision.or(source.frm_merchant_decision), - // payment_confirm_source: payment_confirm_source.or(source.payment_confirm_source), - // updated_by, - // surcharge_applicable: surcharge_applicable.or(source.surcharge_applicable), - // authorization_count: authorization_count.or(source.authorization_count), - // session_expiry: session_expiry.or(source.session_expiry), - // request_external_three_ds_authentication: request_external_three_ds_authentication - // .or(source.request_external_three_ds_authentication), - // frm_metadata: frm_metadata.or(source.frm_metadata), - // customer_details: customer_details.or(source.customer_details), - // billing_address: billing_address.or(source.billing_address), - // shipping_address: shipping_address.or(source.shipping_address), - // merchant_order_reference_id: merchant_order_reference_id - // .or(source.merchant_order_reference_id), - // is_payment_processor_token_flow: is_payment_processor_token_flow - // .or(source.is_payment_processor_token_flow), - // ..source - // } + let PaymentIntentUpdateInternal { + // amount, + // currency, + status, + // amount_captured, + // customer_id, + // return_url, + // setup_future_usage, + // metadata, + modified_at: _, + // active_attempt_id, + // description, + // statement_descriptor, + // order_details, + // attempt_count, + // frm_merchant_decision, + updated_by, + // surcharge_applicable, + // authorization_count, + // session_expiry, + // request_external_three_ds_authentication, + // frm_metadata, + // customer_details, + // billing_address, + // shipping_address, + } = self.into(); + PaymentIntent { + // amount: amount.unwrap_or(source.amount), + // currency: currency.unwrap_or(source.currency), + status: status.unwrap_or(source.status), + // amount_captured: amount_captured.or(source.amount_captured), + // customer_id: customer_id.or(source.customer_id), + // return_url: return_url.or(source.return_url), + // setup_future_usage: setup_future_usage.or(source.setup_future_usage), + // metadata: metadata.or(source.metadata), + modified_at: common_utils::date_time::now(), + // active_attempt_id: active_attempt_id.unwrap_or(source.active_attempt_id), + // description: description.or(source.description), + // statement_descriptor: statement_descriptor.or(source.statement_descriptor), + // order_details: order_details.or(source.order_details), + // attempt_count: attempt_count.unwrap_or(source.attempt_count), + // frm_merchant_decision: frm_merchant_decision.or(source.frm_merchant_decision), + updated_by, + // surcharge_applicable: surcharge_applicable.or(source.surcharge_applicable), + // authorization_count: authorization_count.or(source.authorization_count), + // session_expiry: session_expiry.or(source.session_expiry), + // request_external_three_ds_authentication: request_external_three_ds_authentication + // .or(source.request_external_three_ds_authentication), + // frm_metadata: frm_metadata.or(source.frm_metadata), + // customer_details: customer_details.or(source.customer_details), + // billing_address: billing_address.or(source.billing_address), + // shipping_address: shipping_address.or(source.shipping_address), + ..source + } } } @@ -786,509 +732,18 @@ impl PaymentIntentUpdate { #[cfg(feature = "v2")] impl From for PaymentIntentUpdateInternal { fn from(payment_intent_update: PaymentIntentUpdate) -> Self { - todo!() - // match payment_intent_update { - // PaymentIntentUpdate::MetadataUpdate { - // metadata, - // updated_by, - // } => Self { - // metadata: Some(metadata), - // modified_at: common_utils::date_time::now(), - // updated_by, - // amount: None, - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::Update(value) => Self { - // amount: Some(value.amount), - // currency: Some(value.currency), - // setup_future_usage: value.setup_future_usage, - // status: Some(value.status), - // customer_id: value.customer_id, - // shipping_address: value.shipping_address, - // billing_address: value.billing_address, - // return_url: value.return_url, - // description: value.description, - // statement_descriptor: value.statement_descriptor, - // order_details: value.order_details, - // metadata: value.metadata, - // payment_confirm_source: value.payment_confirm_source, - // updated_by: value.updated_by, - // session_expiry: value.session_expiry, - // request_external_three_ds_authentication: value - // .request_external_three_ds_authentication, - // frm_metadata: value.frm_metadata, - // customer_details: value.customer_details, - // merchant_order_reference_id: value.merchant_order_reference_id, - // amount_captured: None, - // off_session: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // attempt_count: None, - // frm_merchant_decision: None, - // surcharge_applicable: None, - // authorization_count: None, - // is_payment_processor_token_flow: value.is_payment_processor_token_flow, - // }, - // PaymentIntentUpdate::PaymentCreateUpdate { - // return_url, - // status, - // customer_id, - // shipping_address, - // billing_address, - // customer_details, - // updated_by, - // } => Self { - // return_url, - // status, - // customer_id, - // customer_details, - // modified_at: common_utils::date_time::now(), - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // billing_address, - // merchant_order_reference_id: None, - // shipping_address, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::PGStatusUpdate { status, updated_by } => Self { - // status: Some(status), - // modified_at: common_utils::date_time::now(), - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::MerchantStatusUpdate { - // status, - // billing_address, - // shipping_address, - // updated_by, - // } => Self { - // status: Some(status), - // modified_at: common_utils::date_time::now(), - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address, - // merchant_order_reference_id: None, - // shipping_address, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::ResponseUpdate { - // // amount, - // // currency, - // status, - // amount_captured, - // // customer_id, - // return_url, - // updated_by, - // } => Self { - // // amount, - // // currency: Some(currency), - // status: Some(status), - // amount_captured, - // // customer_id, - // return_url, - // modified_at: common_utils::date_time::now(), - // updated_by, - // amount: None, - // currency: None, - // customer_id: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self { - // active_attempt_id: Some(active_attempt_id), - // attempt_count: Some(attempt_count), - // updated_by, - // amount: None, - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // description: None, - // statement_descriptor: None, - // order_details: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::StatusAndAttemptUpdate { - // status, - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self { - // status: Some(status), - // active_attempt_id: Some(active_attempt_id), - // attempt_count: Some(attempt_count), - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // description: None, - // statement_descriptor: None, - // order_details: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::ApproveUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self { - // status: Some(status), - // frm_merchant_decision, - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::RejectUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self { - // status: Some(status), - // frm_merchant_decision, - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::SurchargeApplicableUpdate { - // surcharge_applicable, - // updated_by, - // } => Self { - // surcharge_applicable, - // updated_by, - // amount: None, - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => Self { - // amount: Some(amount), - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // updated_by: String::default(), - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::AuthorizationCountUpdate { - // authorization_count, - // } => Self { - // authorization_count: Some(authorization_count), - // amount: None, - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // updated_by: String::default(), - // surcharge_applicable: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::CompleteAuthorizeUpdate { shipping_address } => Self { - // amount: None, - // currency: None, - // status: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // updated_by: String::default(), - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address, - // is_payment_processor_token_flow: None, - // }, - // PaymentIntentUpdate::ManualUpdate { status, updated_by } => Self { - // status, - // updated_by, - // amount: None, - // currency: None, - // amount_captured: None, - // customer_id: None, - // return_url: None, - // setup_future_usage: None, - // off_session: None, - // metadata: None, - // modified_at: common_utils::date_time::now(), - // active_attempt_id: None, - // description: None, - // statement_descriptor: None, - // order_details: None, - // attempt_count: None, - // frm_merchant_decision: None, - // payment_confirm_source: None, - // surcharge_applicable: None, - // authorization_count: None, - // session_expiry: None, - // request_external_three_ds_authentication: None, - // frm_metadata: None, - // customer_details: None, - // billing_address: None, - // merchant_order_reference_id: None, - // shipping_address: None, - // is_payment_processor_token_flow: None, - // }, - // } + match payment_intent_update { + PaymentIntentUpdate::ConfirmIntent { status, updated_by } => Self { + status: Some(status), + modified_at: common_utils::date_time::now(), + updated_by, + }, + PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => Self { + status: Some(status), + modified_at: common_utils::date_time::now(), + updated_by, + }, + } } } diff --git a/crates/diesel_models/src/query/payment_attempt.rs b/crates/diesel_models/src/query/payment_attempt.rs index 0627fa0048a..549af3ace45 100644 --- a/crates/diesel_models/src/query/payment_attempt.rs +++ b/crates/diesel_models/src/query/payment_attempt.rs @@ -68,11 +68,7 @@ impl PaymentAttempt { _, _, _, - >( - conn, - dsl::id.eq(self.id.to_owned()), - payment_attempt.populate_derived_fields(&self), - ) + >(conn, dsl::id.eq(self.id.to_owned()), payment_attempt) .await { Err(error) => match error.current_context() { diff --git a/crates/diesel_models/src/query/user/sample_data.rs b/crates/diesel_models/src/query/user/sample_data.rs index 27e674f7d7b..b97ea39b82d 100644 --- a/crates/diesel_models/src/query/user/sample_data.rs +++ b/crates/diesel_models/src/query/user/sample_data.rs @@ -14,11 +14,11 @@ use crate::schema_v2::{ use crate::{ errors, schema::{dispute::dsl as dispute_dsl, refund::dsl as refund_dsl}, - user::sample_data::PaymentAttemptBatchNew, - Dispute, DisputeNew, PaymentAttempt, PaymentIntent, PaymentIntentNew, PgPooledConn, Refund, - RefundNew, StorageResult, + user, Dispute, DisputeNew, PaymentAttempt, PaymentIntent, PaymentIntentNew, PgPooledConn, + Refund, RefundNew, StorageResult, }; +#[cfg(feature = "v1")] pub async fn insert_payment_intents( conn: &PgPooledConn, batch: Vec, @@ -33,9 +33,11 @@ pub async fn insert_payment_intents( .change_context(errors::DatabaseError::Others) .attach_printable("Error while inserting payment intents") } + +#[cfg(feature = "v1")] pub async fn insert_payment_attempts( conn: &PgPooledConn, - batch: Vec, + batch: Vec, ) -> StorageResult> { let query = diesel::insert_into(::table()).values(batch); diff --git a/crates/diesel_models/src/schema_v2.rs b/crates/diesel_models/src/schema_v2.rs index 45a4ce03e55..b5e895cde79 100644 --- a/crates/diesel_models/src/schema_v2.rs +++ b/crates/diesel_models/src/schema_v2.rs @@ -749,8 +749,7 @@ diesel::table! { surcharge_amount -> Nullable, #[max_length = 64] payment_method_id -> Nullable, - confirm -> Bool, - authentication_type -> Nullable, + authentication_type -> AuthenticationType, created_at -> Timestamp, modified_at -> Timestamp, last_synced -> Nullable, @@ -782,7 +781,7 @@ diesel::table! { unified_code -> Nullable, #[max_length = 1024] unified_message -> Nullable, - net_amount -> Nullable, + net_amount -> Int8, external_three_ds_authentication_attempted -> Nullable, #[max_length = 64] authentication_connector -> Nullable, @@ -791,8 +790,6 @@ diesel::table! { #[max_length = 64] fingerprint_id -> Nullable, #[max_length = 64] - payment_method_billing_address_id -> Nullable, - #[max_length = 64] charge_id -> Nullable, #[max_length = 64] client_source -> Nullable, @@ -805,16 +802,17 @@ diesel::table! { organization_id -> Varchar, #[max_length = 32] card_network -> Nullable, - payment_method_type_v2 -> Nullable, + payment_method_type_v2 -> Varchar, #[max_length = 128] connector_payment_id -> Nullable, #[max_length = 64] - payment_method_subtype -> Nullable, + payment_method_subtype -> Varchar, routing_result -> Nullable, authentication_applied -> Nullable, #[max_length = 128] external_reference_id -> Nullable, tax_on_surcharge -> Nullable, + payment_method_billing_address -> Nullable, #[max_length = 512] connector_payment_data -> Nullable, #[max_length = 64] diff --git a/crates/diesel_models/src/user/sample_data.rs b/crates/diesel_models/src/user/sample_data.rs index 88617afb392..cfc9e1c4c8e 100644 --- a/crates/diesel_models/src/user/sample_data.rs +++ b/crates/diesel_models/src/user/sample_data.rs @@ -15,122 +15,120 @@ use crate::{ ConnectorMandateReferenceId, PaymentAttemptNew, }; -#[cfg(feature = "v2")] -#[derive( - Clone, Debug, diesel::Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize, -)] -#[diesel(table_name = payment_attempt)] -pub struct PaymentAttemptBatchNew { - pub payment_id: common_utils::id_type::PaymentId, - pub merchant_id: common_utils::id_type::MerchantId, - pub status: AttemptStatus, - pub error_message: Option, - pub surcharge_amount: Option, - pub tax_on_surcharge: Option, - pub payment_method_id: Option, - pub confirm: bool, - pub authentication_type: Option, - #[serde(with = "common_utils::custom_serde::iso8601")] - pub created_at: PrimitiveDateTime, - #[serde(with = "common_utils::custom_serde::iso8601")] - pub modified_at: PrimitiveDateTime, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] - pub last_synced: Option, - pub cancellation_reason: Option, - pub browser_info: Option, - pub payment_token: Option, - pub error_code: Option, - pub connector_metadata: Option, - pub payment_experience: Option, - pub payment_method_data: Option, - pub preprocessing_step_id: Option, - pub error_reason: Option, - pub connector_response_reference_id: Option, - pub multiple_capture_count: Option, - pub amount_capturable: i64, - pub updated_by: String, - pub merchant_connector_id: Option, - pub authentication_data: Option, - pub encoded_data: Option, - pub unified_code: Option, - pub unified_message: Option, - pub net_amount: Option, - pub external_three_ds_authentication_attempted: Option, - pub authentication_connector: Option, - pub authentication_id: Option, - pub payment_method_billing_address_id: Option, - pub fingerprint_id: Option, - pub charge_id: Option, - pub client_source: Option, - pub client_version: Option, - pub customer_acceptance: Option, - pub profile_id: common_utils::id_type::ProfileId, - pub organization_id: common_utils::id_type::OrganizationId, -} +// #[cfg(feature = "v2")] +// #[derive( +// Clone, Debug, diesel::Insertable, router_derive::DebugAsDisplay, Serialize, Deserialize, +// )] +// #[diesel(table_name = payment_attempt)] +// pub struct PaymentAttemptBatchNew { +// pub payment_id: common_utils::id_type::PaymentId, +// pub merchant_id: common_utils::id_type::MerchantId, +// pub status: AttemptStatus, +// pub error_message: Option, +// pub surcharge_amount: Option, +// pub tax_on_surcharge: Option, +// pub payment_method_id: Option, +// pub authentication_type: Option, +// #[serde(with = "common_utils::custom_serde::iso8601")] +// pub created_at: PrimitiveDateTime, +// #[serde(with = "common_utils::custom_serde::iso8601")] +// pub modified_at: PrimitiveDateTime, +// #[serde(default, with = "common_utils::custom_serde::iso8601::option")] +// pub last_synced: Option, +// pub cancellation_reason: Option, +// pub browser_info: Option, +// pub payment_token: Option, +// pub error_code: Option, +// pub connector_metadata: Option, +// pub payment_experience: Option, +// pub payment_method_data: Option, +// pub preprocessing_step_id: Option, +// pub error_reason: Option, +// pub connector_response_reference_id: Option, +// pub multiple_capture_count: Option, +// pub amount_capturable: i64, +// pub updated_by: String, +// pub merchant_connector_id: Option, +// pub authentication_data: Option, +// pub encoded_data: Option, +// pub unified_code: Option, +// pub unified_message: Option, +// pub net_amount: Option, +// pub external_three_ds_authentication_attempted: Option, +// pub authentication_connector: Option, +// pub authentication_id: Option, +// pub fingerprint_id: Option, +// pub charge_id: Option, +// pub client_source: Option, +// pub client_version: Option, +// pub customer_acceptance: Option, +// pub profile_id: common_utils::id_type::ProfileId, +// pub organization_id: common_utils::id_type::OrganizationId, +// } -#[cfg(feature = "v2")] -#[allow(dead_code)] -impl PaymentAttemptBatchNew { - // Used to verify compatibility with PaymentAttemptTable - fn convert_into_normal_attempt_insert(self) -> PaymentAttemptNew { - // PaymentAttemptNew { - // payment_id: self.payment_id, - // merchant_id: self.merchant_id, - // status: self.status, - // error_message: self.error_message, - // surcharge_amount: self.surcharge_amount, - // tax_amount: self.tax_amount, - // payment_method_id: self.payment_method_id, - // confirm: self.confirm, - // authentication_type: self.authentication_type, - // created_at: self.created_at, - // modified_at: self.modified_at, - // last_synced: self.last_synced, - // cancellation_reason: self.cancellation_reason, - // browser_info: self.browser_info, - // payment_token: self.payment_token, - // error_code: self.error_code, - // connector_metadata: self.connector_metadata, - // payment_experience: self.payment_experience, - // card_network: self - // .payment_method_data - // .as_ref() - // .and_then(|data| data.as_object()) - // .and_then(|card| card.get("card")) - // .and_then(|v| v.as_object()) - // .and_then(|v| v.get("card_network")) - // .and_then(|network| network.as_str()) - // .map(|network| network.to_string()), - // payment_method_data: self.payment_method_data, - // straight_through_algorithm: self.straight_through_algorithm, - // preprocessing_step_id: self.preprocessing_step_id, - // error_reason: self.error_reason, - // multiple_capture_count: self.multiple_capture_count, - // connector_response_reference_id: self.connector_response_reference_id, - // amount_capturable: self.amount_capturable, - // updated_by: self.updated_by, - // merchant_connector_id: self.merchant_connector_id, - // authentication_data: self.authentication_data, - // encoded_data: self.encoded_data, - // unified_code: self.unified_code, - // unified_message: self.unified_message, - // net_amount: self.net_amount, - // external_three_ds_authentication_attempted: self - // .external_three_ds_authentication_attempted, - // authentication_connector: self.authentication_connector, - // authentication_id: self.authentication_id, - // payment_method_billing_address_id: self.payment_method_billing_address_id, - // fingerprint_id: self.fingerprint_id, - // charge_id: self.charge_id, - // client_source: self.client_source, - // client_version: self.client_version, - // customer_acceptance: self.customer_acceptance, - // profile_id: self.profile_id, - // organization_id: self.organization_id, - // } - todo!() - } -} +// #[cfg(feature = "v2")] +// #[allow(dead_code)] +// impl PaymentAttemptBatchNew { +// // Used to verify compatibility with PaymentAttemptTable +// fn convert_into_normal_attempt_insert(self) -> PaymentAttemptNew { +// // PaymentAttemptNew { +// // payment_id: self.payment_id, +// // merchant_id: self.merchant_id, +// // status: self.status, +// // error_message: self.error_message, +// // surcharge_amount: self.surcharge_amount, +// // tax_amount: self.tax_amount, +// // payment_method_id: self.payment_method_id, +// // confirm: self.confirm, +// // authentication_type: self.authentication_type, +// // created_at: self.created_at, +// // modified_at: self.modified_at, +// // last_synced: self.last_synced, +// // cancellation_reason: self.cancellation_reason, +// // browser_info: self.browser_info, +// // payment_token: self.payment_token, +// // error_code: self.error_code, +// // connector_metadata: self.connector_metadata, +// // payment_experience: self.payment_experience, +// // card_network: self +// // .payment_method_data +// // .as_ref() +// // .and_then(|data| data.as_object()) +// // .and_then(|card| card.get("card")) +// // .and_then(|v| v.as_object()) +// // .and_then(|v| v.get("card_network")) +// // .and_then(|network| network.as_str()) +// // .map(|network| network.to_string()), +// // payment_method_data: self.payment_method_data, +// // straight_through_algorithm: self.straight_through_algorithm, +// // preprocessing_step_id: self.preprocessing_step_id, +// // error_reason: self.error_reason, +// // multiple_capture_count: self.multiple_capture_count, +// // connector_response_reference_id: self.connector_response_reference_id, +// // amount_capturable: self.amount_capturable, +// // updated_by: self.updated_by, +// // merchant_connector_id: self.merchant_connector_id, +// // authentication_data: self.authentication_data, +// // encoded_data: self.encoded_data, +// // unified_code: self.unified_code, +// // unified_message: self.unified_message, +// // net_amount: self.net_amount, +// // external_three_ds_authentication_attempted: self +// // .external_three_ds_authentication_attempted, +// // authentication_connector: self.authentication_connector, +// // authentication_id: self.authentication_id, +// // payment_method_billing_address_id: self.payment_method_billing_address_id, +// // fingerprint_id: self.fingerprint_id, +// // charge_id: self.charge_id, +// // client_source: self.client_source, +// // client_version: self.client_version, +// // customer_acceptance: self.customer_acceptance, +// // profile_id: self.profile_id, +// // organization_id: self.organization_id, +// // } +// todo!() +// } +// } #[cfg(feature = "v1")] #[derive( diff --git a/crates/drainer/Cargo.toml b/crates/drainer/Cargo.toml index 5cb01dc8fb6..ce7301a0305 100644 --- a/crates/drainer/Cargo.toml +++ b/crates/drainer/Cargo.toml @@ -10,7 +10,7 @@ license.workspace = true [features] release = ["vergen", "external_services/aws_kms"] vergen = ["router_env/vergen"] -v1 = ["diesel_models/v1", "hyperswitch_interfaces/v1"] +v1 = ["diesel_models/v1", "hyperswitch_interfaces/v1", "common_utils/v1"] [dependencies] actix-web = "4.5.1" diff --git a/crates/external_services/Cargo.toml b/crates/external_services/Cargo.toml index fd7391c13bc..735ccc5ebfa 100644 --- a/crates/external_services/Cargo.toml +++ b/crates/external_services/Cargo.toml @@ -12,8 +12,8 @@ aws_kms = ["dep:aws-config", "dep:aws-sdk-kms"] email = ["dep:aws-config"] aws_s3 = ["dep:aws-config", "dep:aws-sdk-s3"] hashicorp-vault = ["dep:vaultrs"] -v1 = ["hyperswitch_interfaces/v1"] -dynamic_routing = ["dep:prost", "dep:tonic", "dep:tonic-reflection", "dep:tonic-types", "dep:api_models", "tokio/macros", "tokio/rt-multi-thread" , "dep:tonic-build", "dep:router_env"] +v1 = ["hyperswitch_interfaces/v1", "common_utils/v1"] +dynamic_routing = ["dep:prost", "dep:tonic", "dep:tonic-reflection", "dep:tonic-types", "dep:api_models", "tokio/macros", "tokio/rt-multi-thread", "dep:tonic-build", "dep:router_env"] [dependencies] async-trait = "0.1.79" @@ -34,7 +34,7 @@ serde = { version = "1.0.197", features = ["derive"] } thiserror = "1.0.58" vaultrs = { version = "0.7.2", optional = true } prost = { version = "0.13", optional = true } -tokio = "1.37.0" +tokio = "1.37.0" tonic = { version = "0.12.2", optional = true } tonic-reflection = { version = "0.12.2", optional = true } tonic-types = { version = "0.12.2", optional = true } @@ -49,7 +49,7 @@ api_models = { version = "0.1.0", path = "../api_models", optional = true } [build-dependencies] -tonic-build = { version = "0.12" , optional = true } +tonic-build = { version = "0.12", optional = true } router_env = { version = "0.1.0", path = "../router_env", default-features = false, optional = true } [lints] diff --git a/crates/hyperswitch_connectors/Cargo.toml b/crates/hyperswitch_connectors/Cargo.toml index 86d6da446ee..1adbe693de4 100644 --- a/crates/hyperswitch_connectors/Cargo.toml +++ b/crates/hyperswitch_connectors/Cargo.toml @@ -8,7 +8,7 @@ license.workspace = true [features] frm = ["hyperswitch_domain_models/frm", "hyperswitch_interfaces/frm"] payouts = ["hyperswitch_domain_models/payouts", "api_models/payouts", "hyperswitch_interfaces/payouts"] -v1 = ["api_models/v1", "hyperswitch_domain_models/v1"] +v1 = ["api_models/v1", "hyperswitch_domain_models/v1", "common_utils/v1"] [dependencies] actix-http = "3.6.0" diff --git a/crates/hyperswitch_connectors/src/connectors/helcim.rs b/crates/hyperswitch_connectors/src/connectors/helcim.rs index 8d632d8b7e8..fcb9c77e104 100644 --- a/crates/hyperswitch_connectors/src/connectors/helcim.rs +++ b/crates/hyperswitch_connectors/src/connectors/helcim.rs @@ -65,9 +65,9 @@ impl api::PaymentToken for Helcim {} impl Helcim { pub fn connector_transaction_id( &self, - connector_meta: &Option, + connector_meta: Option<&serde_json::Value>, ) -> CustomResult, errors::ConnectorError> { - let meta: helcim::HelcimMetaData = to_connector_meta(connector_meta.clone())?; + let meta: helcim::HelcimMetaData = to_connector_meta(connector_meta.cloned())?; Ok(Some(meta.preauth_transaction_id.to_string())) } } diff --git a/crates/hyperswitch_connectors/src/connectors/nexinets.rs b/crates/hyperswitch_connectors/src/connectors/nexinets.rs index 902afe34134..94b24bbe867 100644 --- a/crates/hyperswitch_connectors/src/connectors/nexinets.rs +++ b/crates/hyperswitch_connectors/src/connectors/nexinets.rs @@ -68,9 +68,9 @@ impl api::RefundSync for Nexinets {} impl Nexinets { pub fn connector_transaction_id( &self, - connector_meta: &Option, + connector_meta: Option<&serde_json::Value>, ) -> CustomResult, errors::ConnectorError> { - let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(connector_meta.clone())?; + let meta: nexinets::NexinetsPaymentsMetadata = to_connector_meta(connector_meta.cloned())?; Ok(meta.transaction_id) } } diff --git a/crates/hyperswitch_domain_models/Cargo.toml b/crates/hyperswitch_domain_models/Cargo.toml index 3a0d4b402b7..8fa6d2cc4e8 100644 --- a/crates/hyperswitch_domain_models/Cargo.toml +++ b/crates/hyperswitch_domain_models/Cargo.toml @@ -13,8 +13,8 @@ encryption_service = [] olap = [] payouts = ["api_models/payouts"] frm = ["api_models/frm"] -v2 = ["api_models/v2", "diesel_models/v2"] -v1 = ["api_models/v1", "diesel_models/v1"] +v2 = ["api_models/v2", "diesel_models/v2", "common_utils/v2"] +v1 = ["api_models/v1", "diesel_models/v1", "common_utils/v1"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2"] payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2"] diff --git a/crates/hyperswitch_domain_models/src/lib.rs b/crates/hyperswitch_domain_models/src/lib.rs index 4803514617f..af6c8e65c84 100644 --- a/crates/hyperswitch_domain_models/src/lib.rs +++ b/crates/hyperswitch_domain_models/src/lib.rs @@ -123,11 +123,11 @@ impl From for payments::AmountDetails { order_amount: amount_details.order_amount().into(), currency: amount_details.currency(), shipping_cost: amount_details.shipping_cost(), - tax_details: Some(diesel_models::TaxDetails { - default: amount_details - .order_tax_amount() - .map(|order_tax_amount| diesel_models::DefaultTax { order_tax_amount }), - payment_method_type: None, + tax_details: amount_details.order_tax_amount().map(|order_tax_amount| { + diesel_models::TaxDetails { + default: Some(diesel_models::DefaultTax { order_tax_amount }), + payment_method_type: None, + } }), skip_external_tax_calculation: payments::TaxCalculationOverride::from( amount_details.skip_external_tax_calculation(), @@ -137,6 +137,8 @@ impl From for payments::AmountDetails { ), surcharge_amount: amount_details.surcharge_amount(), tax_on_surcharge: amount_details.tax_on_surcharge(), + // We will not receive this in the request. This will be populated after calling the connector / processor + amount_captured: None, } } } diff --git a/crates/hyperswitch_domain_models/src/payments.rs b/crates/hyperswitch_domain_models/src/payments.rs index 4c8cb9c38ea..933c13416f2 100644 --- a/crates/hyperswitch_domain_models/src/payments.rs +++ b/crates/hyperswitch_domain_models/src/payments.rs @@ -22,7 +22,7 @@ use crate::RemoteStorageObject; #[cfg(feature = "v2")] use crate::{business_profile, merchant_account}; #[cfg(feature = "v2")] -use crate::{errors, ApiModelToDieselModelConvertor}; +use crate::{errors, payment_method_data, ApiModelToDieselModelConvertor}; #[cfg(feature = "v1")] #[derive(Clone, Debug, PartialEq, serde::Serialize)] @@ -101,7 +101,7 @@ impl PaymentIntent { } #[cfg(feature = "v2")] -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, Copy, serde::Serialize)] pub enum TaxCalculationOverride { /// Skip calling the external tax provider Skip, @@ -110,7 +110,7 @@ pub enum TaxCalculationOverride { } #[cfg(feature = "v2")] -#[derive(Clone, Debug, PartialEq, serde::Serialize)] +#[derive(Clone, Debug, PartialEq, Copy, serde::Serialize)] pub enum SurchargeCalculationOverride { /// Skip calculating surcharge Skip, @@ -157,6 +157,9 @@ pub struct AmountDetails { pub surcharge_amount: Option, /// tax on surcharge amount pub tax_on_surcharge: Option, + /// The total amount captured for the order. This is the sum of all the captured amounts for the order. + /// For automatic captures, this will be the same as net amount for the order + pub amount_captured: Option, } #[cfg(feature = "v2")] @@ -176,6 +179,49 @@ impl AmountDetails { TaxCalculationOverride::Calculate => true, } } + + /// Calculate the net amount for the order + pub fn calculate_net_amount(&self) -> MinorUnit { + self.order_amount + + self.shipping_cost.unwrap_or(MinorUnit::zero()) + + self.surcharge_amount.unwrap_or(MinorUnit::zero()) + + self.tax_on_surcharge.unwrap_or(MinorUnit::zero()) + } + + pub fn create_attempt_amount_details( + &self, + confirm_intent_request: &api_models::payments::PaymentsConfirmIntentRequest, + ) -> payment_attempt::AttemptAmountDetails { + let net_amount = self.calculate_net_amount(); + + let surcharge_amount = match self.skip_surcharge_calculation { + SurchargeCalculationOverride::Skip => self.surcharge_amount, + SurchargeCalculationOverride::Calculate => None, + }; + + let tax_on_surcharge = match self.skip_surcharge_calculation { + SurchargeCalculationOverride::Skip => self.tax_on_surcharge, + SurchargeCalculationOverride::Calculate => None, + }; + + let order_tax_amount = match self.skip_external_tax_calculation { + TaxCalculationOverride::Skip => self.tax_details.as_ref().and_then(|tax_details| { + tax_details.get_tax_amount(confirm_intent_request.payment_method_subtype) + }), + TaxCalculationOverride::Calculate => None, + }; + + payment_attempt::AttemptAmountDetails { + net_amount, + amount_to_capture: None, + surcharge_amount, + tax_on_surcharge, + // This will be updated when we receive response from the connector + amount_capturable: MinorUnit::zero(), + shipping_cost: self.shipping_cost, + order_tax_amount, + } + } } #[cfg(feature = "v2")] @@ -294,6 +340,23 @@ impl PaymentIntent { }) .unwrap_or(Ok(common_enums::RequestIncrementalAuthorization::default())) } + + /// Check if the client secret is associated with the payment and if it has been expired + pub fn validate_client_secret( + &self, + client_secret: &common_utils::types::ClientSecret, + ) -> Result<(), errors::api_error_response::ApiErrorResponse> { + common_utils::fp_utils::when(self.client_secret != *client_secret, || { + Err(errors::api_error_response::ApiErrorResponse::ClientSecretInvalid) + })?; + + common_utils::fp_utils::when(self.session_expiry < common_utils::date_time::now(), || { + Err(errors::api_error_response::ApiErrorResponse::ClientSecretExpired) + })?; + + Ok(()) + } + pub async fn create_domain_model_from_request( payment_id: &id_type::GlobalPaymentId, merchant_account: &merchant_account::MerchantAccount, @@ -384,6 +447,48 @@ impl PaymentIntent { } } +#[cfg(feature = "v1")] +#[derive(Default, Debug, Clone)] +pub struct HeaderPayload { + pub payment_confirm_source: Option, + pub client_source: Option, + pub client_version: Option, + pub x_hs_latency: Option, + pub browser_name: Option, + pub x_client_platform: Option, + pub x_merchant_domain: Option, + pub locale: Option, + pub x_app_id: Option, + pub x_redirect_uri: Option, +} + +// TODO: uncomment fields as necessary +#[cfg(feature = "v2")] +#[derive(Default, Debug, Clone)] +pub struct HeaderPayload { + /// The source with which the payment is confirmed. + pub payment_confirm_source: Option, + // pub client_source: Option, + // pub client_version: Option, + pub x_hs_latency: Option, + pub browser_name: Option, + pub x_client_platform: Option, + pub x_merchant_domain: Option, + pub locale: Option, + pub x_app_id: Option, + pub x_redirect_uri: Option, + pub client_secret: Option, +} + +impl HeaderPayload { + pub fn with_source(payment_confirm_source: common_enums::PaymentSource) -> Self { + Self { + payment_confirm_source: Some(payment_confirm_source), + ..Default::default() + } + } +} + #[cfg(feature = "v2")] #[derive(Clone)] pub struct PaymentIntentData @@ -393,3 +498,16 @@ where pub flow: PhantomData, pub payment_intent: PaymentIntent, } + +// TODO: Check if this can be merged with existing payment data +#[cfg(feature = "v2")] +#[derive(Clone)] +pub struct PaymentConfirmData +where + F: Clone, +{ + pub flow: PhantomData, + pub payment_intent: PaymentIntent, + pub payment_attempt: PaymentAttempt, + pub payment_method_data: Option, +} diff --git a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs index 8ecac77e54e..76749097b3b 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_attempt.rs @@ -15,6 +15,8 @@ use diesel_models::{ PaymentAttemptUpdate as DieselPaymentAttemptUpdate, }; use error_stack::ResultExt; +#[cfg(feature = "v2")] +use masking::PeekInterface; use masking::Secret; use serde::{Deserialize, Serialize}; use time::PrimitiveDateTime; @@ -56,7 +58,7 @@ pub trait PaymentAttemptInterface { ) -> error_stack::Result; #[cfg(feature = "v2")] - async fn update_payment_attempt_with_attempt_id( + async fn update_payment_attempt( &self, key_manager_state: &KeyManagerState, merchant_key_store: &MerchantKeyStore, @@ -163,66 +165,139 @@ pub trait PaymentAttemptInterface { ) -> error_stack::Result; } +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] +pub struct AttemptAmountDetails { + /// The total amount for this payment attempt. This includes all the surcharge and tax amounts. + pub net_amount: MinorUnit, + /// The amount that has to be captured, + pub amount_to_capture: Option, + /// Surcharge amount for the payment attempt. + /// This is either derived by surcharge rules, or sent by the merchant + pub surcharge_amount: Option, + /// Tax amount for the payment attempt + /// This is either derived by surcharge rules, or sent by the merchant + pub tax_on_surcharge: Option, + /// The total amount that can be captured for this payment attempt. + pub amount_capturable: MinorUnit, + /// Shipping cost for the payment attempt. + pub shipping_cost: Option, + /// Tax amount for the order. + /// This is either derived by calling an external tax processor, or sent by the merchant + pub order_tax_amount: Option, +} + +#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize)] +pub struct ErrorDetails { + /// The error code that was returned by the connector. + /// This is a mandatory field. This is used to lookup the global status map record for unified code and retries + pub code: String, + /// The error message that was returned by the connector. + /// This is a mandatory field. This is used to lookup the global status map record for unified message and retries + pub message: String, + /// The detailed error reason that was returned by the connector. + pub reason: Option, + /// The unified code that is generated by the application based on the global status map record. + /// This can be relied upon for common error code across all connectors + pub unified_code: Option, + /// The unified message that is generated by the application based on the global status map record. + /// This can be relied upon for common error code across all connectors + /// If there is translation available, message will be translated to the requested language + pub unified_message: Option, +} + +/// Domain model for the payment attempt. +/// Few fields which are related are grouped together for better readability and understandability. +/// These fields will be flattened and stored in the database in individual columns #[cfg(feature = "v2")] -#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +#[derive(Clone, Debug, PartialEq, serde::Serialize)] pub struct PaymentAttempt { + /// Payment id for the payment attempt pub payment_id: id_type::GlobalPaymentId, + /// Merchant id for the payment attempt pub merchant_id: id_type::MerchantId, + /// Amount details for the payment attempt + pub amount_details: AttemptAmountDetails, + /// Status of the payment attempt. This is the status that is updated by the connector. + /// The intent status is updated by the AttemptStatus. pub status: storage_enums::AttemptStatus, - pub net_amount: MinorUnit, + /// Name of the connector that was used for the payment attempt. The connector is either decided by + /// either running the routing algorithm or by straight through processing request. + /// This will be updated before calling the connector + // TODO: use connector enum, this should be done in v1 as well as a part of moving to domain types wherever possible pub connector: Option, - pub amount_to_capture: Option, - pub error_message: Option, - pub surcharge_amount: Option, - pub tax_on_surcharge: Option, - pub confirm: bool, - pub authentication_type: Option, - #[serde(with = "common_utils::custom_serde::iso8601")] + /// Error details in case the payment attempt failed + pub error: Option, + /// The authentication type that was requested for the payment attempt. + /// This authentication type maybe decided by step up 3ds or by running the decision engine. + pub authentication_type: storage_enums::AuthenticationType, + /// The time at which the payment attempt was created pub created_at: PrimitiveDateTime, - #[serde(with = "common_utils::custom_serde::iso8601")] + /// The time at which the payment attempt was last modified pub modified_at: PrimitiveDateTime, - #[serde(default, with = "common_utils::custom_serde::iso8601::option")] pub last_synced: Option, + /// The reason for the cancellation of the payment attempt. Some connectors will have strict rules regarding the values this can have + /// Cancellation reason will be validated at the connector level when building the request pub cancellation_reason: Option, - pub browser_info: Option, - pub error_code: Option, + /// Browser information required for 3DS authentication + pub browser_info: Option, + /// Payment token is the token used for temporary use in case the payment method is stored in vault pub payment_token: Option, - pub connector_metadata: Option, + /// Metadata that is returned by the connector. + pub connector_metadata: Option, pub payment_experience: Option, - pub payment_method_data: Option, + /// The insensitive data of the payment method data is stored here + // TODO: evaluate what details should be stored here. Use a domain type instead of serde_json::Value + pub payment_method_data: Option, + /// The result of the routing algorithm. + /// This will store the list of connectors and other related information that was used to route the payment. + // TODO: change this to type instead of serde_json::Value pub routing_result: Option, pub preprocessing_step_id: Option, - pub error_reason: Option, + /// Number of captures that have happened for the payment attempt pub multiple_capture_count: Option, - // reference to the payment at connector side + /// A reference to the payment at connector side. This is returned by the connector pub connector_response_reference_id: Option, - pub amount_capturable: MinorUnit, + /// Whether the payment was updated by postgres or redis pub updated_by: String, - pub authentication_data: Option, - pub encoded_data: Option, + /// The authentication data which is used for external authentication + pub authentication_data: Option, + pub encoded_data: Option>, pub merchant_connector_id: Option, - pub unified_code: Option, - pub unified_message: Option, + /// Whether external 3DS authentication was attempted for this payment. + /// This is based on the configuration of the merchant in the business profile pub external_three_ds_authentication_attempted: Option, + /// The connector that was used for external authentication pub authentication_connector: Option, + /// The foreign key reference to the authentication details pub authentication_id: Option, - pub payment_method_billing_address_id: Option, pub fingerprint_id: Option, pub charge_id: Option, pub client_source: Option, pub client_version: Option, + // TODO: use a type here instead of value pub customer_acceptance: Option, + /// The profile id for the payment attempt. This will be derived from payment intent. pub profile_id: id_type::ProfileId, + /// The organization id for the payment attempt. This will be derived from payment intent. pub organization_id: id_type::OrganizationId, - pub payment_method_type: Option, - pub payment_method_id: Option, + /// Payment method type for the payment attempt + pub payment_method_type: storage_enums::PaymentMethod, + /// Foreig key reference of Payment method id in case the payment instrument was stored + pub payment_method_id: Option, + /// The reference to the payment at the connector side pub connector_payment_id: Option, - pub payment_method_subtype: Option, + /// The payment method subtype for the payment attempt. + pub payment_method_subtype: storage_enums::PaymentMethodType, + /// The authentication type that was applied for the payment attempt. pub authentication_applied: Option, + /// A reference to the payment at connector side. This is returned by the connector pub external_reference_id: Option, - pub shipping_cost: Option, - pub order_tax_amount: Option, - pub id: String, + /// The billing address for the payment method + // TODO: use a type here instead of value + pub payment_method_billing_address: common_utils::crypto::OptionalEncryptableValue, + /// The global identifier for the payment attempt + pub id: id_type::GlobalAttemptId, + /// The connector mandate details which are stored temporarily pub connector_mandate_detail: Option, } @@ -234,7 +309,8 @@ impl PaymentAttempt { #[cfg(feature = "v2")] pub fn get_payment_method(&self) -> Option { - self.payment_method_type + // TODO: check if we can fix this + Some(self.payment_method_type) } #[cfg(feature = "v1")] @@ -244,7 +320,8 @@ impl PaymentAttempt { #[cfg(feature = "v2")] pub fn get_payment_method_type(&self) -> Option { - self.payment_method_subtype + // TODO: check if we can fix this + Some(self.payment_method_subtype) } #[cfg(feature = "v1")] @@ -253,7 +330,7 @@ impl PaymentAttempt { } #[cfg(feature = "v2")] - pub fn get_id(&self) -> &str { + pub fn get_id(&self) -> &id_type::GlobalAttemptId { &self.id } @@ -266,6 +343,71 @@ impl PaymentAttempt { pub fn get_connector_payment_id(&self) -> Option<&str> { self.connector_payment_id.as_deref() } + + /// Construct the domain model from the ConfirmIntentRequest and PaymentIntent + #[cfg(feature = "v2")] + pub async fn create_domain_model( + payment_intent: &super::PaymentIntent, + cell_id: id_type::CellId, + storage_scheme: storage_enums::MerchantStorageScheme, + request: &api_models::payments::PaymentsConfirmIntentRequest, + ) -> CustomResult { + let id = id_type::GlobalAttemptId::generate(&cell_id); + let intent_amount_details = payment_intent.amount_details.clone(); + + let attempt_amount_details = intent_amount_details.create_attempt_amount_details(request); + + let now = common_utils::date_time::now(); + + Ok(Self { + payment_id: payment_intent.id.clone(), + merchant_id: payment_intent.merchant_id.clone(), + amount_details: attempt_amount_details, + status: common_enums::AttemptStatus::Started, + // This will be decided by the routing algorithm and updated in update trackers + // right before calling the connector + connector: None, + authentication_type: payment_intent.authentication_type, + created_at: now, + modified_at: now, + last_synced: None, + cancellation_reason: None, + browser_info: request.browser_info.clone(), + payment_token: None, + connector_metadata: None, + payment_experience: None, + payment_method_data: None, + routing_result: None, + preprocessing_step_id: None, + multiple_capture_count: None, + connector_response_reference_id: None, + updated_by: storage_scheme.to_string(), + authentication_data: None, + encoded_data: None, + merchant_connector_id: None, + external_three_ds_authentication_attempted: None, + authentication_connector: None, + authentication_id: None, + fingerprint_id: None, + charge_id: None, + client_source: None, + client_version: None, + customer_acceptance: None, + profile_id: payment_intent.profile_id.clone(), + organization_id: payment_intent.organization_id.clone(), + payment_method_type: request.payment_method_type, + payment_method_id: None, + connector_payment_id: None, + payment_method_subtype: request.payment_method_subtype, + authentication_applied: None, + external_reference_id: None, + // TODO: encrypt and store this + payment_method_billing_address: None, + error: None, + connector_mandate_detail: None, + id, + }) + } } #[cfg(feature = "v1")] @@ -336,6 +478,7 @@ pub struct PaymentAttempt { pub connector_mandate_detail: Option, } +#[cfg(feature = "v1")] #[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, Default)] pub struct NetAmount { /// The payment amount @@ -350,6 +493,7 @@ pub struct NetAmount { tax_on_surcharge: Option, } +#[cfg(feature = "v1")] impl NetAmount { pub fn new( order_amount: MinorUnit, @@ -511,57 +655,6 @@ pub struct PaymentListFilters { pub authentication_type: Vec, } -#[cfg(feature = "v2")] -#[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PaymentAttemptNew { - pub payment_id: id_type::PaymentId, - pub merchant_id: id_type::MerchantId, - pub status: storage_enums::AttemptStatus, - pub error_message: Option, - pub surcharge_amount: Option, - pub tax_amount: Option, - pub payment_method_id: Option, - pub confirm: bool, - pub authentication_type: Option, - pub created_at: PrimitiveDateTime, - pub modified_at: PrimitiveDateTime, - pub last_synced: Option, - pub cancellation_reason: Option, - pub browser_info: Option, - pub payment_token: Option, - pub error_code: Option, - pub connector_metadata: Option, - pub payment_experience: Option, - pub payment_method_data: Option, - pub straight_through_algorithm: Option, - pub preprocessing_step_id: Option, - pub error_reason: Option, - pub connector_response_reference_id: Option, - pub multiple_capture_count: Option, - pub amount_capturable: MinorUnit, - pub updated_by: String, - pub merchant_connector_id: Option, - pub authentication_data: Option, - pub encoded_data: Option, - pub unified_code: Option, - pub unified_message: Option, - pub net_amount: Option, - pub external_three_ds_authentication_attempted: Option, - pub authentication_connector: Option, - pub authentication_id: Option, - pub fingerprint_id: Option, - pub payment_method_billing_address_id: Option, - pub charge_id: Option, - pub client_source: Option, - pub client_version: Option, - pub customer_acceptance: Option, - pub profile_id: id_type::ProfileId, - pub organization_id: id_type::OrganizationId, - pub card_network: Option, - pub shipping_cost: Option, - pub order_tax_amount: Option, -} - #[cfg(feature = "v1")] #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PaymentAttemptNew { @@ -1185,8 +1278,28 @@ impl PaymentAttemptUpdate { // TODO: Add fields as necessary #[cfg(feature = "v2")] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub enum PaymentAttemptUpdate {} +#[derive(Debug, Clone, Serialize)] +pub enum PaymentAttemptUpdate { + /// Update the payment attempt on confirming the intent, before calling the connector + ConfirmIntent { + status: storage_enums::AttemptStatus, + updated_by: String, + connector: String, + merchant_connector_id: id_type::MerchantConnectorAccountId, + }, + /// Update the payment attempt on confirming the intent, after calling the connector on success response + ConfirmIntentResponse { + status: storage_enums::AttemptStatus, + connector_payment_id: Option, + updated_by: String, + }, + /// Update the payment attempt on confirming the intent, after calling the connector on error response + ConfirmIntentError { + status: storage_enums::AttemptStatus, + error: ErrorDetails, + updated_by: String, + }, +} #[cfg(feature = "v2")] impl ForeignIDRef for PaymentAttempt { @@ -1463,10 +1576,12 @@ impl behaviour::Conversion for PaymentAttempt { type NewDstType = DieselPaymentAttemptNew; async fn convert(self) -> CustomResult { + use common_utils::encryption::Encryption; + let card_network = self .payment_method_data .as_ref() - .and_then(|data| data.as_object()) + .and_then(|data| data.peek().as_object()) .and_then(|card| card.get("card")) .and_then(|data| data.as_object()) .and_then(|card| card.get("card_network")) @@ -1477,38 +1592,29 @@ impl behaviour::Conversion for PaymentAttempt { payment_id, merchant_id, status, - net_amount, - error_message, - surcharge_amount, - tax_on_surcharge, - confirm, + error, + amount_details, authentication_type, created_at, modified_at, last_synced, cancellation_reason, browser_info, - error_code, payment_token, connector_metadata, payment_experience, payment_method_data, routing_result, preprocessing_step_id, - error_reason, multiple_capture_count, connector_response_reference_id, - amount_capturable, updated_by, authentication_data, encoded_data, merchant_connector_id, - unified_code, - unified_message, external_three_ds_authentication_attempted, authentication_connector, authentication_id, - payment_method_billing_address_id, fingerprint_id, charge_id, client_source, @@ -1522,14 +1628,22 @@ impl behaviour::Conversion for PaymentAttempt { authentication_applied, external_reference_id, id, - amount_to_capture, payment_method_id, - shipping_cost, - order_tax_amount, + payment_method_billing_address, connector, connector_mandate_detail, } = self; + let AttemptAmountDetails { + net_amount, + tax_on_surcharge, + surcharge_amount, + order_tax_amount, + shipping_cost, + amount_capturable, + amount_to_capture, + } = amount_details; + let (connector_payment_id, connector_payment_data) = connector_payment_id .map(ConnectorTransactionId::form_id_and_data) .map(|(txn_id, txn_data)| (Some(txn_id), txn_data)) @@ -1540,13 +1654,10 @@ impl behaviour::Conversion for PaymentAttempt { merchant_id, id, status, - error_message, - surcharge_amount, - tax_on_surcharge, + error_message: error.as_ref().map(|details| details.message.clone()), payment_method_id, payment_method_type_v2: payment_method_type, connector_payment_id, - confirm, authentication_type, created_at, modified_at, @@ -1554,14 +1665,14 @@ impl behaviour::Conversion for PaymentAttempt { cancellation_reason, amount_to_capture, browser_info, - error_code, + error_code: error.as_ref().map(|details| details.code.clone()), payment_token, connector_metadata, payment_experience, payment_method_subtype, payment_method_data, preprocessing_step_id, - error_reason, + error_reason: error.as_ref().and_then(|details| details.reason.clone()), multiple_capture_count, connector_response_reference_id, amount_capturable, @@ -1569,14 +1680,17 @@ impl behaviour::Conversion for PaymentAttempt { merchant_connector_id, authentication_data, encoded_data, - unified_code, - unified_message, - net_amount: Some(net_amount), + unified_code: error + .as_ref() + .and_then(|details| details.unified_code.clone()), + unified_message: error + .as_ref() + .and_then(|details| details.unified_message.clone()), + net_amount, external_three_ds_authentication_attempted, authentication_connector, authentication_id, fingerprint_id, - payment_method_billing_address_id, charge_id, client_source, client_version, @@ -1590,66 +1704,95 @@ impl behaviour::Conversion for PaymentAttempt { authentication_applied, external_reference_id, connector, + surcharge_amount, + tax_on_surcharge, + payment_method_billing_address: payment_method_billing_address.map(Encryption::from), connector_payment_data, connector_mandate_detail, }) } async fn convert_back( - _state: &KeyManagerState, + state: &KeyManagerState, storage_model: Self::DstType, - _key: &Secret>, - _key_manager_identifier: keymanager::Identifier, + key: &Secret>, + key_manager_identifier: keymanager::Identifier, ) -> CustomResult where Self: Sized, { + use crate::type_encryption; + async { let connector_payment_id = storage_model .get_optional_connector_transaction_id() .cloned(); + + let amount_details = AttemptAmountDetails { + net_amount: storage_model.net_amount, + tax_on_surcharge: storage_model.tax_on_surcharge, + surcharge_amount: storage_model.surcharge_amount, + order_tax_amount: storage_model.order_tax_amount, + shipping_cost: storage_model.shipping_cost, + amount_capturable: storage_model.amount_capturable, + amount_to_capture: storage_model.amount_to_capture, + }; + + let inner_decrypt = |inner| async { + type_encryption::crypto_operation( + state, + common_utils::type_name!(Self::DstType), + type_encryption::CryptoOperation::DecryptOptional(inner), + key_manager_identifier.clone(), + key.peek(), + ) + .await + .and_then(|val| val.try_into_optionaloperation()) + }; + + let error = storage_model + .error_code + .zip(storage_model.error_message) + .map(|(error_code, error_message)| ErrorDetails { + code: error_code, + message: error_message, + reason: storage_model.error_reason, + unified_code: storage_model.unified_code, + unified_message: storage_model.unified_message, + }); + Ok::>(Self { payment_id: storage_model.payment_id, merchant_id: storage_model.merchant_id, id: storage_model.id, status: storage_model.status, - net_amount: storage_model.net_amount.unwrap_or(MinorUnit::new(0)), - tax_on_surcharge: storage_model.tax_on_surcharge, - error_message: storage_model.error_message, - surcharge_amount: storage_model.surcharge_amount, + amount_details, + error, payment_method_id: storage_model.payment_method_id, payment_method_type: storage_model.payment_method_type_v2, connector_payment_id, - confirm: storage_model.confirm, authentication_type: storage_model.authentication_type, created_at: storage_model.created_at, modified_at: storage_model.modified_at, last_synced: storage_model.last_synced, cancellation_reason: storage_model.cancellation_reason, - amount_to_capture: storage_model.amount_to_capture, browser_info: storage_model.browser_info, - error_code: storage_model.error_code, payment_token: storage_model.payment_token, connector_metadata: storage_model.connector_metadata, payment_experience: storage_model.payment_experience, payment_method_data: storage_model.payment_method_data, routing_result: storage_model.routing_result, preprocessing_step_id: storage_model.preprocessing_step_id, - error_reason: storage_model.error_reason, multiple_capture_count: storage_model.multiple_capture_count, connector_response_reference_id: storage_model.connector_response_reference_id, - amount_capturable: storage_model.amount_capturable, updated_by: storage_model.updated_by, authentication_data: storage_model.authentication_data, encoded_data: storage_model.encoded_data, merchant_connector_id: storage_model.merchant_connector_id, - unified_code: storage_model.unified_code, - unified_message: storage_model.unified_message, external_three_ds_authentication_attempted: storage_model .external_three_ds_authentication_attempted, authentication_connector: storage_model.authentication_connector, authentication_id: storage_model.authentication_id, - payment_method_billing_address_id: storage_model.payment_method_billing_address_id, fingerprint_id: storage_model.fingerprint_id, charge_id: storage_model.charge_id, client_source: storage_model.client_source, @@ -1657,12 +1800,14 @@ impl behaviour::Conversion for PaymentAttempt { customer_acceptance: storage_model.customer_acceptance, profile_id: storage_model.profile_id, organization_id: storage_model.organization_id, - order_tax_amount: storage_model.order_tax_amount, - shipping_cost: storage_model.shipping_cost, payment_method_subtype: storage_model.payment_method_subtype, authentication_applied: storage_model.authentication_applied, external_reference_id: storage_model.external_reference_id, connector: storage_model.connector, + payment_method_billing_address: inner_decrypt( + storage_model.payment_method_billing_address, + ) + .await?, connector_mandate_detail: storage_model.connector_mandate_detail, }) } @@ -1673,25 +1818,30 @@ impl behaviour::Conversion for PaymentAttempt { } async fn construct_new(self) -> CustomResult { + use common_utils::encryption::Encryption; + let card_network = self .payment_method_data .as_ref() - .and_then(|data| data.as_object()) + .and_then(|data| data.peek().as_object()) .and_then(|card| card.get("card")) .and_then(|data| data.as_object()) .and_then(|card| card.get("card_network")) .and_then(|network| network.as_str()) .map(|network| network.to_string()); + let error_details = self.error; + Ok(DieselPaymentAttemptNew { payment_id: self.payment_id, merchant_id: self.merchant_id, status: self.status, - error_message: self.error_message, - surcharge_amount: self.surcharge_amount, - tax_on_surcharge: self.tax_on_surcharge, + error_message: error_details + .as_ref() + .map(|details| details.message.clone()), + surcharge_amount: self.amount_details.surcharge_amount, + tax_on_surcharge: self.amount_details.tax_on_surcharge, payment_method_id: self.payment_method_id, - confirm: self.confirm, authentication_type: self.authentication_type, created_at: self.created_at, modified_at: self.modified_at, @@ -1699,28 +1849,33 @@ impl behaviour::Conversion for PaymentAttempt { cancellation_reason: self.cancellation_reason, browser_info: self.browser_info, payment_token: self.payment_token, - error_code: self.error_code, + error_code: error_details.as_ref().map(|details| details.code.clone()), connector_metadata: self.connector_metadata, payment_experience: self.payment_experience, payment_method_data: self.payment_method_data, preprocessing_step_id: self.preprocessing_step_id, - error_reason: self.error_reason, + error_reason: error_details + .as_ref() + .and_then(|details| details.reason.clone()), connector_response_reference_id: self.connector_response_reference_id, multiple_capture_count: self.multiple_capture_count, - amount_capturable: self.amount_capturable, + amount_capturable: self.amount_details.amount_capturable, updated_by: self.updated_by, merchant_connector_id: self.merchant_connector_id, authentication_data: self.authentication_data, encoded_data: self.encoded_data, - unified_code: self.unified_code, - unified_message: self.unified_message, - net_amount: Some(self.net_amount), + unified_code: error_details + .as_ref() + .and_then(|details| details.unified_code.clone()), + unified_message: error_details + .as_ref() + .and_then(|details| details.unified_message.clone()), + net_amount: self.amount_details.net_amount, external_three_ds_authentication_attempted: self .external_three_ds_authentication_attempted, authentication_connector: self.authentication_connector, authentication_id: self.authentication_id, fingerprint_id: self.fingerprint_id, - payment_method_billing_address_id: self.payment_method_billing_address_id, charge_id: self.charge_id, client_source: self.client_source, client_version: self.client_version, @@ -1728,9 +1883,15 @@ impl behaviour::Conversion for PaymentAttempt { profile_id: self.profile_id, organization_id: self.organization_id, card_network, - order_tax_amount: self.order_tax_amount, - shipping_cost: self.shipping_cost, - amount_to_capture: self.amount_to_capture, + order_tax_amount: self.amount_details.order_tax_amount, + shipping_cost: self.amount_details.shipping_cost, + amount_to_capture: self.amount_details.amount_to_capture, + payment_method_billing_address: self + .payment_method_billing_address + .map(Encryption::from), + payment_method_subtype: self.payment_method_subtype, + payment_method_type_v2: self.payment_method_type, + id: self.id, connector_mandate_detail: self.connector_mandate_detail, }) } @@ -1739,6 +1900,62 @@ impl behaviour::Conversion for PaymentAttempt { #[cfg(feature = "v2")] impl From for diesel_models::PaymentAttemptUpdateInternal { fn from(update: PaymentAttemptUpdate) -> Self { - todo!() + match update { + PaymentAttemptUpdate::ConfirmIntent { + status, + updated_by, + connector, + merchant_connector_id, + } => Self { + status: Some(status), + error_message: None, + modified_at: common_utils::date_time::now(), + browser_info: None, + error_code: None, + error_reason: None, + updated_by, + merchant_connector_id: Some(merchant_connector_id), + unified_code: None, + unified_message: None, + connector_payment_id: None, + connector: Some(connector), + }, + PaymentAttemptUpdate::ConfirmIntentError { + status, + error, + updated_by, + } => Self { + status: Some(status), + error_message: Some(error.message), + error_code: Some(error.code), + modified_at: common_utils::date_time::now(), + browser_info: None, + error_reason: error.reason, + updated_by, + merchant_connector_id: None, + unified_code: None, + unified_message: None, + connector_payment_id: None, + connector: None, + }, + PaymentAttemptUpdate::ConfirmIntentResponse { + status, + connector_payment_id, + updated_by, + } => Self { + status: Some(status), + error_message: None, + error_code: None, + modified_at: common_utils::date_time::now(), + browser_info: None, + error_reason: None, + updated_by, + merchant_connector_id: None, + unified_code: None, + unified_message: None, + connector_payment_id, + connector: None, + }, + } } } diff --git a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs index ebd630beb62..f1e4de499e6 100644 --- a/crates/hyperswitch_domain_models/src/payments/payment_intent.rs +++ b/crates/hyperswitch_domain_models/src/payments/payment_intent.rs @@ -266,76 +266,15 @@ pub enum PaymentIntentUpdate { }, } -// TODO: remove all enum variants and create new variants that should be used for v2 #[cfg(feature = "v2")] #[derive(Debug, Clone, Serialize)] pub enum PaymentIntentUpdate { - ResponseUpdate { - status: storage_enums::IntentStatus, - amount_captured: Option, - return_url: Option, - updated_by: String, - }, - MetadataUpdate { - metadata: pii::SecretSerdeValue, - updated_by: String, - }, - Update(Box), - PaymentCreateUpdate { - return_url: Option, - status: Option, - customer_id: Option, - shipping_address: Option>>, - billing_address: Option>>, - customer_details: Option>>, - updated_by: String, - }, - MerchantStatusUpdate { - status: storage_enums::IntentStatus, - shipping_address: Option>>, - billing_address: Option>>, - updated_by: String, - }, - PGStatusUpdate { + ConfirmIntent { status: storage_enums::IntentStatus, updated_by: String, }, - PaymentAttemptAndAttemptCountUpdate { - active_attempt_id: String, - attempt_count: i16, - updated_by: String, - }, - StatusAndAttemptUpdate { - status: storage_enums::IntentStatus, - active_attempt_id: String, - attempt_count: i16, - updated_by: String, - }, - ApproveUpdate { - status: storage_enums::IntentStatus, - frm_merchant_decision: Option, - updated_by: String, - }, - RejectUpdate { + ConfirmIntentPostUpdate { status: storage_enums::IntentStatus, - frm_merchant_decision: Option, - updated_by: String, - }, - SurchargeApplicableUpdate { - surcharge_applicable: bool, - updated_by: String, - }, - IncrementalAuthorizationAmountUpdate { - amount: MinorUnit, - }, - AuthorizationCountUpdate { - authorization_count: i32, - }, - CompleteAuthorizeUpdate { - shipping_address: Option>>, - }, - ManualUpdate { - status: Option, updated_by: String, }, } @@ -353,7 +292,7 @@ pub struct PaymentIntentUpdateInternal { pub off_session: Option, pub metadata: Option, pub modified_at: Option, - pub active_attempt_id: Option, + pub active_attempt_id: Option, pub description: Option, pub statement_descriptor: Option, pub order_details: Option>, @@ -417,181 +356,22 @@ pub struct PaymentIntentUpdateInternal { pub tax_details: Option, } +// TODO: convert directly to diesel_models::PaymentIntentUpdateInternal #[cfg(feature = "v2")] impl From for PaymentIntentUpdateInternal { fn from(payment_intent_update: PaymentIntentUpdate) -> Self { - todo!() - // match payment_intent_update { - // PaymentIntentUpdate::MetadataUpdate { - // metadata, - // updated_by, - // } => Self { - // metadata: Some(metadata), - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::Update(value) => Self { - // amount: Some(value.amount), - // currency: Some(value.currency), - // setup_future_usage: value.setup_future_usage, - // status: Some(value.status), - // customer_id: value.customer_id, - // return_url: value.return_url, - // description: value.description, - // statement_descriptor: value.statement_descriptor, - // order_details: value.order_details, - // metadata: value.metadata, - // payment_confirm_source: value.payment_confirm_source, - // updated_by: value.updated_by, - // session_expiry: value.session_expiry, - // request_external_three_ds_authentication: value - // .request_external_three_ds_authentication, - // frm_metadata: value.frm_metadata, - // customer_details: value.customer_details, - // billing_address: value.billing_address, - // merchant_order_reference_id: value.merchant_order_reference_id, - // shipping_address: value.shipping_address, - // is_payment_processor_token_flow: value.is_payment_processor_token_flow, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::PaymentCreateUpdate { - // return_url, - // status, - // customer_id, - // shipping_address, - // billing_address, - // customer_details, - // updated_by, - // } => Self { - // return_url, - // status, - // customer_id, - // shipping_address, - // billing_address, - // customer_details, - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::PGStatusUpdate { status, updated_by } => Self { - // status: Some(status), - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::MerchantStatusUpdate { - // status, - // shipping_address, - // billing_address, - // updated_by, - // } => Self { - // status: Some(status), - // shipping_address, - // billing_address, - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::ResponseUpdate { - // // amount, - // // currency, - // status, - // amount_captured, - // // customer_id, - // return_url, - // updated_by, - // } => Self { - // // amount, - // // currency: Some(currency), - // status: Some(status), - // amount_captured, - // // customer_id, - // return_url, - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self { - // active_attempt_id: Some(active_attempt_id), - // attempt_count: Some(attempt_count), - // updated_by, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::StatusAndAttemptUpdate { - // status, - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self { - // status: Some(status), - // active_attempt_id: Some(active_attempt_id), - // attempt_count: Some(attempt_count), - // updated_by, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::ApproveUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self { - // status: Some(status), - // frm_merchant_decision, - // updated_by, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::RejectUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self { - // status: Some(status), - // frm_merchant_decision, - // updated_by, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::SurchargeApplicableUpdate { - // surcharge_applicable, - // updated_by, - // } => Self { - // surcharge_applicable: Some(surcharge_applicable), - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => Self { - // amount: Some(amount), - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::AuthorizationCountUpdate { - // authorization_count, - // } => Self { - // authorization_count: Some(authorization_count), - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::CompleteAuthorizeUpdate { shipping_address } => Self { - // shipping_address, - // modified_at: Some(common_utils::date_time::now()), - // ..Default::default() - // }, - // PaymentIntentUpdate::ManualUpdate { status, updated_by } => Self { - // status, - // modified_at: Some(common_utils::date_time::now()), - // updated_by, - // ..Default::default() - // }, - // } + match payment_intent_update { + PaymentIntentUpdate::ConfirmIntent { status, updated_by } => Self { + status: Some(status), + updated_by, + ..Default::default() + }, + PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => Self { + status: Some(status), + updated_by, + ..Default::default() + }, + } } } @@ -799,144 +579,14 @@ use diesel_models::{ #[cfg(feature = "v2")] impl From for DieselPaymentIntentUpdate { fn from(value: PaymentIntentUpdate) -> Self { - todo!() - // match value { - // PaymentIntentUpdate::ResponseUpdate { - // status, - // amount_captured, - // return_url, - // updated_by, - // } => Self::ResponseUpdate { - // status, - // amount_captured, - // return_url, - // updated_by, - // }, - // PaymentIntentUpdate::MetadataUpdate { - // metadata, - // updated_by, - // } => Self::MetadataUpdate { - // metadata, - // updated_by, - // }, - // PaymentIntentUpdate::Update(value) => { - // Self::Update(Box::new(DieselPaymentIntentUpdateFields { - // amount: value.amount, - // currency: value.currency, - // setup_future_usage: value.setup_future_usage, - // status: value.status, - // customer_id: value.customer_id, - // return_url: value.return_url, - // description: value.description, - // statement_descriptor: value.statement_descriptor, - // order_details: value.order_details, - // metadata: value.metadata, - // payment_confirm_source: value.payment_confirm_source, - // updated_by: value.updated_by, - // session_expiry: value.session_expiry, - // request_external_three_ds_authentication: value - // .request_external_three_ds_authentication, - // frm_metadata: value.frm_metadata, - // customer_details: value.customer_details.map(Encryption::from), - // billing_address: value.billing_address.map(Encryption::from), - // shipping_address: value.shipping_address.map(Encryption::from), - // merchant_order_reference_id: value.merchant_order_reference_id, - // is_payment_processor_token_flow: value.is_payment_processor_token_flow, - // })) - // } - // PaymentIntentUpdate::PaymentCreateUpdate { - // return_url, - // status, - // customer_id, - // shipping_address, - // billing_address, - // customer_details, - // updated_by, - // } => Self::PaymentCreateUpdate { - // return_url, - // status, - // customer_id, - // shipping_address: shipping_address.map(Encryption::from), - // billing_address: billing_address.map(Encryption::from), - // customer_details: customer_details.map(Encryption::from), - // updated_by, - // }, - // PaymentIntentUpdate::MerchantStatusUpdate { - // status, - // shipping_address, - // billing_address, - // updated_by, - // } => Self::MerchantStatusUpdate { - // status, - // shipping_address: shipping_address.map(Encryption::from), - // billing_address: billing_address.map(Encryption::from), - // updated_by, - // }, - // PaymentIntentUpdate::PGStatusUpdate { status, updated_by } => { - // Self::PGStatusUpdate { status, updated_by } - // } - // PaymentIntentUpdate::PaymentAttemptAndAttemptCountUpdate { - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self::PaymentAttemptAndAttemptCountUpdate { - // active_attempt_id, - // attempt_count, - // updated_by, - // }, - // PaymentIntentUpdate::StatusAndAttemptUpdate { - // status, - // active_attempt_id, - // attempt_count, - // updated_by, - // } => Self::StatusAndAttemptUpdate { - // status, - // active_attempt_id, - // attempt_count, - // updated_by, - // }, - // PaymentIntentUpdate::ApproveUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self::ApproveUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // }, - // PaymentIntentUpdate::RejectUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // } => Self::RejectUpdate { - // status, - // frm_merchant_decision, - // updated_by, - // }, - // PaymentIntentUpdate::SurchargeApplicableUpdate { - // surcharge_applicable, - // updated_by, - // } => Self::SurchargeApplicableUpdate { - // surcharge_applicable: Some(surcharge_applicable), - // updated_by, - // }, - // PaymentIntentUpdate::IncrementalAuthorizationAmountUpdate { amount } => { - // Self::IncrementalAuthorizationAmountUpdate { amount } - // } - // PaymentIntentUpdate::AuthorizationCountUpdate { - // authorization_count, - // } => Self::AuthorizationCountUpdate { - // authorization_count, - // }, - // PaymentIntentUpdate::CompleteAuthorizeUpdate { shipping_address } => { - // Self::CompleteAuthorizeUpdate { - // shipping_address: shipping_address.map(Encryption::from), - // } - // } - // PaymentIntentUpdate::ManualUpdate { status, updated_by } => { - // Self::ManualUpdate { status, updated_by } - // } - // } + match value { + PaymentIntentUpdate::ConfirmIntent { status, updated_by } => { + Self::ConfirmIntent { status, updated_by } + } + PaymentIntentUpdate::ConfirmIntentPostUpdate { status, updated_by } => { + Self::ConfirmIntentPostUpdate { status, updated_by } + } + } } } @@ -1621,7 +1271,9 @@ impl behaviour::Conversion for PaymentIntent { skip_surcharge_calculation: super::SurchargeCalculationOverride::from( storage_model.surcharge_applicable, ), + amount_captured: storage_model.amount_captured, }; + let billing_address = data .billing .map(|billing| { diff --git a/crates/hyperswitch_domain_models/src/router_data.rs b/crates/hyperswitch_domain_models/src/router_data.rs index b41b42eaa2d..ba76cc533ca 100644 --- a/crates/hyperswitch_domain_models/src/router_data.rs +++ b/crates/hyperswitch_domain_models/src/router_data.rs @@ -9,7 +9,7 @@ use common_utils::{ use error_stack::ResultExt; use masking::{ExposeInterface, Secret}; -use crate::{payment_address::PaymentAddress, payment_method_data}; +use crate::{payment_address::PaymentAddress, payment_method_data, payments}; #[derive(Debug, Clone)] pub struct RouterData { @@ -83,7 +83,7 @@ pub struct RouterData { pub additional_merchant_data: Option, - pub header_payload: Option, + pub header_payload: Option, } // Different patterns of authentication. diff --git a/crates/hyperswitch_domain_models/src/router_request_types.rs b/crates/hyperswitch_domain_models/src/router_request_types.rs index fb4c0fd0800..d29672058f8 100644 --- a/crates/hyperswitch_domain_models/src/router_request_types.rs +++ b/crates/hyperswitch_domain_models/src/router_request_types.rs @@ -362,7 +362,7 @@ pub struct PaymentsPostProcessingData { pub connector_transaction_id: Option, pub country: Option, pub connector_meta_data: Option, - pub header_payload: Option, + pub header_payload: Option, } impl TryFrom> diff --git a/crates/hyperswitch_interfaces/Cargo.toml b/crates/hyperswitch_interfaces/Cargo.toml index 7ab885de3a3..99a06ff2e3a 100644 --- a/crates/hyperswitch_interfaces/Cargo.toml +++ b/crates/hyperswitch_interfaces/Cargo.toml @@ -9,7 +9,7 @@ license.workspace = true [features] default = ["dummy_connector", "frm", "payouts"] dummy_connector = [] -v1 = ["hyperswitch_domain_models/v1", "api_models/v1"] +v1 = ["hyperswitch_domain_models/v1", "api_models/v1", "common_utils/v1"] payouts = ["hyperswitch_domain_models/payouts"] frm = ["hyperswitch_domain_models/frm"] diff --git a/crates/kgraph_utils/Cargo.toml b/crates/kgraph_utils/Cargo.toml index 0b7b580e647..0883e148691 100644 --- a/crates/kgraph_utils/Cargo.toml +++ b/crates/kgraph_utils/Cargo.toml @@ -8,8 +8,8 @@ license.workspace = true [features] dummy_connector = ["api_models/dummy_connector", "euclid/dummy_connector"] -v1 = ["api_models/v1"] -v2 = ["api_models/v2"] +v1 = ["api_models/v1", "common_utils/v1"] +v2 = ["api_models/v2", "common_utils/v2"] [dependencies] api_models = { version = "0.1.0", path = "../api_models", package = "api_models" } diff --git a/crates/openapi/Cargo.toml b/crates/openapi/Cargo.toml index dac22071c36..26707479b0d 100644 --- a/crates/openapi/Cargo.toml +++ b/crates/openapi/Cargo.toml @@ -16,8 +16,8 @@ common_utils = { version = "0.1.0", path = "../common_utils", features = ["logs" router_env = { version = "0.1.0", path = "../router_env" } [features] -v2 = ["api_models/v2", "api_models/customer_v2"] -v1 = ["api_models/v1"] +v2 = ["api_models/v2", "api_models/customer_v2", "common_utils/v2"] +v1 = ["api_models/v1", "common_utils/v1"] [lints] workspace = true diff --git a/crates/openapi/src/main.rs b/crates/openapi/src/main.rs index 9d58c8b7c0d..975ff33107f 100644 --- a/crates/openapi/src/main.rs +++ b/crates/openapi/src/main.rs @@ -6,6 +6,9 @@ mod routes; #[allow(clippy::print_stdout)] // Using a logger is not necessary here fn main() { + #[cfg(all(feature = "v1", feature = "v2"))] + compile_error!("features v1 and v2 are mutually exclusive, please enable only one of them"); + #[cfg(feature = "v1")] let relative_file_path = "api-reference/openapi_spec.json"; diff --git a/crates/openapi/src/openapi_v2.rs b/crates/openapi/src/openapi_v2.rs index 7c961b2b2b2..0a19c5a63c5 100644 --- a/crates/openapi/src/openapi_v2.rs +++ b/crates/openapi/src/openapi_v2.rs @@ -123,6 +123,7 @@ Never share your secret api keys. Keep them guarded and secure. //Routes for payments routes::payments::payments_create_intent, + routes::payments::payments_confirm_intent, //Routes for refunds routes::refunds::refunds_create, @@ -130,6 +131,7 @@ Never share your secret api keys. Keep them guarded and secure. components(schemas( common_utils::types::MinorUnit, common_utils::types::TimeRange, + common_utils::types::BrowserInformation, common_utils::link_utils::GenericLinkUiConfig, common_utils::link_utils::EnabledPaymentMethod, common_utils::payout_method_utils::AdditionalPayoutMethodData, @@ -315,10 +317,6 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::CardRedirectData, api_models::payments::CardToken, api_models::payments::CustomerAcceptance, - api_models::payments::PaymentsRequest, - api_models::payments::PaymentsCreateRequest, - api_models::payments::PaymentsUpdateRequest, - api_models::payments::PaymentsConfirmRequest, api_models::payments::PaymentsResponse, api_models::payments::PaymentsCreateResponseOpenApi, api_models::payments::PaymentRetrieveBody, @@ -415,13 +413,15 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::ThreeDsCompletionIndicator, api_models::payments::MifinityData, api_models::enums::TransactionStatus, - api_models::payments::BrowserInformation, api_models::payments::PaymentCreatePaymentLinkConfig, api_models::payments::ThreeDsData, api_models::payments::ThreeDsMethodData, api_models::payments::PollConfigResponse, api_models::payments::ExternalAuthenticationDetailsResponse, api_models::payments::ExtendedCardInfo, + api_models::payments::PaymentsConfirmIntentRequest, + api_models::payments::PaymentsConfirmIntentResponse, + api_models::payments::AmountDetailsResponse, api_models::payment_methods::RequiredFieldInfo, api_models::payment_methods::DefaultPaymentMethod, api_models::payment_methods::MaskedBankDetails, @@ -584,6 +584,9 @@ Never share your secret api keys. Keep them guarded and secure. api_models::payments::PaymentsDynamicTaxCalculationRequest, api_models::payments::PaymentsDynamicTaxCalculationResponse, api_models::payments::DisplayAmountOnSdk, + api_models::payments::ErrorDetails, + common_utils::types::BrowserInformation, + api_models::payments::ConfirmIntentAmountDetailsResponse, )), modifiers(&SecurityAddon) )] diff --git a/crates/openapi/src/routes/payments.rs b/crates/openapi/src/routes/payments.rs index b6a81efda09..3429de60ba7 100644 --- a/crates/openapi/src/routes/payments.rs +++ b/crates/openapi/src/routes/payments.rs @@ -405,7 +405,7 @@ pub fn payments_connector_session() {} /// Creates a session object or a session token for wallets like Apple Pay, Google Pay, etc. These tokens are used by Hyperswitch's SDK to initiate these wallets' SDK. #[utoipa::path( post, - path = "/v2/payments/{payment_id}/create_external_sdk_tokens", + path = "/v2/payments/{payment_id}/create-external-sdk-tokens", request_body=PaymentsSessionRequest, responses( (status = 200, description = "Payment session object created or session token was retrieved from wallets", body = PaymentsSessionResponse), @@ -629,3 +629,43 @@ pub fn payments_post_session_tokens() {} )] #[cfg(feature = "v2")] pub fn payments_create_intent() {} + +/// Payments - Confirm Intent +/// +/// **Confirms a payment intent object with the payment method data** +/// +/// . +#[utoipa::path( + post, + path = "/v2/payments/{id}/confirm-intent", + request_body( + content = PaymentsConfirmIntentRequest, + examples( + ( + "Confirm the payment intent with card details" = ( + value = json!({ + "payment_method_type": "card", + "payment_method_data": { + "card": { + "card_number": "4242424242424242", + "card_exp_month": "10", + "card_exp_year": "25", + "card_holder_name": "joseph Doe", + "card_cvc": "123" + } + }, + }) + ) + ), + ), + ), + responses( + (status = 200, description = "Payment created", body = PaymentsConfirmIntentResponse), + (status = 400, description = "Missing Mandatory fields") + ), + tag = "Payments", + operation_id = "Confirm Payment Intent", + security(("publisable_key" = [])), +)] +#[cfg(feature = "v2")] +pub fn payments_confirm_intent() {} diff --git a/crates/pm_auth/Cargo.toml b/crates/pm_auth/Cargo.toml index df8136ba833..3923d44b7fa 100644 --- a/crates/pm_auth/Cargo.toml +++ b/crates/pm_auth/Cargo.toml @@ -8,7 +8,7 @@ readme = "README.md" license.workspace = true [features] -v1 = ["api_models/v1"] +v1 = ["api_models/v1", "common_utils/v1"] [dependencies] # First party crates diff --git a/crates/router/Cargo.toml b/crates/router/Cargo.toml index 849a3beaaf3..b794443a047 100644 --- a/crates/router/Cargo.toml +++ b/crates/router/Cargo.toml @@ -34,7 +34,7 @@ payout_retry = ["payouts"] recon = ["email", "api_models/recon"] retry = [] v2 = ["customer_v2", "payment_methods_v2", "common_default", "api_models/v2", "diesel_models/v2", "hyperswitch_domain_models/v2", "storage_impl/v2", "kgraph_utils/v2", "common_utils/v2"] -v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1", "kgraph_utils/v1"] +v1 = ["common_default", "api_models/v1", "diesel_models/v1", "hyperswitch_domain_models/v1", "storage_impl/v1", "hyperswitch_interfaces/v1", "kgraph_utils/v1", "common_utils/v1"] customer_v2 = ["api_models/customer_v2", "diesel_models/customer_v2", "hyperswitch_domain_models/customer_v2", "storage_impl/customer_v2"] payment_methods_v2 = ["api_models/payment_methods_v2", "diesel_models/payment_methods_v2", "hyperswitch_domain_models/payment_methods_v2", "storage_impl/payment_methods_v2", "common_utils/payment_methods_v2"] dynamic_routing = ["external_services/dynamic_routing", "storage_impl/dynamic_routing"] diff --git a/crates/router/src/compatibility/stripe/payment_intents.rs b/crates/router/src/compatibility/stripe/payment_intents.rs index 901ca3c11c2..e447e9b9535 100644 --- a/crates/router/src/compatibility/stripe/payment_intents.rs +++ b/crates/router/src/compatibility/stripe/payment_intents.rs @@ -91,7 +91,7 @@ pub async fn payment_intents_create( api::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, eligible_connectors, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &auth::HeaderAuth(auth::ApiKeyAuth), @@ -161,7 +161,7 @@ pub async fn payment_intents_retrieve( auth_flow, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -239,7 +239,7 @@ pub async fn payment_intents_retrieve_with_gateway_creds( api::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -315,7 +315,7 @@ pub async fn payment_intents_update( auth_flow, payments::CallConnectorAction::Trigger, eligible_connectors, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -400,7 +400,7 @@ pub async fn payment_intents_confirm( auth_flow, payments::CallConnectorAction::Trigger, eligible_connectors, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -471,7 +471,7 @@ pub async fn payment_intents_capture( api::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &auth::HeaderAuth(auth::ApiKeyAuth), @@ -546,7 +546,7 @@ pub async fn payment_intents_cancel( auth_flow, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, diff --git a/crates/router/src/compatibility/stripe/setup_intents.rs b/crates/router/src/compatibility/stripe/setup_intents.rs index e5e68fb4a85..66b43e4ebe9 100644 --- a/crates/router/src/compatibility/stripe/setup_intents.rs +++ b/crates/router/src/compatibility/stripe/setup_intents.rs @@ -77,7 +77,7 @@ pub async fn setup_intents_create( api::AuthFlow::Merchant, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &auth::HeaderAuth(auth::ApiKeyAuth), @@ -147,7 +147,7 @@ pub async fn setup_intents_retrieve( auth_flow, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -223,7 +223,7 @@ pub async fn setup_intents_update( auth_flow, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, @@ -300,7 +300,7 @@ pub async fn setup_intents_confirm( auth_flow, payments::CallConnectorAction::Trigger, None, - api_types::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), ) }, &*auth_type, diff --git a/crates/router/src/connector/utils.rs b/crates/router/src/connector/utils.rs index ac99fb4b524..9e9e43734db 100644 --- a/crates/router/src/connector/utils.rs +++ b/crates/router/src/connector/utils.rs @@ -2435,31 +2435,13 @@ impl FraudCheckRecordReturnRequest for fraud_check::FraudCheckRecordReturnData { } } -pub trait AccessPaymentAttemptInfo { - fn get_browser_info( - &self, - ) -> Result, error_stack::Report>; -} - -impl AccessPaymentAttemptInfo for PaymentAttempt { - fn get_browser_info( - &self, - ) -> Result, error_stack::Report> { - self.browser_info - .clone() - .map(|b| b.parse_value("BrowserInformation")) - .transpose() - .change_context(ApiErrorResponse::InvalidDataValue { - field_name: "browser_info", - }) - } -} - +#[cfg(feature = "v1")] pub trait PaymentsAttemptData { fn get_browser_info(&self) -> Result>; } +#[cfg(feature = "v1")] impl PaymentsAttemptData for PaymentAttempt { fn get_browser_info( &self, diff --git a/crates/router/src/core/fraud_check/flows/checkout_flow.rs b/crates/router/src/core/fraud_check/flows/checkout_flow.rs index 64c8694a5bf..87e76b2c5fb 100644 --- a/crates/router/src/core/fraud_check/flows/checkout_flow.rs +++ b/crates/router/src/core/fraud_check/flows/checkout_flow.rs @@ -5,7 +5,6 @@ use masking::ExposeInterface; use super::{ConstructFlowSpecificData, FeatureFrm}; use crate::{ - connector::utils::PaymentsAttemptData, core::{ errors::{ConnectorErrorExt, RouterResult}, fraud_check::types::FrmData, @@ -39,7 +38,7 @@ impl ConstructFlowSpecificData, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult> { todo!() @@ -55,9 +54,11 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult> { + use crate::connector::utils::PaymentsAttemptData; + let status = storage_enums::AttemptStatus::Pending; let auth_type: ConnectorAuthType = merchant_connector_account diff --git a/crates/router/src/core/fraud_check/flows/record_return.rs b/crates/router/src/core/fraud_check/flows/record_return.rs index 1c55bffeb87..f80f604daa4 100644 --- a/crates/router/src/core/fraud_check/flows/record_return.rs +++ b/crates/router/src/core/fraud_check/flows/record_return.rs @@ -36,7 +36,7 @@ impl ConstructFlowSpecificData, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult> { todo!() @@ -52,7 +52,7 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult> { let status = storage_enums::AttemptStatus::Pending; diff --git a/crates/router/src/core/fraud_check/flows/sale_flow.rs b/crates/router/src/core/fraud_check/flows/sale_flow.rs index 9a1899df429..23c0e05fd50 100644 --- a/crates/router/src/core/fraud_check/flows/sale_flow.rs +++ b/crates/router/src/core/fraud_check/flows/sale_flow.rs @@ -34,7 +34,7 @@ impl ConstructFlowSpecificData, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult> { todo!() } @@ -49,7 +49,7 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult> { let status = storage_enums::AttemptStatus::Pending; diff --git a/crates/router/src/core/fraud_check/flows/transaction_flow.rs b/crates/router/src/core/fraud_check/flows/transaction_flow.rs index 68db6423e06..d1c26a32f98 100644 --- a/crates/router/src/core/fraud_check/flows/transaction_flow.rs +++ b/crates/router/src/core/fraud_check/flows/transaction_flow.rs @@ -39,7 +39,7 @@ impl _customer: &Option, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult< RouterData, > { @@ -56,7 +56,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult< RouterData, > { diff --git a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs index 8a9a91fb1e7..deb4a3621ff 100644 --- a/crates/router/src/core/fraud_check/operation/fraud_check_post.rs +++ b/crates/router/src/core/fraud_check/operation/fraud_check_post.rs @@ -1,9 +1,8 @@ -use api_models::payments::HeaderPayload; use async_trait::async_trait; use common_enums::{CaptureMethod, FrmSuggestion}; use common_utils::ext_traits::Encode; use hyperswitch_domain_models::payments::{ - payment_attempt::PaymentAttemptUpdate, payment_intent::PaymentIntentUpdate, + payment_attempt::PaymentAttemptUpdate, payment_intent::PaymentIntentUpdate, HeaderPayload, }; use router_env::{instrument, logger, tracing}; diff --git a/crates/router/src/core/payment_methods/cards.rs b/crates/router/src/core/payment_methods/cards.rs index 8419a600f39..da1c70ebcfc 100644 --- a/crates/router/src/core/payment_methods/cards.rs +++ b/crates/router/src/core/payment_methods/cards.rs @@ -3774,6 +3774,7 @@ async fn validate_payment_method_and_client_secret( Ok(()) } +#[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] pub async fn call_surcharge_decision_management( state: routes::SessionState, @@ -3834,6 +3835,7 @@ pub async fn call_surcharge_decision_management( Ok(merchant_sucharge_configs) } +#[cfg(feature = "v1")] pub async fn call_surcharge_decision_management_for_saved_card( state: &routes::SessionState, merchant_account: &domain::MerchantAccount, diff --git a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs index 7de4f15adba..ca1cdf06768 100644 --- a/crates/router/src/core/payment_methods/surcharge_decision_configs.rs +++ b/crates/router/src/core/payment_methods/surcharge_decision_configs.rs @@ -375,7 +375,9 @@ pub async fn perform_surcharge_decision_management_for_saved_cards( payment_intent: &storage::PaymentIntent, customer_payment_method_list: &mut [api_models::payment_methods::CustomerPaymentMethod], ) -> ConditionalConfigResult { - let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.id.clone()); + // let mut surcharge_metadata = types::SurchargeMetadata::new(payment_attempt.id.clone()); + let mut surcharge_metadata = todo!(); + let surcharge_source = match ( payment_attempt.get_surcharge_details(), algorithm_ref.surcharge_config_algo_id, diff --git a/crates/router/src/core/payments.rs b/crates/router/src/core/payments.rs index fd45c475b6d..2218197743a 100644 --- a/crates/router/src/core/payments.rs +++ b/crates/router/src/core/payments.rs @@ -22,7 +22,7 @@ use api_models::admin::MerchantConnectorInfo; use api_models::{ self, enums, mandates::RecurringDetails, - payments::{self as payments_api, HeaderPayload}, + payments::{self as payments_api}, }; pub use common_enums::enums::CallConnectorAction; use common_utils::{ @@ -36,10 +36,11 @@ use events::EventInfo; use futures::future::join_all; use helpers::{decrypt_paze_token, ApplePayData}; #[cfg(feature = "v2")] -use hyperswitch_domain_models::payments::PaymentIntentData; +use hyperswitch_domain_models::payments::{PaymentConfirmData, PaymentIntentData}; pub use hyperswitch_domain_models::{ mandates::{CustomerAcceptance, MandateData}, payment_address::PaymentAddress, + payments::HeaderPayload, router_data::{PaymentMethodToken, RouterData}, router_request_types::CustomerDetails, }; @@ -105,6 +106,140 @@ use crate::{ types::{api::authentication, BrowserInformation}, }; +#[cfg(feature = "v2")] +#[allow(clippy::too_many_arguments, clippy::type_complexity)] +#[instrument(skip_all, fields(payment_id, merchant_id))] +pub async fn payments_operation_core( + state: &SessionState, + req_state: ReqState, + merchant_account: domain::MerchantAccount, + key_store: domain::MerchantKeyStore, + profile: domain::Profile, + operation: Op, + req: Req, + payment_id: id_type::GlobalPaymentId, + call_connector_action: CallConnectorAction, + header_payload: HeaderPayload, +) -> RouterResult<(D, Req, Option, Option, Option)> +where + F: Send + Clone + Sync, + Req: Send + Sync, + Op: Operation + Send + Sync, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, + + // To create connector flow specific interface data + D: ConstructFlowSpecificData, + RouterData: Feature, + + // To construct connector flow specific api + dyn api::Connector: + services::api::ConnectorIntegration, + + // To perform router related operation for PaymentResponse + PaymentResponse: Operation, + FData: Send + Sync + Clone, +{ + let operation: BoxedOperation<'_, F, Req, D> = Box::new(operation); + + let (operation, validate_result) = operation + .to_validate_request()? + .validate_request(&req, &merchant_account)?; + + let operations::GetTrackerResponse { + operation, + mut payment_data, + } = operation + .to_get_tracker()? + .get_trackers( + state, + &payment_id, + &req, + &merchant_account, + &profile, + &key_store, + &header_payload, + ) + .await?; + + let (_operation, customer) = operation + .to_domain()? + .get_customer_details( + state, + &mut payment_data, + &key_store, + merchant_account.storage_scheme, + ) + .await + .to_not_found_response(errors::ApiErrorResponse::CustomerNotFound) + .attach_printable("Failed while fetching/creating customer")?; + + let connector = get_connector_choice( + &operation, + state, + &req, + &merchant_account, + &profile, + &key_store, + &mut payment_data, + None, + None, + ) + .await?; + + // TODO: do not use if let + let payment_data = if let Some(connector_call_type) = connector { + match connector_call_type { + ConnectorCallType::PreDetermined(connector_data) => { + let (router_data, mca) = call_connector_service( + state, + req_state.clone(), + &merchant_account, + &key_store, + connector_data.clone(), + &operation, + &mut payment_data, + &customer, + call_connector_action.clone(), + &validate_result, + None, + header_payload.clone(), + #[cfg(feature = "frm")] + None, + #[cfg(not(feature = "frm"))] + None, + &profile, + false, + ) + .await?; + + let payments_response_operation = Box::new(PaymentResponse); + + payments_response_operation + .to_post_update_tracker()? + .update_tracker( + state, + payment_data, + router_data, + &key_store, + merchant_account.storage_scheme, + &header_payload.locale, + #[cfg(all(feature = "dynamic_routing", feature = "v1"))] + routable_connectors, + #[cfg(all(feature = "dynamic_routing", feature = "v1"))] + &business_profile, + ) + .await? + } + ConnectorCallType::Retryable(vec) => todo!(), + ConnectorCallType::SessionMultiple(vec) => todo!(), + } + } else { + todo!() + }; + + Ok((payment_data, req, customer, None, None)) +} + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments, clippy::type_complexity)] #[instrument(skip_all, fields(payment_id, merchant_id))] @@ -366,7 +501,6 @@ where .to_post_update_tracker()? .update_tracker( state, - &validate_result.payment_id, payment_data, router_data, &key_store, @@ -504,7 +638,6 @@ where .to_post_update_tracker()? .update_tracker( state, - &validate_result.payment_id, payment_data, router_data, &key_store, @@ -822,7 +955,6 @@ where .to_post_update_tracker()? .update_tracker( state, - &validate_result.payment_id, payment_data, router_data, &key_store, @@ -885,7 +1017,6 @@ pub async fn payments_intent_operation_core( key_store: domain::MerchantKeyStore, operation: Op, req: Req, - auth_flow: services::AuthFlow, header_payload: HeaderPayload, ) -> RouterResult<(D, Req, Option)> where @@ -918,7 +1049,6 @@ where &merchant_account, &profile, &key_store, - auth_flow, &header_payload, ) .await?; @@ -1319,7 +1449,6 @@ pub async fn payments_intent_core( key_store: domain::MerchantKeyStore, operation: Op, req: Req, - auth_flow: services::AuthFlow, header_payload: HeaderPayload, ) -> RouterResponse where @@ -1337,7 +1466,6 @@ where key_store, operation.clone(), req, - auth_flow, header_payload.clone(), ) .await?; @@ -1345,7 +1473,6 @@ where Res::generate_response( payment_data, customer, - auth_flow, &state.base_url, operation, &state.conf.connector_request_reference_id_config, @@ -1355,6 +1482,66 @@ where ) } +#[cfg(feature = "v2")] +#[allow(clippy::too_many_arguments)] +pub async fn payments_core( + state: SessionState, + req_state: ReqState, + merchant_account: domain::MerchantAccount, + profile: domain::Profile, + key_store: domain::MerchantKeyStore, + operation: Op, + req: Req, + payment_id: id_type::GlobalPaymentId, + call_connector_action: CallConnectorAction, + header_payload: HeaderPayload, +) -> RouterResponse +where + F: Send + Clone + Sync, + Req: Send + Sync, + FData: Send + Sync + Clone, + Op: Operation + Send + Sync + Clone, + Req: Debug, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, + Res: transformers::ToResponse, + // To create connector flow specific interface data + D: ConstructFlowSpecificData, + RouterData: Feature, + + // To construct connector flow specific api + dyn api::Connector: + services::api::ConnectorIntegration, + + // To perform router related operation for PaymentResponse + PaymentResponse: Operation, +{ + let (payment_data, _req, customer, connector_http_status_code, external_latency) = + payments_operation_core::<_, _, _, _, _>( + &state, + req_state, + merchant_account, + key_store, + profile, + operation.clone(), + req, + payment_id, + call_connector_action, + header_payload.clone(), + ) + .await?; + + Res::generate_response( + payment_data, + customer, + &state.base_url, + operation, + &state.conf.connector_request_reference_id_config, + connector_http_status_code, + external_latency, + header_payload.x_hs_latency, + ) +} + fn is_start_pay(operation: &Op) -> bool { format!("{operation:?}").eq("PaymentStart") } @@ -2679,32 +2866,6 @@ where Ok(payment_data) } -#[cfg(feature = "v2")] -pub async fn call_create_connector_customer_if_required( - _state: &SessionState, - _customer: &Option, - _merchant_account: &domain::MerchantAccount, - _key_store: &domain::MerchantKeyStore, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, - _payment_data: &mut D, -) -> RouterResult> -where - F: Send + Clone + Sync, - Req: Send + Sync, - - // To create connector flow specific interface data - D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, - D: ConstructFlowSpecificData, - RouterData: Feature + Send, - - // To construct connector flow specific api - dyn api::Connector: - services::api::ConnectorIntegration, -{ - todo!() -} - -#[cfg(feature = "v1")] pub async fn call_create_connector_customer_if_required( state: &SessionState, customer: &Option, @@ -3338,7 +3499,7 @@ pub enum TokenizationAction { pub async fn get_connector_tokenization_action_when_confirm_true( _state: &SessionState, _operation: &BoxedOperation<'_, F, Req, D>, - _payment_data: &mut D, + payment_data: &mut D, _validate_result: &operations::ValidateResult, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_key_store: &domain::MerchantKeyStore, @@ -3349,7 +3510,9 @@ where F: Send + Clone, D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, { - todo!() + // TODO: Implement this function + let payment_data = payment_data.to_owned(); + Ok((payment_data, TokenizationAction::SkipConnectorTokenization)) } #[cfg(feature = "v1")] @@ -4060,6 +4223,7 @@ pub async fn get_aggregates_for_payments( )) } +#[cfg(feature = "v1")] pub async fn add_process_sync_task( db: &dyn StorageInterface, payment_attempt: &storage::PaymentAttempt, @@ -4094,6 +4258,16 @@ pub async fn add_process_sync_task( Ok(()) } +#[cfg(feature = "v2")] +pub async fn reset_process_sync_task( + db: &dyn StorageInterface, + payment_attempt: &storage::PaymentAttempt, + schedule_time: time::PrimitiveDateTime, +) -> Result<(), errors::ProcessTrackerError> { + todo!() +} + +#[cfg(feature = "v1")] pub async fn reset_process_sync_task( db: &dyn StorageInterface, payment_attempt: &storage::PaymentAttempt, @@ -4136,6 +4310,53 @@ where Ok(()) } +#[cfg(feature = "v2")] +#[allow(clippy::too_many_arguments)] +pub async fn get_connector_choice( + operation: &BoxedOperation<'_, F, Req, D>, + state: &SessionState, + req: &Req, + merchant_account: &domain::MerchantAccount, + business_profile: &domain::Profile, + key_store: &domain::MerchantKeyStore, + payment_data: &mut D, + eligible_connectors: Option>, + mandate_type: Option, +) -> RouterResult> +where + F: Send + Clone, + D: OperationSessionGetters + OperationSessionSetters + Send + Sync + Clone, +{ + // Currently rule based routing and other routing features are not implemented for v2 + // So we are using the default fallback connector for now + // Eligibility analysis is not yet implemented + + let fallback_config = super::admin::ProfileWrapper::new(business_profile.clone()) + .get_default_fallback_list_of_connector_under_profile() + .change_context(errors::RoutingError::FallbackConfigFetchFailed) + .change_context(errors::ApiErrorResponse::InternalServerError)?; + + let first_chosen_connector = fallback_config + .first() + .ok_or(errors::ApiErrorResponse::IncorrectPaymentMethodConfiguration)?; + + let connector_name = first_chosen_connector.connector.to_string(); + let merchant_connector_id = first_chosen_connector + .merchant_connector_id + .clone() + .get_required_value("merchant_connector_id")?; + + payment_data.set_connector_in_payment_attempt(Some(connector_name.to_string())); + let connector_data = api::ConnectorData::get_connector_by_name( + &state.conf.connectors, + &connector_name, + api::GetToken::Connector, + Some(merchant_connector_id), + )?; + + Ok(Some(ConnectorCallType::PreDetermined(connector_data))) +} + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] pub async fn get_connector_choice( @@ -6096,6 +6317,7 @@ impl OperationSessionGetters for PaymentData { } } +#[cfg(feature = "v1")] impl OperationSessionSetters for PaymentData { // Setters Implementation fn set_payment_intent(&mut self, payment_intent: storage::PaymentIntent) { @@ -6367,7 +6589,7 @@ impl OperationSessionSetters for PaymentIntentData { fn set_merchant_connector_id_in_attempt( &mut self, - _merchant_connector_id: Option, + merchant_connector_id: Option, ) { todo!() } @@ -6410,3 +6632,213 @@ impl OperationSessionSetters for PaymentIntentData { todo!() } } + +#[cfg(feature = "v2")] +impl OperationSessionGetters for PaymentConfirmData { + fn get_payment_attempt(&self) -> &storage::PaymentAttempt { + &self.payment_attempt + } + + fn get_payment_intent(&self) -> &storage::PaymentIntent { + &self.payment_intent + } + + fn get_payment_method_info(&self) -> Option<&domain::PaymentMethod> { + todo!() + } + + fn get_mandate_id(&self) -> Option<&payments_api::MandateIds> { + todo!() + } + + // what is this address find out and not required remove this + fn get_address(&self) -> &PaymentAddress { + todo!() + } + + fn get_creds_identifier(&self) -> Option<&str> { + None + } + + fn get_token(&self) -> Option<&str> { + todo!() + } + + fn get_multiple_capture_data(&self) -> Option<&types::MultipleCaptureData> { + todo!() + } + + fn get_payment_link_data(&self) -> Option { + todo!() + } + + fn get_ephemeral_key(&self) -> Option { + todo!() + } + + fn get_setup_mandate(&self) -> Option<&MandateData> { + todo!() + } + + fn get_poll_config(&self) -> Option { + todo!() + } + + fn get_authentication(&self) -> Option<&storage::Authentication> { + todo!() + } + + fn get_frm_message(&self) -> Option { + todo!() + } + + fn get_refunds(&self) -> Vec { + todo!() + } + + fn get_disputes(&self) -> Vec { + todo!() + } + + fn get_authorizations(&self) -> Vec { + todo!() + } + + fn get_attempts(&self) -> Option> { + todo!() + } + + fn get_recurring_details(&self) -> Option<&RecurringDetails> { + todo!() + } + + fn get_payment_intent_profile_id(&self) -> Option<&id_type::ProfileId> { + Some(&self.payment_intent.profile_id) + } + + fn get_currency(&self) -> storage_enums::Currency { + self.payment_intent.amount_details.currency + } + + fn get_amount(&self) -> api::Amount { + todo!() + } + + fn get_payment_attempt_connector(&self) -> Option<&str> { + todo!() + } + + fn get_billing_address(&self) -> Option { + todo!() + } + + fn get_payment_method_data(&self) -> Option<&domain::PaymentMethodData> { + self.payment_method_data.as_ref() + } + + fn get_sessions_token(&self) -> Vec { + todo!() + } + + fn get_token_data(&self) -> Option<&storage::PaymentTokenData> { + todo!() + } + + fn get_mandate_connector(&self) -> Option<&MandateConnectorDetails> { + todo!() + } + + fn get_force_sync(&self) -> Option { + todo!() + } + + fn get_capture_method(&self) -> Option { + todo!() + } +} + +#[cfg(feature = "v2")] +impl OperationSessionSetters for PaymentConfirmData { + // Setters Implementation + fn set_payment_intent(&mut self, payment_intent: storage::PaymentIntent) { + self.payment_intent = payment_intent; + } + + fn set_payment_attempt(&mut self, payment_attempt: storage::PaymentAttempt) { + self.payment_attempt = payment_attempt; + } + + fn set_payment_method_data(&mut self, _payment_method_data: Option) { + todo!() + } + + fn set_payment_method_id_in_attempt(&mut self, _payment_method_id: Option) { + todo!() + } + + fn set_email_if_not_present(&mut self, _email: pii::Email) { + todo!() + } + + fn set_pm_token(&mut self, _token: String) { + todo!() + } + + fn set_connector_customer_id(&mut self, _customer_id: Option) { + // TODO: handle this case. Should we add connector_customer_id in paymentConfirmData? + } + + fn push_sessions_token(&mut self, _token: api::SessionToken) { + todo!() + } + + fn set_surcharge_details(&mut self, _surcharge_details: Option) { + todo!() + } + + #[track_caller] + fn set_merchant_connector_id_in_attempt( + &mut self, + merchant_connector_id: Option, + ) { + self.payment_attempt.merchant_connector_id = merchant_connector_id; + } + + fn set_frm_message(&mut self, _frm_message: FraudCheck) { + todo!() + } + + fn set_payment_intent_status(&mut self, status: storage_enums::IntentStatus) { + self.payment_intent.status = status; + } + + fn set_authentication_type_in_attempt( + &mut self, + _authentication_type: Option, + ) { + todo!() + } + + fn set_recurring_mandate_payment_data( + &mut self, + _recurring_mandate_payment_data: + hyperswitch_domain_models::router_data::RecurringMandatePaymentData, + ) { + todo!() + } + + fn set_mandate_id(&mut self, _mandate_id: api_models::payments::MandateIds) { + todo!() + } + + fn set_setup_future_usage_in_payment_intent( + &mut self, + setup_future_usage: storage_enums::FutureUsage, + ) { + self.payment_intent.setup_future_usage = setup_future_usage; + } + + fn set_connector_in_payment_attempt(&mut self, connector: Option) { + self.payment_attempt.connector = connector; + } +} diff --git a/crates/router/src/core/payments/flows.rs b/crates/router/src/core/payments/flows.rs index 3078cf72256..8c84f7ab9a6 100644 --- a/crates/router/src/core/payments/flows.rs +++ b/crates/router/src/core/payments/flows.rs @@ -39,7 +39,7 @@ pub trait ConstructFlowSpecificData { customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult>; #[cfg(all(feature = "v2", feature = "customer_v2"))] @@ -52,7 +52,7 @@ pub trait ConstructFlowSpecificData { _customer: &Option, _merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult>; async fn get_merchant_recipient_data<'a>( @@ -75,7 +75,7 @@ pub trait Feature { call_connector_action: payments::CallConnectorAction, connector_request: Option, business_profile: &domain::Profile, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult where Self: Sized, diff --git a/crates/router/src/core/payments/flows/approve_flow.rs b/crates/router/src/core/payments/flows/approve_flow.rs index c91de9eb3a7..98d204d5264 100644 --- a/crates/router/src/core/payments/flows/approve_flow.rs +++ b/crates/router/src/core/payments/flows/approve_flow.rs @@ -25,7 +25,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::Approve, @@ -67,7 +67,7 @@ impl Feature _call_connector_action: payments::CallConnectorAction, _connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { Err(ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("Flow not supported".to_string()), diff --git a/crates/router/src/core/payments/flows/authorize_flow.rs b/crates/router/src/core/payments/flows/authorize_flow.rs index 03b2a3153ea..09a6fb51924 100644 --- a/crates/router/src/core/payments/flows/authorize_flow.rs +++ b/crates/router/src/core/payments/flows/authorize_flow.rs @@ -1,5 +1,7 @@ use async_trait::async_trait; use common_enums as enums; +#[cfg(feature = "v2")] +use hyperswitch_domain_models::payments::PaymentConfirmData; use router_env::metrics::add_attributes; // use router_env::tracing::Instrument; @@ -20,6 +22,77 @@ use crate::{ utils::OptionExt, }; +#[cfg(feature = "v2")] +#[async_trait] +impl + ConstructFlowSpecificData< + api::Authorize, + types::PaymentsAuthorizeData, + types::PaymentsResponseData, + > for PaymentConfirmData +{ + async fn construct_router_data<'a>( + &self, + state: &SessionState, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + customer: &Option, + merchant_connector_account: &helpers::MerchantConnectorAccountType, + merchant_recipient_data: Option, + header_payload: Option, + ) -> RouterResult< + types::RouterData< + api::Authorize, + types::PaymentsAuthorizeData, + types::PaymentsResponseData, + >, + > { + Box::pin(transformers::construct_payment_router_data_for_authorize( + state, + self.clone(), + connector_id, + merchant_account, + key_store, + customer, + merchant_connector_account, + merchant_recipient_data, + header_payload, + )) + .await + } + + async fn get_merchant_recipient_data<'a>( + &self, + state: &SessionState, + merchant_account: &domain::MerchantAccount, + key_store: &domain::MerchantKeyStore, + merchant_connector_account: &helpers::MerchantConnectorAccountType, + connector: &api::ConnectorData, + ) -> RouterResult> { + let payment_method = &self + .payment_attempt + .get_payment_method() + .get_required_value("PaymentMethod")?; + + let data = if *payment_method == enums::PaymentMethod::OpenBanking { + payments::get_merchant_bank_data_for_open_banking_connectors( + merchant_connector_account, + key_store, + connector, + state, + merchant_account, + ) + .await? + } else { + None + }; + + Ok(data) + } +} + +#[cfg(feature = "v1")] #[async_trait] impl ConstructFlowSpecificData< @@ -37,7 +110,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult< types::RouterData< api::Authorize, @@ -91,6 +164,7 @@ impl Ok(data) } } + #[async_trait] impl Feature for types::PaymentsAuthorizeRouterData { async fn decide_flows<'a>( @@ -100,7 +174,7 @@ impl Feature for types::PaymentsAu call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::Authorize, diff --git a/crates/router/src/core/payments/flows/cancel_flow.rs b/crates/router/src/core/payments/flows/cancel_flow.rs index 1f212cc631b..9c5bc84a621 100644 --- a/crates/router/src/core/payments/flows/cancel_flow.rs +++ b/crates/router/src/core/payments/flows/cancel_flow.rs @@ -25,7 +25,7 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::Void, @@ -67,7 +67,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { metrics::PAYMENT_CANCEL_COUNT.add( &metrics::CONTEXT, diff --git a/crates/router/src/core/payments/flows/capture_flow.rs b/crates/router/src/core/payments/flows/capture_flow.rs index 8f326aa1bcf..aaa245a341f 100644 --- a/crates/router/src/core/payments/flows/capture_flow.rs +++ b/crates/router/src/core/payments/flows/capture_flow.rs @@ -25,7 +25,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::Capture, @@ -67,7 +67,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::Capture, diff --git a/crates/router/src/core/payments/flows/complete_authorize_flow.rs b/crates/router/src/core/payments/flows/complete_authorize_flow.rs index 0e27e4f37ad..24f6d8d0754 100644 --- a/crates/router/src/core/payments/flows/complete_authorize_flow.rs +++ b/crates/router/src/core/payments/flows/complete_authorize_flow.rs @@ -29,7 +29,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult< types::RouterData< api::CompleteAuthorize, @@ -81,7 +81,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::CompleteAuthorize, diff --git a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs index 7a3f9f0ac44..a187146903e 100644 --- a/crates/router/src/core/payments/flows/incremental_authorization_flow.rs +++ b/crates/router/src/core/payments/flows/incremental_authorization_flow.rs @@ -28,7 +28,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::IncrementalAuthorization, @@ -74,7 +74,7 @@ impl Feature, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::IncrementalAuthorization, diff --git a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs index fe83090d795..13738480c90 100644 --- a/crates/router/src/core/payments/flows/post_session_tokens_flow.rs +++ b/crates/router/src/core/payments/flows/post_session_tokens_flow.rs @@ -28,7 +28,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::PostSessionTokens, @@ -74,7 +74,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::PostSessionTokens, diff --git a/crates/router/src/core/payments/flows/psync_flow.rs b/crates/router/src/core/payments/flows/psync_flow.rs index 2bb8fc19083..34ebfdf4bad 100644 --- a/crates/router/src/core/payments/flows/psync_flow.rs +++ b/crates/router/src/core/payments/flows/psync_flow.rs @@ -26,7 +26,7 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult< types::RouterData, > { @@ -70,7 +70,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::PSync, diff --git a/crates/router/src/core/payments/flows/reject_flow.rs b/crates/router/src/core/payments/flows/reject_flow.rs index 3dc4783d37e..43163c1374b 100644 --- a/crates/router/src/core/payments/flows/reject_flow.rs +++ b/crates/router/src/core/payments/flows/reject_flow.rs @@ -24,7 +24,7 @@ impl ConstructFlowSpecificData, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::Reject, @@ -66,7 +66,7 @@ impl Feature _call_connector_action: payments::CallConnectorAction, _connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { Err(ApiErrorResponse::NotImplemented { message: NotImplementedMessage::Reason("Flow not supported".to_string()), diff --git a/crates/router/src/core/payments/flows/session_flow.rs b/crates/router/src/core/payments/flows/session_flow.rs index 31027bc8c52..736ffdd7b8b 100644 --- a/crates/router/src/core/payments/flows/session_flow.rs +++ b/crates/router/src/core/payments/flows/session_flow.rs @@ -40,7 +40,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::Session, @@ -80,7 +80,7 @@ impl Feature for types::PaymentsSessio call_connector_action: payments::CallConnectorAction, _connector_request: Option, business_profile: &domain::Profile, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { metrics::SESSION_TOKEN_CREATED.add( &metrics::CONTEXT, @@ -172,7 +172,7 @@ async fn create_applepay_session_token( router_data: &types::PaymentsSessionRouterData, connector: &api::ConnectorData, business_profile: &domain::Profile, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let delayed_response = is_session_response_delayed(state, connector); if delayed_response { @@ -500,7 +500,7 @@ async fn create_applepay_session_token( fn create_paze_session_token( router_data: &types::PaymentsSessionRouterData, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let paze_wallet_details = router_data .connector_wallets_details @@ -528,7 +528,7 @@ fn create_paze_session_token( fn create_samsung_pay_session_token( router_data: &types::PaymentsSessionRouterData, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let samsung_pay_session_token_data = router_data .connector_wallets_details @@ -682,7 +682,7 @@ fn create_apple_pay_session_response( connector_name: String, delayed_response: bool, next_action: payment_types::NextActionCall, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { match session_response { Some(response) => Ok(types::PaymentsSessionRouterData { @@ -931,7 +931,7 @@ where _confirm: Option, call_connector_action: payments::CallConnectorAction, business_profile: &domain::Profile, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult; } @@ -980,7 +980,7 @@ impl RouterDataSession for types::PaymentsSessionRouterData { _confirm: Option, call_connector_action: payments::CallConnectorAction, business_profile: &domain::Profile, - header_payload: api_models::payments::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { match connector.get_token { api::GetToken::GpayMetadata => { diff --git a/crates/router/src/core/payments/flows/session_update_flow.rs b/crates/router/src/core/payments/flows/session_update_flow.rs index 6cad2500814..e48f90d1bb6 100644 --- a/crates/router/src/core/payments/flows/session_update_flow.rs +++ b/crates/router/src/core/payments/flows/session_update_flow.rs @@ -28,7 +28,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + _header_payload: Option, ) -> RouterResult { Box::pin( transformers::construct_router_data_to_update_calculated_tax::< @@ -74,7 +74,7 @@ impl Feature call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::SdkSessionUpdate, diff --git a/crates/router/src/core/payments/flows/setup_mandate_flow.rs b/crates/router/src/core/payments/flows/setup_mandate_flow.rs index 69720b870a2..2cee81115d6 100644 --- a/crates/router/src/core/payments/flows/setup_mandate_flow.rs +++ b/crates/router/src/core/payments/flows/setup_mandate_flow.rs @@ -32,7 +32,7 @@ impl customer: &Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult { Box::pin(transformers::construct_payment_router_data::< api::SetupMandate, @@ -72,7 +72,7 @@ impl Feature for types::Setup call_connector_action: payments::CallConnectorAction, connector_request: Option, _business_profile: &domain::Profile, - _header_payload: api_models::payments::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult { let connector_integration: services::BoxedPaymentConnectorIntegrationInterface< api::SetupMandate, diff --git a/crates/router/src/core/payments/helpers.rs b/crates/router/src/core/payments/helpers.rs index 27d73d0df46..51cb5793adb 100644 --- a/crates/router/src/core/payments/helpers.rs +++ b/crates/router/src/core/payments/helpers.rs @@ -385,19 +385,6 @@ pub async fn get_address_by_id( } } -#[cfg(all(feature = "v2", feature = "payment_methods_v2"))] -pub async fn get_token_pm_type_mandate_details( - _state: &SessionState, - _request: &api::PaymentsRequest, - _mandate_type: Option, - _merchant_account: &domain::MerchantAccount, - _merchant_key_store: &domain::MerchantKeyStore, - _payment_method_id: Option, - _payment_intent_customer_id: Option<&id_type::CustomerId>, -) -> RouterResult { - todo!() -} - #[cfg(all( any(feature = "v1", feature = "v2"), not(feature = "payment_methods_v2") @@ -1168,7 +1155,7 @@ pub fn create_startpay_url( pub fn create_redirect_url( router_base_url: &String, payment_attempt: &PaymentAttempt, - connector_name: &String, + connector_name: impl std::fmt::Display, creds_identifier: Option<&str>, ) -> String { let creds_identifier_path = creds_identifier.map_or_else(String::new, |cd| format!("/{}", cd)); @@ -1194,7 +1181,7 @@ pub fn create_authentication_url( pub fn create_authorize_url( router_base_url: &str, payment_attempt: &PaymentAttempt, - connector_name: &String, + connector_name: impl std::fmt::Display, ) -> String { format!( "{}/payments/{}/{}/authorize/{}", @@ -1208,7 +1195,7 @@ pub fn create_authorize_url( pub fn create_webhook_url( router_base_url: &String, merchant_id: &id_type::MerchantId, - connector_name: &String, + connector_name: impl std::fmt::Display, ) -> String { format!( "{}/webhooks/{}/{}", @@ -1220,7 +1207,7 @@ pub fn create_webhook_url( pub fn create_complete_authorize_url( router_base_url: &String, payment_attempt: &PaymentAttempt, - connector_name: &String, + connector_name: impl std::fmt::Display, ) -> String { format!( "{}/payments/{}/{}/redirect/complete/{}", @@ -1349,6 +1336,8 @@ pub fn payment_intent_status_fsm( None => storage_enums::IntentStatus::RequiresPaymentMethod, } } + +#[cfg(feature = "v1")] pub async fn add_domain_task_to_pt( operation: &Op, state: &SessionState, @@ -1419,6 +1408,7 @@ pub fn validate_max_amount( } } +#[cfg(feature = "v1")] /// Check whether the customer information that is sent in the root of payments request /// and in the customer object are same, if the values mismatch return an error pub fn validate_customer_information( @@ -1436,6 +1426,7 @@ pub fn validate_customer_information( } } +#[cfg(feature = "v1")] /// Get the customer details from customer field if present /// or from the individual fields in `PaymentsRequest` #[instrument(skip_all)] @@ -1707,6 +1698,7 @@ pub async fn create_customer_if_not_exist<'a, F: Clone, R, D>( )) } +#[cfg(feature = "v1")] pub async fn retrieve_payment_method_with_temporary_token( state: &SessionState, token: &str, @@ -2530,9 +2522,10 @@ pub(crate) fn validate_amount_to_capture( ) } +#[cfg(feature = "v1")] #[instrument(skip_all)] pub(crate) fn validate_payment_method_fields_present( - req: &api::PaymentsRequest, + req: &api_models::payments::PaymentsRequest, ) -> RouterResult<()> { let payment_method_data = req.payment_method_data @@ -3765,14 +3758,18 @@ pub async fn get_merchant_connector_account( ) } #[cfg(feature = "v2")] - // get mca using id { - let _id = merchant_connector_id; - let _ = key_store; - let _ = profile_id; - let _ = connector_name; - let _ = key_manager_state; - todo!() + db.find_merchant_connector_account_by_id( + &state.into(), + merchant_connector_id, + key_store, + ) + .await + .to_not_found_response( + errors::ApiErrorResponse::MerchantConnectorAccountNotFound { + id: merchant_connector_id.get_string_repr().to_string(), + }, + ) } } else { #[cfg(feature = "v1")] @@ -3864,11 +3861,12 @@ pub fn router_data_type_conversion( } } +#[cfg(feature = "v1")] #[instrument(skip_all)] pub fn get_attempt_type( payment_intent: &PaymentIntent, payment_attempt: &PaymentAttempt, - request: &api::PaymentsRequest, + request: &api_models::payments::PaymentsRequest, action: &str, ) -> RouterResult { match payment_intent.status { @@ -4075,24 +4073,25 @@ impl AttemptType { } } - #[cfg(feature = "v2")] - // The function creates a new payment_attempt from the previous payment attempt but doesn't populate fields like payment_method, error_code etc. - // Logic to override the fields with data provided in the request should be done after this if required. - // In case if fields are not overridden by the request then they contain the same data that was in the previous attempt provided it is populated in this function. - #[inline(always)] - fn make_new_payment_attempt( - _payment_method_data: Option<&api_models::payments::PaymentMethodData>, - _old_payment_attempt: PaymentAttempt, - _new_attempt_count: i16, - _storage_scheme: enums::MerchantStorageScheme, - ) -> PaymentAttempt { - todo!() - } + // #[cfg(feature = "v2")] + // // The function creates a new payment_attempt from the previous payment attempt but doesn't populate fields like payment_method, error_code etc. + // // Logic to override the fields with data provided in the request should be done after this if required. + // // In case if fields are not overridden by the request then they contain the same data that was in the previous attempt provided it is populated in this function. + // #[inline(always)] + // fn make_new_payment_attempt( + // _payment_method_data: Option<&api_models::payments::PaymentMethodData>, + // _old_payment_attempt: PaymentAttempt, + // _new_attempt_count: i16, + // _storage_scheme: enums::MerchantStorageScheme, + // ) -> PaymentAttempt { + // todo!() + // } + #[cfg(feature = "v1")] #[instrument(skip_all)] pub async fn modify_payment_intent_and_payment_attempt( &self, - request: &api::PaymentsRequest, + request: &api_models::payments::PaymentsRequest, fetched_payment_intent: PaymentIntent, fetched_payment_attempt: PaymentAttempt, state: &SessionState, @@ -4161,7 +4160,7 @@ impl AttemptType { .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; logger::info!( - "manual_retry payment for {:?} with attempt_id {}", + "manual_retry payment for {:?} with attempt_id {:?}", updated_payment_intent.get_id(), new_payment_attempt.get_id() ); @@ -4706,6 +4705,7 @@ pub async fn populate_bin_details_for_payment_method_create( todo!() } +#[cfg(feature = "v1")] pub fn validate_customer_access( payment_intent: &PaymentIntent, auth_flow: services::AuthFlow, diff --git a/crates/router/src/core/payments/operations.rs b/crates/router/src/core/payments/operations.rs index 56b198c5381..6546638a62e 100644 --- a/crates/router/src/core/payments/operations.rs +++ b/crates/router/src/core/payments/operations.rs @@ -31,6 +31,9 @@ pub mod tax_calculation; #[cfg(feature = "v2")] pub mod payment_create_intent; +#[cfg(feature = "v2")] +pub mod payment_confirm_intent; + use api_models::enums::FrmSuggestion; #[cfg(all(feature = "v1", feature = "dynamic_routing"))] use api_models::routing::RoutableConnectorChoice; @@ -39,7 +42,9 @@ use error_stack::{report, ResultExt}; use router_env::{instrument, tracing}; #[cfg(feature = "v2")] -pub use self::payment_create_intent::PaymentCreateIntent; +pub use self::payment_confirm_intent::PaymentIntentConfirm; +#[cfg(feature = "v2")] +pub use self::payment_create_intent::PaymentIntentCreate; pub use self::payment_response::PaymentResponse; #[cfg(feature = "v1")] pub use self::{ @@ -149,9 +154,11 @@ pub struct GetTrackerResponse<'a, F: Clone, R, D> { pub mandate_type: Option, } -#[cfg(feature = "v1")] +/// This trait is used to fetch / create all the tracker related information for a payment +/// This functions returns the session data that is used by subsequent functions #[async_trait] pub trait GetTracker: Send { + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] async fn get_trackers<'a>( &'a self, @@ -161,13 +168,12 @@ pub trait GetTracker: Send { merchant_account: &domain::MerchantAccount, mechant_key_store: &domain::MerchantKeyStore, auth_flow: services::AuthFlow, - header_payload: &api::HeaderPayload, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>; -} -#[cfg(feature = "v2")] -#[async_trait] -pub trait GetTracker: Send { + // TODO: this need not return the operation, since operation does not change in v2 + // Operation remains the same from start to finish + #[cfg(feature = "v2")] #[allow(clippy::too_many_arguments)] async fn get_trackers<'a>( &'a self, @@ -177,8 +183,7 @@ pub trait GetTracker: Send { merchant_account: &domain::MerchantAccount, profile: &domain::Profile, mechant_key_store: &domain::MerchantKeyStore, - auth_flow: services::AuthFlow, - header_payload: &api::HeaderPayload, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>; } @@ -310,7 +315,7 @@ pub trait UpdateTracker: Send { updated_customer: Option, mechant_key_store: &domain::MerchantKeyStore, frm_suggestion: Option, - header_payload: api::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(BoxedOperation<'b, F, Req, D>, D)> where F: 'b + Send; @@ -322,7 +327,6 @@ pub trait PostUpdateTracker: Send { async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, payment_data: D, response: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -750,3 +754,11 @@ where Ok(false) } } + +/// Validate if a particular operation can be performed for the given intent status +pub trait ValidateStatusForOperation { + fn validate_status_for_operation( + &self, + intent_status: common_enums::IntentStatus, + ) -> Result<(), errors::ApiErrorResponse>; +} diff --git a/crates/router/src/core/payments/operations/payment_approve.rs b/crates/router/src/core/payments/operations/payment_approve.rs index e8814c7e56e..fe5e7a7e72f 100644 --- a/crates/router/src/core/payments/operations/payment_approve.rs +++ b/crates/router/src/core/payments/operations/payment_approve.rs @@ -43,7 +43,7 @@ impl GetTracker, api::PaymentsCaptureRequest> merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse<'a, F, api::PaymentsCaptureRequest, PaymentData>, > { @@ -220,7 +220,7 @@ impl UpdateTracker, api::PaymentsCaptureRequest> for _updated_customer: Option, key_store: &domain::MerchantKeyStore, frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentApproveOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_cancel.rs b/crates/router/src/core/payments/operations/payment_cancel.rs index c84dcc50e6d..8d7361cd257 100644 --- a/crates/router/src/core/payments/operations/payment_cancel.rs +++ b/crates/router/src/core/payments/operations/payment_cancel.rs @@ -43,7 +43,7 @@ impl GetTracker, api::PaymentsCancelRequest> merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse<'a, F, api::PaymentsCancelRequest, PaymentData>, > { @@ -230,7 +230,7 @@ impl UpdateTracker, api::PaymentsCancelRequest> for _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentCancelOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_capture.rs b/crates/router/src/core/payments/operations/payment_capture.rs index 93a79e2d2e3..2451cbcd8e9 100644 --- a/crates/router/src/core/payments/operations/payment_capture.rs +++ b/crates/router/src/core/payments/operations/payment_capture.rs @@ -44,7 +44,7 @@ impl GetTracker, api::PaymentsCaptu merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse< 'a, @@ -283,7 +283,7 @@ impl UpdateTracker, api::PaymentsCaptureRe _updated_customer: Option, _mechant_key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentCaptureOperation<'b, F>, payments::PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_complete_authorize.rs b/crates/router/src/core/payments/operations/payment_complete_authorize.rs index e705c64d6e0..850fa738cd8 100644 --- a/crates/router/src/core/payments/operations/payment_complete_authorize.rs +++ b/crates/router/src/core/payments/operations/payment_complete_authorize.rs @@ -44,7 +44,7 @@ impl GetTracker, api::PaymentsRequest> for Co merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>> { let db = &*state.store; @@ -469,7 +469,7 @@ impl UpdateTracker, api::PaymentsRequest> for Comple _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(CompleteAuthorizeOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_confirm.rs b/crates/router/src/core/payments/operations/payment_confirm.rs index ca32be35e55..74339a88fb6 100644 --- a/crates/router/src/core/payments/operations/payment_confirm.rs +++ b/crates/router/src/core/payments/operations/payment_confirm.rs @@ -66,7 +66,7 @@ impl GetTracker, api::PaymentsRequest> for Pa merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, auth_flow: services::AuthFlow, - header_payload: &api::HeaderPayload, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>> { let key_manager_state = &state.into(); @@ -1065,7 +1065,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( BoxedOperation<'b, F, api::PaymentsRequest, PaymentData>, PaymentData, @@ -1091,7 +1091,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen updated_customer: Option, key_store: &domain::MerchantKeyStore, frm_suggestion: Option, - header_payload: api::HeaderPayload, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( BoxedOperation<'b, F, api::PaymentsRequest, PaymentData>, PaymentData, diff --git a/crates/router/src/core/payments/operations/payment_confirm_intent.rs b/crates/router/src/core/payments/operations/payment_confirm_intent.rs new file mode 100644 index 00000000000..083bb5adca2 --- /dev/null +++ b/crates/router/src/core/payments/operations/payment_confirm_intent.rs @@ -0,0 +1,370 @@ +use api_models::{ + admin::ExtendedCardInfoConfig, + enums::FrmSuggestion, + payments::{ExtendedCardInfo, GetAddressFromPaymentMethodData, PaymentsConfirmIntentRequest}, +}; +use async_trait::async_trait; +use error_stack::ResultExt; +use hyperswitch_domain_models::payments::{ + payment_attempt::PaymentAttempt, PaymentConfirmData, PaymentIntent, +}; +use router_env::{instrument, tracing}; +use tracing_futures::Instrument; + +use super::{Domain, GetTracker, Operation, UpdateTracker, ValidateRequest}; +use crate::{ + core::{ + authentication, + errors::{self, CustomResult, RouterResult, StorageErrorExt}, + payments::{ + self, helpers, + operations::{self, ValidateStatusForOperation}, + populate_surcharge_details, CustomerDetails, PaymentAddress, PaymentData, + }, + utils as core_utils, + }, + routes::{app::ReqState, SessionState}, + services, + types::{ + self, + api::{self, ConnectorCallType, PaymentIdTypeExt}, + domain::{self}, + storage::{self, enums as storage_enums}, + }, + utils::{self, OptionExt}, +}; + +#[derive(Debug, Clone, Copy)] +pub struct PaymentIntentConfirm; + +impl ValidateStatusForOperation for PaymentIntentConfirm { + /// Validate if the current operation can be performed on the current status of the payment intent + fn validate_status_for_operation( + &self, + intent_status: common_enums::IntentStatus, + ) -> Result<(), errors::ApiErrorResponse> { + match intent_status { + common_enums::IntentStatus::RequiresPaymentMethod => Ok(()), + common_enums::IntentStatus::Succeeded + | common_enums::IntentStatus::Failed + | common_enums::IntentStatus::Cancelled + | common_enums::IntentStatus::Processing + | common_enums::IntentStatus::RequiresCustomerAction + | common_enums::IntentStatus::RequiresMerchantAction + | common_enums::IntentStatus::RequiresCapture + | common_enums::IntentStatus::PartiallyCaptured + | common_enums::IntentStatus::RequiresConfirmation + | common_enums::IntentStatus::PartiallyCapturedAndCapturable => { + Err(errors::ApiErrorResponse::PaymentUnexpectedState { + current_flow: format!("{self:?}"), + field_name: "status".to_string(), + current_value: intent_status.to_string(), + states: ["requires_payment_method".to_string()].join(", "), + }) + } + } + } +} + +type BoxedConfirmOperation<'b, F> = + super::BoxedOperation<'b, F, PaymentsConfirmIntentRequest, PaymentConfirmData>; + +// TODO: change the macro to include changes for v2 +// TODO: PaymentData in the macro should be an input +impl Operation for &PaymentIntentConfirm { + type Data = PaymentConfirmData; + fn to_validate_request( + &self, + ) -> RouterResult< + &(dyn ValidateRequest + Send + Sync), + > { + Ok(*self) + } + fn to_get_tracker( + &self, + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> + { + Ok(*self) + } + fn to_domain( + &self, + ) -> RouterResult<&(dyn Domain)> { + Ok(*self) + } + fn to_update_tracker( + &self, + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + { + Ok(*self) + } +} +#[automatically_derived] +impl Operation for PaymentIntentConfirm { + type Data = PaymentConfirmData; + fn to_validate_request( + &self, + ) -> RouterResult< + &(dyn ValidateRequest + Send + Sync), + > { + Ok(self) + } + fn to_get_tracker( + &self, + ) -> RouterResult<&(dyn GetTracker + Send + Sync)> + { + Ok(self) + } + fn to_domain(&self) -> RouterResult<&dyn Domain> { + Ok(self) + } + fn to_update_tracker( + &self, + ) -> RouterResult<&(dyn UpdateTracker + Send + Sync)> + { + Ok(self) + } +} + +impl ValidateRequest> + for PaymentIntentConfirm +{ + #[instrument(skip_all)] + fn validate_request<'a, 'b>( + &'b self, + request: &PaymentsConfirmIntentRequest, + merchant_account: &'a domain::MerchantAccount, + ) -> RouterResult<(BoxedConfirmOperation<'b, F>, operations::ValidateResult)> { + let validate_result = operations::ValidateResult { + merchant_id: merchant_account.get_id().to_owned(), + storage_scheme: merchant_account.storage_scheme, + requeue: false, + }; + + Ok((Box::new(self), validate_result)) + } +} + +#[async_trait] +impl GetTracker, PaymentsConfirmIntentRequest> + for PaymentIntentConfirm +{ + #[instrument(skip_all)] + async fn get_trackers<'a>( + &'a self, + state: &'a SessionState, + payment_id: &common_utils::id_type::GlobalPaymentId, + request: &PaymentsConfirmIntentRequest, + merchant_account: &domain::MerchantAccount, + profile: &domain::Profile, + key_store: &domain::MerchantKeyStore, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult< + operations::GetTrackerResponse<'a, F, PaymentsConfirmIntentRequest, PaymentConfirmData>, + > { + let db = &*state.store; + let key_manager_state = &state.into(); + + let storage_scheme = merchant_account.storage_scheme; + + let payment_intent = db + .find_payment_intent_by_id(key_manager_state, payment_id, key_store, storage_scheme) + .await + .to_not_found_response(errors::ApiErrorResponse::PaymentNotFound)?; + + self.validate_status_for_operation(payment_intent.status)?; + let client_secret = header_payload + .client_secret + .as_ref() + .get_required_value("client_secret header")?; + payment_intent.validate_client_secret(client_secret)?; + + let cell_id = state.conf.cell_information.id.clone(); + + let payment_attempt_domain_model = + hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt::create_domain_model( + &payment_intent, + cell_id, + storage_scheme, + request + ) + .await?; + + let payment_attempt = db + .insert_payment_attempt( + key_manager_state, + key_store, + payment_attempt_domain_model, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Could not insert payment attempt")?; + + let payment_method_data = request + .payment_method_data + .payment_method_data + .clone() + .map(hyperswitch_domain_models::payment_method_data::PaymentMethodData::from); + + let payment_data = PaymentConfirmData { + flow: std::marker::PhantomData, + payment_intent, + payment_attempt, + payment_method_data, + }; + + let get_trackers_response = operations::GetTrackerResponse { + operation: Box::new(self), + payment_data, + }; + + Ok(get_trackers_response) + } +} + +#[async_trait] +impl Domain> + for PaymentIntentConfirm +{ + async fn get_customer_details<'a>( + &'a self, + state: &SessionState, + payment_data: &mut PaymentConfirmData, + merchant_key_store: &domain::MerchantKeyStore, + storage_scheme: storage_enums::MerchantStorageScheme, + ) -> CustomResult<(BoxedConfirmOperation<'a, F>, Option), errors::StorageError> + { + match payment_data.payment_intent.customer_id.clone() { + Some(id) => { + let customer = state + .store + .find_customer_by_global_id( + &state.into(), + id.get_string_repr(), + &payment_data.payment_intent.merchant_id, + merchant_key_store, + storage_scheme, + ) + .await?; + + Ok((Box::new(self), Some(customer))) + } + None => Ok((Box::new(self), None)), + } + } + + #[instrument(skip_all)] + async fn make_pm_data<'a>( + &'a self, + state: &'a SessionState, + payment_data: &mut PaymentConfirmData, + storage_scheme: storage_enums::MerchantStorageScheme, + key_store: &domain::MerchantKeyStore, + customer: &Option, + business_profile: &domain::Profile, + ) -> RouterResult<( + BoxedConfirmOperation<'a, F>, + Option, + Option, + )> { + Ok((Box::new(self), None, None)) + } + + async fn get_connector<'a>( + &'a self, + _merchant_account: &domain::MerchantAccount, + state: &SessionState, + request: &PaymentsConfirmIntentRequest, + _payment_intent: &storage::PaymentIntent, + _key_store: &domain::MerchantKeyStore, + ) -> CustomResult { + todo!() + } +} + +#[async_trait] +impl UpdateTracker, PaymentsConfirmIntentRequest> + for PaymentIntentConfirm +{ + #[instrument(skip_all)] + async fn update_trackers<'b>( + &'b self, + state: &'b SessionState, + req_state: ReqState, + mut payment_data: PaymentConfirmData, + customer: Option, + storage_scheme: storage_enums::MerchantStorageScheme, + updated_customer: Option, + key_store: &domain::MerchantKeyStore, + frm_suggestion: Option, + header_payload: hyperswitch_domain_models::payments::HeaderPayload, + ) -> RouterResult<(BoxedConfirmOperation<'b, F>, PaymentConfirmData)> + where + F: 'b + Send, + { + let db = &*state.store; + let key_manager_state = &state.into(); + + let intent_status = common_enums::IntentStatus::Processing; + let attempt_status = common_enums::AttemptStatus::Pending; + + let connector = payment_data + .payment_attempt + .connector + .clone() + .get_required_value("connector") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Connector is none when constructing response")?; + + let merchant_connector_id = payment_data + .payment_attempt + .merchant_connector_id + .clone() + .get_required_value("merchant_connector_id") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Merchant connector id is none when constructing response")?; + + let payment_intent_update = + hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntent { + status: intent_status, + updated_by: storage_scheme.to_string(), + }; + + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntent { + status: attempt_status, + updated_by: storage_scheme.to_string(), + connector, + merchant_connector_id, + }; + + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent.clone(), + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; + + payment_data.payment_intent = updated_payment_intent; + + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_data.payment_attempt.clone(), + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + + payment_data.payment_attempt = updated_payment_attempt; + + Ok((Box::new(self), payment_data)) + } +} diff --git a/crates/router/src/core/payments/operations/payment_create.rs b/crates/router/src/core/payments/operations/payment_create.rs index fc1f71c2085..46799c3c196 100644 --- a/crates/router/src/core/payments/operations/payment_create.rs +++ b/crates/router/src/core/payments/operations/payment_create.rs @@ -73,7 +73,7 @@ impl GetTracker, api::PaymentsRequest> for Pa merchant_account: &domain::MerchantAccount, merchant_key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - header_payload: &api::HeaderPayload, + header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>> { let db = &*state.store; @@ -775,7 +775,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentCreateOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_create_intent.rs b/crates/router/src/core/payments/operations/payment_create_intent.rs index c0b66b44468..bd82a67e627 100644 --- a/crates/router/src/core/payments/operations/payment_create_intent.rs +++ b/crates/router/src/core/payments/operations/payment_create_intent.rs @@ -24,9 +24,9 @@ use crate::{ }; #[derive(Debug, Clone, Copy)] -pub struct PaymentCreateIntent; +pub struct PaymentIntentCreate; -impl Operation for &PaymentCreateIntent { +impl Operation for &PaymentIntentCreate { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -52,7 +52,7 @@ impl Operation for &PaymentCrea } } -impl Operation for PaymentCreateIntent { +impl Operation for PaymentIntentCreate { type Data = payments::PaymentIntentData; fn to_validate_request( &self, @@ -83,7 +83,7 @@ type PaymentsCreateIntentOperation<'b, F> = #[async_trait] impl GetTracker, PaymentsCreateIntentRequest> - for PaymentCreateIntent + for PaymentIntentCreate { #[instrument(skip_all)] async fn get_trackers<'a>( @@ -94,8 +94,7 @@ impl GetTracker, PaymentsCrea merchant_account: &domain::MerchantAccount, profile: &domain::Profile, key_store: &domain::MerchantKeyStore, - _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse< 'a, @@ -188,7 +187,7 @@ impl GetTracker, PaymentsCrea #[async_trait] impl UpdateTracker, PaymentsCreateIntentRequest> - for PaymentCreateIntent + for PaymentIntentCreate { #[instrument(skip_all)] async fn update_trackers<'b>( @@ -201,7 +200,7 @@ impl UpdateTracker, PaymentsCreateIn _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( PaymentsCreateIntentOperation<'b, F>, payments::PaymentIntentData, @@ -215,7 +214,7 @@ impl UpdateTracker, PaymentsCreateIn impl ValidateRequest> - for PaymentCreateIntent + for PaymentIntentCreate { #[instrument(skip_all)] fn validate_request<'a, 'b>( @@ -239,7 +238,7 @@ impl #[async_trait] impl Domain> - for PaymentCreateIntent + for PaymentIntentCreate { #[instrument(skip_all)] async fn get_customer_details<'a>( diff --git a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs index 81702979ac4..846f739e082 100644 --- a/crates/router/src/core/payments/operations/payment_post_session_tokens.rs +++ b/crates/router/src/core/payments/operations/payment_post_session_tokens.rs @@ -44,7 +44,7 @@ impl GetTracker, api::PaymentsPostSessionToke merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse< 'a, @@ -255,7 +255,7 @@ impl UpdateTracker, api::PaymentsPostSessionTokensRe _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentPostSessionTokensOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_reject.rs b/crates/router/src/core/payments/operations/payment_reject.rs index 2257ff0402c..55b93501275 100644 --- a/crates/router/src/core/payments/operations/payment_reject.rs +++ b/crates/router/src/core/payments/operations/payment_reject.rs @@ -39,7 +39,7 @@ impl GetTracker, PaymentsCancelRequest> for P merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>> { let db = &*state.store; @@ -216,7 +216,7 @@ impl UpdateTracker, PaymentsCancelRequest> for Payme _updated_customer: Option, key_store: &domain::MerchantKeyStore, _should_decline_transaction: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentRejectOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_response.rs b/crates/router/src/core/payments/operations/payment_response.rs index 274b4f43c5d..ae64fe41b1f 100644 --- a/crates/router/src/core/payments/operations/payment_response.rs +++ b/crates/router/src/core/payments/operations/payment_response.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use api_models::payments::{ConnectorMandateReferenceId, MandateReferenceId}; -#[cfg(all(feature = "v1", feature = "dynamic_routing"))] +#[cfg(feature = "dynamic_routing")] use api_models::routing::RoutableConnectorChoice; use async_trait::async_trait; use common_enums::{AuthorizationStatus, SessionUpdateStatus}; @@ -12,6 +12,8 @@ use common_utils::{ use error_stack::{report, ResultExt}; use futures::FutureExt; use hyperswitch_domain_models::payments::payment_attempt::PaymentAttempt; +#[cfg(feature = "v2")] +use hyperswitch_domain_models::payments::PaymentConfirmData; use router_derive; use router_env::{instrument, logger, metrics::add_attributes, tracing}; use storage_impl::DataModelExt; @@ -40,7 +42,7 @@ use crate::{ }, routes::{metrics, SessionState}, types::{ - self, api, domain, + self, domain, storage::{self, enums}, transformers::{ForeignFrom, ForeignTryFrom}, CaptureSyncResponse, ErrorResponse, @@ -68,7 +70,6 @@ impl PostUpdateTracker, types::PaymentsAuthor async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< F, @@ -92,7 +93,6 @@ impl PostUpdateTracker, types::PaymentsAuthor payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -365,7 +365,6 @@ impl PostUpdateTracker, types::PaymentsIncrementalAu async fn update_tracker<'b>( &'b self, state: &'b SessionState, - _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< F, @@ -532,7 +531,6 @@ impl PostUpdateTracker, types::PaymentsSyncData> for async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -548,7 +546,6 @@ impl PostUpdateTracker, types::PaymentsSyncData> for { Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -623,7 +620,6 @@ impl PostUpdateTracker, types::PaymentsSessionData> async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -639,7 +635,6 @@ impl PostUpdateTracker, types::PaymentsSessionData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -664,7 +659,6 @@ impl PostUpdateTracker, types::SdkPaymentsSessionUpd async fn update_tracker<'b>( &'b self, db: &'b SessionState, - _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< F, @@ -789,7 +783,6 @@ impl PostUpdateTracker, types::PaymentsPostSessionTo async fn update_tracker<'b>( &'b self, db: &'b SessionState, - _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< F, @@ -851,7 +844,6 @@ impl PostUpdateTracker, types::PaymentsCaptureData> async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -867,7 +859,6 @@ impl PostUpdateTracker, types::PaymentsCaptureData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -890,7 +881,6 @@ impl PostUpdateTracker, types::PaymentsCancelData> f async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -906,7 +896,6 @@ impl PostUpdateTracker, types::PaymentsCancelData> f { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -931,7 +920,6 @@ impl PostUpdateTracker, types::PaymentsApproveData> async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -947,7 +935,6 @@ impl PostUpdateTracker, types::PaymentsApproveData> { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -970,7 +957,6 @@ impl PostUpdateTracker, types::PaymentsRejectData> f async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -986,7 +972,6 @@ impl PostUpdateTracker, types::PaymentsRejectData> f { payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -1011,7 +996,6 @@ impl PostUpdateTracker, types::SetupMandateRequestDa async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData< F, @@ -1036,7 +1020,6 @@ impl PostUpdateTracker, types::SetupMandateRequestDa payment_data = Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, router_data, key_store, @@ -1134,7 +1117,6 @@ impl PostUpdateTracker, types::CompleteAuthorizeData async fn update_tracker<'b>( &'b self, db: &'b SessionState, - payment_id: &api::PaymentIdType, payment_data: PaymentData, response: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -1150,7 +1132,6 @@ impl PostUpdateTracker, types::CompleteAuthorizeData { Box::pin(payment_response_update_tracker( db, - payment_id, payment_data, response, key_store, @@ -1216,26 +1197,11 @@ impl PostUpdateTracker, types::CompleteAuthorizeData } } -#[cfg(feature = "v2")] -#[instrument(skip_all)] -async fn payment_response_update_tracker( - state: &SessionState, - _payment_id: &api::PaymentIdType, - mut payment_data: PaymentData, - router_data: types::RouterData, - key_store: &domain::MerchantKeyStore, - storage_scheme: enums::MerchantStorageScheme, - locale: &Option, -) -> RouterResult> { - todo!() -} - #[cfg(feature = "v1")] #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] async fn payment_response_update_tracker( state: &SessionState, - _payment_id: &api::PaymentIdType, mut payment_data: PaymentData, router_data: types::RouterData, key_store: &domain::MerchantKeyStore, @@ -2133,6 +2099,195 @@ async fn update_payment_method_status_and_ntid( Ok(()) } +#[cfg(feature = "v2")] +impl Operation for &PaymentResponse { + type Data = PaymentConfirmData; + fn to_post_update_tracker( + &self, + ) -> RouterResult< + &(dyn PostUpdateTracker + Send + Sync), + > { + Ok(*self) + } +} + +#[cfg(feature = "v2")] +impl Operation for PaymentResponse { + type Data = PaymentConfirmData; + fn to_post_update_tracker( + &self, + ) -> RouterResult< + &(dyn PostUpdateTracker + Send + Sync), + > { + Ok(self) + } +} + +#[cfg(feature = "v2")] +#[async_trait] +impl PostUpdateTracker, types::PaymentsAuthorizeData> + for PaymentResponse +{ + async fn update_tracker<'b>( + &'b self, + state: &'b SessionState, + mut payment_data: PaymentConfirmData, + response: types::RouterData, + key_store: &domain::MerchantKeyStore, + storage_scheme: enums::MerchantStorageScheme, + locale: &Option, + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] routable_connector: Vec< + RoutableConnectorChoice, + >, + #[cfg(all(feature = "v1", feature = "dynamic_routing"))] business_profile: &domain::Profile, + ) -> RouterResult> + where + F: 'b + Send + Sync, + { + let db = &*state.store; + let key_manager_state = &state.into(); + + let response_router_data = response; + + match response_router_data.response { + Ok(response) => match response { + types::PaymentsResponseData::TransactionResponse { + resource_id, + redirection_data, + mandate_reference, + connector_metadata, + network_txn_id, + connector_response_reference_id, + incremental_authorization_allowed, + charge_id, + } => { + let attempt_status = response_router_data.status; + let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); + let connector_payment_id = match resource_id { + types::ResponseId::NoResponseId => None, + types::ResponseId::ConnectorTransactionId(id) + | types::ResponseId::EncodedData(id) => Some(id), + }; + + let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; + payment_data.payment_intent = updated_payment_intent; + + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentResponse { status: attempt_status, connector_payment_id, updated_by: storage_scheme.to_string() }; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_data.payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + payment_data.payment_attempt = updated_payment_attempt; + } + types::PaymentsResponseData::MultipleCaptureResponse { + capture_sync_response_list, + } => todo!(), + types::PaymentsResponseData::SessionResponse { session_token } => todo!(), + types::PaymentsResponseData::SessionTokenResponse { session_token } => todo!(), + types::PaymentsResponseData::TransactionUnresolvedResponse { + resource_id, + reason, + connector_response_reference_id, + } => todo!(), + types::PaymentsResponseData::TokenizationResponse { token } => todo!(), + types::PaymentsResponseData::ConnectorCustomerResponse { + connector_customer_id, + } => todo!(), + types::PaymentsResponseData::ThreeDSEnrollmentResponse { + enrolled_v2, + related_transaction_id, + } => todo!(), + types::PaymentsResponseData::PreProcessingResponse { + pre_processing_id, + connector_metadata, + session_token, + connector_response_reference_id, + } => todo!(), + types::PaymentsResponseData::IncrementalAuthorizationResponse { + status, + connector_authorization_id, + error_code, + error_message, + } => todo!(), + types::PaymentsResponseData::PostProcessingResponse { session_token } => todo!(), + types::PaymentsResponseData::SessionUpdateResponse { status } => todo!(), + }, + Err(ErrorResponse { + code, + message, + reason, + status_code, + attempt_status, + connector_transaction_id, + }) => { + let attempt_status = common_enums::AttemptStatus::Failure; + let intent_status = common_enums::IntentStatus::foreign_from(attempt_status); + let payment_intent_update = hyperswitch_domain_models::payments::payment_intent::PaymentIntentUpdate::ConfirmIntentPostUpdate { status: intent_status, updated_by: storage_scheme.to_string() }; + + let updated_payment_intent = db + .update_payment_intent( + key_manager_state, + payment_data.payment_intent, + payment_intent_update, + key_store, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment intent")?; + + payment_data.payment_intent = updated_payment_intent; + + // TODO: populate unified code and message and translation by calling gsm and translation table + let error_details = + hyperswitch_domain_models::payments::payment_attempt::ErrorDetails { + code, + message, + reason, + unified_code: None, + unified_message: None, + }; + + let payment_attempt_update = hyperswitch_domain_models::payments::payment_attempt::PaymentAttemptUpdate::ConfirmIntentError { status: attempt_status, error: error_details,updated_by: storage_scheme.to_string() }; + let updated_payment_attempt = db + .update_payment_attempt( + key_manager_state, + key_store, + payment_data.payment_attempt, + payment_attempt_update, + storage_scheme, + ) + .await + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Unable to update payment attempt")?; + + payment_data.payment_attempt = updated_payment_attempt; + } + } + // TODO: Implement this + Ok(payment_data) + } +} + +#[cfg(feature = "v1")] fn update_connector_mandate_details_for_the_flow( connector_mandate_id: Option, mandate_metadata: Option, diff --git a/crates/router/src/core/payments/operations/payment_session.rs b/crates/router/src/core/payments/operations/payment_session.rs index d2154f16b6a..1bc11854ad0 100644 --- a/crates/router/src/core/payments/operations/payment_session.rs +++ b/crates/router/src/core/payments/operations/payment_session.rs @@ -43,7 +43,7 @@ impl GetTracker, api::PaymentsSessionRequest> merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse<'a, F, api::PaymentsSessionRequest, PaymentData>, > { @@ -239,7 +239,7 @@ impl UpdateTracker, api::PaymentsSessionRequest> for _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentSessionOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_start.rs b/crates/router/src/core/payments/operations/payment_start.rs index 3042b15bfa1..cad5dcfbd67 100644 --- a/crates/router/src/core/payments/operations/payment_start.rs +++ b/crates/router/src/core/payments/operations/payment_start.rs @@ -40,7 +40,7 @@ impl GetTracker, api::PaymentsStartRequest> f merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse<'a, F, api::PaymentsStartRequest, PaymentData>, > { @@ -224,7 +224,7 @@ impl UpdateTracker, api::PaymentsStartRequest> for P _updated_customer: Option, _mechant_key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentSessionOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payment_status.rs b/crates/router/src/core/payments/operations/payment_status.rs index 47f16786ab9..a3a826ccd0e 100644 --- a/crates/router/src/core/payments/operations/payment_status.rs +++ b/crates/router/src/core/payments/operations/payment_status.rs @@ -148,7 +148,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( PaymentStatusOperation<'b, F, api::PaymentsRequest>, PaymentData, @@ -172,7 +172,7 @@ impl UpdateTracker, api::PaymentsRetrieveRequest> fo _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( PaymentStatusOperation<'b, F, api::PaymentsRetrieveRequest>, PaymentData, @@ -197,7 +197,7 @@ impl GetTracker, api::PaymentsRetrieveRequest merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse<'a, F, api::PaymentsRetrieveRequest, PaymentData>, > { diff --git a/crates/router/src/core/payments/operations/payment_update.rs b/crates/router/src/core/payments/operations/payment_update.rs index c1eae806ce0..757370f0c95 100644 --- a/crates/router/src/core/payments/operations/payment_update.rs +++ b/crates/router/src/core/payments/operations/payment_update.rs @@ -54,7 +54,7 @@ impl GetTracker, api::PaymentsRequest> for Pa merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult>> { let (mut payment_intent, mut payment_attempt, currency): (_, _, storage_enums::Currency); @@ -695,7 +695,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _updated_customer: Option, _key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentUpdateOperation<'b, F>, PaymentData)> where F: 'b + Send, @@ -715,7 +715,7 @@ impl UpdateTracker, api::PaymentsRequest> for Paymen _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentUpdateOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs index 9d80206b9f2..1ddaf0b6abf 100644 --- a/crates/router/src/core/payments/operations/payments_incremental_authorization.rs +++ b/crates/router/src/core/payments/operations/payments_incremental_authorization.rs @@ -47,7 +47,7 @@ impl merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse< 'a, @@ -200,7 +200,7 @@ impl UpdateTracker, PaymentsIncrementalAut _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<( PaymentIncrementalAuthorizationOperation<'b, F>, payments::PaymentData, diff --git a/crates/router/src/core/payments/operations/tax_calculation.rs b/crates/router/src/core/payments/operations/tax_calculation.rs index c72dcb6f561..2d4054a60be 100644 --- a/crates/router/src/core/payments/operations/tax_calculation.rs +++ b/crates/router/src/core/payments/operations/tax_calculation.rs @@ -48,7 +48,7 @@ impl GetTracker, api::PaymentsDynamicTaxCalcu merchant_account: &domain::MerchantAccount, key_store: &domain::MerchantKeyStore, _auth_flow: services::AuthFlow, - _header_payload: &api::HeaderPayload, + _header_payload: &hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult< operations::GetTrackerResponse< 'a, @@ -378,7 +378,7 @@ impl UpdateTracker, api::PaymentsDynamicTaxCalculati _updated_customer: Option, key_store: &domain::MerchantKeyStore, _frm_suggestion: Option, - _header_payload: api::HeaderPayload, + _header_payload: hyperswitch_domain_models::payments::HeaderPayload, ) -> RouterResult<(PaymentSessionUpdateOperation<'b, F>, PaymentData)> where F: 'b + Send, diff --git a/crates/router/src/core/payments/retry.rs b/crates/router/src/core/payments/retry.rs index e4b6d0e287c..060e93474b4 100644 --- a/crates/router/src/core/payments/retry.rs +++ b/crates/router/src/core/payments/retry.rs @@ -70,10 +70,19 @@ where .clone() .map(|gsm| gsm.step_up_possible) .unwrap_or(false); + + #[cfg(feature = "v1")] let is_no_three_ds_payment = matches!( payment_data.get_payment_attempt().authentication_type, Some(storage_enums::AuthenticationType::NoThreeDs) ); + + #[cfg(feature = "v2")] + let is_no_three_ds_payment = matches!( + payment_data.get_payment_attempt().authentication_type, + storage_enums::AuthenticationType::NoThreeDs + ); + let should_step_up = if step_up_possible && is_no_three_ds_payment { is_step_up_enabled_for_merchant_connector( state, @@ -338,7 +347,7 @@ where payments::CallConnectorAction::Trigger, validate_result, schedule_time, - api::HeaderPayload::default(), + hyperswitch_domain_models::payments::HeaderPayload::default(), frm_suggestion, business_profile, true, diff --git a/crates/router/src/core/payments/routing.rs b/crates/router/src/core/payments/routing.rs index af540c6dcf6..11908ae0d99 100644 --- a/crates/router/src/core/payments/routing.rs +++ b/crates/router/src/core/payments/routing.rs @@ -826,6 +826,16 @@ pub async fn perform_eligibility_analysis_with_fallback( Ok(final_selection) } +#[cfg(feature = "v2")] +pub async fn perform_session_flow_routing( + session_input: SessionFlowRoutingInput<'_>, + transaction_type: &api_enums::TransactionType, +) -> RoutingResult>> +{ + todo!() +} + +#[cfg(feature = "v1")] pub async fn perform_session_flow_routing( session_input: SessionFlowRoutingInput<'_>, transaction_type: &api_enums::TransactionType, @@ -958,6 +968,7 @@ pub async fn perform_session_flow_routing( allowed_connectors, profile_id: &profile_id, }; + let routable_connector_choice_option = perform_session_routing_for_pm_type( &session_pm_input, transaction_type, diff --git a/crates/router/src/core/payments/transformers.rs b/crates/router/src/core/payments/transformers.rs index 03ae1c88008..58ea3b43462 100644 --- a/crates/router/src/core/payments/transformers.rs +++ b/crates/router/src/core/payments/transformers.rs @@ -16,6 +16,8 @@ use diesel_models::{ payment_attempt::ConnectorMandateReferenceId as DieselConnectorMandateReferenceId, }; use error_stack::{report, ResultExt}; +#[cfg(feature = "v2")] +use hyperswitch_domain_models::payments::PaymentConfirmData; use hyperswitch_domain_models::{payments::payment_intent::CustomerData, router_request_types}; use masking::{ExposeInterface, Maskable, PeekInterface, Secret}; use router_env::{instrument, metrics::add_attributes, tracing}; @@ -43,6 +45,27 @@ use crate::{ utils::{OptionExt, ValueExt}, }; +#[cfg(feature = "v2")] +pub async fn construct_router_data_to_update_calculated_tax<'a, F, T>( + state: &'a SessionState, + payment_data: PaymentData, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + customer: &'a Option, + merchant_connector_account: &helpers::MerchantConnectorAccountType, +) -> RouterResult> +where + T: TryFrom>, + types::RouterData: Feature, + F: Clone, + error_stack::Report: + From<>>::Error>, +{ + todo!() +} + +#[cfg(feature = "v1")] pub async fn construct_router_data_to_update_calculated_tax<'a, F, T>( state: &'a SessionState, payment_data: PaymentData, @@ -140,19 +163,215 @@ where Ok(router_data) } -#[cfg(all(feature = "v2", feature = "customer_v2"))] +#[cfg(feature = "v2")] #[instrument(skip_all)] #[allow(clippy::too_many_arguments)] -pub async fn construct_payment_router_data<'a, F, T>( - _state: &'a SessionState, - _payment_data: PaymentData, - _connector_id: &str, - _merchant_account: &domain::MerchantAccount, +pub async fn construct_payment_router_data_for_authorize<'a>( + state: &'a SessionState, + payment_data: PaymentConfirmData, + connector_id: &str, + merchant_account: &domain::MerchantAccount, _key_store: &domain::MerchantKeyStore, - _customer: &'a Option, - _merchant_connector_account: &helpers::MerchantConnectorAccountType, + customer: &'a Option, + merchant_connector_account: &helpers::MerchantConnectorAccountType, _merchant_recipient_data: Option, - _header_payload: Option, + header_payload: Option, +) -> RouterResult { + use masking::ExposeOptionInterface; + + fp_utils::when(merchant_connector_account.is_disabled(), || { + Err(errors::ApiErrorResponse::MerchantConnectorAccountDisabled) + })?; + + let auth_type: types::ConnectorAuthType = merchant_connector_account + .get_connector_account_details() + .parse_value("ConnectorAuthType") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Failed while parsing value for ConnectorAuthType")?; + + // TODO: Take Globalid and convert to connector reference id + let customer_id = customer + .to_owned() + .map(|customer| customer.id.clone()) + .map(std::borrow::Cow::Owned) + .map(common_utils::id_type::CustomerId::try_from) + .transpose() + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable( + "Invalid global customer generated, not able to convert to reference id", + )?; + + let payment_method = payment_data.payment_attempt.payment_method_type; + + let router_base_url = &state.base_url; + let attempt = &payment_data.payment_attempt; + + let complete_authorize_url = Some(helpers::create_complete_authorize_url( + router_base_url, + attempt, + connector_id, + )); + + let webhook_url = Some(helpers::create_webhook_url( + router_base_url, + &attempt.merchant_id, + connector_id, + )); + + let router_return_url = Some(helpers::create_redirect_url( + router_base_url, + attempt, + connector_id, + None, + )); + + let connector_request_reference_id = payment_data + .payment_intent + .merchant_reference_id + .map(|id| id.get_string_repr().to_owned()) + .unwrap_or(payment_data.payment_attempt.id.get_string_repr().to_owned()); + + // TODO: few fields are repeated in both routerdata and request + let request = types::PaymentsAuthorizeData { + payment_method_data: payment_data + .payment_method_data + .get_required_value("payment_method_data")?, + setup_future_usage: Some(payment_data.payment_intent.setup_future_usage), + mandate_id: None, + off_session: None, + setup_mandate_details: None, + confirm: true, + statement_descriptor_suffix: None, + statement_descriptor: None, + capture_method: Some(payment_data.payment_intent.capture_method), + amount: payment_data + .payment_attempt + .amount_details + .net_amount + .get_amount_as_i64(), + minor_amount: payment_data.payment_attempt.amount_details.net_amount, + currency: payment_data.payment_intent.amount_details.currency, + browser_info: None, + email: None, + customer_name: None, + payment_experience: None, + order_details: None, + order_category: None, + session_token: None, + enrolled_for_3ds: true, + related_transaction_id: None, + payment_method_type: Some(payment_data.payment_attempt.payment_method_subtype), + router_return_url, + webhook_url, + complete_authorize_url, + customer_id: None, + surcharge_details: None, + request_incremental_authorization: matches!( + payment_data + .payment_intent + .request_incremental_authorization, + RequestIncrementalAuthorization::True | RequestIncrementalAuthorization::Default + ), + metadata: payment_data.payment_intent.metadata.expose_option(), + authentication_data: None, + customer_acceptance: None, + charges: None, + merchant_order_reference_id: None, + integrity_object: None, + }; + + // TODO: evaluate the fields in router data, if they are required or not + let router_data = types::RouterData { + flow: PhantomData, + merchant_id: merchant_account.get_id().clone(), + // TODO: evaluate why we need customer id at the connector level. We already have connector customer id. + customer_id, + connector: connector_id.to_owned(), + // TODO: evaluate why we need payment id at the connector level. We already have connector reference id + payment_id: payment_data + .payment_attempt + .payment_id + .get_string_repr() + .to_owned(), + // TODO: evaluate why we need attempt id at the connector level. We already have connector reference id + attempt_id: payment_data + .payment_attempt + .get_id() + .get_string_repr() + .to_owned(), + status: payment_data.payment_attempt.status, + payment_method, + connector_auth_type: auth_type, + description: payment_data + .payment_intent + .description + .as_ref() + .map(|description| description.get_string_repr()) + .map(ToOwned::to_owned), + // TODO: evaluate why we need to send merchant's return url here + // This should be the return url of application, since application takes care of the redirection + return_url: payment_data + .payment_intent + .return_url + .as_ref() + .map(|description| description.get_string_repr()) + .map(ToOwned::to_owned), + // TODO: Create unified address + address: hyperswitch_domain_models::payment_address::PaymentAddress::default(), + auth_type: payment_data.payment_attempt.authentication_type, + connector_meta_data: None, + connector_wallets_details: None, + request, + response: Err(hyperswitch_domain_models::router_data::ErrorResponse::default()), + amount_captured: None, + minor_amount_captured: None, + access_token: None, + session_token: None, + reference_id: None, + payment_method_status: None, + payment_method_token: None, + connector_customer: None, + recurring_mandate_payment_data: None, + // TODO: This has to be generated as the reference id based on the connector configuration + // Some connectros might not accept accept the global id. This has to be done when generating the reference id + connector_request_reference_id, + preprocessing_id: payment_data.payment_attempt.preprocessing_step_id, + #[cfg(feature = "payouts")] + payout_method_data: None, + #[cfg(feature = "payouts")] + quote_id: None, + // TODO: take this based on the env + test_mode: Some(true), + payment_method_balance: None, + connector_api_version: None, + connector_http_status_code: None, + external_latency: None, + apple_pay_flow: None, + frm_metadata: None, + refund_id: None, + dispute_id: None, + connector_response: None, + integrity_check: Ok(()), + additional_merchant_data: None, + header_payload, + }; + + Ok(router_data) +} + +#[cfg(feature = "v2")] +#[instrument(skip_all)] +#[allow(clippy::too_many_arguments)] +pub async fn construct_payment_router_data<'a, F, T>( + state: &'a SessionState, + payment_data: PaymentData, + connector_id: &str, + merchant_account: &domain::MerchantAccount, + _key_store: &domain::MerchantKeyStore, + customer: &'a Option, + merchant_connector_account: &helpers::MerchantConnectorAccountType, + merchant_recipient_data: Option, + header_payload: Option, ) -> RouterResult> where T: TryFrom>, @@ -176,7 +395,7 @@ pub async fn construct_payment_router_data<'a, F, T>( customer: &'a Option, merchant_connector_account: &helpers::MerchantConnectorAccountType, merchant_recipient_data: Option, - header_payload: Option, + header_payload: Option, ) -> RouterResult> where T: TryFrom>, @@ -361,6 +580,7 @@ where Op: Debug, D: OperationSessionGetters, { + #[cfg(feature = "v1")] #[allow(clippy::too_many_arguments)] fn generate_response( data: D, @@ -373,8 +593,22 @@ where external_latency: Option, is_latency_header_enabled: Option, ) -> RouterResponse; + + #[cfg(feature = "v2")] + #[allow(clippy::too_many_arguments)] + fn generate_response( + data: D, + customer: Option, + base_url: &str, + operation: Op, + connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, + connector_http_status_code: Option, + external_latency: Option, + is_latency_header_enabled: Option, + ) -> RouterResponse; } +#[cfg(feature = "v1")] impl ToResponse for api::PaymentsResponse where F: Clone, @@ -530,7 +764,6 @@ where fn generate_response( payment_data: D, _customer: Option, - _auth_flow: services::AuthFlow, _base_url: &str, operation: Op, _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, @@ -542,7 +775,7 @@ where Ok(services::ApplicationResponse::JsonWithHeaders(( Self { id: payment_intent.id.clone(), - amount_details: api_models::payments::AmountDetails::foreign_from( + amount_details: api_models::payments::AmountDetailsResponse::foreign_from( payment_intent.amount_details.clone(), ), client_secret: payment_intent.client_secret.clone(), @@ -592,6 +825,75 @@ where } } +#[cfg(feature = "v2")] +impl ToResponse for api_models::payments::PaymentsConfirmIntentResponse +where + F: Clone, + Op: Debug, + D: OperationSessionGetters, +{ + #[allow(clippy::too_many_arguments)] + fn generate_response( + payment_data: D, + _customer: Option, + _base_url: &str, + operation: Op, + _connector_request_reference_id_config: &ConnectorRequestReferenceIdConfig, + _connector_http_status_code: Option, + _external_latency: Option, + _is_latency_header_enabled: Option, + ) -> RouterResponse { + let payment_intent = payment_data.get_payment_intent(); + let payment_attempt = payment_data.get_payment_attempt(); + + let amount = api_models::payments::ConfirmIntentAmountDetailsResponse::foreign_from(( + &payment_intent.amount_details, + &payment_attempt.amount_details, + )); + + let connector = payment_attempt + .connector + .clone() + .get_required_value("connector") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Connector is none when constructing response")?; + + let merchant_connector_id = payment_attempt + .merchant_connector_id + .clone() + .get_required_value("merchant_connector_id") + .change_context(errors::ApiErrorResponse::InternalServerError) + .attach_printable("Merchant connector id is none when constructing response")?; + + let error = payment_attempt + .error + .clone() + .map(api_models::payments::ErrorDetails::foreign_from); + + let response = Self { + id: payment_intent.id.clone(), + status: payment_intent.status, + amount, + connector, + client_secret: payment_intent.client_secret.clone(), + created: payment_intent.created_at, + payment_method_data: None, + payment_method_type: payment_attempt.payment_method_type, + payment_method_subtype: payment_attempt.payment_method_subtype, + connector_transaction_id: payment_attempt.connector_payment_id.clone(), + connector_reference_id: None, + merchant_connector_id, + browser_info: None, + error, + }; + + Ok(services::ApplicationResponse::JsonWithHeaders(( + response, + vec![], + ))) + } +} + #[cfg(feature = "v1")] impl ToResponse for api::PaymentsPostSessionTokensResponse where @@ -679,6 +981,7 @@ impl ForeignTryFrom<(MinorUnit, Option, Option, Currency)> } } +#[cfg(feature = "v1")] impl ToResponse for api::VerifyResponse where F: Clone, @@ -2004,13 +2307,35 @@ impl TryFrom> } impl ConnectorTransactionId for Helcim { + #[cfg(feature = "v1")] fn connector_transaction_id( &self, payment_attempt: storage::PaymentAttempt, ) -> Result, errors::ApiErrorResponse> { if payment_attempt.get_connector_payment_id().is_none() { let metadata = - Self::connector_transaction_id(self, &payment_attempt.connector_metadata); + Self::connector_transaction_id(self, payment_attempt.connector_metadata.as_ref()); + metadata.map_err(|_| errors::ApiErrorResponse::ResourceIdNotFound) + } else { + Ok(payment_attempt + .get_connector_payment_id() + .map(ToString::to_string)) + } + } + + #[cfg(feature = "v2")] + fn connector_transaction_id( + &self, + payment_attempt: storage::PaymentAttempt, + ) -> Result, errors::ApiErrorResponse> { + if payment_attempt.get_connector_payment_id().is_none() { + let metadata = Self::connector_transaction_id( + self, + payment_attempt + .connector_metadata + .as_ref() + .map(|connector_metadata| connector_metadata.peek()), + ); metadata.map_err(|_| errors::ApiErrorResponse::ResourceIdNotFound) } else { Ok(payment_attempt @@ -2021,11 +2346,28 @@ impl ConnectorTransactionId for Helcim { } impl ConnectorTransactionId for Nexinets { + #[cfg(feature = "v1")] fn connector_transaction_id( &self, payment_attempt: storage::PaymentAttempt, ) -> Result, errors::ApiErrorResponse> { - let metadata = Self::connector_transaction_id(self, &payment_attempt.connector_metadata); + let metadata = + Self::connector_transaction_id(self, payment_attempt.connector_metadata.as_ref()); + metadata.map_err(|_| errors::ApiErrorResponse::ResourceIdNotFound) + } + + #[cfg(feature = "v2")] + fn connector_transaction_id( + &self, + payment_attempt: storage::PaymentAttempt, + ) -> Result, errors::ApiErrorResponse> { + let metadata = Self::connector_transaction_id( + self, + payment_attempt + .connector_metadata + .as_ref() + .map(|connector_metadata| connector_metadata.peek()), + ); metadata.map_err(|_| errors::ApiErrorResponse::ResourceIdNotFound) } } @@ -2258,7 +2600,51 @@ impl TryFrom> for types::PaymentsSessionD type Error = error_stack::Report; fn try_from(additional_data: PaymentAdditionalData<'_, F>) -> Result { - todo!(); + let payment_data = additional_data.payment_data.clone(); + + let order_details = additional_data + .payment_data + .payment_intent + .order_details + .map(|order_details| { + order_details + .iter() + .map(|data| data.to_owned().expose()) + .collect() + }); + + let surcharge_amount = payment_data + .surcharge_details + .as_ref() + .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) + .unwrap_or_default(); + + let amount = payment_data.payment_intent.amount_details.order_amount; + + let shipping_cost = payment_data + .payment_intent + .amount_details + .shipping_cost + .unwrap_or_default(); + + // net_amount here would include amount, surcharge_amount and shipping_cost + let net_amount = amount + surcharge_amount + shipping_cost; + + Ok(Self { + amount: amount.get_amount_as_i64(), //need to change once we move to connector module + minor_amount: amount, + currency: payment_data.currency, + country: payment_data.address.get_payment_method_billing().and_then( + |billing_address| { + billing_address + .address + .as_ref() + .and_then(|address| address.country) + }, + ), + order_details, + surcharge_details: payment_data.surcharge_details, + }) } } @@ -2287,26 +2673,20 @@ impl TryFrom> for types::PaymentsSessionD .collect::, _>>() }) .transpose()?; + let surcharge_amount = payment_data .surcharge_details .as_ref() .map(|surcharge_details| surcharge_details.get_total_surcharge_amount()) .unwrap_or_default(); - #[cfg(feature = "v1")] + let amount = payment_data.payment_intent.amount; - #[cfg(feature = "v2")] - let amount = payment_data.payment_intent.amount_details.order_amount; - #[cfg(feature = "v1")] - let shipping_cost = payment_data - .payment_intent - .shipping_cost - .unwrap_or_default(); - #[cfg(feature = "v2")] + let shipping_cost = payment_data .payment_intent - .amount_details .shipping_cost .unwrap_or_default(); + // net_amount here would include amount, surcharge_amount and shipping_cost let net_amount = amount + surcharge_amount + shipping_cost; @@ -2638,42 +3018,73 @@ impl ForeignFrom for router_request_types::CustomerDetails { } } +/// The response amount details in the confirm intent response will have the combined fields from +/// intent amount details and attempt amount details. #[cfg(feature = "v2")] -impl ForeignFrom - for hyperswitch_domain_models::payments::AmountDetails +impl + ForeignFrom<( + &hyperswitch_domain_models::payments::AmountDetails, + &hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails, + )> for api_models::payments::ConfirmIntentAmountDetailsResponse { - fn foreign_from(amount_details: api_models::payments::AmountDetails) -> Self { + fn foreign_from( + (intent_amount_details, attempt_amount_details): ( + &hyperswitch_domain_models::payments::AmountDetails, + &hyperswitch_domain_models::payments::payment_attempt::AttemptAmountDetails, + ), + ) -> Self { Self { - order_amount: amount_details.order_amount().into(), - currency: amount_details.currency(), - shipping_cost: amount_details.shipping_cost(), - tax_details: amount_details.order_tax_amount().map(|order_tax_amount| { - diesel_models::TaxDetails { - default: Some(diesel_models::DefaultTax { order_tax_amount }), - payment_method_type: None, - } - }), - skip_external_tax_calculation: - hyperswitch_domain_models::payments::TaxCalculationOverride::foreign_from( - amount_details.skip_external_tax_calculation(), - ), - skip_surcharge_calculation: - hyperswitch_domain_models::payments::SurchargeCalculationOverride::foreign_from( - amount_details.skip_surcharge_calculation(), - ), - surcharge_amount: amount_details.surcharge_amount(), - tax_on_surcharge: amount_details.tax_on_surcharge(), + order_amount: intent_amount_details.order_amount, + currency: intent_amount_details.currency, + shipping_cost: attempt_amount_details.shipping_cost, + order_tax_amount: attempt_amount_details.order_tax_amount, + skip_external_tax_calculation: common_enums::TaxCalculationOverride::foreign_from( + intent_amount_details.skip_external_tax_calculation, + ), + skip_surcharge_calculation: common_enums::SurchargeCalculationOverride::foreign_from( + intent_amount_details.skip_surcharge_calculation, + ), + surcharge_amount: attempt_amount_details.surcharge_amount, + tax_on_surcharge: attempt_amount_details.tax_on_surcharge, + net_amount: attempt_amount_details.net_amount, + amount_to_capture: attempt_amount_details.amount_to_capture, + amount_capturable: attempt_amount_details.amount_capturable, + amount_captured: intent_amount_details.amount_captured, + } + } +} + +#[cfg(feature = "v2")] +impl ForeignFrom + for api_models::payments::ErrorDetails +{ + fn foreign_from( + amount_details: hyperswitch_domain_models::payments::payment_attempt::ErrorDetails, + ) -> Self { + let hyperswitch_domain_models::payments::payment_attempt::ErrorDetails { + code, + message, + reason, + unified_code, + unified_message, + } = amount_details; + + Self { + code, + message: reason.unwrap_or(message), + unified_code, + unified_message, } } } #[cfg(feature = "v2")] impl ForeignFrom - for api_models::payments::AmountDetails + for api_models::payments::AmountDetailsResponse { fn foreign_from(amount_details: hyperswitch_domain_models::payments::AmountDetails) -> Self { - Self::new(api_models::payments::AmountDetailsSetter { - order_amount: amount_details.order_amount.into(), + Self { + order_amount: amount_details.order_amount, currency: amount_details.currency, shipping_cost: amount_details.shipping_cost, order_tax_amount: amount_details.tax_details.and_then(|tax_details| { @@ -2687,7 +3098,7 @@ impl ForeignFrom ), surcharge_amount: amount_details.surcharge_amount, tax_on_surcharge: amount_details.tax_on_surcharge, - }) + } } } diff --git a/crates/router/src/core/pm_auth.rs b/crates/router/src/core/pm_auth.rs index 2c3f76c88a0..b8672ee79b4 100644 --- a/crates/router/src/core/pm_auth.rs +++ b/crates/router/src/core/pm_auth.rs @@ -51,7 +51,7 @@ pub async fn create_link_token( merchant_account: domain::MerchantAccount, key_store: domain::MerchantKeyStore, payload: api_models::pm_auth::LinkTokenCreateRequest, - headers: Option, + headers: Option, ) -> RouterResponse { let db = &*state.store; @@ -216,7 +216,7 @@ pub async fn create_link_token( _merchant_account: domain::MerchantAccount, _key_store: domain::MerchantKeyStore, _payload: api_models::pm_auth::LinkTokenCreateRequest, - _headers: Option, + _headers: Option, ) -> RouterResponse { todo!() } diff --git a/crates/router/src/core/user/sample_data.rs b/crates/router/src/core/user/sample_data.rs index 5058ad600e0..453b3edf00f 100644 --- a/crates/router/src/core/user/sample_data.rs +++ b/crates/router/src/core/user/sample_data.rs @@ -1,6 +1,6 @@ use api_models::user::sample_data::SampleDataRequest; use common_utils::errors::ReportSwitchExt; -use diesel_models::{user::sample_data::PaymentAttemptBatchNew, RefundNew}; +use diesel_models::RefundNew; use error_stack::ResultExt; use hyperswitch_domain_models::payments::PaymentIntent; @@ -41,7 +41,7 @@ pub async fn generate_sample_data_for_user( let (payment_intents, payment_attempts, refunds): ( Vec, - Vec, + Vec, Vec, ) = sample_data.into_iter().fold( (Vec::new(), Vec::new(), Vec::new()), diff --git a/crates/router/src/core/utils.rs b/crates/router/src/core/utils.rs index a6a9c36bfda..def86907911 100644 --- a/crates/router/src/core/utils.rs +++ b/crates/router/src/core/utils.rs @@ -290,7 +290,7 @@ pub async fn construct_refund_router_data<'a, F>( let webhook_url = Some(helpers::create_webhook_url( &state.base_url.clone(), merchant_account.get_id(), - &connector_id.to_string(), + connector_id, )); let test_mode: Option = merchant_connector_account.is_test_mode_on(); diff --git a/crates/router/src/core/webhooks/incoming.rs b/crates/router/src/core/webhooks/incoming.rs index 19670fc8ccb..66de5106e6f 100644 --- a/crates/router/src/core/webhooks/incoming.rs +++ b/crates/router/src/core/webhooks/incoming.rs @@ -3,13 +3,11 @@ use std::{str::FromStr, time::Instant}; use actix_web::FromRequest; #[cfg(feature = "payouts")] use api_models::payouts as payout_models; -use api_models::{ - payments::HeaderPayload, - webhooks::{self, WebhookResponseTracker}, -}; +use api_models::webhooks::{self, WebhookResponseTracker}; use common_utils::{errors::ReportSwitchExt, events::ApiEventsType}; use error_stack::{report, ResultExt}; use hyperswitch_domain_models::{ + payments::HeaderPayload, router_request_types::VerifyWebhookSourceRequestData, router_response_types::{VerifyWebhookSourceResponseData, VerifyWebhookStatus}, }; diff --git a/crates/router/src/db/kafka_store.rs b/crates/router/src/db/kafka_store.rs index 3ef9a2d0376..7ff580e37e1 100644 --- a/crates/router/src/db/kafka_store.rs +++ b/crates/router/src/db/kafka_store.rs @@ -1416,7 +1416,7 @@ impl PaymentAttemptInterface for KafkaStore { } #[cfg(feature = "v2")] - async fn update_payment_attempt_with_attempt_id( + async fn update_payment_attempt( &self, key_manager_state: &KeyManagerState, merchant_key_store: &domain::MerchantKeyStore, @@ -1426,7 +1426,7 @@ impl PaymentAttemptInterface for KafkaStore { ) -> CustomResult { let attempt = self .diesel_store - .update_payment_attempt_with_attempt_id( + .update_payment_attempt( key_manager_state, merchant_key_store, this.clone(), diff --git a/crates/router/src/db/user/sample_data.rs b/crates/router/src/db/user/sample_data.rs index 3add7b744d0..37007b13f28 100644 --- a/crates/router/src/db/user/sample_data.rs +++ b/crates/router/src/db/user/sample_data.rs @@ -1,10 +1,11 @@ use common_utils::types::keymanager::KeyManagerState; +#[cfg(feature = "v1")] +use diesel_models::user::sample_data::PaymentAttemptBatchNew; use diesel_models::{ dispute::{Dispute, DisputeNew}, errors::DatabaseError, query::user::sample_data as sample_data_queries, refund::{Refund, RefundNew}, - user::sample_data::PaymentAttemptBatchNew, }; use error_stack::{Report, ResultExt}; use futures::{future::try_join_all, FutureExt}; diff --git a/crates/router/src/lib.rs b/crates/router/src/lib.rs index ef30c99c006..0eff78d38b4 100644 --- a/crates/router/src/lib.rs +++ b/crates/router/src/lib.rs @@ -87,6 +87,7 @@ pub mod headers { pub const X_APP_ID: &str = "x-app-id"; pub const X_REDIRECT_URI: &str = "x-redirect-uri"; pub const X_TENANT_ID: &str = "x-tenant-id"; + pub const X_CLIENT_SECRET: &str = "X-Client-Secret"; pub const X_WP_API_VERSION: &str = "WP-Api-Version"; } diff --git a/crates/router/src/routes/app.rs b/crates/router/src/routes/app.rs index 274ed6a5cc0..33699ed266a 100644 --- a/crates/router/src/routes/app.rs +++ b/crates/router/src/routes/app.rs @@ -43,7 +43,7 @@ use super::payouts::*; ))] use super::pm_auth; #[cfg(feature = "oltp")] -use super::poll::retrieve_poll_status; +use super::poll; #[cfg(feature = "olap")] use super::routing; #[cfg(feature = "olap")] @@ -57,7 +57,7 @@ use super::{ #[cfg(feature = "v1")] use super::{apple_pay_certificates_migration, blocklist, payment_link, webhook_events}; #[cfg(any(feature = "olap", feature = "oltp"))] -use super::{configs::*, customers::*, payments::*}; +use super::{configs::*, customers::*, payments}; #[cfg(all(any(feature = "olap", feature = "oltp"), feature = "v1"))] use super::{mandates::*, refunds::*}; #[cfg(feature = "olap")] @@ -517,17 +517,21 @@ pub struct Payments; impl Payments { pub fn server(state: AppState) -> Scope { let mut route = web::scope("/v2/payments").app_data(web::Data::new(state)); - route = route - .service(web::resource("/create-intent").route(web::post().to(payments_create_intent))); - route = route - .service( - web::resource("/{payment_id}/saved_payment_methods") - .route(web::get().to(list_customer_payment_method_for_payment)), - ) - .service( - web::resource("/{payment_id}/create_external_sdk_tokens") - .route(web::post().to(payments_connector_session)), - ); + route = route.service( + web::resource("/create-intent").route(web::post().to(payments::payments_create_intent)), + ); + + route = route.service( + web::scope("/{payment_id}") + .service( + web::resource("/confirm-intent") + .route(web::post().to(payments::payment_confirm_intent)), + ) + .service( + web::resource("/create-external-sdk-tokens") + .route(web::post().to(payments::payments_connector_session)), + ), + ); route } @@ -543,106 +547,114 @@ impl Payments { route = route .service( web::resource("/list") - .route(web::get().to(payments_list)) - .route(web::post().to(payments_list_by_filter)), + .route(web::get().to(payments::payments_list)) + .route(web::post().to(payments::payments_list_by_filter)), ) .service( web::resource("/profile/list") - .route(web::get().to(profile_payments_list)) - .route(web::post().to(profile_payments_list_by_filter)), + .route(web::get().to(payments::profile_payments_list)) + .route(web::post().to(payments::profile_payments_list_by_filter)), + ) + .service( + web::resource("/filter") + .route(web::post().to(payments::get_filters_for_payments)), + ) + .service( + web::resource("/v2/filter").route(web::get().to(payments::get_payment_filters)), + ) + .service( + web::resource("/aggregate") + .route(web::get().to(payments::get_payments_aggregates)), ) - .service(web::resource("/filter").route(web::post().to(get_filters_for_payments))) - .service(web::resource("/v2/filter").route(web::get().to(get_payment_filters))) - .service(web::resource("/aggregate").route(web::get().to(get_payments_aggregates))) .service( web::resource("/profile/aggregate") - .route(web::get().to(get_payments_aggregates_profile)), + .route(web::get().to(payments::get_payments_aggregates_profile)), ) .service( web::resource("/v2/profile/filter") - .route(web::get().to(get_payment_filters_profile)), + .route(web::get().to(payments::get_payment_filters_profile)), ) .service( web::resource("/{payment_id}/manual-update") - .route(web::put().to(payments_manual_update)), + .route(web::put().to(payments::payments_manual_update)), ) } #[cfg(feature = "oltp")] { route = route - .service(web::resource("").route(web::post().to(payments_create))) + .service(web::resource("").route(web::post().to(payments::payments_create))) .service( web::resource("/session_tokens") - .route(web::post().to(payments_connector_session)), + .route(web::post().to(payments::payments_connector_session)), ) .service( web::resource("/sync") - .route(web::post().to(payments_retrieve_with_gateway_creds)), + .route(web::post().to(payments::payments_retrieve_with_gateway_creds)), ) .service( web::resource("/{payment_id}") - .route(web::get().to(payments_retrieve)) - .route(web::post().to(payments_update)), + .route(web::get().to(payments::payments_retrieve)) + .route(web::post().to(payments::payments_update)), ) .service( - web::resource("/{payment_id}/post_session_tokens").route(web::post().to(payments_post_session_tokens)), + web::resource("/{payment_id}/post_session_tokens").route(web::post().to(payments::payments_post_session_tokens)), ) .service( - web::resource("/{payment_id}/confirm").route(web::post().to(payments_confirm)), + web::resource("/{payment_id}/confirm").route(web::post().to(payments::payments_confirm)), ) .service( - web::resource("/{payment_id}/cancel").route(web::post().to(payments_cancel)), + web::resource("/{payment_id}/cancel").route(web::post().to(payments::payments_cancel)), ) .service( - web::resource("/{payment_id}/capture").route(web::post().to(payments_capture)), + web::resource("/{payment_id}/capture").route(web::post().to(payments::payments_capture)), ) .service( web::resource("/{payment_id}/approve") - .route(web::post().to(payments_approve)), + .route(web::post().to(payments::payments_approve)), ) .service( web::resource("/{payment_id}/reject") - .route(web::post().to(payments_reject)), + .route(web::post().to(payments::payments_reject)), ) .service( web::resource("/redirect/{payment_id}/{merchant_id}/{attempt_id}") - .route(web::get().to(payments_start)), + .route(web::get().to(payments::payments_start)), ) .service( web::resource( "/{payment_id}/{merchant_id}/redirect/response/{connector}/{creds_identifier}", ) - .route(web::get().to(payments_redirect_response_with_creds_identifier)), + .route(web::get().to(payments::payments_redirect_response_with_creds_identifier)), ) .service( web::resource("/{payment_id}/{merchant_id}/redirect/response/{connector}") - .route(web::get().to(payments_redirect_response)) - .route(web::post().to(payments_redirect_response)) + .route(web::get().to(payments::payments_redirect_response)) + .route(web::post().to(payments::payments_redirect_response)) ) .service( web::resource("/{payment_id}/{merchant_id}/redirect/complete/{connector}") - .route(web::get().to(payments_complete_authorize_redirect)) - .route(web::post().to(payments_complete_authorize_redirect)), + .route(web::get().to(payments::payments_complete_authorize_redirect)) + .route(web::post().to(payments::payments_complete_authorize_redirect)), ) .service( web::resource("/{payment_id}/complete_authorize") - .route(web::post().to(payments_complete_authorize)), + .route(web::post().to(payments::payments_complete_authorize)), ) .service( - web::resource("/{payment_id}/incremental_authorization").route(web::post().to(payments_incremental_authorization)), + web::resource("/{payment_id}/incremental_authorization").route(web::post().to(payments::payments_incremental_authorization)), ) .service( - web::resource("/{payment_id}/{merchant_id}/authorize/{connector}").route(web::post().to(post_3ds_payments_authorize)), + web::resource("/{payment_id}/{merchant_id}/authorize/{connector}").route(web::post().to(payments::post_3ds_payments_authorize)), ) .service( - web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments_external_authentication)), + web::resource("/{payment_id}/3ds/authentication").route(web::post().to(payments::payments_external_authentication)), ) .service( - web::resource("/{payment_id}/extended_card_info").route(web::get().to(retrieve_extended_card_info)), + web::resource("/{payment_id}/extended_card_info").route(web::get().to(payments::retrieve_extended_card_info)), ) .service( web::resource("{payment_id}/calculate_tax") - .route(web::post().to(payments_dynamic_tax_calculation)), + .route(web::post().to(payments::payments_dynamic_tax_calculation)), ); } route @@ -1455,12 +1467,14 @@ impl ApplePayCertificatesMigration { pub struct Poll; -#[cfg(feature = "oltp")] +#[cfg(all(feature = "oltp", feature = "v1"))] impl Poll { pub fn server(config: AppState) -> Scope { web::scope("/poll") .app_data(web::Data::new(config)) - .service(web::resource("/status/{poll_id}").route(web::get().to(retrieve_poll_status))) + .service( + web::resource("/status/{poll_id}").route(web::get().to(poll::retrieve_poll_status)), + ) } } diff --git a/crates/router/src/routes/lock_utils.rs b/crates/router/src/routes/lock_utils.rs index cb16d6e0505..a0c5c0f9902 100644 --- a/crates/router/src/routes/lock_utils.rs +++ b/crates/router/src/routes/lock_utils.rs @@ -137,6 +137,7 @@ impl From for ApiIdentifier { | Flow::PaymentsCompleteAuthorize | Flow::PaymentsManualUpdate | Flow::SessionUpdateTaxCalculation + | Flow::PaymentsConfirmIntent | Flow::PaymentsCreateIntent | Flow::PaymentsPostSessionTokens => Self::Payments, diff --git a/crates/router/src/routes/payments.rs b/crates/router/src/routes/payments.rs index eba1fa84c98..f13a873473a 100644 --- a/crates/router/src/routes/payments.rs +++ b/crates/router/src/routes/payments.rs @@ -5,9 +5,9 @@ use crate::{ pub mod helpers; use actix_web::{web, Responder}; -use api_models::payments::HeaderPayload; use common_enums::EntityType; use error_stack::report; +use hyperswitch_domain_models::payments::HeaderPayload; use masking::PeekInterface; use router_env::{env, instrument, logger, tracing, types, Flow}; @@ -138,9 +138,8 @@ pub async fn payments_create_intent( auth.merchant_account, auth.profile, auth.key_store, - payments::operations::PaymentCreateIntent, + payments::operations::PaymentIntentCreate, req, - api::AuthFlow::Client, header_payload.clone(), ) }, @@ -1978,3 +1977,125 @@ pub async fn get_payments_aggregates_profile( )) .await } + +#[cfg(feature = "v2")] +/// A private module to hold internal types to be used in route handlers. +/// This is because we will need to implement certain traits on these types which will have the resource id +/// But the api payload will not contain the resource id +/// So these types can hold the resource id along with actual api payload, on which api event and locking action traits can be implemented +mod internal_payload_types { + use super::*; + + // Serialize is implemented because of api events + #[derive(Debug, serde::Serialize)] + pub struct PaymentsGenericRequestWithResourceId { + pub global_payment_id: common_utils::id_type::GlobalPaymentId, + #[serde(flatten)] + pub payload: T, + } + + impl GetLockingInput for PaymentsGenericRequestWithResourceId { + fn get_locking_input(&self, flow: F) -> api_locking::LockAction + where + F: types::FlowMetric, + lock_utils::ApiIdentifier: From, + { + api_locking::LockAction::Hold { + input: api_locking::LockingInput { + unique_locking_key: self.global_payment_id.get_string_repr().to_owned(), + api_identifier: lock_utils::ApiIdentifier::from(flow), + override_lock_retries: None, + }, + } + } + } + + impl common_utils::events::ApiEventMetric + for PaymentsGenericRequestWithResourceId + { + fn get_api_event_type(&self) -> Option { + Some(common_utils::events::ApiEventsType::Payment { + payment_id: self.global_payment_id.clone(), + }) + } + } +} + +#[cfg(feature = "v2")] +#[instrument(skip_all, fields(flow = ?Flow::PaymentsConfirmIntent, payment_id))] +pub async fn payment_confirm_intent( + state: web::Data, + req: actix_web::HttpRequest, + json_payload: web::Json, + path: web::Path, +) -> impl Responder { + use hyperswitch_domain_models::payments::PaymentConfirmData; + + let flow = Flow::PaymentsConfirmIntent; + + // TODO: Populate browser information into the payload + // if let Err(err) = helpers::populate_ip_into_browser_info(&req, &mut payload) { + // return api::log_and_return_error_response(err); + // } + + let global_payment_id = path.into_inner(); + tracing::Span::current().record("payment_id", global_payment_id.get_string_repr()); + + let internal_payload = internal_payload_types::PaymentsGenericRequestWithResourceId { + global_payment_id, + payload: json_payload.into_inner(), + }; + + let header_payload = match HeaderPayload::foreign_try_from(req.headers()) { + Ok(headers) => headers, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; + + // TODO: handle client secret auth + // let (auth_type, auth_flow) = + // match auth::check_client_secret_and_get_auth(req.headers(), &payload) { + // Ok(auth) => auth, + // Err(e) => return api::log_and_return_error_response(e), + // }; + + let locking_action = internal_payload.get_locking_input(flow.clone()); + + Box::pin(api::server_wrap( + flow, + state, + &req, + internal_payload, + |state, auth: auth::AuthenticationDataV2, req, req_state| async { + let payment_id = req.global_payment_id; + let request = req.payload; + + let operation = payments::operations::PaymentIntentConfirm; + + Box::pin(payments::payments_core::< + api_types::Authorize, + api_models::payments::PaymentsConfirmIntentResponse, + _, + _, + _, + PaymentConfirmData, + >( + state, + req_state, + auth.merchant_account, + auth.profile, + auth.key_store, + operation, + request, + payment_id, + payments::CallConnectorAction::Trigger, + header_payload.clone(), + )) + .await + }, + &auth::PublishableKeyAuth, + locking_action, + )) + .await +} diff --git a/crates/router/src/routes/payments/helpers.rs b/crates/router/src/routes/payments/helpers.rs index 7ff3f1d11ad..5b0ef815b28 100644 --- a/crates/router/src/routes/payments/helpers.rs +++ b/crates/router/src/routes/payments/helpers.rs @@ -7,6 +7,7 @@ use crate::{ utils::{Encode, ValueExt}, }; +#[cfg(feature = "v1")] pub fn populate_ip_into_browser_info( req: &actix_web::HttpRequest, payload: &mut api::PaymentsRequest, diff --git a/crates/router/src/routes/pm_auth.rs b/crates/router/src/routes/pm_auth.rs index cc0ab02b556..31a2a0ba32e 100644 --- a/crates/router/src/routes/pm_auth.rs +++ b/crates/router/src/routes/pm_auth.rs @@ -22,12 +22,13 @@ pub async fn link_token_create( Err(e) => return api::log_and_return_error_response(e), }; - let header_payload = match api_types::payments::HeaderPayload::foreign_try_from(req.headers()) { - Ok(headers) => headers, - Err(err) => { - return api::log_and_return_error_response(err); - } - }; + let header_payload = + match hyperswitch_domain_models::payments::HeaderPayload::foreign_try_from(req.headers()) { + Ok(headers) => headers, + Err(err) => { + return api::log_and_return_error_response(err); + } + }; Box::pin(api::server_wrap( flow, diff --git a/crates/router/src/routes/poll.rs b/crates/router/src/routes/poll.rs index bbb2a9a63a3..aefda589219 100644 --- a/crates/router/src/routes/poll.rs +++ b/crates/router/src/routes/poll.rs @@ -8,6 +8,7 @@ use crate::{ types::api::PollId, }; +#[cfg(feature = "v1")] /// Poll - Retrieve Poll Status #[utoipa::path( get, diff --git a/crates/router/src/services/api.rs b/crates/router/src/services/api.rs index 0d84ba9c30f..6f6eb381669 100644 --- a/crates/router/src/services/api.rs +++ b/crates/router/src/services/api.rs @@ -1225,6 +1225,7 @@ pub trait Authenticate { } } +#[cfg(feature = "v1")] impl Authenticate for api_models::payments::PaymentsRequest { fn get_client_secret(&self) -> Option<&String> { self.client_secret.as_ref() @@ -1333,9 +1334,9 @@ pub fn build_redirection_form( } (PreEscaped(format!(r#"